commit 5b67115268acf849b3e5c7ebb08895a4e38e05d1
parent 0bd78557e526be25ade169f09af521a9da1bf9fc
Author: Christian Ermann <christianermann@gmail.com>
Date: Thu, 5 Aug 2021 19:49:36 -0500
Load surrounding chunks
Diffstat:
10 files changed, 678 insertions(+), 169 deletions(-)
diff --git a/include/chunk.h b/include/chunk.h
@@ -1,16 +1,27 @@
#ifndef CHUNK_H
#define CHUNK_H
-extern const int CHUNK_WIDTH;
+#include "sdf.h"
+
+#include <glad/glad.h>
+
+#define CHUNK_WIDTH 16
+#define CHUNK_VOLUME CHUNK_WIDTH * CHUNK_WIDTH * CHUNK_WIDTH
typedef struct {
- int id[3];
- float origin[3];
+ IVec3 id;
+ unsigned int vertex_count;
+ Vec3 vertices[CHUNK_VOLUME * 15];
+ GLuint vbo;
+ GLuint vao;
} Chunk;
-Chunk Chunk_create(int x, int y, int z);
+void Chunk_init(Chunk *chunk, IVec3 id);
+
+void Chunk_origin(const Chunk *chunk, Vec3 origin);
+
+void Chunk_meshify(Chunk *chunk, SDF f, float isolevel);
-void Chunk_outline(const Chunk* chunk, float corners[24], unsigned int offset,
- unsigned int indices[24]);
+void Chunk_draw(const Chunk *chunk);
#endif
diff --git a/include/chunk_manager.h b/include/chunk_manager.h
@@ -4,15 +4,22 @@
#include "chunk.h"
typedef struct {
+ IVec3 origin;
int radius;
- int chunk_count;
- int origin[3];
- int* offsets;
- Chunk* chunks;
+
+ SDF f;
+ float isolevel;
+
+ unsigned int chunk_count;
+ IVec3 *offsets;
+ Chunk *chunks;
} ChunkManager;
-ChunkManager ChunkManager_create(int radius, float player[3]);
+ChunkManager ChunkManager_create(const Vec3 target, int radius, SDF f,
+ float isolevel);
+
+void ChunkManager_recenter(ChunkManager *cm, const Vec3 target);
-void ChunkManager_update(ChunkManager* chunk_manager, float player[3]);
+void ChunkManager_drawChunks(const ChunkManager *cm);
#endif
diff --git a/include/marching_cubes.h b/include/marching_cubes.h
@@ -0,0 +1,10 @@
+#ifndef MC_H
+#define MC_H
+
+#include "vec.h"
+#include "sdf.h"
+
+int MC_polygonize(const Vec3 corners[8], SDF f, float isolevel,
+ Vec3 triangles[15]);
+
+#endif
diff --git a/include/sdf.h b/include/sdf.h
@@ -0,0 +1,8 @@
+#ifndef SDF_H
+#define SDF_H
+
+#include "vec.h"
+
+typedef float (*SDF)(const Vec3 p);
+
+#endif
diff --git a/include/vec.h b/include/vec.h
@@ -0,0 +1,12 @@
+#ifndef VEC_H
+#define VEC_H
+
+#include <stdbool.h>
+
+typedef int IVec3[3];
+
+bool IVec3_equal(const IVec3 a, const IVec3 b);
+
+typedef float Vec3[3];
+
+#endif
diff --git a/src/chunk.c b/src/chunk.c
@@ -1,93 +1,99 @@
#include "chunk.h"
+#include "marching_cubes.h"
-const int CHUNK_WIDTH = 16;
-
-Chunk Chunk_create(int x, int y, int z)
+void Chunk_init(Chunk *chunk, IVec3 id)
{
- Chunk chunk;
+ chunk->id[0] = id[0];
+ chunk->id[1] = id[1];
+ chunk->id[2] = id[2];
+
+ chunk->vertex_count = 0;
- chunk.id[0] = x;
- chunk.id[1] = y;
- chunk.id[2] = z;
+ glGenVertexArrays(1, &chunk->vao);
+ glBindVertexArray(chunk->vao);
- chunk.origin[0] = x * CHUNK_WIDTH;
- chunk.origin[1] = y * CHUNK_WIDTH;
- chunk.origin[2] = z * CHUNK_WIDTH;
+ glGenBuffers(1, &chunk->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo);
- return chunk;
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), (GLvoid*)0);
+ glEnableVertexAttribArray(0);
+}
+
+void Chunk_origin(const Chunk *chunk, Vec3 origin)
+{
+ origin[0] = chunk->id[0] * CHUNK_WIDTH;
+ origin[1] = chunk->id[1] * CHUNK_WIDTH;
+ origin[2] = chunk->id[2] * CHUNK_WIDTH;
}
-void Cube_corners(const float origin[3], float width, float corners[24])
+static void Cube_corners(const Vec3 origin, float width, Vec3 corners[8])
{
- corners[0] = origin[0];
- corners[1] = origin[1];
- corners[2] = origin[2];
+ corners[0][0] = origin[0];
+ corners[0][1] = origin[1];
+ corners[0][2] = origin[2];
- corners[3] = origin[0] + width;
- corners[4] = origin[1];
- corners[5] = origin[2];
+ corners[1][0] = origin[0] + width;
+ corners[1][1] = origin[1];
+ corners[1][2] = origin[2];
- corners[6] = origin[0] + width;
- corners[7] = origin[1];
- corners[8] = origin[2] + width;
+ corners[2][0] = origin[0] + width;
+ corners[2][1] = origin[1];
+ corners[2][2] = origin[2] + width;
- corners[9] = origin[0];
- corners[10] = origin[1];
- corners[11] = origin[2] + width;
+ corners[3][0] = origin[0];
+ corners[3][1] = origin[1];
+ corners[3][2] = origin[2] + width;
- corners[12] = origin[0];
- corners[13] = origin[1] + width;
- corners[14] = origin[2];
+ corners[4][0] = origin[0];
+ corners[4][1] = origin[1] + width;
+ corners[4][2] = origin[2];
- corners[15] = origin[0] + width;
- corners[16] = origin[1] + width;
- corners[17] = origin[2];
+ corners[5][0] = origin[0] + width;
+ corners[5][1] = origin[1] + width;
+ corners[5][2] = origin[2];
- corners[18] = origin[0] + width;
- corners[19] = origin[1] + width;
- corners[20] = origin[2] + width;
+ corners[6][0] = origin[0] + width;
+ corners[6][1] = origin[1] + width;
+ corners[6][2] = origin[2] + width;
- corners[21] = origin[0];
- corners[22] = origin[1] + width;
- corners[23] = origin[2] + width;
+ corners[7][0] = origin[0];
+ corners[7][1] = origin[1] + width;
+ corners[7][2] = origin[2] + width;
}
-void Cube_outlineIndices(unsigned int offset, unsigned int indices[24])
+void Chunk_meshify(Chunk *chunk, SDF f, float isolevel)
{
- // Bottom edges
- indices[0] = 0 + offset;
- indices[1] = 1 + offset;
- indices[2] = 1 + offset;
- indices[3] = 2 + offset;
- indices[4] = 2 + offset;
- indices[5] = 3 + offset;
- indices[6] = 3 + offset;
- indices[7] = 0 + offset;
-
- // Top edges
- indices[8] = 4 + offset;
- indices[9] = 5 + offset;
- indices[10] = 5 + offset;
- indices[11] = 6 + offset;
- indices[12] = 6 + offset;
- indices[13] = 7 + offset;
- indices[14] = 7 + offset;
- indices[15] = 4 + offset;
-
- // Middle edges
- indices[16] = 0 + offset;
- indices[17] = 4 + offset;
- indices[18] = 1 + offset;
- indices[19] = 5 + offset;
- indices[20] = 2 + offset;
- indices[21] = 6 + offset;
- indices[22] = 3 + offset;
- indices[23] = 7 + offset;
+ chunk->vertex_count = 0;
+ for (int i = 0; i < CHUNK_WIDTH; i++)
+ {
+ for (int j = 0; j < CHUNK_WIDTH; j++)
+ {
+ for (int k = 0; k < CHUNK_WIDTH; k++)
+ {
+ Vec3 chunk_origin;
+ Chunk_origin(chunk, chunk_origin);
+
+ Vec3 cell_origin = {
+ chunk_origin[0] + i,
+ chunk_origin[1] + j,
+ chunk_origin[2] + k
+ };
+
+ Vec3 cell_corners[8];
+ Cube_corners(cell_origin, 1, cell_corners);
+
+ chunk->vertex_count += MC_polygonize(cell_corners, f, isolevel,
+ &chunk->vertices[chunk->vertex_count]);
+ }
+ }
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(Vec3) * chunk->vertex_count,
+ chunk->vertices, GL_STATIC_DRAW);
}
-void Chunk_outline(const Chunk* chunk, float corners[24],
- unsigned int offset, unsigned int indices[24])
+void Chunk_draw(const Chunk *chunk)
{
- Cube_corners(chunk->origin, CHUNK_WIDTH, corners);
- Cube_outlineIndices(offset, indices);
+ glBindVertexArray(chunk->vao);
+ glDrawArrays(GL_TRIANGLES, 0, chunk->vertex_count);
}
diff --git a/src/chunk_manager.c b/src/chunk_manager.c
@@ -1,84 +1,144 @@
-
#include "chunk_manager.h"
-#include <stdlib.h>
#include <math.h>
+#include <stdlib.h>
-int ChunkManager_offsets(int radius, int* offsets)
+static void ChunkManager_setChunkCount(ChunkManager *cm)
{
- int count = 0;
- for (int x = -radius; x <= radius; x++)
+ cm->chunk_count = 0;
+ for (int x = -cm->radius; x <= cm->radius; x++)
{
- for (int y = -radius; y <= radius; y++)
+ for (int y = -cm->radius; y <= cm->radius; y++)
{
- for (int z = -radius; z <= radius; z++)
+ for (int z = -cm->radius; z <= cm->radius; z++)
{
- if (x * x + y * y + z * z <= radius * radius)
- {
- if (offsets != NULL)
- {
- offsets[count] = x;
- offsets[count + 1] = y;
- offsets[count + 2] = z;
- }
- count += 3;
- }
+ cm->chunk_count += 1;
}
}
}
- return count;
}
-void ChunkManager_worldToChunk(const float src[3], int dst[3])
+static void ChunkManager_createOffsets(ChunkManager *cm)
{
- dst[0] = (int)floor(src[0] / CHUNK_WIDTH);
- dst[1] = (int)floor(src[1] / CHUNK_WIDTH);
- dst[2] = (int)floor(src[2] / CHUNK_WIDTH);
+ cm->offsets = malloc(sizeof *cm->offsets * cm->chunk_count);
+ for (int i = 0, x = -cm->radius; x <= cm->radius; x++)
+ {
+ for (int y = -cm->radius; y <= cm->radius; y++)
+ {
+ for (int z = -cm->radius; z <= cm->radius; z++, i++)
+ {
+ cm->offsets[i][0] = x;
+ cm->offsets[i][1] = y;
+ cm->offsets[i][2] = z;
+ }
+ }
+ }
}
-void ChunkManager_recenter(ChunkManager* chunk_manager, const int origin[3])
+static void ChunkManager_createChunks(ChunkManager *cm)
{
- chunk_manager->origin[0] = origin[0];
- chunk_manager->origin[1] = origin[1];
- chunk_manager->origin[2] = origin[2];
- for (int i = 0; i < chunk_manager->chunk_count; i++)
+ cm->chunks = malloc(sizeof *cm->chunks * cm->chunk_count);
+ for (int i = 0; i < cm->chunk_count; i++)
{
- chunk_manager->chunks[i] = Chunk_create(
- origin[0] + chunk_manager->offsets[i * 3],
- origin[1] + chunk_manager->offsets[i * 3 + 1],
- origin[2] + chunk_manager->offsets[i * 3 + 2]
- );
+ Chunk_init(&cm->chunks[i], cm->offsets[i]);
+ Chunk_meshify(&cm->chunks[i], cm->f, cm->isolevel);
}
}
-ChunkManager ChunkManager_create(int radius, float player[3])
+static void ChunkManager_updateChunks(ChunkManager *cm)
{
- ChunkManager chunk_manager;
+ // is_new indicates whether an offset is new
+ bool *is_new = malloc(sizeof *is_new * cm->chunk_count);
+ // is_old indicates whether a chunk is old
+ bool *is_old = malloc(sizeof *is_old * cm->chunk_count);
+ for (int i = 0; i < cm->chunk_count; i++)
+ {
+ is_new[i] = true;
+ is_old[i] = true;
+ }
- chunk_manager.radius = radius;
-
- int offset_count = ChunkManager_offsets(radius, NULL);
- chunk_manager.offsets = (int*)malloc(offset_count * sizeof(int));
- ChunkManager_offsets(radius, chunk_manager.offsets);
-
- chunk_manager.chunk_count = offset_count / 3;
- chunk_manager.chunks = (Chunk*)malloc(chunk_manager.chunk_count
- * sizeof(Chunk));
+ // Determine which offsets are new and which chunks are old
+ IVec3 *new_ids = malloc(sizeof *new_ids * cm->chunk_count);
+ for (int i = 0; i < cm->chunk_count; i++)
+ {
+ new_ids[i][0] = cm->origin[0] + cm->offsets[i][0];
+ new_ids[i][1] = cm->origin[1] + cm->offsets[i][1];
+ new_ids[i][2] = cm->origin[2] + cm->offsets[i][2];
+ for (int j = 0; j < cm->chunk_count; j++)
+ {
+ if (IVec3_equal(new_ids[i], cm->chunks[j].id) != 0)
+ {
+ is_new[i] = false;
+ is_old[j] = false;
+ break;
+ }
+ }
+ }
+
+ // Set old chunks to have new ids
+ for (int i = 0; i < cm->chunk_count; i++)
+ {
+ if (is_new[i])
+ {
+ for (int j = 0; j < cm->chunk_count; j++)
+ {
+ if (is_old[j])
+ {
+ cm->chunks[j].id[0] = new_ids[i][0];
+ cm->chunks[j].id[1] = new_ids[i][1];
+ cm->chunks[j].id[2] = new_ids[i][2];
+ Chunk_meshify(&cm->chunks[j], cm->f, cm->isolevel);
+ is_new[i] = false;
+ is_old[j] = false;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void ChunkManager_worldToChunk(const Vec3 src, IVec3 dst)
+{
+ dst[0] = (int)floorf(src[0] / CHUNK_WIDTH);
+ dst[1] = (int)floorf(src[1] / CHUNK_WIDTH);
+ dst[2] = (int)floorf(src[2] / CHUNK_WIDTH);
+}
+
+ChunkManager ChunkManager_create(const Vec3 target, int radius, SDF f,
+ float isolevel)
+{
+ ChunkManager cm;
+
+ ChunkManager_worldToChunk(target, cm.origin);
+ cm.radius = radius;
+
+ cm.f = f;
+ cm.isolevel = isolevel;
- ChunkManager_worldToChunk(player, chunk_manager.origin);
- ChunkManager_recenter(&chunk_manager, chunk_manager.origin);
+ ChunkManager_setChunkCount(&cm);
+ ChunkManager_createOffsets(&cm);
+ ChunkManager_createChunks(&cm);
- return chunk_manager;
+ return cm;
+}
+
+void ChunkManager_recenter(ChunkManager *cm, const Vec3 target)
+{
+ IVec3 new_origin;
+ ChunkManager_worldToChunk(target, new_origin);
+ if (!IVec3_equal(new_origin, cm->origin))
+ {
+ cm->origin[0] = new_origin[0];
+ cm->origin[1] = new_origin[1];
+ cm->origin[2] = new_origin[2];
+ ChunkManager_updateChunks(cm);
+ }
}
-void ChunkManager_update(ChunkManager* chunk_manager, float player[3])
+void ChunkManager_drawChunks(const ChunkManager *cm)
{
- int new_origin[3];
- ChunkManager_worldToChunk(player, new_origin);
- if (new_origin[0] != chunk_manager->origin[0]
- || new_origin[1] != chunk_manager->origin[1]
- || new_origin[2] != chunk_manager->origin[2])
+ for (int i = 0; i < cm->chunk_count; i++)
{
- ChunkManager_recenter(chunk_manager, new_origin);
+ Chunk_draw(&cm->chunks[i]);
}
}
diff --git a/src/main.c b/src/main.c
@@ -1,16 +1,12 @@
#include "camera.h"
-#include "chunk.h"
#include "chunk_manager.h"
-#include "glh/buffer.h"
#include "glh/shader.h"
#include "glad/glad.h"
#include <cglm/cglm.h>
-
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
-#include <stdbool.h>
#include <stdio.h>
const int WIDTH = 512, HEIGHT = 512;
@@ -31,6 +27,11 @@ void Camera_update(Camera* camera)
Camera_updateMatrix(camera);
}
+float sphereSDF(const float p[3])
+{
+ return sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]) - 25.0f;
+}
+
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
@@ -47,6 +48,7 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE);
}
+
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
@@ -62,7 +64,7 @@ int main(int argc, char** argv)
SDL_ShowCursor(SDL_DISABLE);
SDL_SetRelativeMouseMode(SDL_TRUE);
- Camera camera = Camera_create(0, 0, 3, -90, 0);
+ Camera camera = Camera_create(0, 0, -3, 0, 0);
gladLoadGLLoader(SDL_GL_GetProcAddress);
@@ -72,23 +74,11 @@ int main(int argc, char** argv)
glClearColor(0.4f, 0.4f, 0.6f, 1.0f);
- ChunkManager chunk_manager = ChunkManager_create(2, camera.position);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- float vertices[24 * chunk_manager.chunk_count];
- unsigned int indices[24 * chunk_manager.chunk_count];
- for (int i = 0; i < chunk_manager.chunk_count; i++)
- {
- Chunk_outline(&chunk_manager.chunks[i], &vertices[i * 24], i * 8,
- &indices[i * 24]);
- }
- GLuint vertex_buffer = createVertexBuffer(24 * chunk_manager.chunk_count
- * sizeof(float), vertices, GL_DYNAMIC_DRAW);
- GLuint index_buffer = createIndexBuffer(24 * chunk_manager.chunk_count
- * sizeof(unsigned int), indices, GL_STATIC_DRAW);
-
- int vertex[] = { 3 };
- GLuint vertex_array = createVertexArray(vertex_buffer, index_buffer, 1,
- vertex);
+ sphereSDF(camera.position);
+ ChunkManager chunk_manager = ChunkManager_create(camera.position, 1,
+ sphereSDF, 0.0f);
Shader shader = Shader_create("shaders/basic.vs", "shaders/basic.fs");
glUseProgram(shader.program);
@@ -123,19 +113,8 @@ int main(int argc, char** argv)
Camera_update(&camera);
glUniformMatrix4fv(cam_loc, 1, GL_FALSE, camera.matrix[0]);
- ChunkManager_update(&chunk_manager, camera.position);
- for (int i = 0; i < chunk_manager.chunk_count; i++)
- {
- Chunk_outline(&chunk_manager.chunks[i], &vertices[i * 24], i * 8,
- &indices[i * 24]);
- }
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
- glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * chunk_manager.chunk_count
- * sizeof(float), vertices);
-
- glBindVertexArray(vertex_array);
- glDrawElements(GL_LINES, 24 * chunk_manager.chunk_count,
- GL_UNSIGNED_INT, 0);
+ ChunkManager_recenter(&chunk_manager, camera.position);
+ ChunkManager_drawChunks(&chunk_manager);
SDL_GL_SwapWindow(window);
}
diff --git a/src/marching_cubes.c b/src/marching_cubes.c
@@ -0,0 +1,410 @@
+#include "marching_cubes.h"
+
+#include <math.h>
+
+const int EDGE_TABLE[256] = {
+ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905,
+ 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99 , 0x393, 0x29a,
+ 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93,
+ 0xf99, 0xe90, 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9,
+ 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6,
+ 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f,
+ 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5,
+ 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a,
+ 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53,
+ 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9,
+ 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6,
+ 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f,
+ 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5,
+ 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a,
+ 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663,
+ 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39,
+ 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636,
+ 0x13a, 0x33 , 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f,
+ 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605,
+ 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
+};
+
+const int TRI_TABLE[256][16] = {
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+};
+
+int MC_index(const Vec3 corners[8], SDF f, float isolevel)
+{
+ int mc_index = 0;
+ if (f(corners[0]) < isolevel) mc_index |= 1;
+ if (f(corners[1]) < isolevel) mc_index |= 2;
+ if (f(corners[2]) < isolevel) mc_index |= 4;
+ if (f(corners[3]) < isolevel) mc_index |= 8;
+ if (f(corners[4]) < isolevel) mc_index |= 16;
+ if (f(corners[5]) < isolevel) mc_index |= 32;
+ if (f(corners[6]) < isolevel) mc_index |= 64;
+ if (f(corners[7]) < isolevel) mc_index |= 128;
+ return mc_index;
+}
+
+void MC_interpVertex(const Vec3 a, const Vec3 b, SDF f, float isolevel,
+ Vec3 dst)
+{
+ float fa = f(a);
+ float fb = f(b);
+ if (fabsf(isolevel - fa) < 0.0001f || fabsf(fa - fb) < 0.0001f)
+ {
+ dst[0] = a[0];
+ dst[1] = a[1];
+ dst[2] = a[2];
+ return;
+ }
+ if (fabsf(isolevel - fb) < 0.0001f)
+ {
+ dst[0] = b[0];
+ dst[1] = b[1];
+ dst[2] = b[2];
+ return;
+ }
+ float t = (isolevel - fa) / (fb - fa);
+ dst[0] = a[0] + t * (b[0] - a[0]);
+ dst[1] = a[1] + t * (b[1] - a[1]);
+ dst[2] = a[2] + t * (b[2] - a[2]);
+ return;
+}
+
+void MC_vertices(const Vec3 corners[8], SDF f, float isolevel, int mc_index,
+ Vec3 vertices[12])
+{
+ if (EDGE_TABLE[mc_index] & 1)
+ {
+ MC_interpVertex(corners[0], corners[1], f, isolevel, vertices[0]);
+ }
+ if (EDGE_TABLE[mc_index] & 2)
+ {
+ MC_interpVertex(corners[1], corners[2], f, isolevel, vertices[1]);
+ }
+ if (EDGE_TABLE[mc_index] & 4)
+ {
+ MC_interpVertex(corners[2], corners[3], f, isolevel, vertices[2]);
+ }
+ if (EDGE_TABLE[mc_index] & 8)
+ {
+ MC_interpVertex(corners[3], corners[0], f, isolevel, vertices[3]);
+ }
+ if (EDGE_TABLE[mc_index] & 16)
+ {
+ MC_interpVertex(corners[4], corners[5], f, isolevel, vertices[4]);
+ }
+ if (EDGE_TABLE[mc_index] & 32)
+ {
+ MC_interpVertex(corners[5], corners[6], f, isolevel, vertices[5]);
+ }
+ if (EDGE_TABLE[mc_index] & 64)
+ {
+ MC_interpVertex(corners[6], corners[7], f, isolevel, vertices[6]);
+ }
+ if (EDGE_TABLE[mc_index] & 128)
+ {
+ MC_interpVertex(corners[7], corners[4], f, isolevel, vertices[7]);
+ }
+ if (EDGE_TABLE[mc_index] & 256)
+ {
+ MC_interpVertex(corners[0], corners[4], f, isolevel, vertices[8]);
+ }
+ if (EDGE_TABLE[mc_index] & 512)
+ {
+ MC_interpVertex(corners[1], corners[5], f, isolevel, vertices[9]);
+ }
+ if (EDGE_TABLE[mc_index] & 1024)
+ {
+ MC_interpVertex(corners[2], corners[6], f, isolevel, vertices[10]);
+ }
+ if (EDGE_TABLE[mc_index] & 2048)
+ {
+ MC_interpVertex(corners[3], corners[7], f, isolevel, vertices[11]);
+ }
+}
+
+int MC_triangles(const Vec3 vertices[12], SDF f, float isolevel, int mc_index,
+ Vec3* triangles)
+{
+ int vertex_count = 0;
+ for (int i = 0; TRI_TABLE[mc_index][i] != -1; i++)
+ {
+ triangles[i][0] = vertices[TRI_TABLE[mc_index][i]][0];
+ triangles[i][1] = vertices[TRI_TABLE[mc_index][i]][1];
+ triangles[i][2] = vertices[TRI_TABLE[mc_index][i]][2];
+ vertex_count++;
+ }
+ return vertex_count;
+}
+
+int MC_polygonize(const Vec3 corners[8], SDF f, float isolevel,
+ Vec3 triangles[15])
+{
+ int mc_index = MC_index(corners, f, isolevel);
+
+ Vec3 vertices[12];
+ MC_vertices(corners, f, isolevel, mc_index, vertices);
+
+ return MC_triangles(vertices, f, isolevel, mc_index,
+ triangles);
+}
diff --git a/src/vec.c b/src/vec.c
@@ -0,0 +1,6 @@
+#include "vec.h"
+
+bool IVec3_equal(const IVec3 a, const IVec3 b)
+{
+ return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]);
+}