erebus
view liberebus/src/scene.cc @ 41:2e817711d0f6
console: proper input line windowing and clipping
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 10 Jun 2014 12:28:56 +0300 |
parents | 4a0a288ffb27 |
children | ed18af9da8f7 |
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 void Scene::update(long msec)
115 {
116 root->update(msec);
117 }
119 bool Scene::intersect(const Ray &ray, RayHit *hit) const
120 {
121 return root->intersect(ray, hit);
122 }
124 bool Scene::load(const char *fname)
125 {
126 FILE *fp = fopen(fname, "r");
127 if(!fp) {
128 fprintf(stderr, "failed to open scene file: %s\n", fname);
129 return false;
130 }
132 bool res = load(fp);
133 fclose(fp);
134 return res;
135 }
137 static char *strip_wspace(char *str)
138 {
139 while(*str && isspace(*str)) str++;
141 char *comment = strchr(str, '#');
142 if(comment) *comment = 0;
144 if(str) {
145 char *end = str + strlen(str) - 1;
146 while(end > str && isspace(*end)) end--;
147 end[1] = 0;
148 }
150 return str;
151 }
153 bool Scene::load(FILE *fp)
154 {
155 static char buf[4096];
156 int offset = 0;
158 while(fgets(buf + offset, sizeof buf - offset, fp)) {
159 // handle line continuations
160 int len = strlen(buf);
161 if(strcmp(buf + len - 2, "\\\n") == 0 || strcmp(buf + len - 2, "\\\r") == 0) {
162 offset = len - 2;
163 continue;
164 }
165 if(strcmp(buf + len - 3, "\\\r\n") == 0) {
166 offset = len - 3;
167 continue;
168 }
169 offset = 0;
171 char *line = strip_wspace(buf);
172 if(!line || !*line || *line == '#') {
173 continue;
174 }
176 std::vector<char*> cmd;
178 char *tok = 0;
179 while((tok = strtok(tok ? 0 : line, " \t\v\n\r"))) {
180 cmd.push_back(tok);
181 }
182 cmd.push_back(0);
185 if(!proc_cmd((int)cmd.size() - 1, &cmd[0])) {
186 return false;
187 }
188 }
190 return true;
191 }
193 static int parse_vec(char **argv, float *vec)
194 {
195 int nelem = 0;
196 char *endp;
198 for(int i=0; i<4; i++) {
199 if(!argv[i]) break;
201 vec[nelem] = strtod(argv[i], &endp);
202 if(endp == argv[i]) {
203 break;
204 }
205 nelem++;
206 }
207 return nelem;
208 }
210 static int parse_brdf(char **argv, Reflectance **brdf_ptr)
211 {
212 CompositeRefl *composite = 0;
213 Reflectance *brdf = 0;
214 float weight = 1.0;
215 int i;
217 for(i=0; argv[i]; i++) {
218 if(strcmp(argv[i], "-brdf") == 0) {
219 if(strcmp(argv[++i], "lambert") == 0) {
220 if(composite && brdf) {
221 composite->add_brdf(brdf, weight);
222 }
223 brdf = new LambertRefl;
224 if(!composite) break;
226 } else if(strcmp(argv[i], "phong") == 0) {
227 if(composite && brdf) {
228 composite->add_brdf(brdf, weight);
229 }
230 brdf = new PhongRefl;
231 if(!composite) break;
233 } else if(strcmp(argv[i], "mirror") == 0) {
234 if(composite && brdf) {
235 composite->add_brdf(brdf, weight);
236 }
237 brdf = new MirrorRefl;
238 if(!composite) break;
240 } else if(strcmp(argv[i], "composite") == 0) {
241 if(composite) {
242 fprintf(stderr, "can't have nested composite BRDFs\n");
243 return -1;
244 }
245 composite = new CompositeRefl;
247 } else {
248 --i;
249 break;
250 }
252 } else if(strcmp(argv[i], "-brdf-weight") == 0) {
253 if(!composite) {
254 fprintf(stderr, "-brdf-weight is invalid without a composite brdf\n");
255 return -1;
256 }
257 char *endp;
258 weight = strtod(argv[++i], &endp);
259 if(endp == argv[i]) {
260 fprintf(stderr, "-brdf-weight must be followed by a number\n");
261 return -1;
262 }
263 } else {
264 --i;
265 break;
266 }
267 }
269 if(composite && brdf) {
270 composite->add_brdf(brdf, weight);
271 *brdf_ptr = composite;
272 } else {
273 *brdf_ptr = brdf;
274 }
275 return i;
276 }
278 static SceneNode *proc_object(Object *obj, int argc, char **argv)
279 {
280 float vec[4];
281 SceneNode *node = new SceneNode(obj);
282 GeomObject *gobj = (GeomObject*)obj;
284 for(int i=1; i<argc; i++) {
285 if(strcmp(argv[i], "-position") == 0) {
286 int nelem = parse_vec(argv + i + 1, vec);
287 if(nelem < 3) {
288 fprintf(stderr, "-position must be followed by 3 numbers\n");
289 goto err;
290 }
291 node->set_position(Vector3(vec[0], vec[1], vec[2]));
292 i += 3;
294 } else if(strcmp(argv[i], "-rotation") == 0) {
295 int nelem = parse_vec(argv + i + 1, vec);
296 if(nelem < 4) {
297 fprintf(stderr, "-rotation must be followed by axis vector and angle\n");
298 goto err;
299 }
300 node->set_rotation(Quaternion(Vector3(vec[0], vec[1], vec[2]), vec[3]));
301 i += 4;
303 } else if(strcmp(argv[i], "-scaling") == 0) {
304 int nelem = parse_vec(argv + i + 1, vec);
305 Vector3 s;
306 if(nelem == 1) {
307 s.x = s.y = s.z = vec[0];
308 } else if(nelem == 3) {
309 s = Vector3(vec[0], vec[1], vec[2]);
310 } else {
311 fprintf(stderr, "-scaling must be followed by 1 or 3 numbers\n");
312 goto err;
313 }
314 node->set_scaling(s);
315 i += nelem;
317 } else if(strcmp(argv[i], "-diffuse") == 0) {
318 int nelem = parse_vec(argv + i + 1, vec);
319 if(nelem < 3) {
320 fprintf(stderr, "-diffuse must be followed by a color (r g b)\n");
321 goto err;
322 }
323 gobj->mtl.set_attrib("diffuse", Color(vec[0], vec[1], vec[2]));
324 i += 3;
326 } else if(strcmp(argv[i], "-specular") == 0) {
327 int nelem = parse_vec(argv + i + 1, vec);
328 if(nelem < 3) {
329 fprintf(stderr, "-specular must be followed by a color\n");
330 goto err;
331 }
332 gobj->mtl.set_attrib("specular", Color(vec[0], vec[1], vec[2]));
333 i += 3;
335 } else if(strcmp(argv[i], "-emissive") == 0) {
336 int nelem = parse_vec(argv + i + 1, vec);
337 Color emissive;
338 if(nelem == 1) {
339 emissive = Vector3(1, 1, 1);
340 } else if(nelem == 3) {
341 emissive = Vector3(vec[0], vec[1], vec[2]);
342 } else {
343 fprintf(stderr, "-emissive must be followed by an intensity or a color\n");
344 goto err;
345 }
346 i += nelem;
347 gobj->mtl.set_attrib("emissive", emissive);
349 } else if(strcmp(argv[i], "-brdf") == 0) {
350 int nelem = parse_brdf(argv + i, &gobj->brdf);
351 if(nelem == -1) {
352 goto err;
353 }
354 i += nelem;
356 } else {
357 fprintf(stderr, "unrecognized %s option: %s\n", argv[0], argv[i]);
358 goto err;
359 }
360 }
362 return node;
363 err:
364 delete node;
365 return 0;
366 }
368 static Camera *proc_camera(int argc, char **argv)
369 {
370 float vec[4];
371 TargetCamera *cam = new TargetCamera;
373 for(int i=1; i<argc; i++) {
374 if(strcmp(argv[i], "-position") == 0) {
375 int nelem = parse_vec(argv + i + 1, vec);
376 if(nelem < 3) {
377 fprintf(stderr, "-position must be followed by 3 numbers\n");
378 goto err;
379 }
380 cam->set_position(Vector3(vec[0], vec[1], vec[2]));
381 i += 3;
383 } else if(strcmp(argv[i], "-target") == 0) {
384 int nelem = parse_vec(argv + i + 1, vec);
385 if(nelem < 3) {
386 fprintf(stderr, "-target must be followed by 3 numbers\n");
387 goto err;
388 }
389 cam->set_target(Vector3(vec[0], vec[1], vec[2]));
390 i += 3;
392 } else if(strcmp(argv[i], "-fov") == 0) {
393 int nelem = parse_vec(argv + i + 1, vec);
394 if(nelem < 1) {
395 fprintf(stderr, "-fov must be followed by the field of view in degrees\n");
396 goto err;
397 }
398 cam->set_fov(vec[0]);
399 i += 1;
401 } else {
402 fprintf(stderr, "unrecognized camera option: %s\n", argv[i]);
403 goto err;
404 }
405 }
406 return cam;
408 err:
409 delete cam;
410 return 0;
411 }
413 bool Scene::proc_cmd(int argc, char **argv)
414 {
415 Object *obj = 0;
416 SceneNode *node = 0;
418 if(strcmp(argv[0], "sphere") == 0) {
419 obj = new Sphere;
420 node = proc_object(obj, argc, argv);
422 } else if(strcmp(argv[0], "box") == 0) {
423 obj = new Box;
424 node = proc_object(obj, argc, argv);
426 } else if(strcmp(argv[0], "mesh") == 0) {
427 fprintf(stderr, "meshes not implemented yet\n");
428 return false;
430 } else if(strcmp(argv[0], "camera") == 0) {
431 Camera *cam = proc_camera(argc, argv);
432 if(!cam) {
433 return false;
434 }
435 use_camera(cam);
437 } else {
438 fprintf(stderr, "unknown command: %s\n", argv[0]);
439 return false;
440 }
442 if(obj) {
443 if(!node) {
444 return false;
445 }
446 add_object(obj);
447 add_node(node);
448 }
450 return true;
451 }