erebus

view liberebus/src/scene.cc @ 44:a2afaf8af09b

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