erebus

annotate liberebus/src/scene.cc @ 23:56d504cc555a

- debugging scale factor for render size - fixed un-normalized normals after transforms in the SceneNode
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 29 May 2014 07:47:52 +0300
parents 11cdaa510201
children 4a0a288ffb27
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@23 128
nuclear@23 129 char *comment = strchr(str, '#');
nuclear@23 130 if(comment) *comment = 0;
nuclear@23 131
nuclear@23 132 if(str) {
nuclear@23 133 char *end = str + strlen(str) - 1;
nuclear@23 134 while(end > str && isspace(*end)) end--;
nuclear@23 135 end[1] = 0;
nuclear@23 136 }
nuclear@23 137
nuclear@19 138 return str;
nuclear@19 139 }
nuclear@19 140
nuclear@19 141 bool Scene::load(FILE *fp)
nuclear@19 142 {
nuclear@22 143 static char buf[256];
nuclear@19 144
nuclear@19 145 while(fgets(buf, sizeof buf, fp)) {
nuclear@19 146 char *line = strip_wspace(buf);
nuclear@19 147 if(!line || !*line || *line == '#') {
nuclear@19 148 continue;
nuclear@19 149 }
nuclear@19 150
nuclear@19 151 std::vector<char*> cmd;
nuclear@19 152
nuclear@19 153 char *tok = 0;
nuclear@19 154 while((tok = strtok(tok ? 0 : line, " \t\v\n\r"))) {
nuclear@19 155 cmd.push_back(tok);
nuclear@19 156 }
nuclear@19 157 cmd.push_back(0);
nuclear@19 158
nuclear@19 159
nuclear@19 160 if(!proc_cmd((int)cmd.size() - 1, &cmd[0])) {
nuclear@19 161 return false;
nuclear@19 162 }
nuclear@19 163 }
nuclear@19 164
nuclear@19 165 return true;
nuclear@19 166 }
nuclear@19 167
nuclear@19 168 static int parse_vec(char **argv, float *vec)
nuclear@19 169 {
nuclear@19 170 int nelem = 0;
nuclear@19 171 char *endp;
nuclear@19 172
nuclear@19 173 for(int i=0; i<4; i++) {
nuclear@19 174 if(!argv[i]) break;
nuclear@19 175
nuclear@19 176 vec[nelem] = strtod(argv[i], &endp);
nuclear@19 177 if(endp == argv[i]) {
nuclear@19 178 break;
nuclear@19 179 }
nuclear@19 180 nelem++;
nuclear@19 181 }
nuclear@19 182 return nelem;
nuclear@19 183 }
nuclear@19 184
nuclear@22 185 static int parse_brdf(char **argv, Reflectance **brdf_ptr)
nuclear@22 186 {
nuclear@22 187 CompositeRefl *composite = 0;
nuclear@22 188 Reflectance *brdf = 0;
nuclear@22 189 float weight = 1.0;
nuclear@22 190 int i;
nuclear@22 191
nuclear@22 192 for(i=0; argv[i]; i++) {
nuclear@22 193 if(strcmp(argv[i], "-brdf") == 0) {
nuclear@22 194 if(strcmp(argv[++i], "lambert") == 0) {
nuclear@22 195 if(composite && brdf) {
nuclear@22 196 composite->add_brdf(brdf, weight);
nuclear@22 197 }
nuclear@22 198 brdf = new LambertRefl;
nuclear@22 199 if(!composite) break;
nuclear@22 200
nuclear@22 201 } else if(strcmp(argv[i], "mirror") == 0) {
nuclear@22 202 if(composite && brdf) {
nuclear@22 203 composite->add_brdf(brdf, weight);
nuclear@22 204 }
nuclear@22 205 brdf = new MirrorRefl;
nuclear@22 206 if(!composite) break;
nuclear@22 207
nuclear@22 208 } else if(strcmp(argv[i], "composite") == 0) {
nuclear@22 209 if(composite) {
nuclear@22 210 fprintf(stderr, "can't have nested composite BRDFs\n");
nuclear@22 211 return -1;
nuclear@22 212 }
nuclear@22 213 composite = new CompositeRefl;
nuclear@22 214
nuclear@22 215 } else {
nuclear@22 216 --i;
nuclear@22 217 break;
nuclear@22 218 }
nuclear@22 219
nuclear@22 220 } else if(strcmp(argv[i], "-brdf-weight") == 0) {
nuclear@22 221 if(!composite) {
nuclear@22 222 fprintf(stderr, "-brdf-weight is invalid without a composite brdf\n");
nuclear@22 223 return -1;
nuclear@22 224 }
nuclear@22 225 char *endp;
nuclear@22 226 weight = strtod(argv[++i], &endp);
nuclear@22 227 if(endp == argv[i]) {
nuclear@22 228 fprintf(stderr, "-brdf-weight must be followed by a number\n");
nuclear@22 229 return -1;
nuclear@22 230 }
nuclear@22 231 } else {
nuclear@22 232 --i;
nuclear@22 233 break;
nuclear@22 234 }
nuclear@22 235 }
nuclear@22 236
nuclear@22 237 if(composite && brdf) {
nuclear@22 238 composite->add_brdf(brdf, weight);
nuclear@22 239 *brdf_ptr = composite;
nuclear@22 240 } else {
nuclear@22 241 *brdf_ptr = brdf;
nuclear@22 242 }
nuclear@22 243 return i;
nuclear@22 244 }
nuclear@22 245
nuclear@19 246 static SceneNode *proc_object(Object *obj, int argc, char **argv)
nuclear@19 247 {
nuclear@19 248 float vec[4];
nuclear@19 249 SceneNode *node = new SceneNode(obj);
nuclear@19 250 GeomObject *gobj = (GeomObject*)obj;
nuclear@19 251
nuclear@19 252 for(int i=1; i<argc; i++) {
nuclear@19 253 if(strcmp(argv[i], "-position") == 0) {
nuclear@19 254 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 255 if(nelem < 3) {
nuclear@19 256 fprintf(stderr, "-position must be followed by 3 numbers\n");
nuclear@19 257 goto err;
nuclear@19 258 }
nuclear@19 259 node->set_position(Vector3(vec[0], vec[1], vec[2]));
nuclear@19 260 i += 3;
nuclear@19 261
nuclear@19 262 } else if(strcmp(argv[i], "-rotation") == 0) {
nuclear@19 263 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 264 if(nelem < 4) {
nuclear@19 265 fprintf(stderr, "-rotation must be followed by axis vector and angle\n");
nuclear@19 266 goto err;
nuclear@19 267 }
nuclear@19 268 node->set_rotation(Quaternion(Vector3(vec[0], vec[1], vec[2]), vec[3]));
nuclear@19 269 i += 4;
nuclear@19 270
nuclear@19 271 } else if(strcmp(argv[i], "-scaling") == 0) {
nuclear@19 272 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 273 Vector3 s;
nuclear@19 274 if(nelem == 1) {
nuclear@19 275 s.x = s.y = s.z = vec[0];
nuclear@19 276 } else if(nelem == 3) {
nuclear@19 277 s = Vector3(vec[0], vec[1], vec[2]);
nuclear@19 278 } else {
nuclear@19 279 fprintf(stderr, "-scaling must be followed by 1 or 3 numbers\n");
nuclear@19 280 goto err;
nuclear@19 281 }
nuclear@19 282 node->set_scaling(s);
nuclear@19 283 i += nelem;
nuclear@19 284
nuclear@19 285 } else if(strcmp(argv[i], "-diffuse") == 0) {
nuclear@19 286 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 287 if(nelem < 3) {
nuclear@19 288 fprintf(stderr, "-diffuse must be followed by a color (r g b)\n");
nuclear@19 289 goto err;
nuclear@19 290 }
nuclear@19 291 gobj->mtl.set_attrib("diffuse", Color(vec[0], vec[1], vec[2]));
nuclear@19 292 i += 3;
nuclear@19 293
nuclear@19 294 } else if(strcmp(argv[i], "-specular") == 0) {
nuclear@19 295 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 296 if(nelem < 3) {
nuclear@19 297 fprintf(stderr, "-specular must be followed by a color\n");
nuclear@19 298 goto err;
nuclear@19 299 }
nuclear@19 300 gobj->mtl.set_attrib("specular", Color(vec[0], vec[1], vec[2]));
nuclear@19 301 i += 3;
nuclear@19 302
nuclear@19 303 } else if(strcmp(argv[i], "-emissive") == 0) {
nuclear@19 304 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 305 Color emissive;
nuclear@19 306 if(nelem == 1) {
nuclear@19 307 emissive = Vector3(1, 1, 1);
nuclear@19 308 } else if(nelem == 3) {
nuclear@19 309 emissive = Vector3(vec[0], vec[1], vec[2]);
nuclear@19 310 } else {
nuclear@19 311 fprintf(stderr, "-emissive must be followed by an intensity or a color\n");
nuclear@19 312 goto err;
nuclear@19 313 }
nuclear@19 314 i += nelem;
nuclear@19 315 gobj->mtl.set_attrib("emissive", emissive);
nuclear@19 316
nuclear@22 317 } else if(strcmp(argv[i], "-brdf") == 0) {
nuclear@22 318 int nelem = parse_brdf(argv + i, &gobj->brdf);
nuclear@22 319 if(nelem == -1) {
nuclear@22 320 goto err;
nuclear@22 321 }
nuclear@22 322 i += nelem;
nuclear@22 323
nuclear@19 324 } else {
nuclear@19 325 fprintf(stderr, "unrecognized %s option: %s\n", argv[0], argv[i]);
nuclear@19 326 goto err;
nuclear@19 327 }
nuclear@19 328 }
nuclear@19 329
nuclear@19 330 return node;
nuclear@19 331 err:
nuclear@19 332 delete node;
nuclear@19 333 return 0;
nuclear@19 334 }
nuclear@19 335
nuclear@19 336 static Camera *proc_camera(int argc, char **argv)
nuclear@19 337 {
nuclear@19 338 float vec[4];
nuclear@19 339 TargetCamera *cam = new TargetCamera;
nuclear@19 340
nuclear@19 341 for(int i=1; i<argc; i++) {
nuclear@19 342 if(strcmp(argv[i], "-position") == 0) {
nuclear@19 343 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 344 if(nelem < 3) {
nuclear@19 345 fprintf(stderr, "-position must be followed by 3 numbers\n");
nuclear@19 346 goto err;
nuclear@19 347 }
nuclear@19 348 cam->set_position(Vector3(vec[0], vec[1], vec[2]));
nuclear@19 349 i += 3;
nuclear@19 350
nuclear@19 351 } else if(strcmp(argv[i], "-target") == 0) {
nuclear@19 352 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 353 if(nelem < 3) {
nuclear@19 354 fprintf(stderr, "-target must be followed by 3 numbers\n");
nuclear@19 355 goto err;
nuclear@19 356 }
nuclear@19 357 cam->set_target(Vector3(vec[0], vec[1], vec[2]));
nuclear@19 358 i += 3;
nuclear@19 359
nuclear@19 360 } else if(strcmp(argv[i], "-fov") == 0) {
nuclear@19 361 int nelem = parse_vec(argv + i + 1, vec);
nuclear@19 362 if(nelem < 1) {
nuclear@19 363 fprintf(stderr, "-fov must be followed by the field of view in degrees\n");
nuclear@19 364 goto err;
nuclear@19 365 }
nuclear@19 366 cam->set_fov(vec[0]);
nuclear@19 367 i += 1;
nuclear@19 368
nuclear@19 369 } else {
nuclear@19 370 fprintf(stderr, "unrecognized camera option: %s\n", argv[i]);
nuclear@19 371 goto err;
nuclear@19 372 }
nuclear@19 373 }
nuclear@19 374 return cam;
nuclear@19 375
nuclear@19 376 err:
nuclear@19 377 delete cam;
nuclear@19 378 return 0;
nuclear@19 379 }
nuclear@19 380
nuclear@19 381 bool Scene::proc_cmd(int argc, char **argv)
nuclear@19 382 {
nuclear@19 383 Object *obj = 0;
nuclear@19 384 SceneNode *node = 0;
nuclear@19 385
nuclear@19 386 if(strcmp(argv[0], "sphere") == 0) {
nuclear@19 387 obj = new Sphere;
nuclear@19 388 node = proc_object(obj, argc, argv);
nuclear@19 389
nuclear@19 390 } else if(strcmp(argv[0], "box") == 0) {
nuclear@19 391 obj = new Box;
nuclear@19 392 node = proc_object(obj, argc, argv);
nuclear@19 393
nuclear@19 394 } else if(strcmp(argv[0], "mesh") == 0) {
nuclear@19 395 fprintf(stderr, "meshes not implemented yet\n");
nuclear@19 396 return false;
nuclear@19 397
nuclear@19 398 } else if(strcmp(argv[0], "camera") == 0) {
nuclear@19 399 Camera *cam = proc_camera(argc, argv);
nuclear@19 400 if(!cam) {
nuclear@19 401 return false;
nuclear@19 402 }
nuclear@19 403 use_camera(cam);
nuclear@19 404
nuclear@19 405 } else {
nuclear@19 406 fprintf(stderr, "unknown command: %s\n", argv[0]);
nuclear@19 407 return false;
nuclear@19 408 }
nuclear@19 409
nuclear@19 410 if(obj) {
nuclear@19 411 if(!node) {
nuclear@19 412 return false;
nuclear@19 413 }
nuclear@19 414 add_object(obj);
nuclear@19 415 add_node(node);
nuclear@19 416 }
nuclear@19 417
nuclear@19 418 return true;
nuclear@19 419 }