X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=scene.c;h=d079e17ac7c4788617beb42d6c1ff4665ddb428a;hp=be185113988fc11ecc7e840763d22f9aa46c14f8;hb=95850b98f73ad7033af60a30e324e9c3cda55389;hpb=e16cf0578f4baaf879e4ab9d3528a765bfd29be0 diff --git a/scene.c b/scene.c index be18511..d079e17 100644 --- a/scene.c +++ b/scene.c @@ -6,360 +6,25 @@ */ #include -#include -#include -#include "common.h" -#include "mat.h" #include "list.h" +#include "model.h" +#include "mat.h" #include "scene.h" -#include "tri.h" - -#if PRE_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 // PRE_NORMALS - - -/* - * A group of triangles and a transformation. - */ -struct _group -{ - list_t* triangles; - mat_t model; - color_t specular; - scal_t shininess; - char* name; - int count; -}; -typedef struct _group _group_t; - - -#define _CHECK_IO(X) if ((X) <= 0) goto fail - -/* - * Try to read the triangle geometry from the cache file. - */ -static int _group_try_read_cache(const char* filename, list_t** l) -{ - char* cachename = mem_strcat(".", filename); - FILE* file = fopen(cachename, "rb"); - if (file == NULL) { - goto fail; - } - - int count = 0; - _CHECK_IO(fread(&count, sizeof(count), 1, file)); - - float x1, y1, z1, x2, y2, z2, x3, y3, z3; - for (int i = 0; i < count; ++i) { - _CHECK_IO(fread(&x1, sizeof(float), 1, file)); - _CHECK_IO(fread(&y1, sizeof(float), 1, file)); - _CHECK_IO(fread(&z1, sizeof(float), 1, file)); - _CHECK_IO(fread(&x2, sizeof(float), 1, file)); - _CHECK_IO(fread(&y2, sizeof(float), 1, file)); - _CHECK_IO(fread(&z2, sizeof(float), 1, file)); - _CHECK_IO(fread(&x3, sizeof(float), 1, file)); - _CHECK_IO(fread(&y3, sizeof(float), 1, file)); - _CHECK_IO(fread(&z3, sizeof(float), 1, file)); - tri_t* t = tri_alloc( - 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(l, t, mem_free); - _CHECK_IO(fread(&x1, sizeof(float), 1, file)); - _CHECK_IO(fread(&y1, sizeof(float), 1, file)); - _CHECK_IO(fread(&z1, sizeof(float), 1, file)); - _CHECK_IO(fread(&x2, sizeof(float), 1, file)); - _CHECK_IO(fread(&y2, sizeof(float), 1, file)); - _CHECK_IO(fread(&z2, sizeof(float), 1, file)); - _CHECK_IO(fread(&x3, sizeof(float), 1, file)); - _CHECK_IO(fread(&y3, sizeof(float), 1, file)); - _CHECK_IO(fread(&z3, sizeof(float), 1, file)); - t->a.n = vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1); - t->b.n = vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2); - t->c.n = vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3); - } - -fail: - mem_free(cachename); - if (file != NULL) { - fclose(file); - } - - return count; -} - -/* - * Write the triangle data to the cache. - */ -static void _group_write_cache(const char* filename, int count, list_t* l) -{ - char* cachename = mem_strcat(".", filename); - FILE* file = fopen(cachename, "wb"); - if (file == NULL) { - fprintf(stderr, "Cannot write %s: %s\n", cachename, strerror(errno)); - goto fail; - } - - _CHECK_IO(fwrite(&count, sizeof(count), 1, file)); - for (list_t* i = l; i; i = i->link) { - tri_t* t = (tri_t*)i->val; - _CHECK_IO(fwrite(&t->a.v.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->a.v.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->a.v.z, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.v.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.v.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.v.z, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.v.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.v.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.v.z, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->a.n.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->a.n.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->a.n.z, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.n.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.n.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->b.n.z, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.n.x, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.n.y, sizeof(float), 1, file)); - _CHECK_IO(fwrite(&t->c.n.z, sizeof(float), 1, file)); - } - -fail: - mem_free(cachename); - if (file != NULL) { - fclose(file); - } -} - -#undef _CHECK_IO - - -/* - * Destroy a group. - */ -static void _group_destroy(_group_t* g) -{ - mem_free(g->name); - list_destroy(&g->triangles); - mem_free(g); -} - -/* - * Allocate a group by reading raw triangle coordinates from a file. - */ -static _group_t* _group_alloc(const char* filename) -{ - _group_t* g = (_group_t*)mem_alloc(sizeof(_group_t)); - g->triangles = NULL; - g->model = MAT_IDENTITY; - g->name = mem_strdup(filename); - g->count = 0; - g->specular = COLOR_WHITE; - g->shininess = S(64.0); - -#if PRE_NORMALS == 3 - int r = _group_try_read_cache(filename, &g->triangles); - if (0 < r) { - g->count = r; - return g; - } -#endif - - FILE* file = fopen(filename, "r"); - if (file == NULL) { - fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno)); - _group_destroy(g); - return NULL; - } - -#if PRE_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), - 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); - ++g->count; - -#if PRE_NORMALS == 1 - vec_t n = vec_normalize(tri_normal(*t)); - t->a.n = n; - t->b.n = n; - t->c.n = n; -#elif PRE_NORMALS >= 2 - _find_normals_add_triangle(m, t); -#endif - } - -#if PRE_NORMALS >= 2 - map_vnorm_call(m, _find_normals_average); - rbtree_destroy(m); -#if PRE_NORMALS == 3 - list_reverse(&g->triangles); - _group_write_cache(filename, g->count, g->triangles); -#endif -#endif - - fclose(file); - - if (g->triangles == NULL) { - fprintf(stderr, "No triangles read from %s\n", filename); - _group_destroy(g); - return NULL; - } - - return g; -} - - -/* - * Set the colors of the triangles in the group as defined in a file. - */ -static int _group_set_colors(_group_t* g, 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 (list_t* i = g->triangles; 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 _group_add_translate(_group_t* g, 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; - } - g->model = mat_mult(g->model, MAT_TRANSLATE((scal_t)tx, (scal_t)ty, (scal_t)tz)); - return 0; -} - -/* - * Concat a rotation matrix to the transformation as defined in a file. - */ -static int _group_add_rotate(_group_t* g, 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; - } - g->model = mat_mult(g->model, MAT_ROTATE((scal_t)theta, (scal_t)ax, (scal_t)ay, (scal_t)az)); - return 0; -} - -/* - * Concat a scale matrix to the transformation as defined in a file. - */ -static int _group_add_scale(_group_t* g, 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; - } - g->model = mat_mult(g->model, MAT_SCALE((scal_t)sx, (scal_t)sy, (scal_t)sz)); - return 0; -} - -/* - * Set the specular highlight and shininess factor for the group. - */ -static int _group_set_material(_group_t* g, 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; - } - g->specular = color_new((scal_t)sr, (scal_t)sg, (scal_t)sb, S(1.0)); - g->shininess = (scal_t)shininess; - return 0; -} +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* groups; + list_t* models; int w, h; mat_t view; mat_t projection; @@ -369,53 +34,23 @@ struct scene }; -/* - * 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; -} - -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; -} - - 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", + double aR, aG, aB; + if (fscanf(file, "U4 %d %d %lf %lf %lf %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) { + &fovy, &aspect, &near, &far, + &aR, &aG, &aB) != 18) { fprintf(stderr, "Cannot read scene header.\n"); return NULL; } scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t)); - s->groups = NULL; + s->models = NULL; s->w = w; s->h = h; s->view = MAT_LOOKAT(vec_new( (scal_t)eyeX, (scal_t)eyeY, (scal_t)eyeZ), @@ -424,13 +59,13 @@ scene_t* scene_alloc(FILE* file) 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)); + s->ambient = color_new((scal_t)aR, (scal_t)aG, (scal_t)aB, S(1.0)); - char grp_filename[4096]; - _group_t* g = NULL; + char filename[4096]; + model_t* m = NULL; #define _ASSERT_G \ -if (g == NULL) { \ +if (m == NULL) { \ fprintf(stderr, "Unexpected line before group is specified.\n"); \ goto fail; \ } @@ -439,59 +74,52 @@ if (g == NULL) { \ 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"); + if (fgets(filename, 4096, file) == NULL) { + fprintf(stderr, "Cannot read model filename.\n"); } - trim(grp_filename); - g = _group_alloc(grp_filename); - if (g == NULL) { + m = model_alloc(trim(filename)); + if (m == NULL) { goto fail; } - list_push2(&s->groups, g, DTOR(_group_destroy)); + list_push2(&s->models, m, DTOR(model_destroy)); break; case 'c': _ASSERT_G; - if (_group_set_colors(g, file) != 0) { + if (_model_set_colors(m, file) != 0) { goto fail; } break; case 't': _ASSERT_G; - if (_group_add_translate(g, file) != 0) { + if (_model_add_translate(m, file) != 0) { goto fail; } break; case 'r': - if (_group_add_rotate(g, file) != 0) { + if (_model_add_rotate(m, file) != 0) { goto fail; } break; case 's': _ASSERT_G; - if (_group_add_scale(g, file) != 0) { - goto fail; - } - break; - - case 'A': - if (_scene_set_ambient(s, file) != 0) { + if (_model_add_scale(m, file) != 0) { goto fail; } break; - case 'L': + case 'l': if (_scene_add_light(s, file) != 0) { goto fail; } break; - case 'M': + case 'p': _ASSERT_G; - if (_group_set_material(g, file) != 0) { + if (_model_set_material(m, file) != 0) { goto fail; } break; @@ -506,6 +134,7 @@ if (g == NULL) { \ #undef _ASSERT_G done: + list_reverse(&s->models); return s; fail: @@ -515,12 +144,112 @@ fail: void scene_destroy(scene_t* s) { - list_destroy(&s->groups); + 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 a, r, g, b; + if (fscanf(file, " %lf %lf %lf %lf", &a, &r, &g, &b) != 4) { + 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)r, (colorchan_t)g, (colorchan_t)b, (colorchan_t)a); + t->b.c = color_new((colorchan_t)r, (colorchan_t)g, (colorchan_t)b, (colorchan_t)a); + t->c.c = color_new((colorchan_t)r, (colorchan_t)g, (colorchan_t)b, (colorchan_t)a); + } + 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; +} + +/* + * Add a light to the scene. + */ +static int _scene_add_light(scene_t* s, FILE* file) +{ + double lx, ly, lz, r, g, b; + if (fscanf(file, " %lf %lf %lf %lf %lf %lf", + &lx, &ly, &lz, &r, &g, &b) != 6) { + fprintf(stderr, "Cannot read light values from scene.\n"); + return -1; + } + light_t* l = light_alloc( + vec_new(lx, ly, lz), + color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)), + color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)) + ); + list_push2(&s->lights, l, mem_free); + return 0; +} + + raster_t* scene_render(scene_t* s) { #if VERBOSITY >= 3 @@ -537,35 +266,18 @@ raster_t* scene_render(scene_t* s) raster_light(p, *(light_t*)i->val); } -#if VERBOSITY >= 4 -#define PROGRESS_FMT "\033[80D\033[2K %s\t %9d / %d" - int tri; - printf("render scene:\n"); +#if VERBOSITY >= 3 + printf("rendering scene...\n"); #endif - for (list_t* gi = s->groups; gi; gi = gi->link) { - _group_t* g = (_group_t*)gi->val; - raster_model(p, &g->model); - raster_material(p, g->specular, g->shininess); - IF_RENDER_PROGRESS(tri = 0); - for (list_t* ti = g->triangles; ti; ti = ti->link) { -#if VERBOSITY >= 4 - if (++tri % 100 == 0) { - printf(PROGRESS_FMT, g->name, tri, g->count); - fflush(stdout); - } -#endif - raster_draw_tri(p, (tri_t*)ti->val); - } -#if VERBOSITY >= 4 - printf(PROGRESS_FMT"\n", g->name, tri, g->count); -#endif + for (list_t* gi = s->models; gi; gi = gi->link) { + model_t* m = (model_t*)gi->val; + raster_draw_model(p, m); } - IF_RENDER_PROGRESS(printf("render complete!\n")); #if VERBOSITY >= 3 long dt = timer_stop(); - printf("time\t%.3fms\n", (float)dt / 1000.0f); + printf("render complete!\ntime\t%.3fms\n", (float)dt / 1000.0f); #endif return p;