Browse Source

Implement Depth Buffer

rexim 3 years ago
parent
commit
56aef62f5e
9 changed files with 128 additions and 24 deletions
  1. 6 3
      build.sh
  2. 1 1
      demos/triangle.c
  3. 53 16
      demos/triangle3d.c
  4. 0 1
      index.html
  5. 68 3
      olive.c
  6. BIN
      wasm/3d.wasm
  7. BIN
      wasm/squish.wasm
  8. BIN
      wasm/triangle.wasm
  9. BIN
      wasm/triangle3d.wasm

+ 6 - 3
build.sh

@@ -2,15 +2,18 @@
 
 
 set -xe
 set -xe
 
 
+# TODO: enable -Wconversion
+# We can't enable it right now cause it produces to many warnings to fix on the stream.
+# I fix it later, when I have time.
 COMMON_CFLAGS="-Wall -Wextra -ggdb -I. -I./build/ -I./thirdparty/"
 COMMON_CFLAGS="-Wall -Wextra -ggdb -I. -I./build/ -I./thirdparty/"
 
 
 build_vc_demo() {
 build_vc_demo() {
     NAME=$1
     NAME=$1
 
 
-    clang $COMMON_CFLAGS -Os -fno-builtin --target=wasm32 --no-standard-libraries -Wl,--no-entry -Wl,--export=render -Wl,--export=__heap_base -Wl,--allow-undefined -o ./build/$NAME.wasm -DPLATFORM=WASM_PLATFORM ./demos/$NAME.c
+    clang $COMMON_CFLAGS -O2 -fno-builtin --target=wasm32 --no-standard-libraries -Wl,--no-entry -Wl,--export=render -Wl,--export=__heap_base -Wl,--allow-undefined -o ./build/$NAME.wasm -DPLATFORM=WASM_PLATFORM ./demos/$NAME.c
     cp ./build/$NAME.wasm ./wasm/
     cp ./build/$NAME.wasm ./wasm/
-    clang $COMMON_CFLAGS -o ./build/$NAME.sdl -DPLATFORM=SDL_PLATFORM ./demos/$NAME.c -lm -lSDL2
-    clang $COMMON_CFLAGS -o ./build/$NAME.term -DPLATFORM=TERM_PLATFORM ./demos/$NAME.c -lm
+    clang $COMMON_CFLAGS -O2 -o ./build/$NAME.sdl -DPLATFORM=SDL_PLATFORM ./demos/$NAME.c -lm -lSDL2
+    clang $COMMON_CFLAGS -O2 -o ./build/$NAME.term -DPLATFORM=TERM_PLATFORM ./demos/$NAME.c -lm
 }
 }
 
 
 mkdir -p ./build/
 mkdir -p ./build/

+ 1 - 1
demos/triangle.c

@@ -50,7 +50,7 @@ Olivec_Canvas render(float dt)
         rotate_point(&x1, &y1);
         rotate_point(&x1, &y1);
         rotate_point(&x2, &y2);
         rotate_point(&x2, &y2);
         rotate_point(&x3, &y3);
         rotate_point(&x3, &y3);
-        olivec_triangle3(oc, x1, y1, x2, y2, x3, y3, 0xFF2020FF, 0xFF20FF20, 0xFFFF2020);
+        olivec_triangle3c(oc, x1, y1, x2, y2, x3, y3, 0xFF2020FF, 0xFF20FF20, 0xFFFF2020);
     }
     }
 
 
     // Circle
     // Circle

+ 53 - 16
demos/triangle3d.c

@@ -3,7 +3,10 @@
 
 
 #define WIDTH 800
 #define WIDTH 800
 #define HEIGHT 600
 #define HEIGHT 600
-uint32_t pixels[WIDTH*HEIGHT];
+uint32_t pixels1[WIDTH*HEIGHT];
+float zbuffer1[WIDTH*HEIGHT];
+uint32_t pixels2[WIDTH*HEIGHT];
+float zbuffer2[WIDTH*HEIGHT];
 
 
 typedef struct {
 typedef struct {
     float x, y;
     float x, y;
@@ -40,7 +43,7 @@ Vector2 project_2d_scr(Vector2 v2)
     return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
     return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
 }
 }
 
 
