X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=scene.c;h=940767d4f339b6ea44478a8821c1cd6e4f7bd49f;hp=449dab661774e9770dd4ac18049740dc7be3ea97;hb=c875478cdd823c7df8fdc859941bd9e5948c9315;hpb=0f2508a4f227523a6b7e54798487af19d06a6ce9 diff --git a/scene.c b/scene.c index 449dab6..940767d 100644 --- a/scene.c +++ b/scene.c @@ -16,13 +16,83 @@ #include "tri.h" +#if FIND_NORMALS == 2 + +#include "map.h" +DECLARE_AND_DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b)); + + +/* + * Associate a triangle with one of its vertices. + */ +static void _find_normals_add_vertex(map_t* m, vec_t v, tri_t* t) +{ + list_t** l = map_vnorm_search(m, v); + if (l == NULL) { + map_vnorm_data_t* d = map_vnorm_insert(m, v, NULL); + l = &d->val; + } + list_push(l, t); +} + +/* + * Associate a triangle with all of its vertices. + */ +static void _find_normals_add_triangle(map_t* m, tri_t* t) +{ + _find_normals_add_vertex(m, t->a.v, t); + _find_normals_add_vertex(m, t->b.v, t); + _find_normals_add_vertex(m, t->c.v, t); +} + + +/* + * Calculate an averaged normal from a list of triangles that share a common + * vertex. + */ +static void _find_normals_average(const vec_t* v, list_t** l) +{ + // first, compute the average normal + vec_t n = VEC_ZERO; + for (list_t* i = *l; i; i = i->link) { + tri_t* t = (tri_t*)i->val; + n = vec_add(n, tri_normal(*t)); + } + n = vec_normalize(n); + + // set the normal on each triangle's vertex that is shared + while (*l) { + tri_t* t = (tri_t*)(*l)->val; + if (vec_isequal(*v, t->a.v)) { + t->a.n = n; + } + else if (vec_isequal(*v, t->b.v)) { + t->b.n = n; + } + else if (vec_isequal(*v, t->c.v)) { + t->c.n = n; + } + list_pop(l); + } +} + +#endif // FIND_NORMALS + + /* * A group of triangles and a transformation. */ struct _group { - list_t* triangles; - mat_t modelview; + list_t* triangles; + mat_t model; +#if RENDER_PROGRESS + char* name; + int count; +#define IF_RENDER_PROGRESS(X) X +#else +#define IF_RENDER_PROGRESS(X) +#endif }; typedef struct _group _group_t; @@ -39,19 +109,41 @@ static _group_t* _group_alloc(const char* filename) _group_t* g = (_group_t*)mem_alloc(sizeof(_group_t)); g->triangles = NULL; - g->modelview = MAT_IDENTITY; + g->model = MAT_IDENTITY; +#if RENDER_PROGRESS + g->name = mem_strdup(filename); + g->count = 0; +#endif + +#if FIND_NORMALS == 2 + map_t* m = map_vnorm_alloc(); +#endif 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) + vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1), + vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2), + vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3) ); list_push2(&g->triangles, t, mem_free); + IF_RENDER_PROGRESS(++g->count); + +#if FIND_NORMALS == 1 + vec_t n = vec_normalize(tri_normal(*t)); + t->a.n = n; + t->b.n = n; + t->c.n = n; +#elif FIND_NORMALS == 2 + _find_normals_add_triangle(m, t); +#endif } - list_reverse(&g->triangles); + +#if FIND_NORMALS == 2 + map_vnorm_call(m, _find_normals_average); + rbtree_destroy(m); +#endif fclose(file); @@ -69,6 +161,7 @@ static _group_t* _group_alloc(const char* filename) */ static void _group_destroy(_group_t* g) { + IF_RENDER_PROGRESS(mem_free(g->name)); list_destroy(g->triangles); mem_free(g); } @@ -100,13 +193,12 @@ static int _group_set_colors(_group_t* g, FILE* file) */ static int _group_add_translate(_group_t* g, FILE* file) { - double tx, ty; - if (fscanf(file, " %lf %lf", &tx, &ty) != 2) { + double tx, ty, tz; + if (fscanf(file, " %lf %lf %lf", &tx, &ty, &tz) != 3) { fprintf(stderr, "Cannot read translate coordinates from scene file.\n"); return -1; } - - g->modelview = mat_mult(g->modelview, MAT_TRANSLATE((scal_t)tx, (scal_t)ty, S(1.0))); + g->model = mat_mult(g->model, MAT_TRANSLATE((scal_t)tx, (scal_t)ty, (scal_t)tz)); return 0; } @@ -115,13 +207,12 @@ static int _group_add_translate(_group_t* g, FILE* file) */ static int _group_add_rotate(_group_t* g, FILE* file) { - double theta; - if (fscanf(file, " %lf", &theta) != 1) { + 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 file.\n"); return -1; } - - g->modelview = mat_mult(g->modelview, MAT_ROTATE_Z((scal_t)theta)); + g->model = mat_mult(g->model, MAT_ROTATE((scal_t)theta, (scal_t)ax, (scal_t)ay, (scal_t)az)); return 0; } @@ -130,13 +221,12 @@ static int _group_add_rotate(_group_t* g, FILE* file) */ static int _group_add_scale(_group_t* g, FILE* file) { - double sx, sy; - if (fscanf(file, " %lf %lf", &sx, &sy) != 2) { + double sx, sy, sz; + if (fscanf(file, " %lf %lf %lf", &sx, &sy, &sz) != 3) { fprintf(stderr, "Cannot read scale factors from scene file.\n"); return -1; } - - g->modelview = mat_mult(g->modelview, MAT_SCALE((scal_t)sx, (scal_t)sy, S(1.0))); + g->model = mat_mult(g->model, MAT_SCALE((scal_t)sx, (scal_t)sy, (scal_t)sz)); return 0; } @@ -144,36 +234,48 @@ static int _group_add_scale(_group_t* g, FILE* file) struct scene { list_t* groups; - int w; - int h; + list_t* lights; + int w, h; + mat_t view; mat_t projection; + vec_t eye; }; scene_t* scene_alloc(const char* filename) { - scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t)); - s->groups = NULL; - FILE* file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno)); + return NULL; + } 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) { + 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 file header.\n"); return NULL; } + scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t)); + s->groups = NULL; s->w = w; s->h = h; - s->projection = MAT_ORTHO((scal_t)minX, (scal_t)maxX, (scal_t)minY, (scal_t)maxY); + 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); char grp_filename[4096]; _group_t* g = NULL; #define _ASSERT_G \ if (g == NULL) { \ - fprintf(stderr, "Unexpected line before group is loaded.\n"); \ + fprintf(stderr, "Unexpected line before group is specified.\n"); \ goto fail; \ } @@ -223,7 +325,6 @@ if (g == NULL) { \ fprintf(stderr, "Unknown identifier: %c\n", type); } } - list_reverse(&s->groups); #undef _ASSERT_G @@ -242,19 +343,50 @@ void scene_destroy(scene_t* s) } -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); +#if RENDER_TIMER + 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_light(p, light_new(COLOR_WHITE, vec_new(S(5.0), S(3.0), S(6.0)))); + raster_light(p, light_new(COLOR_MAGENTA, vec_new(S(-2.0), S(2.0), S(-2.0)))); + +#if RENDER_PROGRESS +#define PROGRESS_FMT "\033[80D\033[2K %s\t %9d / %d" + int tri; + printf("render scene:\n"); +#endif for (list_t* gi = s->groups; gi; gi = gi->link) { _group_t* g = (_group_t*)gi->val; - pixmap_modelview(pix, &g->modelview); + raster_model(p, &g->model); + IF_RENDER_PROGRESS(tri = 0); for (list_t* ti = g->triangles; ti; ti = ti->link) { - pixmap_draw_tri(pix, (tri_t*)ti->val); +#if RENDER_PROGRESS + if (++tri % 100 == 0) { + printf(PROGRESS_FMT, g->name, tri, g->count); + fflush(stdout); + } +#endif + raster_draw_tri(p, (tri_t*)ti->val); } +#if RENDER_PROGRESS + printf(PROGRESS_FMT"\n", g->name, tri, g->count); +#endif } + IF_RENDER_PROGRESS(printf("render complete!\n")); + +#if RENDER_TIMER + long dt = timer_stop(); + printf("time\t%.3fms\n", (float)dt / 1000.0f); +#endif - return pix; + return p; }