]> Dogcows Code - chaz/rasterize/blobdiff - model.c
add texture mapping with perspective correction
[chaz/rasterize] / model.c
diff --git a/model.c b/model.c
index c136ae940ddf2200e80bd6134e4703884c8b279e..4ed8a8e2be41e097bc0945002c062db733d44839 100644 (file)
--- a/model.c
+++ b/model.c
@@ -7,18 +7,25 @@
 
 #include <errno.h>
 
-#include "tri.h"
+#include "array.h"
 #include "model.h"
+#include "raster.h"
+#include "tri.h"
+
+
+// create an interface for a vector array
+DEFINE_ARRAY_TYPE(vec);
 
 
 struct model
 {
-    list_t*     triangles;
-    mat_t       model;
-    color_t     specular;
-    scal_t      shininess;
-    char*       name;
-    int         count;
+    list_t*         triangles;
+    mat_t           model;
+    color_t         specular;
+    scal_t          shininess;
+    const raster_t* texture;
+    char*           name;
+    int             count;
 };
 
 
@@ -55,14 +62,15 @@ model_t* model_alloc2(const char* filename, int type)
     model_t* m = (model_t*)mem_alloc(sizeof(model_t));
     m->triangles = NULL;
     m->model = MAT_IDENTITY;
-    m->specular = COLOR_WHITE;
+    m->specular = COLOR_BLACK;
     m->shininess = S(64.0);
+    m->texture = NULL;
     m->name = mem_strdup(filename);
     m->count = 0;
 
 #if CACHE_GEOMETRY
-    int count = _model_try_read_cache(filename, &m->triangles);
-    if (0 < count) {
+    m->count = _model_try_read_cache(filename, &m->triangles);
+    if (0 < m->count) {
         return m;
     }
 #endif
@@ -91,6 +99,9 @@ model_t* model_alloc2(const char* filename, int type)
 void model_destroy(model_t* m)
 {
     list_destroy(&m->triangles);
+    if (m->texture) {
+        raster_destroy((raster_t*)m->texture);
+    }
     mem_free(m->name);
     mem_free(m);
 }
@@ -126,6 +137,14 @@ void model_transformation(const model_t* m, mat_t* transform)
     *transform = m->model;
 }
 
+color_t model_tcolor(const model_t* m, vec_t pt)
+{
+    if (m->texture) {
+        return raster_color(m->texture, pt);
+    }
+    return COLOR_WHITE;
+}
+
 
 void model_transform(model_t* m, const mat_t* transform)
 {
@@ -138,11 +157,16 @@ void model_material(model_t* m, color_t specular, scal_t shininess)
     m->shininess = shininess;
 }
 
+void model_texture(model_t* m, const void* p)
+{
+    m->texture = (const raster_t*)p;
+}
+
 
 #if CALC_NORMALS
 
 #include "map.h"
