diff options
Diffstat (limited to 'rotord/src/rotor.h')
| -rw-r--r-- | rotord/src/rotor.h | 869 |
1 files changed, 69 insertions, 800 deletions
diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h index ec9a193..0a81b36 100644 --- a/rotord/src/rotor.h +++ b/rotord/src/rotor.h @@ -7,6 +7,43 @@ Definitions of base classes and types for rotor rendering graph -------------------------*/ +/*------------------------ + +Aims + +-realtime, what does this entail? + + patchbay must be working + + incremental graph editing - examine new graph and make alterations + + window manager + + network stream? rtp? + + realtime architecture - maybe a tiny amount of buffering + + framerate limiting + +-undefined number of message types - a mssage is a pointer to a struct + +-documentation embedded in nodes + +-------------------------*/ + +/*------------------------ + +Requirements + +-stretch a video to fit a segment + + either use a signal as a playhead {seconds|stretched + + or deliver segment information with a signal + +-------------------------*/ + + #include <unordered_map> #include <deque> #include <math.h> @@ -290,126 +327,6 @@ namespace Rotor { int channels,bits,samples,rate; }; //actual nodes------------------------------------------------- - class Time: public Signal_node { - public: - Time(){ - title="Time"; - description="Outputs the time in seconds as a signal"; - UID="432b0d1e-2d09-11e3-a8b9-e3affcfd2b31"; - }; - Time(map<string,string> &settings): Time() { - base_settings(settings); - }; - Time* clone(map<string,string> &_settings) { return new Time(_settings);}; - const float output(const Time_spec &time) { - return time.time; - } - }; - class Track_time: public Signal_node { - public: - Track_time(){ - title="Track time"; - description="Outputs the fraction of the track as a signal"; - UID="5892933e-2d09-11e3-8f2e-47c1defdb1d7"; - }; - Track_time(map<string,string> &settings): Track_time() { - base_settings(settings); - }; - Track_time* clone(map<string,string> &_settings) { return new Track_time(_settings);}; - const float output(const Time_spec &time) { - return time.time/time.duration; - } - }; - class At_track_time: public Signal_node { - public: - At_track_time(){ - create_signal_input("signal","Signal Input"); - create_parameter("time","number","Track time to evaluate","Time",0.0f); - title="@Track time"; - description="Gets input from a different point in the track"; - UID="6a3edb9c-2d09-11e3-975c-df9df6d19f0a"; - }; - At_track_time(map<string,string> &settings): At_track_time() { - base_settings(settings); - }; - At_track_time* clone(map<string,string> &_settings) { return new At_track_time(_settings);}; - const float output(const Time_spec &time) { - Time_spec t=Time_spec(parameters["time"]->value*time.duration,time.framerate,time.duration); - return inputs[0]->get(t); - } - }; - class Signal_output: public Signal_node { - public: - Signal_output(){ - create_signal_input("signal","Signal Input"); - title="Signal output"; - description="Outputs a signal to xml for testing"; - UID="74773190-2d09-11e3-ae26-7f2bb9af632c"; - }; - Signal_output(map<string,string> &settings): Signal_output() { - base_settings(settings); - }; - Signal_output* clone(map<string,string> &_settings) { return new Signal_output(_settings);}; - bool render(const float duration, const float framerate,string &xml_out); - const float output(const Time_spec &time) { - return inputs[0]->get(time); - } - }; - class Testcard: public Image_node { - public: - Testcard(){ - //internal testing node only - }; - Testcard(map<string,string> &settings): Testcard() { - base_settings(settings); - }; - ~Testcard(){}; - Testcard* clone(map<string,string> &_settings) { return new Testcard(_settings);}; - Image *output(const Frame_spec &frame){ - float hs=(255.0f/frame.h); - for (int i=0;i<frame.h;i++){ - for (int j=0;j<frame.w;j++){ - image.RGBdata[(i*frame.w+j)*3]=(uint8_t)((int)((i+(frame.time*25.0f)*hs))%255); - image.RGBdata[((i*frame.w+j)*3)+1]=(uint8_t)((int)((j+(frame.time*100.0f)*hs))%255); - image.RGBdata[((i*frame.w+j)*3)+2]=(uint8_t)(0); - //image->Adata[i*frame.w+j]=(uint8_t)255; - //image->Zdata[i*frame.w+j]=(uint16_t)512; //1.0 in fixed point 8.8 bits - } - } - return ℑ - } - private: - - }; - class Invert: public Image_node { - public: - Invert(){ - create_image_input("Image to invert","Image input"); - create_parameter("invert","number","Invert when greater than 0.0","Negative",1.0f,0.0f,1.0f); - title="Negative"; - description="Inverts the input picture"; - UID="8676c25c-2d09-11e3-80a7-db36c774523c"; - }; - Invert(map<string,string> &settings) :Invert() { - base_settings(settings); - }; - ~Invert(){}; - Invert* clone(map<string,string> &_settings) { return new Invert(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in=image_inputs[0]->get(frame); - if (in) { - if (parameters["invert"]->value>0.0f){ - for (int i=0;i<in->w*in->h*3;i++) { - image.RGBdata[i]=255-in->RGBdata[i]; - } - return ℑ - } - return in; - } - return nullptr; - } - private: - }; #define CYCLER_cut 1 #define CYCLER_mix 2 #define CYCLER_abs 1 @@ -487,439 +404,6 @@ namespace Rotor { } Video_cycler* clone(map<string,string> &_settings) { return new Video_cycler(_settings);}; }; - class Signal_colour: public Image_node { - public: - Signal_colour(){ - create_signal_input("Selector","Selector input"); - create_attribute("palette","palette list of web colours","Colour palette","000000"); - title="Signal colour"; - description="Cycles through a palette of background colours according to selector signal"; - UID="a2183fe0-2d09-11e3-9a64-538ee2cf40bc"; - }; - Signal_colour(map<string,string> &settings):Signal_colour() { - base_settings(settings); - for (int i=0;i<attributes["palette"]->value.size()/6;i++){ - palette.push_back(Colour(attributes["palette"]->value.substr(i*6,6))); - } - prevcol=-1; - }; - ~Signal_colour(){}; - Image *output(const Frame_spec &frame){ - if (palette.size()) { - int col=((int)inputs[0]->get((Time_spec)frame))%palette.size(); - //if (col!=prevcol){ //how about when starting a new render? - for (int i=0;i<image.w*image.h;i++){ - image.RGBdata[i*3]=palette[col].r; - image.RGBdata[i*3+1]=palette[col].g; - image.RGBdata[i*3+2]=palette[col].b; - } - prevcol=col; - //} - return ℑ - } - return nullptr; - } - Signal_colour* clone(map<string,string> &_settings) { return new Signal_colour(_settings);}; - private: - vector<Rotor::Colour> palette; - int prevcol; - }; - class Signal_greyscale: public Image_node { - //Draws signal bars in greyscale - public: - Signal_greyscale(){ - create_signal_input("Signal","Signal input"); - title="Signal greyscale"; - description="Renders signal level as greyscale background"; - UID="ae91b8a0-2d09-11e3-aa7d-8b7f1ef1a439"; - }; - Signal_greyscale(map<string,string> &settings):Signal_greyscale() { - base_settings(settings); - prevcol=-1; - }; - ~Signal_greyscale(){}; - Image *output(const Frame_spec &frame){ - uint8_t col=((uint8_t)(inputs[0]->get((Time_spec)frame)*255.0f)); - if (col!=prevcol){ //how about when starting a new render? - for (int i=0;i<image.w*image.h*3;i++){ - image.RGBdata[i]=col; - } - prevcol=col; - } - return ℑ - - } - Signal_greyscale* clone(map<string,string> &_settings) { return new Signal_greyscale(_settings);}; - private: - uint8_t prevcol; - }; - #define ARITHMETIC_plus 1 - #define ARITHMETIC_minus 2 - #define ARITHMETIC_multiply 3 - #define ARITHMETIC_divide 4 - #define ARITHMETIC_modulo 5 - class Image_arithmetic: public Image_node { - public: - Image_arithmetic(){ - create_image_input("image input","Image input"); - create_parameter("value","number","Value or signal for operation","Value",1.0f); - create_attribute("operator","operator for image","Operator","+",{"+","-","*","/"}); - title="Image arithmetic"; - description="Performs arithmetic on an image with a signal or value"; - UID="bc3b633e-2d09-11e3-86b2-7fbba3d71604"; - }; - Image_arithmetic(map<string,string> &settings):Image_arithmetic() { - base_settings(settings); - } - ~Image_arithmetic(){}; - Image *output(const Frame_spec &frame){ - Image *in=image_inputs[0]->get(frame); - if (in){ - switch (attributes["operator"]->intVal) { - case ARITHMETIC_plus: - image=(*in); //could be poss without copy? - image+=parameters["value"]->value; - break; - case ARITHMETIC_minus: - image=(*in); - image-=parameters["value"]->value; - break; - case ARITHMETIC_multiply: - image=(*in); - image*=parameters["value"]->value; - break; - case ARITHMETIC_divide: - image=(*in); - image/=parameters["value"]->value; - break; - } - } - return ℑ - } - Image_arithmetic* clone(map<string,string> &_settings) { return new Image_arithmetic(_settings);}; - private: - }; - #define BLEND_blend 1 - #define BLEND_screen 2 - #define BLEND_multiply 3 - #define BLEND_alpha 4 - #define BLEND_wrap 5 - #define BLEND_xor 6 - class Blend: public Image_node { - public: - Blend(){ - create_image_input("image input 1","Image input 1"); - create_image_input("image input 2","Image input 2"); - create_parameter("amount","number","amount to blend input 2","Blend amount",0.5f,0.0f,1.0f); - create_attribute("mode","Blend mode","Blend mode","blend",{"blend","screen","multiply","alpha","wrap","xor"}); - title ="Blend"; - description="Blend images in various modes"; - UID="12ed7af0-2d0a-11e3-ae32-2b44203b93c9"; - }; - Blend(map<string,string> &settings):Blend() { - base_settings(settings); - }; - ~Blend(){}; - Blend* clone(map<string,string> &_settings) { return new Blend(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in1=image_inputs[0]->get(frame); - if (in1){ - Image *in2=image_inputs[1]->get(frame); - if (in2) { - image=*(in1); - switch(attributes["mode"]->intVal){ - case BLEND_screen: - image+=(*in2); - break; - case BLEND_multiply: - image*=(*in2); - break; - case BLEND_xor: - image^=(*in2); - break; - case BLEND_alpha: - image=image.alpha_blend(*in2); - break; - case BLEND_wrap: - image=image.add_wrap(*in2); - break; - case BLEND_blend: //has to be last because of initialser of *in? go figure - - image*=(1.0f-parameters["amount"]->value); - /* //problem here with leak - //opencv handles not being released - Image *in=(*in2)*parameters["amount"]->value; - image+=(*in); - delete in; - */ - in=(*in2); //removed allocator - in*=parameters["amount"]->value; - image+=in; - break; - } - return ℑ - } - //if there aren't 2 image inputs connected just return the first - return in1; - } - return nullptr; - } - private: - Image in; - }; - #define MIRROR_horiz 1 - #define MIRROR_vert 2 - #define MIRROR_horizR 3 - #define MIRROR_vertR 4 - class Mirror: public Image_node { - public: - Mirror(){ - create_image_input("image input","Image input"); - create_attribute("mode","Mirror mode","Mirror mode","horiz",{"horiz","vert","horizR","vertR"}); - title="Mirror"; - description="Mirror video across a central axis"; - UID="1fed5b26-2d0a-11e3-9901-4b5ea78a005d"; - }; - Mirror(map<string,string> &settings):Mirror() { - base_settings(settings); - }; - ~Mirror(){ }; - Mirror* clone(map<string,string> &_settings) { return new Mirror(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in=image_inputs[0]->get(frame); - if (in){ - //copy incoming image **writable - image=(*in); - //could be more efficient here by only copying once - switch (attributes["mode"]->intVal) { - case MIRROR_horiz: - for (int i=0;i<image.w/2;i++){ - for (int j=0;j<image.h;j++){ - for (int k=0;k<3;k++){ - image.RGBdata[(((j*image.w)+((image.w/2)+i))*3)+k]=image.RGBdata[(((j*image.w)+((image.w/2)-i))*3)+k]; - } - } - } - break; - case MIRROR_vert: - for (int i=0;i<image.w;i++){ - for (int j=0;j<image.h/2;j++){ - for (int k=0;k<3;k++){ - image.RGBdata[((((image.h/2+j)*image.w)+i)*3)+k]=image.RGBdata[((((image.h/2-j)*image.w)+i)*3)+k]; - } - } - } - break; - case MIRROR_horizR: - for (int i=0;i<image.w/2;i++){ - for (int j=0;j<image.h;j++){ - for (int k=0;k<3;k++){ - image.RGBdata[(((j*image.w)+((image.w/2)-i))*3)+k]=image.RGBdata[(((j*image.w)+((image.w/2)+i))*3)+k]; - } - } - } - break; - case MIRROR_vertR: - for (int i=0;i<image.w;i++){ - for (int j=0;j<image.h/2;j++){ - for (int k=0;k<3;k++){ - image.RGBdata[((((image.h/2-j)*image.w)+i)*3)+k]=image.RGBdata[((((image.h/2+j)*image.w)+i)*3)+k]; - } - } - } - break; - } - return ℑ - } - return nullptr; - } - private: - }; - class Monochrome: public Image_node { - public: - Monochrome(){ - create_image_input("image input","Image input"); - title="Monochrome"; - description="Render video greyscale"; - UID="2c3cb12e-2d0a-11e3-a46b-a34e44493cef"; - }; - Monochrome(map<string,string> &settings):Monochrome() { - base_settings(settings); - }; - ~Monochrome(){ - }; - Monochrome* clone(map<string,string> &_settings) { return new Monochrome(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in=image_inputs[0]->get(frame); - if (in){ - for (int i=0;i<image.w;i++){ - for (int j=0;j<image.h;j++){ - uint8_t luma=0; - for (int l=0;l<3;l++) luma+=pixels.mono_weights[l][in->RGBdata[(((j*image.w)+i)*3)+l]]; - for (int k=0;k<3;k++) image.RGBdata[(((j*image.w)+i)*3)+k]=luma; - } - } - return ℑ - } - return nullptr; - } - private: - }; - class Alpha_merge: public Image_node { - public: - Alpha_merge(){ - create_image_input("image input","Image input"); - create_image_input("alpha input","Alpha input"); - title="Alpha merge"; - description="Alpha merge two images"; - UID="3f5e3eee-2d0a-11e3-8679-1374154a9fa8"; - }; - Alpha_merge(map<string,string> &settings):Alpha_merge() { - base_settings(settings); - }; - ~Alpha_merge(){}; - Alpha_merge* clone(map<string,string> &_settings) { return new Alpha_merge(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in1=image_inputs[0]->get(frame); - if (in1){ - //copy incoming image **writable - Image *in2=image_inputs[1]->get(frame); - if (in2) { - image=(*in1); - image.alpha_merge(*in2); - return ℑ - } - //if there aren't 2 image inputs connected just return the first - return in1; - } - return nullptr; - } - private: - }; - class Difference_matte: public Image_node { - public: - Difference_matte(){ - create_image_input("image input","Image input"); - create_image_input("background input","Background input"); - create_parameter("threshold","number","Difference threshold","Threshold",0.2f,0.0f,1.0f); - create_parameter("feather","number","Feather width","Feather",0.1f,0.0f,1.0f); - create_parameter("weight_h","number","H component weight","Weight H",0.5f,0.0f,1.0f); - create_parameter("weight_s","number","S component weight","Weight S",0.5f,0.0f,1.0f); - create_parameter("weight_v","number","V component weight","Weight V",0.5f,0.0f,1.0f); - create_parameter("blursize","number","Blur size","Blur size",2.0f,0.0f,10.0f); - create_attribute("mode","Output {image|alpha}","output mode","alpha",{"image","alpha"}); - title="Difference matte"; - description="Create an alpha channel using a background reference picture"; - LUT=nullptr; - UID="4db4d2c8-2d0a-11e3-b08b-7fb00f8c562a"; - }; - Difference_matte(map<string,string> &settings):Difference_matte() { - base_settings(settings); - }; - ~Difference_matte(){if (LUT) delete[] LUT;}; - Difference_matte* clone(map<string,string> &_settings) { return new Difference_matte(_settings);}; - Image *output(const Frame_spec &frame){ - Image *in1=image_inputs[0]->get(frame); - if (in1){ - Image *in2=image_inputs[1]->get(frame); - if (in2) { - generate_LUT(); - - /* - cv::cvtColor(in1->rgb,greyfg,CV_RGB2GRAY); - cv::cvtColor(in2->rgb,greybg,CV_RGB2GRAY); - cv::absdiff(greyfg,greybg,greyDiff); - - //parameters["threshold"]->value - cv::threshold(greyDiff,mask,parameters["threshold"]->value,255,CV_THRESH_BINARY); //int block_size=3, double param1=5); //int blockSize, int offset=0,bool invert=false, bool gauss=false); - - //cv::adaptiveThreshold(greyDiff,mask,255,CV_ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY, 3,5); //int block_size=3, double param1=5); //int blockSize, int offset=0,bool invert=false, bool gauss=false); - */ - - cv::cvtColor(in1->rgb, hsv1, CV_RGB2HSV); - cv::cvtColor(in2->rgb, hsv2, CV_RGB2HSV); - - mask.create(frame.h,frame.w,CV_8UC1); - lutmask.create(frame.h,frame.w,CV_8UC1); - - //get euclidean distance in HSV space - int dist,d; - uint8_t m; - - float weights[3] = {parameters["weight_h"]->value,parameters["weight_s"]->value,parameters["weight_v"]->value}; - float weight_total=255.0f/pow(pow(weights[0]*255,2)+pow(weights[1]*255,2)+pow(weights[2]*255,2),0.5); - - for (int i=0;i<frame.w*frame.h;i++){ - dist=0; - for (int j=0;j<3;j++){ - d=((int)hsv1.data[i*3+j])-((int)hsv2.data[i*3+j]); - dist+=(d*d)*weights[j]; - } - uint8_t id=(uint8_t)(sqrt((float)dist)*weight_total); - mask.data[i]=id; - } - - /* - - for (int i=0;i<frame.w*frame.h;i++){ - dist=0; - for (int j=0;j<3;j++){ - d=((int)hsv1.data[i*3+j])-((int)hsv2.data[i*3+j]); - dist+=(abs(d))*weights[j]; - } - uint8_t id=(uint8_t)(((float)dist)/weight_total); - m=LUT[id]; - mask.data[i]=m; - } - */ - - //cv::bilateralFilter(mask,filtmask, 4,8,2 ); - //cv::GaussianBlur(mask,filtmask,cv::Size( 4, 4 ), 2, 2); - - int ksize=max((ceil(parameters["blursize"]->value/2.0)*2)+1,1.0); - //nb this doesn't do the intended: create 'continuously variable' blur - cv::GaussianBlur(mask,filtmask,cvSize(ksize,ksize),parameters["blursize"]->value); - - - for (int i=0;i<frame.w*frame.h;i++){ - lutmask.data[i]=LUT[filtmask.data[i]]; - } - - - image=(*in1); - if (attributes["mode"]->value=="image"){ - cv::cvtColor(lutmask, image.rgb, CV_GRAY2RGB); - } - else image.alpha_from_cv(lutmask); - return ℑ - - - - } - //if there aren't 2 image inputs connected just return the first - return in1; - } - return nullptr; - } - void generate_LUT(){ - //can check here if anything has changed - //cerr<<"generating LUT: threshold "<<parameters["threshold"]->value<<", feather "<<parameters["feather"]->value<<endl; - if (LUT) delete[] LUT; - LUT=new uint8_t[256]; - float fltmax=(255.0f/256.0f); - float minf=max(0.0f,parameters["threshold"]->value-(parameters["feather"]->value*0.5f)); - float maxf=min(1.0f,parameters["threshold"]->value+(parameters["feather"]->value*0.5f)); - for (int i=0;i<256;i++){ - LUT[i]=(uint8_t)(min(1.0f,max(0.0f,((((float)i)/255.0f)-minf)/(maxf-minf)))*255.0f); - // cerr<<((int)LUT[i])<<" "; - } - //cerr<<endl; - } - private: - cv::Mat greyfg,greybg,greyDiff,mask,filtmask,lutmask; - cv::Mat hsv1,hsv2; - uint8_t *LUT; - }; #define VIDEOFRAMES_frame 1 #define VIDEOFRAMES_blend 2 #define VIDEOTIME_play 1 @@ -930,6 +414,10 @@ namespace Rotor { class Video_loader: public Image_node { public: Video_loader(){ + create_signal_input("playhead","Playhead"); + //floating point control of playback time + //if signal is connected it overrides normal playback + //time_mode dictates whether control is seconds, or duration create_parameter("speed","number","video playback speed","Speed",1.0f,0.0f,0.0f); create_parameter("framerate","number","framerate override","Frame rate",0.0f,0.0f,0.0f); create_attribute("filename","name of video file to load","File name",""); @@ -972,13 +460,28 @@ namespace Rotor { float clipframerate=(parameters["framerate"]->value==0.0f?player.get_framerate():parameters["framerate"]->value); float clipspeed=(clipframerate/frame.framerate)*parameters["speed"]->value; float wanted; - switch (attributes["frame_mode"]->intVal){ - case VIDEOTIME_play: - wanted=fmod(frame.time*frame.framerate*clipspeed,(float)player.get_number_frames()); - break; - case VIDEOTIME_stretch: - wanted=fmod((frame.time/frame.duration)*((float)player.get_number_frames())*clipspeed,(float)player.get_number_frames()); - break; + if (inputs[0]->connection) { + //using playhead + //should speed affect it? + //if you want absolute control then you just want absolute control? + switch (attributes["frame_mode"]->intVal){ + case VIDEOTIME_play: + wanted=fmod(inputs[0]->get((Time_spec)frame)*frame.framerate*clipspeed,(float)player.get_number_frames()); + break; + case VIDEOTIME_stretch: + wanted=fmod(fmod(inputs[0]->get((Time_spec)frame),1.0f)*((float)player.get_number_frames())*clipspeed,(float)player.get_number_frames()); + break; + } + } + else { + switch (attributes["frame_mode"]->intVal){ + case VIDEOTIME_play: + wanted=fmod(frame.time*frame.framerate*clipspeed,(float)player.get_number_frames()); + break; + case VIDEOTIME_stretch: + wanted=fmod((frame.time/frame.duration)*((float)player.get_number_frames())*clipspeed,(float)player.get_number_frames()); + break; + } } if (attributes["frame_mode"]->intVal==VIDEOFRAMES_blend){ if (((int)wanted)!=lastframe){ @@ -1158,246 +661,12 @@ namespace Rotor { } return NULL; }; - bool list_node(const string &t,xmlIO XML){ - for (auto& type: type_map) { - if (type.first==t) { - list_node(type.second,XML); - return true; - } - } - XML.addValue("error","Node /"+t+"/ not found"); - }; - void list_node(Rotor::Node* type,xmlIO XML,int i=0){ - XML.addTag("node"); - XML.addAttribute("node","type",type->type,i); - XML.addAttribute("node","inputs",type->duplicate_inputs?"expandable":"fixed",i); - XML.addAttribute("node","title",type->title,i); - XML.addAttribute("node","description",type->description,i); - XML.addAttribute("node","UID",type->UID,i); - if (dynamic_cast<Signal_node*> (type)!=nullptr) XML.addAttribute("node","output","signal",i); - if (dynamic_cast<Image_node*> (type)!=nullptr) XML.addAttribute("node","output","image",i); - XML.pushTag("node",i); - //if (type->description!="") { - // XML.addTag("description"); - // XML.setValue("description",type->description,0); - //} - int j=0; - for (auto& input: type->inputs) { - XML.addTag("signal_input"); - XML.addAttribute("signal_input","title",input->title,j); - XML.addAttribute("signal_input","description",input->description,j); - j++; - } - j=0; - if (dynamic_cast<Image_node*> (type)!=nullptr) { - for (auto& input: (dynamic_cast<Image_node*>(type))->image_inputs) { - XML.addTag("image_input"); - XML.addAttribute("image_input","title",input->title,j); - XML.addAttribute("image_input","description",input->description,j); - j++; - } - } - j=0; - for (auto& parameter: type->parameters) { - XML.addTag("parameter"); - XML.addAttribute("parameter","name",parameter.first,j); - XML.addAttribute("parameter","type",parameter.second->type,j); - XML.addAttribute("parameter","title",parameter.second->title,j); - XML.addAttribute("parameter","description",parameter.second->description,j); - XML.addAttribute("parameter","value",parameter.second->value,j); - XML.addAttribute("parameter","min",parameter.second->min,j); - XML.addAttribute("parameter","max",parameter.second->max,j); - j++; - } - j=0; - for (auto& attribute: type->attributes) { - XML.addTag("attribute"); - XML.addAttribute("attribute","name",attribute.first,j); - XML.addAttribute("attribute","title",attribute.second->title,j); - XML.addAttribute("attribute","description",attribute.second->description,j); - XML.addAttribute("attribute","value",attribute.second->value,j); - if (attribute.second->vals.size()){ //document attribute enumeration - XML.addAttribute("attribute","type","enum",j); - XML.pushTag("attribute",j); - int k=0; - for (auto val: attribute.second->vals){ - XML.addTag("option"); - XML.addAttribute("option","value",val,k); - k++; - } - XML.popTag(); - } - else XML.addAttribute("attribute","type","string",j); - j++; - } - XML.popTag(); - } - void list_nodes(xmlIO XML){ - int i=0; - for (auto& type: type_map) { - if (type.second->description!="") { //blank description = internal/ testing node - list_node(type.second,XML,i); - i++; - } - } - } - void list_categories(xmlIO XML){ - int i=0; - for (auto& category: categories) { - XML.addTag("category"); - XML.addAttribute("category","name",category.first,i); - XML.pushTag("category",i); - int j=0; - for (auto& node: category.second){ - list_node(node,XML,j); - j++; - } - XML.popTag(); - i++; - } - } - void list_categories(Json::Value &JSON){ - JSON["categories"]=Json::arrayValue; - for (auto& _category: categories) { - Json::Value category; - category["name"]=_category.first; - category["nodes"]=Json::arrayValue; - for (auto& _node: _category.second){ - Json::Value node; - node["type"]=_node->type; - node["title"]=_node->title; - node["inputs"]=_node->duplicate_inputs?"expandable":"fixed"; - if (dynamic_cast<Signal_node*> (_node)!=nullptr) node["output"]="signal"; - if (dynamic_cast<Image_node*> (_node)!=nullptr) node["output"]="image"; - node["description"]=_node->description; - node["UID"]=_node->UID; - if (_node->inputs.size()){ - node["signal_inputs"]=Json::arrayValue; - for (auto& input: _node->inputs) { - Json::Value signal_input; - signal_input["title"]=input->title; - signal_input["description"]=input->description; - node["signal_inputs"].append(signal_input); - } - } - if (dynamic_cast<Image_node*> (_node)!=nullptr) { - if ((dynamic_cast<Image_node*>(_node))->image_inputs.size()){ - node["image_inputs"]=Json::arrayValue; - for (auto& input: (dynamic_cast<Image_node*>(_node))->image_inputs) { - Json::Value image_input; - image_input["title"]=input->title; - image_input["description"]=input->description; - node["image_inputs"].append(image_input); - } - } - } - if (_node->parameters.size()){ - node["parameters"]=Json::arrayValue; - for (auto& param: _node->parameters) { - Json::Value parameter; - parameter["name"]=param.first; - parameter["type"]=param.second->type; - parameter["title"]=param.second->title; - parameter["description"]=param.second->description; - parameter["value"]=param.second->value; - parameter["min"]=param.second->min; - parameter["max"]=param.second->max; - node["parameters"].append(parameter); - } - } - if (_node->attributes.size()){ - node["attributes"]=Json::arrayValue; - for (auto& attr: _node->attributes) { - Json::Value attribute; - attribute["name"]=attr.first; - attribute["title"]=attr.second->title; - attribute["description"]=attr.second->description; - attribute["value"]=attr.second->value; - if (attr.second->vals.size()){ //document attribute enumeration - attribute["type"]="enum"; - attribute["options"]=Json::arrayValue; - for (auto val: attr.second->vals){ - attribute["options"].append(val); - } - } - else attribute["type"]="string"; - node["attributes"].append(attribute); - } - } - category["nodes"].append(node); - } - JSON["categories"].append(category); - } - } - void list_nodes(Json::Value &JSON){ - JSON["nodeslist"]=Json::arrayValue; - for (auto& type: type_map) { - if (type.second->description!="") { //blank description = internal/ testing node - Json::Value node; - node["type"]=type.first; - node["title"]=type.second->title; - node["inputs"]=type.second->duplicate_inputs?"expandable":"fixed"; - if (dynamic_cast<Signal_node*> (type.second)!=nullptr) node["output"]="signal"; - if (dynamic_cast<Image_node*> (type.second)!=nullptr) node["output"]="image"; - node["description"]=type.second->description; - node["UID"]=type.second->UID; - if (type.second->inputs.size()){ - node["signal_inputs"]=Json::arrayValue; - for (auto& input: type.second->inputs) { - Json::Value signal_input; - signal_input["title"]=input->title; - signal_input["description"]=input->description; - node["signal_inputs"].append(signal_input); - } - } - if (dynamic_cast<Image_node*> (type.second)!=nullptr) { - if ((dynamic_cast<Image_node*>(type.second))->image_inputs.size()){ - node["image_inputs"]=Json::arrayValue; - for (auto& input: (dynamic_cast<Image_node*>(type.second))->image_inputs) { - Json::Value image_input; - image_input["title"]=input->title; - image_input["description"]=input->description; - node["image_inputs"].append(image_input); - } - } - } - if (type.second->parameters.size()){ - node["parameters"]=Json::arrayValue; - for (auto& param: type.second->parameters) { - Json::Value parameter; - parameter["name"]=param.first; - parameter["type"]=param.second->type; - parameter["title"]=param.second->title; - parameter["description"]=param.second->description; - parameter["value"]=param.second->value; - parameter["min"]=param.second->min; - parameter["max"]=param.second->max; - node["parameters"].append(parameter); - } - } - if (type.second->attributes.size()){ - node["attributes"]=Json::arrayValue; - for (auto& attr: type.second->attributes) { - Json::Value attribute; - attribute["name"]=attr.first; - attribute["title"]=attr.second->title; - attribute["description"]=attr.second->description; - attribute["value"]=attr.second->value; - if (attr.second->vals.size()){ //document attribute enumeration - attribute["type"]="enum"; - attribute["options"]=Json::arrayValue; - for (auto val: attr.second->vals){ - attribute["options"].append(val); - } - } - else attribute["type"]="string"; - node["attributes"].append(attribute); - } - } - JSON["nodeslist"].append(node); - } - } - } + bool list_node(const string &t,xmlIO XML); + void list_node(Rotor::Node* type,xmlIO XML,int i=0); + void list_nodes(xmlIO XML); + void list_nodes(Json::Value &JSON); + void list_categories(xmlIO XML); + void list_categories(Json::Value &JSON); private: unordered_map<string,Node*> type_map; unordered_map<string,vector<Rotor::Node*> > categories; |
