/* * CS5600 University of Utah * Charles McGarvey * mcgarvey@eng.utah.edu */ #include #include "list.h" #include "model.h" #include "mat.h" #include "scene.h" static int _model_set_colors(model_t* m, FILE* file); static int _model_add_translate(model_t* m, FILE* file); static int _model_add_rotate(model_t* m, FILE* file); static int _model_add_scale(model_t* m, FILE* file); static int _model_set_material(model_t* m, FILE* file); static int _scene_set_ambient(scene_t* s, FILE* file); static int _scene_add_light(scene_t* s, FILE* file); struct scene { list_t* models; int w, h; mat_t view; mat_t projection; vec_t eye; list_t* lights; color_t ambient; }; scene_t* scene_alloc(FILE* file) { int w, h; double eyeX, eyeY, eyeZ, spotX, spotY, spotZ, upX, upY, upZ; double fovy, aspect, near, far; if (fscanf(file, "U3 %d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &w, &h, &eyeX, &eyeY, &eyeZ, &spotX, &spotY, &spotZ, &upX, &upY, &upZ, &fovy, &aspect, &near, &far) != 15) { fprintf(stderr, "Cannot read scene header.\n"); return NULL; } scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t)); s->models = NULL; s->w = w; s->h = h; s->view = MAT_LOOKAT(vec_new( (scal_t)eyeX, (scal_t)eyeY, (scal_t)eyeZ), vec_new((scal_t)spotX, (scal_t)spotY, (scal_t)spotZ), vec_new( (scal_t)upX, (scal_t)upY, (scal_t)upZ)); s->eye = vec_new(eyeX, eyeY, eyeZ); s->projection = MAT_PERSPECTIVE((scal_t)fovy, (scal_t)aspect, (scal_t)near, (scal_t)far); s->lights = NULL; s->ambient = color_new(S(0.05), S(0.05), S(0.05), S(1.0)); char filename[4096]; model_t* m = NULL; #define _ASSERT_G \ if (m == NULL) { \ fprintf(stderr, "Unexpected line before group is specified.\n"); \ goto fail; \ } char type; while (fscanf(file, " %c", &type) == 1) { switch (type) { case 'g': if (fgets(filename, 4096, file) == NULL) { fprintf(stderr, "Cannot read model filename.\n"); } m = model_alloc(trim(filename)); if (m == NULL) { goto fail; } list_push2(&s->models, m, DTOR(model_destroy)); break; case 'c': _ASSERT_G; if (_model_set_colors(m, file) != 0) { goto fail; } break; case 't': _ASSERT_G; if (_model_add_translate(m, file) != 0) { goto fail; } break; case 'r': if (_model_add_rotate(m, file) != 0) { goto fail; } break; case 's': _ASSERT_G; if (_model_add_scale(m, file) != 0) { goto fail; } break; case 'A': if (_scene_set_ambient(s, file) != 0) { goto fail; } break; case 'L': if (_scene_add_light(s, file) != 0) { goto fail; } break; case 'M': _ASSERT_G; if (_model_set_material(m, file) != 0) { goto fail; } break; case 'X': goto done; default: fprintf(stderr, "Unknown identifier: %c\n", type); } } #undef _ASSERT_G done: return s; fail: scene_destroy(s); return NULL; } void scene_destroy(scene_t* s) { list_destroy(&s->models); list_destroy(&s->lights); mem_free(s); } /* * Set the colors of the triangles in the group as defined in a file. */ static int _model_set_colors(model_t* m, FILE* file) { double r1, g1, b1, r2, g2, b2, r3, g3, b3; if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf", &r1, &g1, &b1, &r2, &g2, &b2, &r3, &g3, &b3) != 9) { fprintf(stderr, "Cannot read color values from scene.\n"); return -1; } for (const list_t* i = model_geometry(m); i; i = i->link) { tri_t* t = (tri_t*)i->val; t->a.c = color_new((colorchan_t)r1, (colorchan_t)g1, (colorchan_t)b1, S(1.0)); t->b.c = color_new((colorchan_t)r2, (colorchan_t)g2, (colorchan_t)b2, S(1.0)); t->c.c = color_new((colorchan_t)r3, (colorchan_t)g3, (colorchan_t)b3, S(1.0)); } return 0; } /* * Concat a translation matrix to the transformation as defined in a file. */ static int _model_add_translate(model_t* m, FILE* file) { double tx, ty, tz; if (fscanf(file, " %lf %lf %lf", &tx, &ty, &tz) != 3) { fprintf(stderr, "Cannot read translate coordinates from scene.\n"); return -1; } mat_t transform = MAT_TRANSLATE((scal_t)tx, (scal_t)ty, (scal_t)tz); model_transform(m, &transform); return 0; } /* * Concat a rotation matrix to the transformation as defined in a file. */ static int _model_add_rotate(model_t* m, FILE* file) { double theta, ax, ay, az; if (fscanf(file, " %lf %lf %lf %lf", &theta, &ax, &ay, &az) != 4) { fprintf(stderr, "Cannot read rotation angle from scene.\n"); return -1; } mat_t transform = MAT_ROTATE((scal_t)theta, (scal_t)ax, (scal_t)ay, (scal_t)az); model_transform(m, &transform); return 0; } /* * Concat a scale matrix to the transformation as defined in a file. */ static int _model_add_scale(model_t* m, FILE* file) { double sx, sy, sz; if (fscanf(file, " %lf %lf %lf", &sx, &sy, &sz) != 3) { fprintf(stderr, "Cannot read scale factors from scene.\n"); return -1; } mat_t transform = MAT_SCALE((scal_t)sx, (scal_t)sy, (scal_t)sz); model_transform(m, &transform); return 0; } /* * Set the specular highlight and shininess factor for the group. */ static int _model_set_material(model_t* m, FILE* file) { double sr, sg, sb, shininess; if (fscanf(file, " %lf %lf %lf %lf", &sr, &sg, &sb, &shininess) != 4) { fprintf(stderr, "Cannot read material information from scene.\n"); return -1; } model_material(m, color_new((scal_t)sr, (scal_t)sg, (scal_t)sb, S(1.0)), (scal_t)shininess); return 0; } /* * Set the ambient light properties of a scene. */ static int _scene_set_ambient(scene_t* s, FILE* file) { double r, g, b; if (fscanf(file, " %lf %lf %lf", &r, &g, &b) != 3) { fprintf(stderr, "Cannot read ambient light from scene.\n"); return -1; } s->ambient = color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)); return 0; } /* * Add a light to the scene. */ static int _scene_add_light(scene_t* s, FILE* file) { double lx, ly, lz, dr, dg, db, sr, sg, sb; if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf", &lx, &ly, &lz, &dr, &dg, &db, &sr, &sg, &sb) != 9) { fprintf(stderr, "Cannot read light values from scene.\n"); return -1; } light_t* l = light_alloc( vec_new(lx, ly, lz), color_new(dr, dg, db, S(1.0)), color_new(sr, sg, sb, S(1.0)) ); list_push2(&s->lights, l, mem_free); return 0; } raster_t* scene_render(scene_t* s) { #if VERBOSITY >= 3 timer_start(); #endif raster_t* p = raster_alloc(s->w, s->h, COLOR_BLACK); raster_view(p, &s->view); raster_projection(p, &s->projection); raster_eye(p, s->eye); raster_ambient(p, s->ambient); for (list_t* i = s->lights; i; i = i->link) { raster_light(p, *(light_t*)i->val); } #if VERBOSITY >= 3 printf("rendering scene...\n"); #endif for (list_t* gi = s->models; gi; gi = gi->link) { model_t* m = (model_t*)gi->val; raster_draw_model(p, m); } #if VERBOSITY >= 3 long dt = timer_stop(); printf("render complete!\ntime\t%.3fms\n", (float)dt / 1000.0f); #endif return p; }