]> Dogcows Code - chaz/rasterize/blobdiff - raster.c
add texture mapping with perspective correction
[chaz/rasterize] / raster.c
index b4f466fcb0504dfc9b69a7a32e8770e7b01f1b93..9ab926a0a30030374bd0b695c5b0e990b6fc8386 100644 (file)
--- a/raster.c
+++ b/raster.c
@@ -26,6 +26,7 @@ struct raster
     mat_t       modelviewprojection;
     mat_t       viewport;
     bool        dirty;
+    const model_t* current;
 #if LIGHTING
     list_t*     lights;
     color_t     ambient;
@@ -54,6 +55,7 @@ raster_t* raster_alloc(int width, int height, color_t fill)
     raster_viewport(p, 0, 0, width, height);
     p->model = p->view = p->projection = MAT_IDENTITY;
     p->dirty = false;
+    p->current = NULL;
 
 #if LIGHTING
     p->ambient = color_new(S(0.2), S(0.2), S(0.2), S(1.0));
@@ -94,6 +96,14 @@ void raster_printstats(raster_t* p)
 }
 
 
+color_t raster_color(const raster_t* p, vec_t pt)
+{
+    int u = (int)((scal_t)p->w * pt.x);
+    int v = (int)((scal_t)p->h * pt.y);
+    return p->pixels[p->w * (p->h - v - 1) + u];
+}
+
+
 void raster_clear(raster_t* p, color_t fill)
 {
     size_t size = p->w * p->h;
@@ -167,7 +177,7 @@ void raster_material(raster_t* p, color_t specular, scal_t shininess)
 }
 
 
-#define _CHECK_WRITE(X) if ((X) <= 0) goto fail
+#define _DO_OR_DIE(X) if ((X) <= 0) goto fail
 
 int raster_export_ppm(const raster_t* p, const char* filename)
 {
@@ -177,12 +187,12 @@ fail:   fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno));
         return -1;
     }
 
-    _CHECK_WRITE(fprintf(file, "P3\n%u %u\n255\n", p->w, p->h));
+    _DO_OR_DIE(fprintf(file, "P3\n%u %u\n255\n", p->w, p->h));
     for (int y = (int)p->h - 1; y >= 0; --y) {
         for (int x = 0; x < p->w; ++x) {
             rgbachan_t r, g, b;
             color_split(p->pixels[y * p->w + x], &r, &g, &b, NULL);
-            _CHECK_WRITE(fprintf(file, "%hhu %hhu %hhu\n", r, g, b));
+            _DO_OR_DIE(fprintf(file, "%hhu %hhu %hhu\n", r, g, b));
         }
     }
 
@@ -222,22 +232,22 @@ fail:   fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno));
     /*
      * Check the return values to avoid loud warnings.
      */
-    _CHECK_WRITE(fwrite(&magicNumber, sizeof(magicNumber), 1, file));
-    _CHECK_WRITE(fwrite(&fileSize, sizeof(fileSize), 1, file));
-    _CHECK_WRITE(fwrite(&reserved0, sizeof(reserved0), 1, file));
-    _CHECK_WRITE(fwrite(&reserved1, sizeof(reserved1), 1, file));
-    _CHECK_WRITE(fwrite(&dataOffset, sizeof(dataOffset), 1, file));
-    _CHECK_WRITE(fwrite(&infoHeaderSize, sizeof(infoHeaderSize), 1, file));
-    _CHECK_WRITE(fwrite(&width, sizeof(width), 1, file));
-    _CHECK_WRITE(fwrite(&height, sizeof(height), 1, file));
-    _CHECK_WRITE(fwrite(&colorPlanes, sizeof(colorPlanes), 1, file));
-    _CHECK_WRITE(fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, file));
-    _CHECK_WRITE(fwrite(&compression, sizeof(compression), 1, file));
-    _CHECK_WRITE(fwrite(&dataSize, sizeof(dataSize), 1, file));
-    _CHECK_WRITE(fwrite(&horizontalResolution, sizeof(horizontalResolution), 1, file));
-    _CHECK_WRITE(fwrite(&verticalResolution, sizeof(verticalResolution), 1, file));
-    _CHECK_WRITE(fwrite(&paletteColorCount, sizeof(paletteColorCount), 1, file));
-    _CHECK_WRITE(fwrite(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file));
+    _DO_OR_DIE(fwrite(&magicNumber, sizeof(magicNumber), 1, file));
+    _DO_OR_DIE(fwrite(&fileSize, sizeof(fileSize), 1, file));
+    _DO_OR_DIE(fwrite(&reserved0, sizeof(reserved0), 1, file));
+    _DO_OR_DIE(fwrite(&reserved1, sizeof(reserved1), 1, file));
+    _DO_OR_DIE(fwrite(&dataOffset, sizeof(dataOffset), 1, file));
+    _DO_OR_DIE(fwrite(&infoHeaderSize, sizeof(infoHeaderSize), 1, file));
+    _DO_OR_DIE(fwrite(&width, sizeof(width), 1, file));
+    _DO_OR_DIE(fwrite(&height, sizeof(height), 1, file));
+    _DO_OR_DIE(fwrite(&colorPlanes, sizeof(colorPlanes), 1, file));
+    _DO_OR_DIE(fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, file));
+    _DO_OR_DIE(fwrite(&compression, sizeof(compression), 1, file));
+    _DO_OR_DIE(fwrite(&dataSize, sizeof(dataSize), 1, file));
+    _DO_OR_DIE(fwrite(&horizontalResolution, sizeof(horizontalResolution), 1, file));
+    _DO_OR_DIE(fwrite(&verticalResolution, sizeof(verticalResolution), 1, file));
+    _DO_OR_DIE(fwrite(&paletteColorCount, sizeof(paletteColorCount), 1, file));
+    _DO_OR_DIE(fwrite(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file));
     
     size_t size = width * height;
     for (int i = 0; i < size; ++i)
