Browse Source

Port bilinear interpolation to triangle functions

rexim 2 years ago
parent
commit
1caba08290
10 changed files with 106 additions and 47 deletions
  1. 1 0
      CREDITS.txt
  2. BIN
      assets/lavastone-origin.png
  3. BIN
      assets/lavastone.png
  4. BIN
      assets/oldstone-origin.png
  5. BIN
      assets/oldstone.png
  6. 1 1
      demos/squish.c
  7. 21 6
      demos/triangle3dTex.c
  8. 1 1
      demos/triangleTex.c
  9. 2 0
      nobuild.c
  10. 80 39
      olive.c

+ 1 - 0
CREDITS.txt

@@ -0,0 +1 @@
+- https://opengameart.org/content/handpainted-stone-texture

BIN
assets/lavastone-origin.png


BIN
assets/lavastone.png


BIN
assets/oldstone-origin.png


BIN
assets/oldstone.png


+ 1 - 1
demos/squish.c

@@ -25,7 +25,7 @@ Olivec_Canvas vc_render(float dt)
     int w = tsodinPog_width*SRC_SCALE - t*factor;
     int w = tsodinPog_width*SRC_SCALE - t*factor;
     int h = tsodinPog_height*SRC_SCALE + t*factor;
     int h = tsodinPog_height*SRC_SCALE + t*factor;
 
 
-    olivec_sprite_blend(
+    olivec_sprite_copy_bilinear(
         dst_canvas,
         dst_canvas,
         WIDTH/2 - w/2, HEIGHT - h, w, h,
         WIDTH/2 - w/2, HEIGHT - h, w, h,
         olivec_canvas(tsodinPog_pixels, tsodinPog_width, tsodinPog_height, tsodinPog_width));
         olivec_canvas(tsodinPog_pixels, tsodinPog_width, tsodinPog_height, tsodinPog_width));

+ 21 - 6
demos/triangle3dTex.c

@@ -1,5 +1,8 @@
+#define VC_TERM_SCALE_DOWN_FACTOR 10
 #include "vc.c"
 #include "vc.c"
 #include "./assets/tsodinPog.c"
 #include "./assets/tsodinPog.c"
+#include "./assets/oldstone.c"
+#include "./assets/lavastone.c"
 
 
 #define WIDTH 960
 #define WIDTH 960
 #define HEIGHT 720
 #define HEIGHT 720
@@ -56,11 +59,12 @@ Olivec_Canvas vc_render(float dt)
     global_time += dt;
     global_time += dt;
 
 
     Olivec_Canvas oc1 = olivec_canvas(pixels1, WIDTH, HEIGHT, WIDTH);
     Olivec_Canvas oc1 = olivec_canvas(pixels1, WIDTH, HEIGHT, WIDTH);
-    olivec_fill(oc1, 0xFF181818);
+    olivec_fill(oc1, 0xFF202020);
     Olivec_Canvas zb1 = olivec_canvas((uint32_t*)zbuffer1, WIDTH, HEIGHT, WIDTH);
     Olivec_Canvas zb1 = olivec_canvas((uint32_t*)zbuffer1, WIDTH, HEIGHT, WIDTH);
     olivec_fill(zb1, 0);
     olivec_fill(zb1, 0);
 
 
-    Olivec_Canvas tsodinPog = olivec_canvas(tsodinPog_pixels, tsodinPog_width, tsodinPog_height, tsodinPog_width);
+    Olivec_Canvas oldstone = olivec_canvas(oldstone_pixels, oldstone_width, oldstone_height, oldstone_width);
+    Olivec_Canvas lavastone = olivec_canvas(lavastone_pixels, lavastone_width, lavastone_height, lavastone_width);
 
 
     float z = 1.5;
     float z = 1.5;
     float t = 0.75;
     float t = 0.75;
@@ -73,12 +77,14 @@ Olivec_Canvas vc_render(float dt)
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));
 
 
-        olivec_triangle3uv(
+        olivec_triangle3uv_bilinear(
             oc1,
             oc1,
             p1.x, p1.y, p2.x, p2.y, p3.x, p3.y,
             p1.x, p1.y, p2.x, p2.y, p3.x, p3.y,
-            0/v1.z, 1/v1.z, 0.5/v2.z, 0/v2.z, 1/v3.z, 0/v3.z,
+            0/v1.z, 1/v1.z,
+            1/v2.z, 1/v2.z,
+            0.5/v3.z, 0/v3.z,
             1/v1.z, 1/v2.z, 1/v3.z,
             1/v1.z, 1/v2.z, 1/v3.z,
-            tsodinPog
+            oldstone
         );
         );
         olivec_triangle3z(zb1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
         olivec_triangle3z(zb1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
     }
     }
