瀏覽代碼

Implement Cup 3D demo

rexim 2 年之前
父節點
當前提交
ee91cc0f8a
共有 13 個文件被更改,包括 768 次插入32 次删除
  1. 343 0
      assets/tsodinCupLowPoly.obj
  2. 6 1
      build.sh
  3. 115 0
      demos/cup3d.c
  4. 5 0
      index.html
  5. 260 0
      obj2c.c
  6. 39 31
      olive.c
  7. 二進制
      wasm/3d.wasm
  8. 二進制
      wasm/cup3d.wasm
  9. 二進制
      wasm/squish.wasm
  10. 二進制
      wasm/triangle.wasm
  11. 二進制
      wasm/triangle3d.wasm
  12. 二進制
      wasm/triangle3dTex.wasm
  13. 二進制
      wasm/triangleTex.wasm

+ 343 - 0
assets/tsodinCupLowPoly.obj

@@ -0,0 +1,343 @@
+v 0.000000 -0.000156 -1.066203
+v -0.626698 -0.000156 -0.862576
+v -1.014019 -0.000156 -0.329475
+v -1.014019 -0.000156 0.329475
+v -0.626698 -0.000156 0.862576
+v 0.000000 -0.000156 1.066203
+v 0.626698 -0.000156 0.862576
+v 1.014019 -0.000156 0.329475
+v 1.014019 -0.000156 -0.329475
+v 0.626698 -0.000156 -0.862576
+v 0.000000 -0.542991 -0.955058
+v -0.561369 -0.542991 -0.772658
+v -0.908314 -0.542991 -0.295129
+v -0.908314 -0.542991 0.295129
+v -0.561369 -0.542991 0.772658
+v 0.000000 -0.542991 0.955058
+v 0.561369 -0.542991 0.772658
+v 0.908314 -0.542991 0.295129
+v 0.908314 -0.542991 -0.295129
+v 0.561369 -0.542991 -0.772658
+v 0.000000 -1.034103 -0.766091
+v -0.450297 -1.034103 -0.619781
+v -0.728596 -1.034103 -0.236735
+v -0.728596 -1.034103 0.236735
+v -0.450297 -1.034103 0.619781
+v 0.000000 -1.034103 0.766091
+v 0.450297 -1.034103 0.619781
+v 0.728596 -1.034103 0.236735
+v 0.728596 -1.034103 -0.236735
+v 0.450297 -1.034103 -0.619781
+v -0.000000 -1.422396 -0.497612
+v -0.292489 -1.422396 -0.402576
+v -0.473257 -1.422396 -0.153770
+v -0.473257 -1.422396 0.153770
+v -0.292489 -1.422396 0.402576
+v 0.000000 -1.422396 0.497612
+v 0.292489 -1.422396 0.402576
+v 0.473257 -1.422396 0.153771
+v 0.473257 -1.422396 -0.153771
+v 0.292489 -1.422396 -0.402576
+v -0.000000 -1.514935 -0.497612
+v -0.292489 -1.514935 -0.402576
+v -0.473257 -1.514935 -0.153770
+v -0.473257 -1.514935 0.153770
+v -0.292489 -1.514935 0.402576
+v 0.000000 -1.514935 0.497612
+v 0.292489 -1.514935 0.402576
+v 0.473257 -1.514935 0.153771
+v 0.473257 -1.514935 -0.153771
+v 0.292489 -1.514935 -0.402576
+v 0.000000 0.010858 -0.987583
+v -0.580486 0.010858 -0.798971
+v -0.939247 0.010858 -0.305180
+v -0.939247 0.010858 0.305180
+v -0.580486 0.010858 0.798971
+v 0.000000 0.010858 0.987583
+v 0.580487 0.010858 0.798971
+v 0.939247 0.010858 0.305180
+v 0.939247 0.010858 -0.305180
+v 0.580487 0.010858 -0.798971
+v 0.000000 -0.521118 -0.875554
+v -0.514638 -0.521118 -0.708338
+v -0.832702 -0.521118 -0.270561
+v -0.832702 -0.521118 0.270561
+v -0.514638 -0.521118 0.708338
+v 0.000000 -0.521118 0.875554
+v 0.514638 -0.521118 0.708338
+v 0.832701 -0.521118 0.270561
+v 0.832701 -0.521118 -0.270561
+v 0.514638 -0.521118 -0.708338
+v 0.000000 -0.993567 -0.691708
+v -0.406576 -0.993567 -0.559603
+v -0.657853 -0.993567 -0.213749
+v -0.657853 -0.993567 0.213749
+v -0.406576 -0.993567 0.559603
+v 0.000000 -0.993567 0.691708
+v 0.406576 -0.993567 0.559603
+v 0.657853 -0.993567 0.213749
+v 0.657853 -0.993567 -0.213750
+v 0.406576 -0.993567 -0.559603
+v 0.000000 -1.367126 -0.422987
+v -0.248625 -1.367126 -0.342204
+v -0.402285 -1.367126 -0.130710
+v -0.402285 -1.367126 0.130710
+v -0.248625 -1.367126 0.342204
+v 0.000000 -1.367126 0.422987
+v 0.248626 -1.367126 0.342204
+v 0.402285 -1.367126 0.130710
+v 0.402285 -1.367126 -0.130710
+v 0.248626 -1.367126 -0.342204
+v -0.893877 -0.278278 0.402886
+v -0.659723 -0.278431 0.724741
+v -0.870406 -0.405366 0.393083
+v -0.643093 -0.405514 0.705535
+v -1.043524 -0.292722 0.541859
+v -0.838261 -0.292879 0.824072
+v -1.024132 -0.402048 0.527565
+v -0.818596 -0.402206 0.810154
+v -1.142123 -0.391251 0.633202
+v -0.955602 -0.391372 0.889584
+v -1.064234 -0.441499 0.576417
+v -0.877453 -0.441621 0.833156
+v -1.130418 -0.567091 0.651982
+v -0.969656 -0.567208 0.872953
+v -1.050666 -0.531856 0.594071
+v -0.889901 -0.531973 0.815046
+v -0.921231 -0.971574 0.540621
+v -0.798838 -0.971662 0.708883
+v -0.879760 -0.912354 0.510614
+v -0.757484 -0.912441 0.678716
+v -0.695367 -1.185602 0.388707
+v -0.584510 -1.185674 0.541085
+v -0.698309 -1.121105 0.391044
+v -0.587667 -1.121177 0.543127
+v -0.617364 -1.109944 0.305061
+v -0.480793 -1.110033 0.492785
+v -0.583260 -1.173834 0.280524
+v -0.446870 -1.173923 0.467997
+
+f 27 18 17
+f 10 11 1
+f 17 8 7
+f 14 5 4
+f 1 12 2
+f 8 19 9
+f 15 6 5
+f 2 13 3
+f 19 10 9
+f 16 7 6
+f 13 4 3
+f 24 35 25
+f 24 15 14
+f 21 12 11
+f 18 29 19
+f 25 16 15
+f 22 13 12
+f 29 20 19
+f 26 17 16
+f 23 14 13
+f 30 11 20
+f 34 45 35
+f 21 32 22
+f 28 39 29
+f 35 26 25
+f 22 33 23
+f 29 40 30
+f 36 27 26
+f 33 24 23
+f 40 21 30
+f 37 28 27
+f 46 44 42
+f 41 32 31
+f 48 39 38
+f 35 46 36
+f 42 33 32
+f 49 40 39
+f 46 37 36
+f 43 34 33
+f 50 31 40
+f 47 38 37
+f 101 95 97
+f 91 96 92
+f 97 91 93
+f 98 93 94
+f 92 98 94
+f 104 102 100
+f 102 97 98
+f 96 102 98
+f 95 100 96
+f 104 110 106
+f 103 100 99
+f 101 103 99
+f 102 105 101
+f 111 108 107
+f 107 104 103
+f 109 103 105
+f 106 109 105
+f 115 111 113
+f 113 107 109
+f 110 113 109
+f 108 114 110
+f 117 112 111
+f 116 112 118
+f 115 114 116
+f 27 28 18
+f 10 20 11
+f 17 18 8
+f 14 15 5
+f 1 11 12
+f 8 18 19
+f 15 16 6
+f 2 12 13
+f 19 20 10
+f 16 17 7
+f 13 14 4
+f 24 34 35
+f 24 25 15
+f 21 22 12
+f 18 28 29
+f 25 26 16
+f 22 23 13
+f 29 30 20
+f 26 27 17
+f 23 24 14
+f 30 21 11
+f 34 44 45
+f 21 31 32
+f 28 38 39
+f 35 36 26
+f 22 32 33
+f 29 39 40
+f 36 37 27
+f 33 34 24
+f 40 31 21
+f 37 38 28
+f 42 41 50
+f 50 49 42
+f 49 48 42
+f 48 47 46
+f 46 45 44
+f 44 43 42
+f 48 46 42
+f 41 42 32
+f 48 49 39
+f 35 45 46
+f 42 43 33
+f 49 50 40
+f 46 47 37
+f 43 44 34
+f 50 41 31
+f 47 48 38
+f 101 99 95
+f 91 95 96
+f 97 95 91
+f 98 97 93
+f 92 96 98
+f 104 106 102
+f 102 101 97
+f 96 100 102
+f 95 99 100
+f 104 108 110
+f 103 104 100
+f 101 105 103
+f 102 106 105
+f 111 112 108
+f 107 108 104
+f 109 107 103
+f 106 110 109
+f 115 117 111
+f 113 111 107
+f 110 114 113
+f 108 112 114
+f 117 118 112
+f 116 114 112
+f 115 113 114
+f 69 58 59
+f 79 68 69
+f 66 55 56
+f 63 52 53
+f 70 59 60
+f 57 66 56
+f 64 53 54
+f 61 60 51
+f 68 57 58
+f 65 54 55
+f 52 61 51
+f 76 85 75
+f 66 75 65
+f 73 62 63
+f 80 69 70
+f 67 76 66
+f 64 73 63
+f 61 80 70
+f 68 77 67
+f 75 64 65
+f 72 61 62
+f 84 88 90
+f 83 72 73
+f 90 79 80
+f 77 86 76
+f 74 83 73
+f 81 80 71
+f 78 87 77
+f 85 74 75
+f 82 71 72
+f 89 78 79
+f 69 68 58
+f 79 78 68
+f 66 65 55
+f 63 62 52
+f 70 69 59
+f 57 67 66
+f 64 63 53
+f 61 70 60
+f 68 67 57
+f 65 64 54
+f 52 62 61
+f 76 86 85
+f 66 76 75
+f 73 72 62
+f 80 79 69
+f 67 77 76
+f 64 74 73
+f 61 71 80
+f 68 78 77
+f 75 74 64
+f 72 71 61
+f 90 81 82
+f 82 83 84
+f 84 85 86
+f 86 87 88
+f 88 89 90
+f 90 82 84
+f 84 86 88
+f 83 82 72
+f 90 89 79
+f 77 87 86
+f 74 84 83
+f 81 90 80
+f 78 88 87
+f 85 84 74
+f 82 81 71
+f 89 88 78
+f 4 53 3
+f 1 60 10
+f 58 7 8
+f 5 54 4
+f 52 1 2
+f 59 8 9
+f 56 5 6
+f 53 2 3
+f 10 59 9
+f 57 6 7
+f 4 54 53
+f 1 51 60
+f 58 57 7
+f 5 55 54
+f 52 51 1
+f 59 58 8
+f 56 55 5
+f 53 52 2
+f 10 60 59
+f 57 56 6