@@ -248,14 +258,147 @@ fail:   fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno));
         argb = PACK(argb, 2, r);
         argb = PACK(argb, 1, g);
         argb = PACK(argb, 0, b);
-        _CHECK_WRITE(fwrite(&argb, sizeof(argb), 1, file));
+        _DO_OR_DIE(fwrite(&argb, sizeof(argb), 1, file));
     }
     
     fclose(file);
     return 0;
 }
 
-#undef _CHECK_WRITE
+
+raster_t* raster_import(const char* filename)
+{
+    int     type = 0;
+    char*   ext = strrchr(filename, '.');
+    if (ext == NULL) {
+        goto fail;
+    }
+    ++ext;
+
+    if (strcmp(ext, "bmp") == 0) {
+        return raster_import_bmp(filename);
+    }
+    if (strcmp(ext, "ppm") == 0) {
+        return raster_import_ppm(filename);
+    }
+
+fail:
+    fprintf(stderr, "Unknown file type: %s", filename);
+    return NULL;
+}
+
+raster_t* raster_import_ppm(const char* filename)
+{
+    FILE* file = fopen(filename, "r");
+    if (file == NULL) {
+        fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno));
+        return NULL;
+    }
+
+    int w, h;
+    if (fscanf(file, "P3 %d %d 255 ", &w, &h) != 2) {
+        fprintf(stderr, "Cannot read header from %s: %s\n", filename, strerror(errno));
+        return NULL;
+    }
+
+    raster_t* p = raster_alloc(w, h, COLOR_WHITE);
+
+    for (int y = h - 1; y >= 0; --y) {
+        for (int x = 0; x < w; ++x) {
+            rgbachan_t r, g, b;
+            if (fscanf(file, "%hhu %hhu %hhu ", &r, &g, &b) != 3) {
+                fprintf(stderr, "Failed reading color values from %s: %s\n", filename, strerror(errno));
+                return NULL;
+            }
+            rgba_t rgba = PACK(rgba, 3, r);
+            rgba = PACK(rgba, 2, g);
+            rgba = PACK(rgba, 1, b);
+            rgba = PACK(rgba, 0, 255);
+            p->pixels[y * w + x] = color_from_rgba(rgba);
+        }
+    }
+
+    fclose(file);
+    return p;
+
+fail:
+    raster_destroy(p);
+    fclose(file);
+    fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno));
+    return NULL;
+}
+
+raster_t* raster_import_bmp(const char* filename)
+{
+    FILE* file = fopen(filename, "rb");
+    if (file == NULL) {
+        fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno));
+        return NULL;
+    }
+
+    uint16_t magicNumber;
+    uint16_t reserved0;//0x4D41;
+    uint16_t reserved1;//0x5454;
+    uint32_t dataOffset;
+    uint32_t infoHeaderSize;
+    uint32_t width;
+    uint32_t height;
+    uint16_t colorPlanes;
+    uint16_t bitsPerPixel;
+    uint32_t compression;
+    uint32_t dataSize;
+    uint32_t horizontalResolution;
+    uint32_t verticalResolution;
+    uint32_t paletteColorCount;
+    uint32_t importantPaletteColorCount;
+    uint32_t fileSize;
+
+    raster_t* p = NULL;
+
+    _DO_OR_DIE(fread(&magicNumber, sizeof(magicNumber), 1, file));
+    _DO_OR_DIE(fread(&fileSize, sizeof(fileSize), 1, file));
+    _DO_OR_DIE(fread(&reserved0, sizeof(reserved0), 1, file));
+    _DO_OR_DIE(fread(&reserved1, sizeof(reserved1), 1, file));
+    _DO_OR_DIE(fread(&dataOffset, sizeof(dataOffset), 1, file));
+    _DO_OR_DIE(fread(&infoHeaderSize, sizeof(infoHeaderSize), 1, file));
+    _DO_OR_DIE(fread(&width, sizeof(width), 1, file));
+    _DO_OR_DIE(fread(&height, sizeof(height), 1, file));
+    _DO_OR_DIE(fread(&colorPlanes, sizeof(colorPlanes), 1, file));
+    _DO_OR_DIE(fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, file));
+    _DO_OR_DIE(fread(&compression, sizeof(compression), 1, file));
+    _DO_OR_DIE(fread(&dataSize, sizeof(dataSize), 1, file));
+    _DO_OR_DIE(fread(&horizontalResolution, sizeof(horizontalResolution), 1, file));
+    _DO_OR_DIE(fread(&verticalResolution, sizeof(verticalResolution), 1, file));
+    _DO_OR_DIE(fread(&paletteColorCount, sizeof(paletteColorCount), 1, file));
+    _DO_OR_DIE(fread(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file));
+
+    p = raster_alloc((int)width, (int)height, COLOR_WHITE);
+
+    size_t size = width * height;
+    for (int i = 0; i < size; ++i)
+    {
+        uint32_t argb;
+        _DO_OR_DIE(fread(&argb, sizeof(argb), 1, file));
+        rgba_t rgba = PACK(rgba, 3, UNPACK(argb, 2));
+        rgba = PACK(rgba, 2, UNPACK(argb, 1));
+        rgba = PACK(rgba, 1, UNPACK(argb, 0));
+        rgba = PACK(rgba, 0, UNPACK(argb, 3));
+        p->pixels[i] = color_from_rgba(rgba);
+    }
+
+    fclose(file);
+    return p;
+
+fail:
+    if (p) {
+        raster_destroy(p);
+    }
+    fclose(file);
+    fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno));
+    return NULL;
+}
+
+#undef _DO_OR_DIE
 
 
 void raster_draw_model(raster_t* p, const model_t* model)
