X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=scene.c;h=be185113988fc11ecc7e840763d22f9aa46c14f8;hp=940767d4f339b6ea44478a8821c1cd6e4f7bd49f;hb=e16cf0578f4baaf879e4ab9d3528a765bfd29be0;hpb=c875478cdd823c7df8fdc859941bd9e5948c9315 diff --git a/scene.c b/scene.c index 940767d..be18511 100644 --- a/scene.c +++ b/scene.c @@ -16,7 +16,7 @@ #include "tri.h" -#if FIND_NORMALS == 2 +#if PRE_NORMALS >= 2 #include "map.h" DECLARE_AND_DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b)); @@ -45,7 +45,6 @@ static void _find_normals_add_triangle(map_t* m, tri_t* t) _find_normals_add_vertex(m, t->c.v, t); } - /* * Calculate an averaged normal from a list of triangles that share a common * vertex. @@ -76,7 +75,7 @@ static void _find_normals_average(const vec_t* v, list_t** l) } } -#endif // FIND_NORMALS +#endif // PRE_NORMALS /* @@ -86,36 +85,154 @@ struct _group { list_t* triangles; mat_t model; -#if RENDER_PROGRESS + color_t specular; + scal_t shininess; char* name; int count; -#define IF_RENDER_PROGRESS(X) X -#else -#define IF_RENDER_PROGRESS(X) -#endif }; typedef struct _group _group_t; + +#define _CHECK_IO(X) if ((X) <= 0) goto fail + /* - * Allocate a group by reading raw triangle coordinates from a file. + * Try to read the triangle geometry from the cache file. */ -static _group_t* _group_alloc(const char* filename) +static int _group_try_read_cache(const char* filename, list_t** l) { - FILE* file = fopen(filename, "r"); + char* cachename = mem_strcat(".", filename); + FILE* file = fopen(cachename, "rb"); if (file == NULL) { - fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno)); - return 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; -#if RENDER_PROGRESS 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 -#if FIND_NORMALS == 2 + 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 @@ -128,44 +245,38 @@ static _group_t* _group_alloc(const char* filename) vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3) ); list_push2(&g->triangles, t, mem_free); - IF_RENDER_PROGRESS(++g->count); + ++g->count; -#if FIND_NORMALS == 1 +#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 FIND_NORMALS == 2 +#elif PRE_NORMALS >= 2 _find_normals_add_triangle(m, t); #endif } -#if FIND_NORMALS == 2 +#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 coordinates read from %s\n", filename); - mem_free(g); + fprintf(stderr, "No triangles read from %s\n", filename); + _group_destroy(g); return NULL; } return g; } -/* - * Destroy a group. - */ -static void _group_destroy(_group_t* g) -{ - IF_RENDER_PROGRESS(mem_free(g->name)); - list_destroy(g->triangles); - mem_free(g); -} - /* * Set the colors of the triangles in the group as defined in a file. @@ -175,7 +286,7 @@ 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 file.\n"); + fprintf(stderr, "Cannot read color values from scene.\n"); return -1; } @@ -195,7 +306,7 @@ 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 file.\n"); + 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)); @@ -209,7 +320,7 @@ 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 file.\n"); + 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)); @@ -223,32 +334,75 @@ 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 file.\n"); + 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; +} + struct scene { list_t* groups; - list_t* lights; int w, h; mat_t view; mat_t projection; vec_t eye; + list_t* lights; + color_t ambient; }; -scene_t* scene_alloc(const char* filename) + +/* + * Set the ambient light properties of a scene. + */ +static int _scene_set_ambient(scene_t* s, FILE* file) { - FILE* file = fopen(filename, "r"); - if (file == NULL) { - fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno)); - return NULL; + 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; @@ -256,7 +410,7 @@ scene_t* scene_alloc(const char* filename) &w, &h, &eyeX, &eyeY, &eyeZ, &spotX, &spotY, &spotZ, &upX, &upY, &upZ, &fovy, &aspect, &near, &far) != 15) { - fprintf(stderr, "Cannot read scene file header.\n"); + fprintf(stderr, "Cannot read scene header.\n"); return NULL; } @@ -269,6 +423,8 @@ scene_t* scene_alloc(const char* filename) 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 grp_filename[4096]; _group_t* g = NULL; @@ -321,14 +477,35 @@ if (g == NULL) { \ } 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 (_group_set_material(g, file) != 0) { + goto fail; + } + break; + + case 'X': + goto done; + default: fprintf(stderr, "Unknown identifier: %c\n", type); } } - #undef _ASSERT_G - fclose(file); +done: return s; fail: @@ -338,14 +515,15 @@ fail: void scene_destroy(scene_t* s) { - list_destroy(s->groups); + list_destroy(&s->groups); + list_destroy(&s->lights); mem_free(s); } raster_t* scene_render(scene_t* s) { -#if RENDER_TIMER +#if VERBOSITY >= 3 timer_start(); #endif @@ -353,11 +531,13 @@ raster_t* scene_render(scene_t* s) raster_view(p, &s->view); raster_projection(p, &s->projection); raster_eye(p, s->eye); + raster_ambient(p, s->ambient); - 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)))); + for (list_t* i = s->lights; i; i = i->link) { + raster_light(p, *(light_t*)i->val); + } -#if RENDER_PROGRESS +#if VERBOSITY >= 4 #define PROGRESS_FMT "\033[80D\033[2K %s\t %9d / %d" int tri; printf("render scene:\n"); @@ -366,9 +546,10 @@ raster_t* scene_render(scene_t* s) 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 RENDER_PROGRESS +#if VERBOSITY >= 4 if (++tri % 100 == 0) { printf(PROGRESS_FMT, g->name, tri, g->count); fflush(stdout); @@ -376,13 +557,13 @@ raster_t* scene_render(scene_t* s) #endif raster_draw_tri(p, (tri_t*)ti->val); } -#if RENDER_PROGRESS +#if VERBOSITY >= 4 printf(PROGRESS_FMT"\n", g->name, tri, g->count); #endif } IF_RENDER_PROGRESS(printf("render complete!\n")); -#if RENDER_TIMER +#if VERBOSITY >= 3 long dt = timer_stop(); printf("time\t%.3fms\n", (float)dt / 1000.0f); #endif