+ 6 - 1
build.sh

@@ -35,14 +35,19 @@ build_all_vc_demos() {
     build_vc_demo triangle3d &
     build_vc_demo triangleTex &
     build_vc_demo triangle3dTex &
+    build_vc_demo cup3d &
     wait # TODO: the whole script must fail if one of the jobs fails
 }
 
 build_assets() {
     mkdir -p ./build/assets/
+
     clang $COMMON_CFLAGS -o ./build/png2c -Ithirdparty png2c.c -lm
     ./build/png2c -n tsodinPog -o ./build/assets/tsodinPog.c ./assets/tsodinPog.png
     ./build/png2c -n Sadge -o ./build/assets/Sadge.c ./assets/Sadge.png
+
+    clang $COMMON_CFLAGS -o ./build/obj2c -Ithirdparty obj2c.c -lm
+    ./build/obj2c ./assets/tsodinCupLowPoly.obj ./build/assets/tsodinCupLowPoly.c
 }
 
 build_tests() {
@@ -53,4 +58,4 @@ build_tests() {
 build_assets
 build_tests
 build_all_vc_demos
-clang $COMMON_CFLAGS -O2 -o viewobj viewobj.c 
+# clang $COMMON_CFLAGS -O2 -o viewobj viewobj.c 

+ 115 - 0
demos/cup3d.c

@@ -0,0 +1,115 @@
+#define SCALE_DOWN_FACTOR 10
+#include "vc.c"
+#include "./assets/tsodinCupLowPoly.c"
+
+#define WIDTH 960
+#define HEIGHT 720
+#define BACKGROUND_COLOR 0xFF181818
+
+#define PI 3.14159265359
+
+float sqrtf(float x);
+float atan2f(float y, float x);
+float sinf(float x);
+float cosf(float x);
+
+static uint32_t pixels[WIDTH*HEIGHT];
+static float zbuffer[WIDTH*HEIGHT] = {0};
+static float angle = 0;
+
+typedef struct {
+    float x, y;
+} Vector2;
+
+Vector2 make_vector2(float x, float y)
+{
+    Vector2 v2;
+    v2.x = x;
+    v2.y = y;
+    return v2;
+}
+
+typedef struct {
+    float x, y, z;
+} Vector3;
+
+Vector3 make_vector3(float x, float y, float z)
+{
+    Vector3 v3;
+    v3.x = x;
+    v3.y = y;
+    v3.z = z;
+    return v3;
+}
+
+Vector2 project_3d_2d(Vector3 v3)
+{
+    return make_vector2(v3.x/v3.z, v3.y/v3.z);
+}
+
+Vector2 project_2d_scr(Vector2 v2)
+{
+    return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
+}
+
+Vector3 rotate_y(Vector3 p, float delta_angle)
+{
+    float angle = atan2f(p.z - 1.5, p.x) + delta_angle;
+    float mag = sqrtf(p.x*p.x + (p.z - 1.5)*(p.z - 1.5));
+    return make_vector3(cosf(angle)*mag, p.y, sinf(angle)*mag + 1.5);
+}
+
+Olivec_Canvas render(float dt)
+{
+    angle += 0.25*PI*dt;
+
+    Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(oc, BACKGROUND_COLOR);
+    for (size_t i = 0; i < WIDTH*HEIGHT; ++i) zbuffer[i] = 0;
+
+    for (size_t i = 0; i < faces_count; ++i) {
+        int a = faces[i][0];
+        int b = faces[i][1];
+        int c = faces[i][2];
+        Vector3 v1 = rotate_y(make_vector3(vertices[a][0], vertices[a][1], vertices[a][2]), angle);
+        Vector3 v2 = rotate_y(make_vector3(vertices[b][0], vertices[b][1], vertices[b][2]), angle);
+        Vector3 v3 = rotate_y(make_vector3(vertices[c][0], vertices[c][1], vertices[c][2]), angle);
+        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));
+
+        int x1 = p1.x;
+        int x2 = p2.x;
+        int x3 = p3.x;
+        int y1 = p1.y;
+        int y2 = p2.y;
+        int y3 = p3.y;
+        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;
+                    barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
+                    int u3 = det - u1 - u2;
+                    if ((OLIVEC_SIGN(int, u1) == OLIVEC_SIGN(int, det) || u1 == 0) && (OLIVEC_SIGN(int, u2) == OLIVEC_SIGN(int, det) || u2 == 0) && (OLIVEC_SIGN(int, u3) == OLIVEC_SIGN(int, det) || u3 == 0)) {
+                        float z = 1/v1.z*u1/det + 1/v2.z*u2/det + 1/v3.z*u3/det;
+                        if (z > zbuffer[y*WIDTH + x]) {
+                            zbuffer[y*WIDTH + x] = z;
+                            OLIVEC_PIXEL(oc, x, y) = mix_colors3(0xFF1818FF, 0xFF18FF18, 0xFFFF1818, u1, u2, det);
+
+                            z = 1.0f/z;
+                            if (z >= 1.0) {
+                                z -= 1.0;
+                                uint32_t v = z*255;
+                                if (v > 255) v = 255;
+                                olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), (v<<(3*8)));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return oc;
+}

+ 5 - 0
index.html

@@ -34,6 +34,10 @@
     Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle3dTex.c">demos/triangle3dTex.c</a></p>
     <canvas id="app-triangle3dTex"></canvas>
 
+    <h2 id="demo-cup3d"><a href="#demo-cup3d">Cup 3D</a></h2>
+    Design by <a href="https://github.com/tsoding/rexim">rexim</a>. 3D model by <a href="https://github.com/kolumb">kolumb</a>. Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/cup3d.c">demos/cup3d.c</a></p>
+    <canvas id="app-cup3d"></canvas>
+
     <script src="js/vc.js"></script>
     <script>
       startDemo("app-triangle", "./wasm/triangle.wasm");
@@ -42,6 +46,7 @@
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
       startDemo("app-triangleTex", "./wasm/triangleTex.wasm");
       startDemo("app-triangle3dTex", "./wasm/triangle3dTex.wasm");
+      startDemo("app-cup3d", "./wasm/cup3d.wasm");
     </script>
   </body>
 </html>

+ 260 - 0
obj2c.c

@@ -0,0 +1,260 @@
+#include <stdio.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <string.h>
+
+#define SV_IMPLEMENTATION
+#include "sv.h"
+
+#define ARENA_IMPLEMENTATION
+#include "arena.h"
+
+#define return_defer(value) do { result = (value); goto defer; } while (0)
+typedef int Errno;
+#define UNUSED(x) (void)(x)
+
+static Arena default_arena = {0};
+static Arena *context_arena = &default_arena;
+
+static void *context_alloc(size_t size)
+{
+    assert(context_arena);
+    return arena_alloc(context_arena, size);
+}
+
+static void *context_realloc(void *oldp, size_t oldsz, size_t newsz)
+{
+    if (newsz <= oldsz) return oldp;
+    return memcpy(context_alloc(newsz), oldp, oldsz);
+}
+
+Errno read_entire_file(const char *file_path, char **buffer, size_t *buffer_size)
+{
+    Errno result = 0;
+    FILE *f = NULL;
+
+    f = fopen(file_path, "rb");
+    if (f == NULL) return_defer(errno);
+
+    if (fseek(f, 0, SEEK_END) < 0) return_defer(errno);
+    long m = ftell(f);
+    if (m < 0) return_defer(errno);
+    if (fseek(f, 0, SEEK_SET) < 0) return_defer(errno);
+
+    *buffer_size = m;
+    *buffer = context_alloc(*buffer_size);
+
+    fread(*buffer, *buffer_size, 1, f);
+    if (ferror(f)) return_defer(errno);
+
+defer:
+    if (f) fclose(f);
+    return result;
+}
+
+typedef struct {
+    float x, y;
+} Vector2;
+
+Vector2 make_vector2(float x, float y)
+{
+    Vector2 v2;
+    v2.x = x;
+    v2.y = y;
+    return v2;
+}
+
+typedef struct {
+    float x, y, z;
+} Vector3;
+
+Vector3 make_vector3(float x, float y, float z)
+{
+    Vector3 v3;
+    v3.x = x;
+    v3.y = y;
+    v3.z = z;
+    return v3;
+}
+
+typedef struct {
+    Vector3 *items;
+    size_t capacity;
+    size_t count;
+} Vertices;
+
+typedef struct {
+    int a, b, c;
+} Face;
+
+Face make_face(int a, int b, int c)
+{
+    Face f = {
+        .a = a,
+        .b = b,
+        .c = c,
+    };
+    return f;
+}
+
+typedef struct {
+    Face *items;
+    size_t capacity;
+    size_t count;
+} Faces;
+
+#define DA_INIT_CAPACITY 8192
+#define DA_REALLOC context_realloc
+#define da_append(da, item)                                                 \
+    do {                                                                    \
+        if ((da)->count >= (da)->capacity) {                                \
+            size_t new_capacity = (da)->capacity*2;                         \
+            if (new_capacity == 0) {                                        \
+                new_capacity = DA_INIT_CAPACITY;                            \
+            }                                                               \
+                                                                            \
+            (da)->items = DA_REALLOC((da)->items,                           \
+                                     (da)->capacity*sizeof((da)->items[0]), \
+                                     new_capacity*sizeof((da)->items[0]));  \
+            (da)->capacity = new_capacity;                                  \
+        }                                                                   \
+                                                                            \
+        (da)->items[(da)->count++] = (item);                                \
+    } while (0)
+
+void generate_code(FILE *out, Vertices vertices, Faces faces)
+{
+    fprintf(out, "#ifndef OBJ_H_\n");
+    fprintf(out, "#define OBJ_H_\n");
+    fprintf(out, "float vertices[%zu][3] = {\n", vertices.count);
+    for (size_t i = 0; i < vertices.count; ++i) {
+        Vector3 v = vertices.items[i];
+        fprintf(out, "    {%f, %f, %f},\n", v.x, v.y, v.z);
+    }
+    fprintf(out, "};\n");
+    fprintf(out, "size_t vertices_count = %zu;\n", vertices.count);
+
+    fprintf(out, "int faces[%zu][3] = {\n", faces.count);
+    for (size_t i = 0; i < faces.count; ++i) {
+        Face f = faces.items[i];
+        fprintf(out, "    {%d, %d, %d},\n", f.a, f.b, f.c);
+    }
+    fprintf(out, "};\n");
+    fprintf(out, "size_t faces_count = %zu;\n", faces.count);
+    fprintf(out, "#endif // OBJ_H_\n");
+}
+
+Vector3 remap_teapot(Vector3 v, float lx, float hx, float ly, float hy, float lz, float hz)
+{
+    float scale = 1.0;
+    v.z = ((v.z - lz)/(hz - lz)*scale + 1);
+    v.x = ((v.x - lx)/(hx - lx)*2 - 1)*scale;
+    v.y = ((v.y - ly)/(hy - ly)*2 - 1)*scale;
+    return v;
+}
+
+int main(int argc, char **argv)
+{
+    int result = 0;
+
+    if (argc < 3) {
+        fprintf(stderr, "Usage: obj2c <input.obj> <output.c>\n");
+        fprintf(stderr, "ERROR: no input/output is provide\n");
+        return 1;
+    }
+
+    const char *obj_file_path = argv[1];
+    const char *out_file_path = argv[2];
+    char *buffer;
+    size_t buffer_size;
+    Errno err = read_entire_file(obj_file_path, &buffer, &buffer_size);
+    if (err != 0) {
+        fprintf(stderr, "ERROR: could not read file %s: %s\n", obj_file_path, strerror(errno));
+        return_defer(1);
+    }
+
+    String_View content = sv_from_parts(buffer, buffer_size);
+    Vertices vertices = {0};
+    Faces faces = {0};
+    float lx = FLT_MAX, hx = FLT_MIN;
+    float ly = FLT_MAX, hy = FLT_MIN;
+    float lz = FLT_MAX, hz = FLT_MIN;
+    int lf = INT_MAX, hf = INT_MIN;
+    for (size_t line_number = 0; content.count > 0; ++line_number) {
+        String_View line = sv_trim_left(sv_chop_by_delim(&content, '\n'));
+        if (line.count > 0) {
+            String_View kind = sv_chop_by_delim(&line, ' ');
+            if (sv_eq(kind, SV("v"))) {
+                char *endptr;
+
+                line = sv_trim_left(line);
+                float x = strtof(line.data, &endptr);
+                line.data = endptr;
+                if (lx > x) lx = x;
+                if (hx < x) hx = x;
+
+                line = sv_trim_left(line);
+                float y = strtof(line.data, &endptr);
+                line.data = endptr;
+                if (ly > y) ly = y;
+                if (hy < y) hy = y;
+
+                line = sv_trim_left(line);
+                float z = strtof(line.data, &endptr);
+                line.data = endptr;
+                if (lz > z) lz = z;
+                if (hz < z) hz = z;
+
+                da_append(&vertices, make_vector3(x, y, z));
+            } else if (sv_eq(kind, SV("f"))) {
+                char *endptr;
+
+                line = sv_trim_left(line);
+                int a = strtol(line.data, &endptr, 10);
+                line.data = endptr;
+                if (lf > a) lf = a;
+                if (hf < a) hf = a;
+
+                line = sv_trim_left(line);
+                int b = strtol(line.data, &endptr, 10);
+                line.data = endptr;
+                if (lf > b) lf = b;
+                if (hf < b) hf = b;
+
+                line = sv_trim_left(line);
+                int c = strtol(line.data, &endptr, 10);
+                line.data = endptr;
+                if (lf > c) lf = c;
+                if (hf < c) hf = c;
+
+                da_append(&faces, make_face(a, b, c));
+            } else {
+                fprintf(stderr, "%s:%zu: unknown kind of entry `"SV_Fmt"`\n", obj_file_path, line_number, SV_Arg(kind));
+                return_defer(1);
+            }
+        }
+    }
+    printf("Vertices: %zu (x: %f..%f, y: %f..%f, z: %f..%f)\n", vertices.count, lx, hx, ly, hy, lz, hz);
+    printf("Faces:    %zu (index: %d..%d)\n", faces.count, lf, hf);
+
+    for (size_t i = 0; i < vertices.count; ++i) {
+        vertices.items[i] = remap_teapot(vertices.items[i], lx, hx, ly, hy, lz, hz);
+    }
+
+    for (size_t i = 0; i < faces.count; ++i) {
+        faces.items[i].a -= 1;
+        faces.items[i].b -= 1;
+        faces.items[i].c -= 1;
+    }
+
+    FILE *out = fopen(out_file_path, "wb");
+    if (out == NULL) {
+        fprintf(stderr, "ERROR: Could not write file %s: %s\n", out_file_path, strerror(errno));
+        return_defer(1);
+    }
+    generate_code(out, vertices, faces);
+
+defer:
+    return result;
+}

+ 39 - 31
olive.c

@@ -616,40 +616,48 @@ OLIVECDEF void barycentric(int x1, int y1, int x2, int y2, int x3, int y3,
     // u3 = det - u1 - u2
 }
 
+OLIVECDEF bool olivec_normalize_triangle(size_t width, size_t height, int x1, int y1, int x2, int y2, int x3, int y3, int *lx, int *hx, int *ly, int *hy)
+{
+    *lx = x1;
+    *hx = x1;
+    if (*lx > x2) *lx = x2;
+    if (*lx > x3) *lx = x3;
+    if (*hx < x2) *hx = x2;
+    if (*hx < x3) *hx = x3;
+    if (*lx < 0) *lx = 0;
+    if ((size_t) *lx >= width) return false;;
+    if (*hx < 0) return false;;
+    if ((size_t) *hx >= width) *hx = width-1;
+
+    *ly = y1;
+    *hy = y1;
+    if (*ly > y2) *ly = y2;
+    if (*ly > y3) *ly = y3;
+    if (*hy < y2) *hy = y2;
+    if (*hy < y3) *hy = y3;
+    if (*ly < 0) *ly = 0;
+    if ((size_t) *ly >= height) return false;;
+    if (*hy < 0) return false;;
+    if ((size_t) *hy >= height) *hy = height-1;
+
+    return true;
+}
+
 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)
 {
-    int lx = x1;
-    int hx = x1;
-    if (lx > x2) lx = x2;
-    if (lx > x3) lx = x3;
-    if (hx < x2) hx = x2;
-    if (hx < x3) hx = x3;
-    if (lx < 0) lx = 0;
-    if ((size_t) lx >= oc.width) return;
-    if (hx < 0) return;
-    if ((size_t) hx >= oc.width) hx = oc.width-1;
-
-    int ly = y1;
-    int hy = y1;
-    if (ly > y2) ly = y2;
-    if (ly > y3) ly = y3;
-    if (hy < y2) hy = y2;
-    if (hy < y3) hy = y3;
-    if (ly < 0) ly = 0;
-    if ((size_t) ly >= oc.height) return;
-    if (hy < 0) return;
-    if ((size_t) hy >= oc.height) hy = oc.height-1;
-
-    for (int y = ly; y <= hy; ++y) {
-        for (int x = lx; x <= hx; ++x) {
-            int u1, u2, det;
-            barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
-            int u3 = det - u1 - u2;
-            if ((OLIVEC_SIGN(int, u1) == OLIVEC_SIGN(int, det) || u1 == 0) &&
-                (OLIVEC_SIGN(int, u2) == OLIVEC_SIGN(int, det) || u2 == 0) &&
-                (OLIVEC_SIGN(int, u3) == OLIVEC_SIGN(int, det) || u3 == 0)) {
-                OLIVEC_PIXEL(oc, x, y) = mix_colors3(c1, c2, c3, u1, u2, det);
+    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;
+                barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
+                int u3 = det - u1 - u2;
+                if ((OLIVEC_SIGN(int, u1) == OLIVEC_SIGN(int, det) || u1 == 0) &&
+                    (OLIVEC_SIGN(int, u2) == OLIVEC_SIGN(int, det) || u2 == 0) &&
+                    (OLIVEC_SIGN(int, u3) == OLIVEC_SIGN(int, det) || u3 == 0)) {
+                    OLIVEC_PIXEL(oc, x, y) = mix_colors3(c1, c2, c3, u1, u2, det);
+                }
             }
         }
     }

二進制
wasm/3d.wasm


二進制
wasm/cup3d.wasm


二進制
wasm/squish.wasm


二進制
wasm/triangle.wasm


二進制
wasm/triangle3d.wasm


二進制
wasm/triangle3dTex.wasm


二進制
wasm/triangleTex.wasm