summaryrefslogtreecommitdiff
path: root/rotord/src/rotor.h
diff options
context:
space:
mode:
Diffstat (limited to 'rotord/src/rotor.h')
-rw-r--r--rotord/src/rotor.h869
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 &image;
- }
- 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 &image;
- }
- 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 &image;
- }
- 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 &image;
-
- }
- 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;
- }
- 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 &image;
- }
- //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 &image;
- }
- 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 &image;
- }
- 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 &image;
- }
- //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 &image;
-
-
-
- }
- //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;