rev |
line source |
nuclear@19
|
1 #include <stdio.h>
|
nuclear@19
|
2 #include <stdlib.h>
|
nuclear@19
|
3 #include <string.h>
|
nuclear@4
|
4 #include "scene.h"
|
nuclear@19
|
5 #include "snode.h"
|
nuclear@19
|
6 #include "object.h"
|
nuclear@19
|
7 #include "geomobj.h"
|
nuclear@4
|
8
|
nuclear@8
|
9 // default enviromental parameters
|
nuclear@8
|
10 Environment::Environment()
|
nuclear@19
|
11 : bgcolor(0.01, 0.01, 0.01), ambient(0.01, 0.01, 0.01)
|
nuclear@8
|
12 {
|
nuclear@8
|
13 }
|
nuclear@8
|
14
|
nuclear@4
|
15 Scene::Scene()
|
nuclear@4
|
16 {
|
nuclear@4
|
17 active_cam = 0;
|
nuclear@4
|
18 root = new SceneNode;
|
nuclear@4
|
19 }
|
nuclear@4
|
20
|
nuclear@4
|
21 Scene::~Scene()
|
nuclear@4
|
22 {
|
nuclear@40
|
23 clear();
|
nuclear@40
|
24 }
|
nuclear@40
|
25
|
nuclear@40
|
26 void Scene::clear()
|
nuclear@40
|
27 {
|
nuclear@4
|
28 for(auto obj : objects) {
|
nuclear@4
|
29 delete obj;
|
nuclear@4
|
30 }
|
nuclear@40
|
31 objects.clear();
|
nuclear@40
|
32
|
nuclear@4
|
33 for(auto node : nodes) {
|
nuclear@4
|
34 delete node;
|
nuclear@4
|
35 }
|
nuclear@40
|
36 nodes.clear();
|
nuclear@40
|
37
|
nuclear@4
|
38 delete root;
|
nuclear@40
|
39 root = 0;
|
nuclear@40
|
40
|
nuclear@40
|
41 active_cam = 0;
|
nuclear@4
|
42 }
|
nuclear@4
|
43
|
nuclear@8
|
44 void Scene::set_env(const Environment &env)
|
nuclear@8
|
45 {
|
nuclear@8
|
46 this->env = env;
|
nuclear@8
|
47 }
|
nuclear@8
|
48
|
nuclear@8
|
49 Environment &Scene::get_env()
|
nuclear@8
|
50 {
|
nuclear@8
|
51 return env;
|
nuclear@8
|
52 }
|
nuclear@8
|
53
|
nuclear@8
|
54 const Environment &Scene::get_env() const
|
nuclear@8
|
55 {
|
nuclear@8
|
56 return env;
|
nuclear@8
|
57 }
|
nuclear@8
|
58
|
nuclear@8
|
59 Color Scene::get_env_color() const
|
nuclear@8
|
60 {
|
nuclear@8
|
61 return env.bgcolor;
|
nuclear@8
|
62 }
|
nuclear@8
|
63
|
nuclear@8
|
64 Color Scene::get_env_color(const Ray &ray) const
|
nuclear@8
|
65 {
|
nuclear@8
|
66 // TODO
|
nuclear@8
|
67 return get_env_color();
|
nuclear@8
|
68 }
|
nuclear@8
|
69
|
nuclear@4
|
70 void Scene::add_object(Object *obj)
|
nuclear@4
|
71 {
|
nuclear@4
|
72 objects.push_back(obj);
|
nuclear@4
|
73 }
|
nuclear@4
|
74
|
nuclear@4
|
75 int Scene::get_object_count() const
|
nuclear@4
|
76 {
|
nuclear@4
|
77 return (int)objects.size();
|
nuclear@4
|
78 }
|
nuclear@4
|
79
|
nuclear@4
|
80 Object *Scene::get_object(int idx) const
|
nuclear@4
|
81 {
|
nuclear@4
|
82 return objects[idx];
|
nuclear@4
|
83 }
|
nuclear@4
|
84
|
nuclear@4
|
85 void Scene::add_node(SceneNode *node)
|
nuclear@4
|
86 {
|
nuclear@4
|
87 nodes.push_back(node);
|
nuclear@4
|
88
|
nuclear@4
|
89 if(!node->get_parent()) {
|
nuclear@4
|
90 root->add_child(node);
|
nuclear@4
|
91 }
|
nuclear@4
|
92 }
|
nuclear@4
|
93
|
nuclear@4
|
94 int Scene::get_node_count() const
|
nuclear@4
|
95 {
|
nuclear@4
|
96 return (int)nodes.size();
|
nuclear@4
|
97 }
|
nuclear@4
|
98
|
nuclear@4
|
99 SceneNode *Scene::get_node(int idx) const
|
nuclear@4
|
100 {
|
nuclear@4
|
101 return nodes[idx];
|
nuclear@4
|
102 }
|
nuclear@4
|
103
|
nuclear@4
|
104 void Scene::use_camera(Camera *cam)
|
nuclear@4
|
105 {
|
nuclear@4
|
106 active_cam = cam;
|
nuclear@4
|
107 }
|
nuclear@4
|
108
|
nuclear@4
|
109 Camera *Scene::get_active_camera() const
|
nuclear@4
|
110 {
|
nuclear@4
|
111 return active_cam;
|
nuclear@4
|
112 }
|
nuclear@4
|
113
|
nuclear@43
|
114 std::list<ObjectInstance> Scene::gen_light_list() const
|
nuclear@43
|
115 {
|
nuclear@43
|
116 std::list<ObjectInstance> list;
|
nuclear@43
|
117
|
nuclear@43
|
118 for(auto n : nodes) {
|
nuclear@43
|
119 int nobj = n->get_num_objects();
|
nuclear@43
|
120 for(int i=0; i<nobj; i++) {
|
nuclear@43
|
121 Object *o = n->get_object(i);
|
nuclear@43
|
122 if(o->get_type() != ObjType::geom) {
|
nuclear@43
|
123 continue;
|
nuclear@43
|
124 }
|
nuclear@43
|
125 GeomObject *go = (GeomObject*)o;
|
nuclear@43
|
126
|
nuclear@43
|
127 if(go->mtl.get_attrib_value("emissive") > 0.0) {
|
nuclear@43
|
128 ObjectInstance inst;
|
nuclear@43
|
129 inst.obj = go;
|
nuclear@43
|
130 inst.node = n;
|
nuclear@43
|
131
|
nuclear@43
|
132 list.push_back(inst);
|
nuclear@43
|
133 }
|
nuclear@43
|
134 }
|
nuclear@43
|
135 }
|
nuclear@43
|
136 return std::move(list);
|
nuclear@43
|
137 }
|
nuclear@43
|
138
|
nuclear@4
|
139 void Scene::update(long msec)
|
nuclear@4
|
140 {
|
nuclear@4
|
141 root->update(msec);
|
nuclear@4
|
142 }
|
nuclear@4
|
143
|
nuclear@4
|
144 bool Scene::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
145 {
|
nuclear@4
|
146 return root->intersect(ray, hit);
|
nuclear@4
|
147 }
|
nuclear@4
|
148
|
nuclear@4
|
149 bool Scene::load(const char *fname)
|
nuclear@4
|
150 {
|
nuclear@19
|
151 FILE *fp = fopen(fname, "r");
|
nuclear@19
|
152 if(!fp) {
|
nuclear@19
|
153 fprintf(stderr, "failed to open scene file: %s\n", fname);
|
nuclear@19
|
154 return false;
|
nuclear@19
|
155 }
|
nuclear@19
|
156
|
nuclear@19
|
157 bool res = load(fp);
|
nuclear@19
|
158 fclose(fp);
|
nuclear@19
|
159 return res;
|
nuclear@4
|
160 }
|
nuclear@19
|
161
|
nuclear@19
|
162 static char *strip_wspace(char *str)
|
nuclear@19
|
163 {
|
nuclear@19
|
164 while(*str && isspace(*str)) str++;
|
nuclear@23
|
165
|
nuclear@23
|
166 char *comment = strchr(str, '#');
|
nuclear@23
|
167 if(comment) *comment = 0;
|
nuclear@23
|
168
|
nuclear@23
|
169 if(str) {
|
nuclear@23
|
170 char *end = str + strlen(str) - 1;
|
nuclear@23
|
171 while(end > str && isspace(*end)) end--;
|
nuclear@23
|
172 end[1] = 0;
|
nuclear@23
|
173 }
|
nuclear@23
|
174
|
nuclear@19
|
175 return str;
|
nuclear@19
|
176 }
|
nuclear@19
|
177
|
nuclear@19
|
178 bool Scene::load(FILE *fp)
|
nuclear@19
|
179 {
|
nuclear@28
|
180 static char buf[4096];
|
nuclear@28
|
181 int offset = 0;
|
nuclear@19
|
182
|
nuclear@28
|
183 while(fgets(buf + offset, sizeof buf - offset, fp)) {
|
nuclear@28
|
184 // handle line continuations
|
nuclear@28
|
185 int len = strlen(buf);
|
nuclear@28
|
186 if(strcmp(buf + len - 2, "\\\n") == 0 || strcmp(buf + len - 2, "\\\r") == 0) {
|
nuclear@28
|
187 offset = len - 2;
|
nuclear@28
|
188 continue;
|
nuclear@28
|
189 }
|
nuclear@28
|
190 if(strcmp(buf + len - 3, "\\\r\n") == 0) {
|
nuclear@28
|
191 offset = len - 3;
|
nuclear@28
|
192 continue;
|
nuclear@28
|
193 }
|
nuclear@28
|
194 offset = 0;
|
nuclear@28
|
195
|
nuclear@19
|
196 char *line = strip_wspace(buf);
|
nuclear@19
|
197 if(!line || !*line || *line == '#') {
|
nuclear@19
|
198 continue;
|
nuclear@19
|
199 }
|
nuclear@19
|
200
|
nuclear@19
|
201 std::vector<char*> cmd;
|
nuclear@19
|
202
|
nuclear@19
|
203 char *tok = 0;
|
nuclear@19
|
204 while((tok = strtok(tok ? 0 : line, " \t\v\n\r"))) {
|
nuclear@19
|
205 cmd.push_back(tok);
|
nuclear@19
|
206 }
|
nuclear@19
|
207 cmd.push_back(0);
|
nuclear@19
|
208
|
nuclear@19
|
209
|
nuclear@19
|
210 if(!proc_cmd((int)cmd.size() - 1, &cmd[0])) {
|
nuclear@19
|
211 return false;
|
nuclear@19
|
212 }
|
nuclear@19
|
213 }
|
nuclear@19
|
214
|
nuclear@19
|
215 return true;
|
nuclear@19
|
216 }
|
nuclear@19
|
217
|
nuclear@19
|
218 static int parse_vec(char **argv, float *vec)
|
nuclear@19
|
219 {
|
nuclear@19
|
220 int nelem = 0;
|
nuclear@19
|
221 char *endp;
|
nuclear@19
|
222
|
nuclear@19
|
223 for(int i=0; i<4; i++) {
|
nuclear@19
|
224 if(!argv[i]) break;
|
nuclear@19
|
225
|
nuclear@19
|
226 vec[nelem] = strtod(argv[i], &endp);
|
nuclear@19
|
227 if(endp == argv[i]) {
|
nuclear@19
|
228 break;
|
nuclear@19
|
229 }
|
nuclear@19
|
230 nelem++;
|
nuclear@19
|
231 }
|
nuclear@19
|
232 return nelem;
|
nuclear@19
|
233 }
|
nuclear@19
|
234
|
nuclear@22
|
235 static int parse_brdf(char **argv, Reflectance **brdf_ptr)
|
nuclear@22
|
236 {
|
nuclear@22
|
237 CompositeRefl *composite = 0;
|
nuclear@22
|
238 Reflectance *brdf = 0;
|
nuclear@22
|
239 float weight = 1.0;
|
nuclear@22
|
240 int i;
|
nuclear@22
|
241
|
nuclear@22
|
242 for(i=0; argv[i]; i++) {
|
nuclear@22
|
243 if(strcmp(argv[i], "-brdf") == 0) {
|
nuclear@22
|
244 if(strcmp(argv[++i], "lambert") == 0) {
|
nuclear@22
|
245 if(composite && brdf) {
|
nuclear@22
|
246 composite->add_brdf(brdf, weight);
|
nuclear@22
|
247 }
|
nuclear@22
|
248 brdf = new LambertRefl;
|
nuclear@22
|
249 if(!composite) break;
|
nuclear@22
|
250
|
nuclear@28
|
251 } else if(strcmp(argv[i], "phong") == 0) {
|
nuclear@28
|
252 if(composite && brdf) {
|
nuclear@28
|
253 composite->add_brdf(brdf, weight);
|
nuclear@28
|
254 }
|
nuclear@28
|
255 brdf = new PhongRefl;
|
nuclear@28
|
256 if(!composite) break;
|
nuclear@28
|
257
|
nuclear@22
|
258 } else if(strcmp(argv[i], "mirror") == 0) {
|
nuclear@22
|
259 if(composite && brdf) {
|
nuclear@22
|
260 composite->add_brdf(brdf, weight);
|
nuclear@22
|
261 }
|
nuclear@22
|
262 brdf = new MirrorRefl;
|
nuclear@22
|
263 if(!composite) break;
|
nuclear@22
|
264
|
nuclear@22
|
265 } else if(strcmp(argv[i], "composite") == 0) {
|
nuclear@22
|
266 if(composite) {
|
nuclear@22
|
267 fprintf(stderr, "can't have nested composite BRDFs\n");
|
nuclear@22
|
268 return -1;
|
nuclear@22
|
269 }
|
nuclear@22
|
270 composite = new CompositeRefl;
|
nuclear@22
|
271
|
nuclear@22
|
272 } else {
|
nuclear@22
|
273 --i;
|
nuclear@22
|
274 break;
|
nuclear@22
|
275 }
|
nuclear@22
|
276
|
nuclear@22
|
277 } else if(strcmp(argv[i], "-brdf-weight") == 0) {
|
nuclear@22
|
278 if(!composite) {
|
nuclear@22
|
279 fprintf(stderr, "-brdf-weight is invalid without a composite brdf\n");
|
nuclear@22
|
280 return -1;
|
nuclear@22
|
281 }
|
nuclear@22
|
282 char *endp;
|
nuclear@22
|
283 weight = strtod(argv[++i], &endp);
|
nuclear@22
|
284 if(endp == argv[i]) {
|
nuclear@22
|
285 fprintf(stderr, "-brdf-weight must be followed by a number\n");
|
nuclear@22
|
286 return -1;
|
nuclear@22
|
287 }
|
nuclear@22
|
288 } else {
|
nuclear@22
|
289 --i;
|
nuclear@22
|
290 break;
|
nuclear@22
|
291 }
|
nuclear@22
|
292 }
|
nuclear@22
|
293
|
nuclear@22
|
294 if(composite && brdf) {
|
nuclear@22
|
295 composite->add_brdf(brdf, weight);
|
nuclear@22
|
296 *brdf_ptr = composite;
|
nuclear@22
|
297 } else {
|
nuclear@22
|
298 *brdf_ptr = brdf;
|
nuclear@22
|
299 }
|
nuclear@22
|
300 return i;
|
nuclear@22
|
301 }
|
nuclear@22
|
302
|
nuclear@19
|
303 static SceneNode *proc_object(Object *obj, int argc, char **argv)
|
nuclear@19
|
304 {
|
nuclear@19
|
305 float vec[4];
|
nuclear@19
|
306 SceneNode *node = new SceneNode(obj);
|
nuclear@19
|
307 GeomObject *gobj = (GeomObject*)obj;
|
nuclear@19
|
308
|
nuclear@19
|
309 for(int i=1; i<argc; i++) {
|
nuclear@19
|
310 if(strcmp(argv[i], "-position") == 0) {
|
nuclear@19
|
311 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
312 if(nelem < 3) {
|
nuclear@19
|
313 fprintf(stderr, "-position must be followed by 3 numbers\n");
|
nuclear@19
|
314 goto err;
|
nuclear@19
|
315 }
|
nuclear@46
|
316 node->set_position(Vec3(vec[0], vec[1], vec[2]));
|
nuclear@19
|
317 i += 3;
|
nuclear@19
|
318
|
nuclear@19
|
319 } else if(strcmp(argv[i], "-rotation") == 0) {
|
nuclear@19
|
320 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
321 if(nelem < 4) {
|
nuclear@19
|
322 fprintf(stderr, "-rotation must be followed by axis vector and angle\n");
|
nuclear@19
|
323 goto err;
|
nuclear@19
|
324 }
|
nuclear@46
|
325 node->set_rotation(Quat(Vec3(vec[0], vec[1], vec[2]), vec[3]));
|
nuclear@19
|
326 i += 4;
|
nuclear@19
|
327
|
nuclear@19
|
328 } else if(strcmp(argv[i], "-scaling") == 0) {
|
nuclear@19
|
329 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@46
|
330 Vec3 s;
|
nuclear@19
|
331 if(nelem == 1) {
|
nuclear@19
|
332 s.x = s.y = s.z = vec[0];
|
nuclear@19
|
333 } else if(nelem == 3) {
|
nuclear@46
|
334 s = Vec3(vec[0], vec[1], vec[2]);
|
nuclear@19
|
335 } else {
|
nuclear@19
|
336 fprintf(stderr, "-scaling must be followed by 1 or 3 numbers\n");
|
nuclear@19
|
337 goto err;
|
nuclear@19
|
338 }
|
nuclear@19
|
339 node->set_scaling(s);
|
nuclear@19
|
340 i += nelem;
|
nuclear@19
|
341
|
nuclear@19
|
342 } else if(strcmp(argv[i], "-diffuse") == 0) {
|
nuclear@19
|
343 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
344 if(nelem < 3) {
|
nuclear@19
|
345 fprintf(stderr, "-diffuse must be followed by a color (r g b)\n");
|
nuclear@19
|
346 goto err;
|
nuclear@19
|
347 }
|
nuclear@19
|
348 gobj->mtl.set_attrib("diffuse", Color(vec[0], vec[1], vec[2]));
|
nuclear@19
|
349 i += 3;
|
nuclear@19
|
350
|
nuclear@19
|
351 } else if(strcmp(argv[i], "-specular") == 0) {
|
nuclear@19
|
352 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
353 if(nelem < 3) {
|
nuclear@19
|
354 fprintf(stderr, "-specular must be followed by a color\n");
|
nuclear@19
|
355 goto err;
|
nuclear@19
|
356 }
|
nuclear@19
|
357 gobj->mtl.set_attrib("specular", Color(vec[0], vec[1], vec[2]));
|
nuclear@19
|
358 i += 3;
|
nuclear@19
|
359
|
nuclear@19
|
360 } else if(strcmp(argv[i], "-emissive") == 0) {
|
nuclear@19
|
361 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
362 Color emissive;
|
nuclear@19
|
363 if(nelem == 1) {
|
nuclear@46
|
364 emissive = Vec3(1, 1, 1);
|
nuclear@19
|
365 } else if(nelem == 3) {
|
nuclear@46
|
366 emissive = Vec3(vec[0], vec[1], vec[2]);
|
nuclear@19
|
367 } else {
|
nuclear@19
|
368 fprintf(stderr, "-emissive must be followed by an intensity or a color\n");
|
nuclear@19
|
369 goto err;
|
nuclear@19
|
370 }
|
nuclear@19
|
371 i += nelem;
|
nuclear@19
|
372 gobj->mtl.set_attrib("emissive", emissive);
|
nuclear@19
|
373
|
nuclear@22
|
374 } else if(strcmp(argv[i], "-brdf") == 0) {
|
nuclear@22
|
375 int nelem = parse_brdf(argv + i, &gobj->brdf);
|
nuclear@22
|
376 if(nelem == -1) {
|
nuclear@22
|
377 goto err;
|
nuclear@22
|
378 }
|
nuclear@22
|
379 i += nelem;
|
nuclear@22
|
380
|
nuclear@19
|
381 } else {
|
nuclear@19
|
382 fprintf(stderr, "unrecognized %s option: %s\n", argv[0], argv[i]);
|
nuclear@19
|
383 goto err;
|
nuclear@19
|
384 }
|
nuclear@19
|
385 }
|
nuclear@19
|
386
|
nuclear@19
|
387 return node;
|
nuclear@19
|
388 err:
|
nuclear@19
|
389 delete node;
|
nuclear@19
|
390 return 0;
|
nuclear@19
|
391 }
|
nuclear@19
|
392
|
nuclear@19
|
393 static Camera *proc_camera(int argc, char **argv)
|
nuclear@19
|
394 {
|
nuclear@19
|
395 float vec[4];
|
nuclear@19
|
396 TargetCamera *cam = new TargetCamera;
|
nuclear@19
|
397
|
nuclear@19
|
398 for(int i=1; i<argc; i++) {
|
nuclear@19
|
399 if(strcmp(argv[i], "-position") == 0) {
|
nuclear@19
|
400 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
401 if(nelem < 3) {
|
nuclear@19
|
402 fprintf(stderr, "-position must be followed by 3 numbers\n");
|
nuclear@19
|
403 goto err;
|
nuclear@19
|
404 }
|
nuclear@46
|
405 cam->set_position(Vec3(vec[0], vec[1], vec[2]));
|
nuclear@19
|
406 i += 3;
|
nuclear@19
|
407
|
nuclear@19
|
408 } else if(strcmp(argv[i], "-target") == 0) {
|
nuclear@19
|
409 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
410 if(nelem < 3) {
|
nuclear@19
|
411 fprintf(stderr, "-target must be followed by 3 numbers\n");
|
nuclear@19
|
412 goto err;
|
nuclear@19
|
413 }
|
nuclear@46
|
414 cam->set_target(Vec3(vec[0], vec[1], vec[2]));
|
nuclear@19
|
415 i += 3;
|
nuclear@19
|
416
|
nuclear@19
|
417 } else if(strcmp(argv[i], "-fov") == 0) {
|
nuclear@19
|
418 int nelem = parse_vec(argv + i + 1, vec);
|
nuclear@19
|
419 if(nelem < 1) {
|
nuclear@19
|
420 fprintf(stderr, "-fov must be followed by the field of view in degrees\n");
|
nuclear@19
|
421 goto err;
|
nuclear@19
|
422 }
|
nuclear@19
|
423 cam->set_fov(vec[0]);
|
nuclear@19
|
424 i += 1;
|
nuclear@19
|
425
|
nuclear@19
|
426 } else {
|
nuclear@19
|
427 fprintf(stderr, "unrecognized camera option: %s\n", argv[i]);
|
nuclear@19
|
428 goto err;
|
nuclear@19
|
429 }
|
nuclear@19
|
430 }
|
nuclear@19
|
431 return cam;
|
nuclear@19
|
432
|
nuclear@19
|
433 err:
|
nuclear@19
|
434 delete cam;
|
nuclear@19
|
435 return 0;
|
nuclear@19
|
436 }
|
nuclear@19
|
437
|
nuclear@19
|
438 bool Scene::proc_cmd(int argc, char **argv)
|
nuclear@19
|
439 {
|
nuclear@19
|
440 Object *obj = 0;
|
nuclear@19
|
441 SceneNode *node = 0;
|
nuclear@19
|
442
|
nuclear@19
|
443 if(strcmp(argv[0], "sphere") == 0) {
|
nuclear@19
|
444 obj = new Sphere;
|
nuclear@19
|
445 node = proc_object(obj, argc, argv);
|
nuclear@19
|
446
|
nuclear@19
|
447 } else if(strcmp(argv[0], "box") == 0) {
|
nuclear@19
|
448 obj = new Box;
|
nuclear@19
|
449 node = proc_object(obj, argc, argv);
|
nuclear@19
|
450
|
nuclear@19
|
451 } else if(strcmp(argv[0], "mesh") == 0) {
|
nuclear@19
|
452 fprintf(stderr, "meshes not implemented yet\n");
|
nuclear@19
|
453 return false;
|
nuclear@19
|
454
|
nuclear@19
|
455 } else if(strcmp(argv[0], "camera") == 0) {
|
nuclear@19
|
456 Camera *cam = proc_camera(argc, argv);
|
nuclear@19
|
457 if(!cam) {
|
nuclear@19
|
458 return false;
|
nuclear@19
|
459 }
|
nuclear@19
|
460 use_camera(cam);
|
nuclear@19
|
461
|
nuclear@19
|
462 } else {
|
nuclear@19
|
463 fprintf(stderr, "unknown command: %s\n", argv[0]);
|
nuclear@19
|
464 return false;
|
nuclear@19
|
465 }
|
nuclear@19
|
466
|
nuclear@19
|
467 if(obj) {
|
nuclear@19
|
468 if(!node) {
|
nuclear@19
|
469 return false;
|
nuclear@19
|
470 }
|
nuclear@19
|
471 add_object(obj);
|
nuclear@19
|
472 add_node(node);
|
nuclear@19
|
473 }
|
nuclear@19
|
474
|
nuclear@19
|
475 return true;
|
nuclear@19
|
476 }
|