-float global_time = 0;
+float global_time = 1.0;
 
 
 #define PI 3.14159265359
 #define PI 3.14159265359
 
 
@@ -51,27 +54,61 @@ Olivec_Canvas render(float dt)
 {
 {
     global_time += dt;
     global_time += dt;
 
 
-    Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
-    olivec_fill(oc, 0xFF181818);
+    Olivec_Canvas oc1 = olivec_canvas(pixels1, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(oc1, 0xFF181818);
+    Olivec_Canvas zb1 = olivec_canvas((uint32_t*)zbuffer1, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(zb1, 0);
 
 
     float z = 1.5;
     float z = 1.5;
+    float t = 0.75;
     {
     {
-        Vector2 p1 = project_2d_scr(project_3d_2d(make_vector3(cosf(global_time)*0.5, -0.5, z + sinf(global_time)*0.5)));
-        Vector2 p2 = project_2d_scr(project_3d_2d(make_vector3(cosf(global_time + PI)*0.5, -0.5, z + sinf(global_time + PI)*0.5)));
-        Vector2 p3 = project_2d_scr(project_3d_2d(make_vector3(0, 0.5, z)));
-        olivec_triangle3(oc, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0xFF1818FF, 0xFF18FF18, 0xFFFF1818);
+        Vector3 v1 = make_vector3(cosf(global_time)*t, -t, z + sinf(global_time)*t);
+        Vector3 v2 = make_vector3(cosf(global_time + PI)*t, -t, z + sinf(global_time + PI)*t);
+        Vector3 v3 = make_vector3(0, t, z);
+
+        Vector2 p1 = project_2d_scr(project_3d_2d(v1));
+        Vector2 p2 = project_2d_scr(project_3d_2d(v2));
+        Vector2 p3 = project_2d_scr(project_3d_2d(v3));
+
+        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_triangle3c(oc1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0xFF1818FF, 0xFF18FF18, 0xFFFF1818);
     }
     }
 
 
-#if 0
+    Olivec_Canvas oc2 = olivec_canvas(pixels2, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(oc2, 0xFF181818);
+    Olivec_Canvas zb2 = olivec_canvas((uint32_t*)zbuffer2, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(zb2, 0);
+
     {
     {
-        Vector2 p1 = project_2d_scr(project_3d_2d(make_vector3(cosf(global_time + PI/2)*0.5, -0.5, z + sinf(global_time + PI/2)*0.5)));
-        Vector2 p2 = project_2d_scr(project_3d_2d(make_vector3(cosf(global_time + PI + PI/2)*0.5, -0.5, z + sinf(global_time + PI + PI/2)*0.5)));
-        Vector2 p3 = project_2d_scr(project_3d_2d(make_vector3(0, 0.5, z)));
-        olivec_triangle3(oc, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0xFF1818FF, 0xFF18FF18, 0xFFFF1818);
-    }
-#endif
+        Vector3 v1 = make_vector3(cosf(global_time + PI/2)*t, -t, z + sinf(global_time + PI/2)*t);
+        Vector3 v2 = make_vector3(cosf(global_time + PI + PI/2)*t, -t, z + sinf(global_time + PI + PI/2)*t);
+        Vector3 v3 = make_vector3(0, t, z);
 
 
+        Vector2 p1 = project_2d_scr(project_3d_2d(v1));
+        Vector2 p2 = project_2d_scr(project_3d_2d(v2));
+        Vector2 p3 = project_2d_scr(project_3d_2d(v3));
 
 
+        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 x = 0; x < WIDTH; ++x) {
+            float z1 = *(float*)&OLIVEC_PIXEL(zb1, x, y);
+            float z2 = *(float*)&OLIVEC_PIXEL(zb2, x, y);
+            if (z1 < z2) {
+                OLIVEC_PIXEL(oc1, x, y) = OLIVEC_PIXEL(oc2, x, y);
+                z1 = z2;
+            }
+            z1 = 1.0f/z1;
+            if (z1 >= 1.0) {
+                z1 -= 1.0;
+                uint32_t v = z1*255;
+                if (v > 255) v = 255;
+                olivec_blend_color(&OLIVEC_PIXEL(oc1, x, y), (v<<(3*8)));
+            }
+        }
+    }
     
     
-    return oc;
+    return oc1;
 }
 }

+ 0 - 1
index.html

@@ -32,7 +32,6 @@
       startDemo("app-3d", "./wasm/3d.wasm");
       startDemo("app-3d", "./wasm/3d.wasm");
       startDemo("app-squish", "./wasm/squish.wasm");
       startDemo("app-squish", "./wasm/squish.wasm");
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
-      startDemo("app-squish", "./wasm/squish.wasm");
     </script>
     </script>
   </body>
   </body>
 </html>
 </html>

+ 68 - 3
olive.c

@@ -299,7 +299,8 @@ OLIVECDEF void olivec_circle(Olivec_Canvas oc, int cx, int cy, int r, uint32_t c
 // TODO: lines with different thiccness
 // TODO: lines with different thiccness
 OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uint32_t color);
 OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uint32_t color);
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color);
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color);
-OLIVECDEF void olivec_triangle3(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_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);
@@ -582,8 +583,8 @@ OLIVECDEF void barycentric(int x1, int y1, int x2, int y2, int x3, int y3,
     // u3 = det - u1 - u2
     // u3 = det - u1 - u2
 }
 }
 
 
