X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=scene.c;h=85f15e6c02f093b61c7e7ddd1ac384faa80e0385;hp=449dab661774e9770dd4ac18049740dc7be3ea97;hb=09dd89d10e65029f0be313dd463ba1f43cac2fbb;hpb=0f2508a4f227523a6b7e54798487af19d06a6ce9 diff --git a/scene.c b/scene.c index 449dab6..85f15e6 100644 --- a/scene.c +++ b/scene.c @@ -6,87 +6,166 @@ */ #include -#include -#include -#include "common.h" -#include "mat.h" #include "list.h" +#include "model.h" +#include "mat.h" #include "scene.h" -#include "tri.h" -/* - * A group of triangles and a transformation. - */ -struct _group +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* triangles; - mat_t modelview; + list_t* models; + int w, h; + mat_t view; + mat_t projection; + vec_t eye; + list_t* lights; + color_t ambient; }; -typedef struct _group _group_t; -/* - * Allocate a group by reading raw triangle coordinates from a file. - */ -static _group_t* _group_alloc(const char* filename) + +scene_t* scene_alloc(FILE* file) { - FILE* file = fopen(filename, "r"); - if (file == NULL) { - fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno)); + 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; } - _group_t* g = (_group_t*)mem_alloc(sizeof(_group_t)); - g->triangles = NULL; - g->modelview = MAT_IDENTITY; - - double x1, y1, z1, x2, y2, z2, x3, y3, z3; - while (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3) == 9) { - tri_t* t = tri_alloc( - vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1, COLOR_WHITE), - vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2, COLOR_WHITE), - vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3, COLOR_WHITE) - ); - list_push2(&g->triangles, t, mem_free); - } - list_reverse(&g->triangles); + 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)); - fclose(file); + char filename[4096]; + model_t* m = NULL; - if (g->triangles == NULL) { - fprintf(stderr, "No triangles coordinates read from %s\n", filename); - mem_free(g); - return 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; - return g; +fail: + scene_destroy(s); + return NULL; } -/* - * Destroy a group. - */ -static void _group_destroy(_group_t* g) +void scene_destroy(scene_t* s) { - list_destroy(g->triangles); - mem_free(g); + 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 _group_set_colors(_group_t* g, FILE* 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 file.\n"); + fprintf(stderr, "Cannot read color values from scene.\n"); return -1; } - for (list_t* i = g->triangles; i; i = i->link) { + 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)); @@ -98,163 +177,127 @@ static int _group_set_colors(_group_t* g, FILE* file) /* * Concat a translation matrix to the transformation as defined in a file. */ -static int _group_add_translate(_group_t* g, FILE* file) +static int _model_add_translate(model_t* m, FILE* file) { - double tx, ty; - if (fscanf(file, " %lf %lf", &tx, &ty) != 2) { - fprintf(stderr, "Cannot read translate coordinates from scene file.\n"); + 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; } - - g->modelview = mat_mult(g->modelview, MAT_TRANSLATE((scal_t)tx, (scal_t)ty, S(1.0))); + 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 _group_add_rotate(_group_t* g, FILE* file) +static int _model_add_rotate(model_t* m, FILE* file) { - double theta; - if (fscanf(file, " %lf", &theta) != 1) { - fprintf(stderr, "Cannot read rotation angle from scene file.\n"); + 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; } - - g->modelview = mat_mult(g->modelview, MAT_ROTATE_Z((scal_t)theta)); + 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 _group_add_scale(_group_t* g, FILE* file) +static int _model_add_scale(model_t* m, FILE* file) { - double sx, sy; - if (fscanf(file, " %lf %lf", &sx, &sy) != 2) { - fprintf(stderr, "Cannot read scale factors from scene file.\n"); + 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; } - - g->modelview = mat_mult(g->modelview, MAT_SCALE((scal_t)sx, (scal_t)sy, S(1.0))); + mat_t transform = MAT_SCALE((scal_t)sx, (scal_t)sy, (scal_t)sz); + model_transform(m, &transform); return 0; } - -struct scene -{ - list_t* groups; - int w; - int h; - mat_t projection; -}; - -scene_t* scene_alloc(const char* filename) +/* + * Set the specular highlight and shininess factor for the group. + */ +static int _model_set_material(model_t* m, FILE* file) { - scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t)); - s->groups = NULL; - - FILE* file = fopen(filename, "r"); - - int w, h; - double minX, minY, maxX, maxY; - if (fscanf(file, "U2 %d %d %lf %lf %lf %lf", - &w, &h, &minX, &minY, &maxX, &maxY) != 6) { - fprintf(stderr, "Cannot read scene file header.\n"); - return NULL; + 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; } - - s->w = w; - s->h = h; - s->projection = MAT_ORTHO((scal_t)minX, (scal_t)maxX, (scal_t)minY, (scal_t)maxY); - - char grp_filename[4096]; - _group_t* g = NULL; - -#define _ASSERT_G \ -if (g == NULL) { \ - fprintf(stderr, "Unexpected line before group is loaded.\n"); \ - goto fail; \ + model_material(m, color_new((scal_t)sr, (scal_t)sg, (scal_t)sb, S(1.0)), (scal_t)shininess); + return 0; } - char type; - while (fscanf(file, " %c", &type) == 1) { - switch (type) { - case 'g': - if (fgets(grp_filename, 4096, file) == NULL) { - fprintf(stderr, "Cannot read raw triangle filename.\n"); - } - trim(grp_filename); - g = _group_alloc(grp_filename); - if (g == NULL) { - goto fail; - } - list_push2(&s->groups, g, DTOR(_group_destroy)); - break; - - case 'c': - _ASSERT_G; - if (_group_set_colors(g, file) != 0) { - goto fail; - } - break; - - case 't': - _ASSERT_G; - if (_group_add_translate(g, file) != 0) { - goto fail; - } - break; - - case 'r': - if (_group_add_rotate(g, file) != 0) { - goto fail; - } - break; - - case 's': - _ASSERT_G; - if (_group_add_scale(g, file) != 0) { - goto fail; - } - break; - - default: - fprintf(stderr, "Unknown identifier: %c\n", type); - } +/* + * 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; } - list_reverse(&s->groups); - -#undef _ASSERT_G - - fclose(file); - return s; - -fail: - scene_destroy(s); - return NULL; + s->ambient = color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)); + return 0; } -void scene_destroy(scene_t* s) +/* + * Add a light to the scene. + */ +static int _scene_add_light(scene_t* s, FILE* file) { - list_destroy(s->groups); - mem_free(s); + 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; } -pixmap_t* scene_render(scene_t* s) +raster_t* scene_render(scene_t* s) { - pixmap_t* pix = pixmap_alloc(s->w, s->h, COLOR_BLACK); - pixmap_projection(pix, &s->projection); - - for (list_t* gi = s->groups; gi; gi = gi->link) { - _group_t* g = (_group_t*)gi->val; - pixmap_modelview(pix, &g->modelview); - for (list_t* ti = g->triangles; ti; ti = ti->link) { - pixmap_draw_tri(pix, (tri_t*)ti->val); - } +#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); } - return pix; +#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; }