Browse Source

Rotating textures

rexim 2 years ago
parent
commit
b21d7ae5a1
9 changed files with 159 additions and 0 deletions
  1. 1 0
      build.sh
  2. 62 0
      demos/triangle_tex.c
  3. 5 0
      index.html
  4. 91 0
      olive.c
  5. BIN
      wasm/3d.wasm
  6. BIN
      wasm/squish.wasm
  7. BIN
      wasm/triangle.wasm
  8. BIN
      wasm/triangle3d.wasm
  9. BIN
      wasm/triangle_tex.wasm

+ 1 - 0
build.sh

@@ -32,4 +32,5 @@ build_vc_demo triangle &
 build_vc_demo 3d &
 build_vc_demo squish &
 build_vc_demo triangle3d &
+build_vc_demo triangle_tex &
 wait # TODO: the whole script must fail if one of the jobs fails

+ 62 - 0
demos/triangle_tex.c

@@ -0,0 +1,62 @@
+// This example renders a rotating triangle.
+// This idea is that you can take this code and compile it to different platforms with different rendering machanisms:
+// native with SDL, WebAssembly with HTML5 canvas, etc.
+#define SCALE_DOWN_FACTOR 20
+#include "vc.c"
+#include "assets/tsodinPog.c"
+
+#define WIDTH 960
+#define HEIGHT 720
+#define BACKGROUND_COLOR 0xFF181818
+
+static uint32_t pixels[WIDTH*HEIGHT];
+static float triangle_angle = 0;
+
+float sqrtf(float x);
+float atan2f(float y, float x);
+float sinf(float x);
+float cosf(float x);
+
+#define PI 3.14159265359
+
+Olivec_Canvas render(float dt)
+{
+    Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
+    Olivec_Canvas tsodinPog = olivec_canvas(tsodinPog_pixels, tsodinPog_width, tsodinPog_height, tsodinPog_width);
+
+    olivec_fill(oc, BACKGROUND_COLOR);
+
+    // Triangle
+    {
+        triangle_angle += 0.5f*PI*dt;
+
+        float ps[4][2];
+        Uv uvs[4] = {
+            {0, 0},
+            {1, 0},
+            {1, 1},
+            {0, 1},
+        };
+        float len = WIDTH/4;
+        for (size_t i = 0; i < 4; ++i) {
+            ps[i][0] = WIDTH/2  + cosf(PI/2*i + triangle_angle)*len;
+            ps[i][1] = HEIGHT/2 + sinf(PI/2*i + triangle_angle)*len;
+        }
+        for (size_t i = 0; i < 2; ++i) {
+            int i1 = (i*2 + 0)%4;
+            int i2 = (i*2 + 1)%4;
+            int i3 = (i*2 + 2)%4;
+            olivec_triangle3uv(
+                oc,
+                ps[i1][0], ps[i1][1],
+                ps[i2][0], ps[i2][1],
+                ps[i3][0], ps[i3][1],
+                uvs[i1], uvs[i2], uvs[i3],
+                tsodinPog
+            );
+       }
+    }
+
+    return oc;
+}
+

+ 5 - 0
index.html

@@ -26,12 +26,17 @@
     Rotating rainbow triangle in 3D. Unlike <a href="#demo-3d">3D dots above</a> this is a solid shape. Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle3d.c">demos/triangle3d.c</a></p>
     <canvas id="app-triangle3d"></canvas>
 
+    <h2 id="demo-triangle_tex"><a href="#demo-triangle_tex">Rotating Textures</a></h2>
+    Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle_tex.c">demos/triangle_tex.c</a></p>
+    <canvas id="app-triangle_tex"></canvas>
+
     <script src="js/vc.js"></script>
     <script>
       startDemo("app-triangle", "./wasm/triangle.wasm");
       startDemo("app-3d", "./wasm/3d.wasm");
       startDemo("app-squish", "./wasm/squish.wasm");
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
+      startDemo("app-triangle_tex", "./wasm/triangle_tex.wasm");
     </script>
   </body>
 </html>

+ 91 - 0
olive.c

@@ -303,6 +303,11 @@ typedef struct {
 #define OLIVEC_CANVAS_NULL ((Olivec_Canvas) {0})
 #define OLIVEC_PIXEL(oc, x, y) (oc).pixels[(y)*(oc).stride + (x)]
 
+typedef struct {
+    float u;
+    float v;
+} Uv;
+
 OLIVECDEF Olivec_Canvas olivec_canvas(uint32_t *pixels, size_t width, size_t height, size_t stride);
 OLIVECDEF Olivec_Canvas olivec_subcanvas(Olivec_Canvas oc, int x, int y, int w, int h);
 OLIVECDEF void olivec_blend_color(uint32_t *c1, uint32_t c2);
@@ -315,9 +320,11 @@ OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uin
 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_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_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, 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_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 Uv olivec_uv(float u, float v);
 
 typedef struct {
     // Safe ranges to iterate over.
@@ -726,6 +733,82 @@ OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y
     }
 }
 
+OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, Olivec_Canvas texture)
+{
+    if (y1 > y2) {
+        OLIVEC_SWAP(int, x1, x2);
+        OLIVEC_SWAP(int, y1, y2);
+        OLIVEC_SWAP(Uv, uv1, uv2);
+    }
+
+    if (y2 > y3) {
+        OLIVEC_SWAP(int, x2, x3);
+        OLIVEC_SWAP(int, y2, y3);
+        OLIVEC_SWAP(Uv, uv2, uv3);
+    }
+
+    if (y1 > y2) {
+        OLIVEC_SWAP(int, x1, x2);
+        OLIVEC_SWAP(int, y1, y2);
+        OLIVEC_SWAP(Uv, uv1, uv2);
+    }
+
+    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);
+                    int u3 = det - u1 - u2;
+                    Uv uv = olivec_uv(
+                        uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
+                        uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
+                    );
+                    int texture_x = uv.u*texture.width;
+                    int texture_y = uv.v*texture.height;
+                    OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
+                }
+            }
+        }
+    }
+
+    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);
+                    int u3 = det - u1 - u2;
+                    Uv uv = olivec_uv(
+                        uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
+                        uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
+                    );
+                    int texture_x = uv.u*texture.width;
+                    int texture_y = uv.v*texture.height;
+                    OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
+                }
+            }
+        }
+    }
+}
+
 // 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)
 {
@@ -841,6 +924,14 @@ OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h,
     }
 }
 
+OLIVECDEF Uv olivec_uv(float u, float v)
+{
+    Uv uv;
+    uv.u = u;
+    uv.v = v;
+    return uv;
+}
+
 #endif // OLIVEC_IMPLEMENTATION
 
 // TODO: 3D textures

BIN
wasm/3d.wasm


BIN
wasm/squish.wasm


BIN
wasm/triangle.wasm


BIN
wasm/triangle3d.wasm


BIN
wasm/triangle_tex.wasm