]> Dogcows Code - chaz/rasterize/blobdiff - scene.c
import project 3 files; added blending
[chaz/rasterize] / scene.c
diff --git a/scene.c b/scene.c
index 449dab661774e9770dd4ac18049740dc7be3ea97..d079e17ac7c4788617beb42d6c1ff4665ddb428a 100644 (file)
--- a/scene.c
+++ b/scene.c
  */
 
 #include <errno.h>
-#include <stdio.h>
-#include <string.h>
 
-#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
-{
-    list_t* triangles;
-    mat_t   modelview;
-};
-typedef struct _group _group_t;
-
-/*
- * Allocate a group by reading raw triangle coordinates from a file.
- */
-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));
-        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);
-
-    fclose(file);
-
-    if (g->triangles == NULL) {
-        fprintf(stderr, "No triangles coordinates read from %s\n", filename);
-        mem_free(g);
-        return NULL;
-    }
-
-    return g;
-}
-
-/*
- * Destroy a group.
- */
-static void _group_destroy(_group_t* g)
-{
-    list_destroy(g->triangles);
-    mem_free(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 file.\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;
-    if (fscanf(file, " %lf %lf", &tx, &ty) != 2) {
-        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)));
-    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;
-    if (fscanf(file, " %lf", &theta) != 1) {
-        fprintf(stderr, "Cannot read rotation angle from scene file.\n");
-        return -1;
-    }
-
-    g->modelview = mat_mult(g->modelview, MAT_ROTATE_Z((scal_t)theta));
-    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;
-    if (fscanf(file, " %lf %lf", &sx, &sy) != 2) {
-        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)));
-    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;
-    int     w;
-    int     h;
+    list_t* models;
+    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)
-{
-    scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t));
-    s->groups = NULL;
-
-    FILE* file = fopen(filename, "r");
 
+scene_t* scene_alloc(FILE* file)
+{
     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");
+    double eyeX, eyeY, eyeZ, spotX, spotY, spotZ, upX, upY, upZ;
+    double fovy, aspect, near, far;
+    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,
+               &aR, &aG, &aB) != 18) {
+        fprintf(stderr, "Cannot read scene header.\n");
         return NULL;
     }
 
+    scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t));
+    s->models = 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);
+    s->lights = NULL;
+    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) { \
-    fprintf(stderr, "Unexpected line before group is loaded.\n"); \
+if (m == NULL) { \
+    fprintf(stderr, "Unexpected line before group is specified.\n"); \
     goto fail; \
 }
 
@@ -181,53 +74,67 @@ 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) {
+                if (_model_add_scale(m, file) != 0) {
                     goto fail;
                 }
                 break;
 
+            case 'l':
+                if (_scene_add_light(s, file) != 0) {
+                    goto fail;
+                }
+                break;
+
+            case 'p':
+                _ASSERT_G;
+                if (_model_set_material(m, file) != 0) {
+                    goto fail;
+                }
+                break;
+
+            case 'X':
+                goto done;
+
             default:
                 fprintf(stderr, "Unknown identifier: %c\n", type);
         }
     }
-    list_reverse(&s->groups);
-
 #undef _ASSERT_G
 
-    fclose(file);
+done:
+    list_reverse(&s->models);
     return s;
 
 fail:
@@ -237,24 +144,142 @@ fail:
 
 void scene_destroy(scene_t* s)
 {
-    list_destroy(s->groups);
+    list_destroy(&s->models);
+    list_destroy(&s->lights);
     mem_free(s);
 }
 
 
-pixmap_t* scene_render(scene_t* 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)
 {
-    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);
-        }
+    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
+    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);
+    }
+
+#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 pix;
+    return p;
 }
 
This page took 0.026296 seconds and 4 git commands to generate.