erebus

view liberebus/src/scene.cc @ 28:4a0a288ffb27

phong/lafortune BRDF
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 06 Jun 2014 14:39:40 +0300
parents 56d504cc555a
children 9d6368850fe1
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 for(auto obj : objects) {
24 delete obj;
25 }
26 for(auto node : nodes) {
27 delete node;
28 }
29 delete root;
30 }
32 void Scene::set_env(const Environment &env)
33 {
34 this->env = env;
35 }
37 Environment &Scene::get_env()
38 {
39 return env;
40 }
42 const Environment &Scene::get_env() const
43 {
44 return env;
45 }
47 Color Scene::get_env_color() const
48 {
49 return env.bgcolor;
50 }
52 Color Scene::get_env_color(const Ray &ray) const
53 {
54 // TODO
55 return get_env_color();
56 }
58 void Scene::add_object(Object *obj)
59 {
60 objects.push_back(obj);
61 }
63 int Scene::get_object_count() const
64 {
65 return (int)objects.size();
66 }
68 Object *Scene::get_object(int idx) const
69 {
70 return objects[idx];
71 }
73 void Scene::add_node(SceneNode *node)
74 {
75 nodes.push_back(node);
77 if(!node->get_parent()) {
78 root->add_child(node);
79 }
80 }
82 int Scene::get_node_count() const
83 {
84 return (int)nodes.size();
85 }
87 SceneNode *Scene::get_node(int idx) const
88 {
89 return nodes[idx];
90 }
92 void Scene::use_camera(Camera *cam)
93 {
94 active_cam = cam;
95 }
97 Camera *Scene::get_active_camera() const
98 {
99 return active_cam;
100 }
102 void Scene::update(long msec)
103 {
104 root->update(msec);
105 }
107 bool Scene::intersect(const Ray &ray, RayHit *hit) const
108 {
109 return root->intersect(ray, hit);
110 }
112 bool Scene::load(const char *fname)
113 {
114 FILE *fp = fopen(fname, "r");
115 if(!fp) {
116 fprintf(stderr, "failed to open scene file: %s\n", fname);
117 return false;
118 }
120 bool res = load(fp);
121 fclose(fp);
122 return res;
123 }
125 static char *strip_wspace(char *str)
126 {
127 while(*str && isspace(*str)) str++;
129 char *comment = strchr(str, '#');
130 if(comment) *comment = 0;
132 if(str) {
133 char *end = str + strlen(str) - 1;
134 while(end > str && isspace(*end)) end--;
135 end[1] = 0;
136 }
138 return str;
139 }
141 bool Scene::load(FILE *fp)
142 {
143 static char buf[4096];
144 int offset = 0;
146 while(fgets(buf + offset, sizeof buf - offset, fp)) {
147 // handle line continuations
148 int len = strlen(buf);
149 if(strcmp(buf + len - 2, "\\\n") == 0 || strcmp(buf + len - 2, "\\\r") == 0) {
150 offset = len - 2;
151 continue;
152 }
153 if(strcmp(buf + len - 3, "\\\r\n") == 0) {
154 offset = len - 3;
155 continue;
156 }
157 offset = 0;
159 char *line = strip_wspace(buf);
160 if(!line || !*line || *line == '#') {
161 continue;
162 }
164 std::vector<char*> cmd;
166 char *tok = 0;
167 while((tok = strtok(tok ? 0 : line, " \t\v\n\r"))) {
168 cmd.push_back(tok);
169 }
170 cmd.push_back(0);
173 if(!proc_cmd((int)cmd.size() - 1, &cmd[0])) {
174 return false;
175 }
176 }
178 return true;
179 }
181 static int parse_vec(char **argv, float *vec)
182 {
183 int nelem = 0;
184 char *endp;
186 for(int i=0; i<4; i++) {
187 if(!argv[i]) break;
189 vec[nelem] = strtod(argv[i], &endp);
190 if(endp == argv[i]) {
191 break;
192 }
193 nelem++;
194 }
195 return nelem;
196 }
198 static int parse_brdf(char **argv, Reflectance **brdf_ptr)
199 {
200 CompositeRefl *composite = 0;
201 Reflectance *brdf = 0;
202 float weight = 1.0;
203 int i;
205 for(i=0; argv[i]; i++) {
206 if(strcmp(argv[i], "-brdf") == 0) {
207 if(strcmp(argv[++i], "lambert") == 0) {
208 if(composite && brdf) {
209 composite->add_brdf(brdf, weight);
210 }
211 brdf = new LambertRefl;
212 if(!composite) break;
214 } else if(strcmp(argv[i], "phong") == 0) {
215 if(composite && brdf) {
216 composite->add_brdf(brdf, weight);
217 }
218 brdf = new PhongRefl;
219 if(!composite) break;
221 } else if(strcmp(argv[i], "mirror") == 0) {
222 if(composite && brdf) {
223 composite->add_brdf(brdf, weight);
224 }
225 brdf = new MirrorRefl;
226 if(!composite) break;
228 } else if(strcmp(argv[i], "composite") == 0) {
229 if(composite) {
230 fprintf(stderr, "can't have nested composite BRDFs\n");
231 return -1;
232 }
233 composite = new CompositeRefl;
235 } else {
236 --i;
237 break;
238 }
240 } else if(strcmp(argv[i], "-brdf-weight") == 0) {
241 if(!composite) {
242 fprintf(stderr, "-brdf-weight is invalid without a composite brdf\n");
243 return -1;
244 }
245 char *endp;
246 weight = strtod(argv[++i], &endp);
247 if(endp == argv[i]) {
248 fprintf(stderr, "-brdf-weight must be followed by a number\n");
249 return -1;
250 }
251 } else {
252 --i;
253 break;
254 }
255 }
257 if(composite && brdf) {
258 composite->add_brdf(brdf, weight);
259 *brdf_ptr = composite;
260 } else {
261 *brdf_ptr = brdf;
262 }
263 return i;
264 }
266 static SceneNode *proc_object(Object *obj, int argc, char **argv)
267 {
268 float vec[4];
269 SceneNode *node = new SceneNode(obj);
270 GeomObject *gobj = (GeomObject*)obj;
272 for(int i=1; i<argc; i++) {
273 if(strcmp(argv[i], "-position") == 0) {
274 int nelem = parse_vec(argv + i + 1, vec);
275 if(nelem < 3) {
276 fprintf(stderr, "-position must be followed by 3 numbers\n");
277 goto err;
278 }
279 node->set_position(Vector3(vec[0], vec[1], vec[2]));
280 i += 3;
282 } else if(strcmp(argv[i], "-rotation") == 0) {
283 int nelem = parse_vec(argv + i + 1, vec);
284 if(nelem < 4) {
285 fprintf(stderr, "-rotation must be followed by axis vector and angle\n");
286 goto err;
287 }
288 node->set_rotation(Quaternion(Vector3(vec[0], vec[1], vec[2]), vec[3]));
289 i += 4;
291 } else if(strcmp(argv[i], "-scaling") == 0) {
292 int nelem = parse_vec(argv + i + 1, vec);
293 Vector3 s;
294 if(nelem == 1) {
295 s.x = s.y = s.z = vec[0];
296 } else if(nelem == 3) {
297 s = Vector3(vec[0], vec[1], vec[2]);
298 } else {
299 fprintf(stderr, "-scaling must be followed by 1 or 3 numbers\n");
300 goto err;
301 }
302 node->set_scaling(s);
303 i += nelem;
305 } else if(strcmp(argv[i], "-diffuse") == 0) {
306 int nelem = parse_vec(argv + i + 1, vec);
307 if(nelem < 3) {
308 fprintf(stderr, "-diffuse must be followed by a color (r g b)\n");
309 goto err;
310 }
311 gobj->mtl.set_attrib("diffuse", Color(vec[0], vec[1], vec[2]));
312 i += 3;
314 } else if(strcmp(argv[i], "-specular") == 0) {
315 int nelem = parse_vec(argv + i + 1, vec);
316 if(nelem < 3) {
317 fprintf(stderr, "-specular must be followed by a color\n");
318 goto err;
319 }
320 gobj->mtl.set_attrib("specular", Color(vec[0], vec[1], vec[2]));
321 i += 3;
323 } else if(strcmp(argv[i], "-emissive") == 0) {
324 int nelem = parse_vec(argv + i + 1, vec);
325 Color emissive;
326 if(nelem == 1) {
327 emissive = Vector3(1, 1, 1);
328 } else if(nelem == 3) {
329 emissive = Vector3(vec[0], vec[1], vec[2]);
330 } else {
331 fprintf(stderr, "-emissive must be followed by an intensity or a color\n");
332 goto err;
333 }
334 i += nelem;
335 gobj->mtl.set_attrib("emissive", emissive);
337 } else if(strcmp(argv[i], "-brdf") == 0) {
338 int nelem = parse_brdf(argv + i, &gobj->brdf);
339 if(nelem == -1) {
340 goto err;
341 }
342 i += nelem;
344 } else {
345 fprintf(stderr, "unrecognized %s option: %s\n", argv[0], argv[i]);
346 goto err;
347 }
348 }
350 return node;
351 err:
352 delete node;
353 return 0;
354 }
356 static Camera *proc_camera(int argc, char **argv)
357 {
358 float vec[4];
359 TargetCamera *cam = new TargetCamera;
361 for(int i=1; i<argc; i++) {
362 if(strcmp(argv[i], "-position") == 0) {
363 int nelem = parse_vec(argv + i + 1, vec);
364 if(nelem < 3) {
365 fprintf(stderr, "-position must be followed by 3 numbers\n");
366 goto err;
367 }
368 cam->set_position(Vector3(vec[0], vec[1], vec[2]));
369 i += 3;
371 } else if(strcmp(argv[i], "-target") == 0) {
372 int nelem = parse_vec(argv + i + 1, vec);
373 if(nelem < 3) {
374 fprintf(stderr, "-target must be followed by 3 numbers\n");
375 goto err;
376 }
377 cam->set_target(Vector3(vec[0], vec[1], vec[2]));
378 i += 3;
380 } else if(strcmp(argv[i], "-fov") == 0) {
381 int nelem = parse_vec(argv + i + 1, vec);
382 if(nelem < 1) {
383 fprintf(stderr, "-fov must be followed by the field of view in degrees\n");
384 goto err;
385 }
386 cam->set_fov(vec[0]);
387 i += 1;
389 } else {
390 fprintf(stderr, "unrecognized camera option: %s\n", argv[i]);
391 goto err;
392 }
393 }
394 return cam;
396 err:
397 delete cam;
398 return 0;
399 }
401 bool Scene::proc_cmd(int argc, char **argv)
402 {
403 Object *obj = 0;
404 SceneNode *node = 0;
406 if(strcmp(argv[0], "sphere") == 0) {
407 obj = new Sphere;
408 node = proc_object(obj, argc, argv);
410 } else if(strcmp(argv[0], "box") == 0) {
411 obj = new Box;
412 node = proc_object(obj, argc, argv);
414 } else if(strcmp(argv[0], "mesh") == 0) {
415 fprintf(stderr, "meshes not implemented yet\n");
416 return false;
418 } else if(strcmp(argv[0], "camera") == 0) {
419 Camera *cam = proc_camera(argc, argv);
420 if(!cam) {
421 return false;
422 }
423 use_camera(cam);
425 } else {
426 fprintf(stderr, "unknown command: %s\n", argv[0]);
427 return false;
428 }
430 if(obj) {
431 if(!node) {
432 return false;
433 }
434 add_object(obj);
435 add_node(node);
436 }
438 return true;
439 }