@@ -97,8 +103,17 @@ Olivec_Canvas vc_render(float dt)
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));
 
 
+        olivec_triangle3uv_bilinear(
+            oc2,
+            p1.x, p1.y, p2.x, p2.y, p3.x, p3.y,
+            0/v1.z, 1/v1.z,
+            1/v2.z, 1/v2.z,
+            0.5/v3.z, 0/v3.z,
+            1/v1.z, 1/v2.z, 1/v3.z,
+            lavastone
+        );
+
         olivec_triangle3z(zb2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
         olivec_triangle3z(zb2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
-        olivec_triangle3c(oc2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0xFF1818FF, 0xFF18FF18, 0xFFFF1818);
     }
     }
 
 
     for (size_t y = 0; y < HEIGHT; ++y) {
     for (size_t y = 0; y < HEIGHT; ++y) {

+ 1 - 1
demos/triangleTex.c

@@ -42,7 +42,7 @@ Olivec_Canvas vc_render(float dt)
             int i1 = (i*2 + 0)%4;
             int i1 = (i*2 + 0)%4;
             int i2 = (i*2 + 1)%4;
             int i2 = (i*2 + 1)%4;
             int i3 = (i*2 + 2)%4;
             int i3 = (i*2 + 2)%4;
-            olivec_triangle3uv(
+            olivec_triangle3uv_bilinear(
                 oc,
                 oc,
                 ps[i1][0], ps[i1][1],
                 ps[i1][0], ps[i1][1],
                 ps[i2][0], ps[i2][1],
                 ps[i2][0], ps[i2][1],

+ 2 - 0
nobuild.c

@@ -15,6 +15,8 @@ void build_assets(void)
     MKDIRS("build", "assets");
     MKDIRS("build", "assets");
     CMD("./build/tools/png2c", "-n", "tsodinPog", "-o", "./build/assets/tsodinPog.c", "./assets/tsodinPog.png");
     CMD("./build/tools/png2c", "-n", "tsodinPog", "-o", "./build/assets/tsodinPog.c", "./assets/tsodinPog.png");
     CMD("./build/tools/png2c", "-n", "tsodinCup", "-o", "./build/assets/tsodinCup.c", "./assets/tsodinCup.png");
     CMD("./build/tools/png2c", "-n", "tsodinCup", "-o", "./build/assets/tsodinCup.c", "./assets/tsodinCup.png");
+    CMD("./build/tools/png2c", "-n", "oldstone", "-o", "./build/assets/oldstone.c", "./assets/oldstone.png");
+    CMD("./build/tools/png2c", "-n", "lavastone", "-o", "./build/assets/lavastone.c", "./assets/lavastone.png");
     CMD("./build/tools/obj2c", "-o", "./build/assets/tsodinCupLowPoly.c", "./assets/tsodinCupLowPoly.obj");
     CMD("./build/tools/obj2c", "-o", "./build/assets/tsodinCupLowPoly.c", "./assets/tsodinCupLowPoly.obj");
     CMD("./build/tools/obj2c", "-s", "0.40", "-o", "./build/assets/utahTeapot.c", "./assets/utahTeapot.obj");
     CMD("./build/tools/obj2c", "-s", "0.40", "-o", "./build/assets/utahTeapot.c", "./assets/utahTeapot.obj");
 }
 }

+ 80 - 39
olive.c

@@ -339,10 +339,12 @@ OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2,
 OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t c1, uint32_t c2, uint32_t c3);
 OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t c1, uint32_t c2, uint32_t c3);
 OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3);
 OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3);
 OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture);
 OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture);
+OLIVECDEF void olivec_triangle3uv_bilinear(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture);
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
+OLIVECDEF uint32_t olivec_pixel_bilinear(Olivec_Canvas sprite, int nx, int ny, int w, int h);
 
 
 typedef struct {
 typedef struct {
     // Safe ranges to iterate over.
     // Safe ranges to iterate over.
@@ -724,13 +726,47 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
                     float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
                     float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
                     float tx = tx1*u1/det + tx2*u2/det + tx3*u3/det;
                     float tx = tx1*u1/det + tx2*u2/det + tx3*u3/det;
                     float ty = ty1*u1/det + ty2*u2/det + ty3*u3/det;
                     float ty = ty1*u1/det + ty2*u2/det + ty3*u3/det;
+
                     int texture_x = tx/z*texture.width;
                     int texture_x = tx/z*texture.width;
                     if (texture_x < 0) texture_x = 0;
                     if (texture_x < 0) texture_x = 0;
                     if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
                     if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
+
                     int texture_y = ty/z*texture.height;
                     int texture_y = ty/z*texture.height;
                     if (texture_y < 0) texture_y = 0;
                     if (texture_y < 0) texture_y = 0;
                     if ((size_t) texture_y >= texture.height) texture_y = texture.height - 1;
                     if ((size_t) texture_y >= texture.height) texture_y = texture.height - 1;
-                    OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
+                    OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, (int)texture_x, (int)texture_y);
+                }
+            }
+        }
+    }
+}
+
+OLIVECDEF void olivec_triangle3uv_bilinear(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float z1, float z2, float z3, Olivec_Canvas texture)
+{
+    int lx, hx, ly, hy;
+    if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
+        for (int y = ly; y <= hy; ++y) {
+            for (int x = lx; x <= hx; ++x) {
+                int u1, u2, det;
+                if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
+                    int u3 = det - u1 - u2;
+                    float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
+                    float tx = tx1*u1/det + tx2*u2/det + tx3*u3/det;
+                    float ty = ty1*u1/det + ty2*u2/det + ty3*u3/det;
+
+                    float texture_x = tx/z*texture.width;
+                    if (texture_x < 0) texture_x = 0;
+                    if (texture_x >= (float) texture.width) texture_x = texture.width - 1;
+
+                    float texture_y = ty/z*texture.height;
+                    if (texture_y < 0) texture_y = 0;
+                    if (texture_y >= (float) texture.height) texture_y = texture.height - 1;
+
+                    int precision = 100;
+                    OLIVEC_PIXEL(oc, x, y) = olivec_pixel_bilinear(
+                                                 texture,
+                                                 texture_x*precision, texture_y*precision,
+                                                 precision, precision);
                 }
                 }
             }
             }
         }
         }
