]> Dogcows Code - chaz/rasterize/blobdiff - scene.c
add scene lighting constructs; real stdin support
[chaz/rasterize] / scene.c
diff --git a/scene.c b/scene.c
index 3e0010fa399cb4c016a365e88cfbd700785c845d..be185113988fc11ecc7e840763d22f9aa46c14f8 100644 (file)
--- a/scene.c
+++ b/scene.c
 #include "tri.h"
 
 
-#if RENDER_PROGRESS
-#define IF_RENDER_PROGRESS(X) X
-#else
-#define IF_RENDER_PROGRESS(X)
-#endif
-
 #if PRE_NORMALS >= 2
 
 #include "map.h"
@@ -91,6 +85,8 @@ struct _group
 {
     list_t*     triangles;
     mat_t       model;
+    color_t     specular;
+    scal_t      shininess;
     char*       name;
     int         count;
 };
@@ -107,7 +103,7 @@ 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) {
-        return 0;
+        goto fail;
     }
 
     int count = 0;
@@ -129,6 +125,7 @@ static int _group_try_read_cache(const char* filename, list_t** l)
             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));
@@ -141,13 +138,13 @@ static int _group_try_read_cache(const char* filename, list_t** l)
         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);
-
-        list_push2(l, t, mem_free);
     }
 
 fail:
-    fclose(file);
     mem_free(cachename);
+    if (file != NULL) {
+        fclose(file);
+    }
 
     return count;
 }
@@ -161,7 +158,7 @@ static void _group_write_cache(const char* filename, int count, list_t* l)
     FILE*   file = fopen(cachename, "wb");
     if (file == NULL) {
         fprintf(stderr, "Cannot write %s: %s\n", cachename, strerror(errno));
-        return;
+        goto fail;
     }
 
     _CHECK_IO(fwrite(&count, sizeof(count), 1, file));
@@ -189,11 +186,24 @@ static void _group_write_cache(const char* filename, int count, list_t* l)
 
 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.
  */
@@ -204,6 +214,8 @@ static _group_t* _group_alloc(const char* filename)
     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);
@@ -216,6 +228,7 @@ static _group_t* _group_alloc(const char* filename)
     FILE* file = fopen(filename, "r");
     if (file == NULL) {
         fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
+        _group_destroy(g);
         return NULL;
     }
 
@@ -256,24 +269,14 @@ static _group_t* _group_alloc(const char* filename)
     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)
-{
-    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.
@@ -283,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;
     }
 
@@ -303,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));
@@ -317,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));
@@ -331,38 +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;
-    if (strcmp(filename, "-") == 0) {
-        file = stdin;
-    }
-    else {
-        file = fopen(filename, "r");
+    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;
     }
-    if (file == NULL) {
-        fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
-        return NULL;
+    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;
@@ -370,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;
     }
 
@@ -383,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;
@@ -435,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:
@@ -452,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
 
@@ -467,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");
@@ -480,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);
@@ -490,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
This page took 0.028358 seconds and 4 git commands to generate.