summaryrefslogtreecommitdiff
path: root/rotord/src/graph.cpp
blob: 8b85113c35fa90ae9ee284ce09454d5c83c19188 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "rotor.h"

using namespace Rotor;
const string Graph::toString(){
	string xmlgraph;
	if (loaded) {
		xml.copyXmlToString(xmlgraph);
		return xmlgraph;
	}
	else return "";
}
vector<Node*> Graph::find_nodes(const string &type){
	vector<Node*> found;
	for (std::unordered_map<string,Node*>::iterator it=nodes.begin();it!=nodes.end();++it) {
		if (it->second->type==type) found.push_back(it->second);
	}
	return found;
};
Node* Graph::find_node(const string &type){
	for (std::unordered_map<string,Node*>::iterator it=nodes.begin();it!=nodes.end();++it) {
		if (it->second->type==type) return it->second;
	}
	return nullptr; //can be tested against
};
bool Graph::signal_render(string &signal_xml,const float framerate) {
	if (find_node("signal_output")) {
		Signal_output *signal_output=dynamic_cast<Signal_output*>(find_node("signal_output"));
		return signal_output->render(duration,framerate,signal_xml);
	}
	cerr<<"Rotor: signal output node not found"<<endl;

	return false;
}
bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress) {
	vector<Node*> loaders=find_nodes("video_loader");
	for (auto i:loaders){
		if (!dynamic_cast<Video_loader*>(i)->isLoaded) {
			cerr<<"Rotor: all loaders must be populated before rendering"<<endl;
			return false;
		}
	}
	if (find_node("video_output")) {
		Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output"));
		return video_output->render(duration,framerate,output_filename,audio_filename,progress,outW,outH);
	}
	
	cerr<<"Rotor: video output node not found"<<endl;
	return false;
}
bool Graph::set_resolution(int w,int h){
	if (w>64&&h>48){
		outW=w;
		outH=h;
		return true;
	}
	else return false;
}
bool Graph::load(string data){
	if (xml.loadFromBuffer(data)){
		return parseXml();
	}
	return false;
}
bool Graph::loadFile(string &filename){
	loaded=false;
	printf("loading graph: %s\n",filename.c_str());
	if(xml.loadFile(filename) ){
		return parseXml();
	}
	else return false;
}
bool Graph::parseXml(){
	init(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0));
		if(xml.pushTag("patchbay")) {
			int n1=xml.getNumTags("node");
			for (int i1=0;i1<n1;i1++){
				map<string,string> settings;
				vector<string> attrs;
				xml.getAttributeNames("node",attrs,i1);
				for (auto& attr: attrs) {
					settings[attr]=xml.getAttribute("node",attr,"",i1);
					//cerr << "Got attribute: " << attr << ":" << xml.getAttribute("node",attr,"",i1) << endl;
				}
				settings["description"]=xml.getValue("node","",i1);
				Node* node=factory.create(settings);
				if (node) {
					string nodeID=xml.getAttribute("node","ID","",i1);
					if (nodes.find(nodeID)==nodes.end()){
						cerr << "Rotor: creating node '"<<nodeID<<"': '"<< xml.getAttribute("node","type","",i1) << "'" << endl;
						nodes[nodeID]=node;
						if(xml.pushTag("node",i1)) {
							int n2=xml.getNumTags("signal_input");
							for (int i2=0;i2<n2;i2++){
								nodes[nodeID]->create_signal_input(xml.getValue("signal_input","",i2));
								string fromID=xml.getAttribute("signal_input","from","",i2);
								if (nodes.find(fromID)!=nodes.end()) {
									if (!nodes[nodeID]->inputs[i2]->connect((Signal_node*)nodes[fromID])){
										cerr << "Rotor: graph loader cannot connect input " << i2 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
										return false;
									}
									else cerr << "Rotor: linked input " << i2 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
								}
								else cerr << "Rotor: linking input " << i2 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
							}
							int n3=xml.getNumTags("image_input");
							for (int i3=0;i3<n3;i3++){
								((Image_node*)nodes[nodeID])->create_image_input(xml.getValue("image_input","",i3));
								string fromID=xml.getAttribute("image_input","from","",i3);
								if (nodes.find(fromID)!=nodes.end()) {
									if (!(((Image_node*)nodes[nodeID])->image_inputs[i3]->connect((Image_node*)nodes[fromID]))){
										cerr << "Rotor: graph loader cannot connect image input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
										return false;
									}
									else cerr << "Rotor: linked image input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
								}
								else cerr << "Rotor: linking image input " << i3 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
							}
							int n4=xml.getNumTags("parameter_input");
							for (int i4=0;i4<n4;i4++){
								nodes[nodeID]->create_parameter_input(xml.getAttribute("parameter_input","parameter","",i4),xml.getValue("parameter_input","",i4));
								string fromID=xml.getAttribute("parameter_input","from","",i4);
								if (nodes.find(fromID)!=nodes.end()) {
									if (!nodes[nodeID]->parameter_inputs[i4]->connect(nodes[fromID])){
										cerr << "Rotor: graph loader cannot connect parameter input " << i4 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
										return false;
									}
									else cerr << "Rotor: linked parameter input " << i4 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
								}
								else cerr << "Rotor: linking parameter input " << i4 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
							}
							nodes[nodeID]->link_params();
							//extra key/value pairs that can be specific to sub-settings
							int n5=xml.getNumTags("parameter");
							for (int i5=0;i5<n5;i5++){
								nodes[nodeID]->set_parameter(xml.getAttribute("parameter","name","",i5),xml.getAttribute("parameter","value","",i5));
							}
							if (n5>0) cerr << "Rotor: found " << n5 << " extra parameters for node '" << nodeID << "'" << endl;
							
							xml.popTag();
						}
					}
					else cerr << "Rotor: duplicate node '"<<nodeID<<"' "<< endl;
				}
				else {
					cerr << "Rotor: graph loader cannot find node '" << xml.getAttribute("node","type","",i1) << "'" << endl;
					return false;
				}
			}
			xml.popTag();
		}
		loaded=true;
		return true;
}