-OLIVECDEF void olivec_triangle3(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)
 {
 {
     if (y1 > y2) {
     if (y1 > y2) {
         OLIVEC_SWAP(int, x1, x2);
         OLIVEC_SWAP(int, x1, x2);
@@ -647,6 +648,70 @@ OLIVECDEF void olivec_triangle3(Olivec_Canvas oc, int x1, int y1, int x2, int y2
     }
     }
 }
 }
 
 
+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)
+{
+    if (y1 > y2) {
+        OLIVEC_SWAP(int, x1, x2);
+        OLIVEC_SWAP(int, y1, y2);
+        OLIVEC_SWAP(float, z1, z2);
+    }
+
+    if (y2 > y3) {
+        OLIVEC_SWAP(int, x2, x3);
+        OLIVEC_SWAP(int, y2, y3);
+        OLIVEC_SWAP(float, z2, z3);
+    }
+
+    if (y1 > y2) {
+        OLIVEC_SWAP(int, x1, x2);
+        OLIVEC_SWAP(int, y1, y2);
+        OLIVEC_SWAP(float, z1, z2);
+    }
+
+    int dx12 = x2 - x1;
+    int dy12 = y2 - y1;
+    int dx13 = x3 - x1;
+    int dy13 = y3 - y1;
+
+    for (int y = y1; y <= y2; ++y) {
+        // TODO: move boundary checks outside of loops in olivec_fill_triangle
+        if (0 <= y && (size_t) y < oc.height) {
+            int s1 = dy12 != 0 ? (y - y1)*dx12/dy12 + x1 : x1;
+            int s2 = dy13 != 0 ? (y - y1)*dx13/dy13 + x1 : x1;
+            if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
+            for (int x = s1; x <= s2; ++x) {
+                if (0 <= x && (size_t) x < oc.width) {
+                    int u1, u2, det;
+                    barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
+                    float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
+                    OLIVEC_PIXEL(oc, x, y) = *(uint32_t*)&z;
+                }
+            }
+        }
+    }
+
+    int dx32 = x2 - x3;
+    int dy32 = y2 - y3;
+    int dx31 = x1 - x3;
+    int dy31 = y1 - y3;
+
+    for (int y = y2; y <= y3; ++y) {
+        if (0 <= y && (size_t) y < oc.height) {
+            int s1 = dy32 != 0 ? (y - y3)*dx32/dy32 + x3 : x3;
+            int s2 = dy31 != 0 ? (y - y3)*dx31/dy31 + x3 : x3;
+            if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
+            for (int x = s1; x <= s2; ++x) {
+                if (0 <= x && (size_t) x < oc.width) {
+                    int u1, u2, det;
+                    barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
+                    float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
+                    OLIVEC_PIXEL(oc, x, y) = *(uint32_t*)&z;
+                }
+            }
+        }
+    }
+}
+
 // TODO: AA for triangle
 // TODO: AA for triangle
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color)
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color)
 {
 {

BIN
wasm/3d.wasm


BIN
wasm/squish.wasm


BIN
wasm/triangle.wasm


BIN
wasm/triangle3d.wasm