@@ -818,6 +854,48 @@ OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h,
     }
     }
 }
 }
 
 
+// TODO: olivec_pixel_bilinear does not check for out-of-bounds
+// But maybe it shouldn't. Maybe it's a responsibility of the caller of the function.
+OLIVECDEF uint32_t olivec_pixel_bilinear(Olivec_Canvas sprite, int nx, int ny, int w, int h)
+{
+    int px = nx%w;
+    int py = ny%h;
+
+    int x1 = nx/w, x2 = nx/w;
+    int y1 = ny/h, y2 = ny/h;
+    if (px < w/2) {
+        // left
+        px += w/2;
+        x1 -= 1;
+        if (x1 < 0) x1 = 0;
+    } else {
+        // right
+        px -= w/2;
+        x2 += 1;
+        if ((size_t) x2 >= sprite.width) x2 = sprite.width - 1;
+    }
+
+    if (py < h/2) {
+        // top
+        py += h/2;
+        y1 -= 1;
+        if (y1 < 0) y1 = 0;
+    } else {
+        // bottom
+        py -= h/2;
+        y2 += 1;
+        if ((size_t) y2 >= sprite.height) y2 = sprite.height - 1;
+    }
+
+    return mix_colors2(mix_colors2(OLIVEC_PIXEL(sprite, x1, y1),
+                                   OLIVEC_PIXEL(sprite, x2, y1),
+                                   px, w),
+                       mix_colors2(OLIVEC_PIXEL(sprite, x1, y2),
+                                   OLIVEC_PIXEL(sprite, x2, y2),
+                                   px, w),
+                       py, h);
+}
+
 OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite)
 OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite)
 {
 {
     // TODO: support negative size in olivec_sprite_copy_bilinear()
     // TODO: support negative size in olivec_sprite_copy_bilinear()
@@ -831,44 +909,7 @@ OLIVECDEF void olivec_sprite_copy_bilinear(Olivec_Canvas oc, int x, int y, int w
         for (int x = nr.x1; x <= nr.x2; ++x) {
         for (int x = nr.x1; x <= nr.x2; ++x) {
             size_t nx = (x - nr.ox1)*sprite.width;
             size_t nx = (x - nr.ox1)*sprite.width;
             size_t ny = (y - nr.oy1)*sprite.height;
             size_t ny = (y - nr.oy1)*sprite.height;
-
-            int px = nx%w;
-            int py = ny%h;
-
-            int x1 = nx/w, x2 = nx/w;
-            int y1 = ny/h, y2 = ny/h;
-            if (px < w/2) {
-                // left
-                px += w/2;
-                x1 -= 1;
-                if (x1 < 0) x1 = 0;
-            } else {
-                // right
-                px -= w/2;
-                x2 += 1;
-                if ((size_t) x2 >= sprite.width) x2 = sprite.width - 1;
-            }
-
-            if (py < h/2) {
-                // top
-                py += h/2;
-                y1 -= 1;
-                if (y1 < 0) y1 = 0;
-            } else {
-                // bottom
-                py -= h/2;
-                y2 += 1;
-                if ((size_t) y2 >= sprite.height) y2 = sprite.height - 1;
-            }
-
-            OLIVEC_PIXEL(oc, x, y) =
-                mix_colors2(mix_colors2(OLIVEC_PIXEL(sprite, x1, y1),
-                                        OLIVEC_PIXEL(sprite, x2, y1),
-                                        px, w),
-                            mix_colors2(OLIVEC_PIXEL(sprite, x1, y2),
-                                        OLIVEC_PIXEL(sprite, x2, y2),
-                                        px, w),
-                            py, h);
+            OLIVEC_PIXEL(oc, x, y) = olivec_pixel_bilinear(sprite, nx, ny, w, h);
         }
         }
     }
     }
 }
 }