@@ -268,6 +411,7 @@ void raster_draw_model(raster_t* p, const model_t* model)
     model_transformation(model, &p->model);
     p->dirty = true;
     raster_material(p, model_specular(model), model_shininess(model));
+    p->current = model;
     IF_RENDER_PROGRESS(tri = 0);
     for (const list_t* ti = model_geometry(model); ti; ti = ti->link) {
 #if VERBOSITY >= 4
@@ -332,6 +476,9 @@ bool _try_cull_backface(tri_t t)
 INLINE_MAYBE
 color_t _do_phong_lighting(raster_t* p, vert_t vert)
 {
+#if TEXTURING
+    vert.c = color_mult(vert.c, model_tcolor(p->current, vert.t));
+#endif
 #if LIGHTING
     color_t color = COLOR_BLACK;
     color.a = vert.c.a;
@@ -371,7 +518,14 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle)
         p->modelviewprojection = mat_mult(p->projection, p->modelviewprojection);
         p->dirty = false;
     }
+
     t = tri_transform(t, p->modelviewprojection);
+
+    // save w-values for texture mapping perspective correction
+    scal_t w1 = t.a.v.w;
+    scal_t w2 = t.b.v.w;
+    scal_t w3 = t.c.v.w;
+
     t = tri_homodiv(t);
 
     if (!_try_cull_backface(t)) {
@@ -393,6 +547,9 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle)
 
 #if LIGHTING >= 1
     tri_t tl = tri_transform(*triangle, p->model);
+    tl.a.t.w = w1;
+    tl.b.t.w = w2;
+    tl.c.t.w = w3;
 #endif
 
 #if LIGHTING == 1
This page took 0.028179 seconds and 4 git commands to generate.