-DECLARE_AND_DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b));
+DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b));
 
 
 /*
@@ -249,10 +273,129 @@ static int _model_read_raw(model_t* m, const char* filename)
 
 static int _model_read_obj(model_t* m, const char* filename)
 {
+    FILE* file = fopen(filename, "r");
+    if (file == NULL) {
+        fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
+        return -1;
+    }
+
+#if CALC_NORMALS
+    map_t* nlookup = map_vnorm_alloc();
+#endif
+
+    array_t* v  = array_vec_alloc();
+    array_t* vt = array_vec_alloc();
+    array_t* vn = array_vec_alloc();
+
+    array_vec_push(v, VEC_ZERO);
+    array_vec_push(vt, VEC_ZERO);
+    array_vec_push(vn, VEC_ZERO);
+
+    char line[4096];
+    while (fgets(line, 4096, file)) {
+        char name[4096];
+        double f1, f2, f3, f4;
+        int i1, i2, i3, i4, i5, i6, i7, i8, i9;
+        if (sscanf(line, "v %lf %lf %lf %lf ", &f1, &f2, &f3, &f4) == 4) {
+            array_vec_push(v, vec_new2((scal_t)f1, (scal_t)f2, (scal_t)f3, (scal_t)f4));
+        }
+        else if (sscanf(line, "v %lf %lf %lf ", &f1, &f2, &f3) == 3) {
+            array_vec_push(v, vec_new((scal_t)f1, (scal_t)f2, (scal_t)f3));
+        }
+        else if (sscanf(line, "vt %lf %lf ", &f1, &f2) == 2) {
+            array_vec_push(vt, vec_new((scal_t)f1, (scal_t)f2, S(0.0)));
+        }
+        else if (sscanf(line, "vn %lf %lf %lf ", &f1, &f2, &f3) == 3) {
+            array_vec_push(vn, vec_new((scal_t)f1, (scal_t)f2, (scal_t)f3));
+        }
+        else if (sscanf(line, "f %d %d %d ", &i1, &i2, &i3) == 3) {
+            tri_t* t = tri_alloc(
+                vert_new(*array_vec_index(v, i1)),
+                vert_new(*array_vec_index(v, i2)),
+                vert_new(*array_vec_index(v, i3))
+            );
+            list_push2(&m->triangles, t, mem_free);
+            ++m->count;
+
+#if CALC_NORMALS
+            _find_normals_add_triangle(nlookup, t);
+#else
+            vec_t n = vec_normalize(tri_normal(*t));
+            t->a.n = n;
+            t->b.n = n;
+            t->c.n = n;
+#endif
+        }
+        else if (sscanf(line, "f %d/%d %d/%d %d/%d ", &i1, &i2, &i3, &i4, &i5, &i6) == 6) {
+            tri_t* t = tri_alloc(
+                vert_new(*array_vec_index(v, i1)),
+                vert_new(*array_vec_index(v, i3)),
+                vert_new(*array_vec_index(v, i5))
+            );
+            list_push2(&m->triangles, t, mem_free);
+            ++m->count;
+            t->a.t = *array_vec_index(vt, i2);
+            t->b.t = *array_vec_index(vt, i4);
+            t->c.t = *array_vec_index(vt, i6);
+#if CALC_NORMALS
+            _find_normals_add_triangle(nlookup, t);
+#else
+            vec_t n = vec_normalize(tri_normal(*t));
+            t->a.n = n;
+            t->b.n = n;
+            t->c.n = n;
+#endif
+        }
+        else if (sscanf(line, "f %d//%d %d//%d %d//%d ",
+                        &i1, &i2, &i3, &i4, &i5, &i6) == 6) {
+            tri_t* t = tri_alloc(
+                vert_new(*array_vec_index(v, i1)),
+                vert_new(*array_vec_index(v, i3)),
+                vert_new(*array_vec_index(v, i5))
+            );
+            list_push2(&m->triangles, t, mem_free);
+            ++m->count;
+            t->a.n = *array_vec_index(vn, i2);
+            t->b.n = *array_vec_index(vn, i4);
+            t->c.n = *array_vec_index(vn, i6);
+        }
+        else if (sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d ",
+                        &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9) {
+            tri_t* t = tri_alloc(
+                vert_new(*array_vec_index(v, i1)),
+                vert_new(*array_vec_index(v, i4)),
+                vert_new(*array_vec_index(v, i7))
+            );
+            list_push2(&m->triangles, t, mem_free);
+            ++m->count;
+            t->a.t = *array_vec_index(vt, i2);
+            t->b.t = *array_vec_index(vt, i5);
+            t->c.t = *array_vec_index(vt, i8);
+            t->a.n = *array_vec_index(vn, i3);
+            t->b.n = *array_vec_index(vn, i6);
+            t->c.n = *array_vec_index(vn, i9);
+        }
+    }
+
+    array_destroy(v);
+    array_destroy(vt);
+    array_destroy(vn);
+
+#if CALC_NORMALS
+    map_vnorm_call(nlookup, _find_normals_average);
+    rbtree_destroy(nlookup);
+#endif
+
+    fclose(file);
+    if (m->triangles == NULL) {
+        fprintf(stderr, "No triangles read from %s\n", filename);
+        return -1;
+    }
+    return 0;
 }
 
 
-#define _CHECK_IO(X) if ((X) <= 0) goto fail
+#define _DO_OR_DONE(X) if ((X) <= 0) goto done
 
 /*
  * Try to read the triangle geometry from the cache file.
@@ -263,43 +406,51 @@ static int _model_try_read_cache(const char* filename, list_t** l)
     char*   cachename  = mem_strcat(".", filename);
     FILE*   file = fopen(cachename, "rb");
     if (file == NULL) {
-        goto fail;
+        goto done;
     }
 
-    _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));
+    while (1) {
+        _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&z1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&z2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
+        _DO_OR_DONE(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)
         );
+        ++count;
         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));
+        _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&z1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&z2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
+        _DO_OR_DONE(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);
+        _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
+        t->a.t = vec_new((scal_t)x1, (scal_t)y1, S(0.0));
+        t->b.t = vec_new((scal_t)x2, (scal_t)y2, S(0.0));
+        t->c.t = vec_new((scal_t)x3, (scal_t)y3, S(0.0));
     }
 
-fail:
+done:
     mem_free(cachename);
     if (file != NULL) {
         fclose(file);
@@ -317,39 +468,54 @@ static void _model_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));
-        goto fail;
+        goto done;
     }
 
-    _CHECK_IO(fwrite(&count, sizeof(count), 1, file));
+    float x1, y1, z1, x2, y2, z2, x3, y3, z3;
     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));
+        x1 = (float)t->a.v.x; y1 = (float)t->a.v.y; z1 = (float)t->a.v.z;
+        x2 = (float)t->b.v.x; y2 = (float)t->b.v.y; z2 = (float)t->b.v.z;
+        x3 = (float)t->c.v.x; y3 = (float)t->c.v.y; z3 = (float)t->c.v.z;
+        _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z3, sizeof(float), 1, file));
+        x1 = (float)t->a.n.x; y1 = (float)t->a.n.y; z1 = (float)t->a.n.z;
+        x2 = (float)t->b.n.x; y2 = (float)t->b.n.y; z2 = (float)t->b.n.z;
+        x3 = (float)t->c.n.x; y3 = (float)t->c.n.y; z3 = (float)t->c.n.z;
+        _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&z3, sizeof(float), 1, file));
+        x1 = (float)t->a.t.x; y1 = (float)t->a.t.y;
+        x2 = (float)t->b.t.x; y2 = (float)t->b.t.y;
+        x3 = (float)t->c.t.x; y3 = (float)t->c.t.y;
+        _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
+        _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
     }
 
-fail:
+done:
     mem_free(cachename);
     if (file != NULL) {
         fclose(file);
     }
 }
 
-#undef _CHECK_IO
+#undef _DO_OR_DIE
 
 
This page took 0.026478 seconds and 4 git commands to generate.