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