aboutsummaryrefslogtreecommitdiff
path: root/examples/voxelize/voxelizer.h
diff options
context:
space:
mode:
Diffstat (limited to 'examples/voxelize/voxelizer.h')
-rw-r--r--examples/voxelize/voxelizer.h764
1 files changed, 764 insertions, 0 deletions
diff --git a/examples/voxelize/voxelizer.h b/examples/voxelize/voxelizer.h
new file mode 100644
index 0000000..4958695
--- /dev/null
+++ b/examples/voxelize/voxelizer.h
@@ -0,0 +1,764 @@
+//
+// LICENCE:
+// The MIT License (MIT)
+//
+// Copyright (c) 2016 Karim Naaji, karim.naaji@gmail.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE
+//
+// REFERENCES:
+// http://matthias-mueller-fischer.ch/publications/tetraederCollision.pdf
+// http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tribox2.txt
+//
+// HOWTO:
+// #define VOXELIZER_IMPLEMENTATION
+// #define VOXELIZER_DEBUG // Only if assertions need to be checked
+// #include "voxelizer.h"
+//
+// HISTORY:
+// - version 0.9.0: Initial
+//
+// TODO:
+// - Triangle face merging
+// - Add colors from input mesh
+// - Potential issue with voxel bigger than triangle
+//
+
+#ifndef VOXELIZER_H
+#define VOXELIZER_H
+
+// ------------------------------------------------------------------------------------------------
+// VOXELIZER PUBLIC API
+//
+
+#ifndef VOXELIZER_HELPERS
+#include <stdlib.h> // malloc, calloc, free
+#endif
+
+typedef struct vx_vertex {
+ union {
+ float v[3];
+ struct {
+ float x;
+ float y;
+ float z;
+ };
+ };
+} vx_vertex_t;
+
+typedef struct vx_mesh {
+ vx_vertex_t* vertices; // Contiguous mesh vertices
+ vx_vertex_t* normals; // Contiguous mesh normals
+ unsigned int* indices; // Mesh indices
+ unsigned int* normalindices; // Mesh normal indices
+ size_t nindices; // The number of normal indices
+ size_t nvertices; // The number of vertices
+ size_t nnormals; // The number of normals
+} vx_mesh_t;
+
+vx_mesh_t* vx_voxelize(vx_mesh_t* _mesh, // The input mesh
+ float voxelsizex, // Voxel size on X-axis
+ float voxelsizey, // Voxel size on Y-axis
+ float voxelsizez, // Voxel size on Z-axis
+ float precision); // A precision factor that reduces "holes" artifact
+ // usually a precision = voxelsize / 10. works ok.
+
+void vx_mesh_free(vx_mesh_t* _mesh);
+vx_mesh_t* vx_mesh_alloc(int nindices, int nvertices);
+
+// Voxelizer Helpers, define your own if needed
+#ifndef VOXELIZER_HELPERS
+#define VOXELIZER_HELPERS 1
+#define VX_MIN(a, b) (a > b ? b : a)
+#define VX_MAX(a, b) (a > b ? a : b)
+#define VX_FINDMINMAX(x0, x1, x2, min, max) \
+ min = max = x0; \
+ if (x1 < min) min = x1; \
+ if (x1 > max) max = x1; \
+ if (x2 < min) min = x2; \
+ if (x2 > max) max = x2;
+#define VX_CLAMP(v, lo, hi) VX_MAX(lo, VX_MIN(hi, v))
+#define VX_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
+#define VX_FREE(T) free(T)
+#define VX_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
+#define VX_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
+#ifdef VOXELIZER_DEBUG
+#define VX_ASSERT(STMT) if (!(STMT)) { *(int *)0 = 0; }
+#else
+#define VX_ASSERT(STMT)
+#endif // VOXELIZER_DEBUG
+#endif // VOXELIZER_HELPERS
+
+//
+// END VOXELIZER PUBLIC API
+// ------------------------------------------------------------------------------------------------
+
+#endif // VOXELIZER_H
+
+#ifdef VOXELIZER_IMPLEMENTATION
+
+#include <math.h> // ceil, fabs & al.
+#include <stdbool.h> // hughh
+#include <string.h> // memcpy
+
+#define VOXELIZER_EPSILON (0.0000001)
+#define VOXELIZER_NORMAL_INDICES_SIZE (6)
+#define VOXELIZER_INDICES_SIZE (36)
+#define VOXELIZER_HASH_TABLE_SIZE (4096)
+
+unsigned int vx_voxel_indices[VOXELIZER_INDICES_SIZE] = {
+ 0, 1, 2,
+ 0, 2, 3,
+ 3, 2, 6,
+ 3, 6, 7,
+ 0, 7, 4,
+ 0, 3, 7,
+ 4, 7, 5,
+ 7, 6, 5,
+ 0, 4, 5,
+ 0, 5, 1,
+ 1, 5, 6,
+ 1, 6, 2,
+};
+
+float vx_normals[18] = {
+ 0.0, -1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0,
+ -1.0, 0.0, 0.0,
+ 0.0, 0.0, -1.0,
+};
+
+unsigned int vx_normal_indices[VOXELIZER_NORMAL_INDICES_SIZE] = {
+ 3, 2, 1, 5, 4, 0,
+};
+
+typedef struct vx_aabb {
+ vx_vertex_t min;
+ vx_vertex_t max;
+} vx_aabb_t;
+
+typedef struct vx_edge {
+ vx_vertex_t p1;
+ vx_vertex_t p2;
+} vx_edge_t;
+
+typedef struct vx_triangle {
+ vx_vertex_t p1;
+ vx_vertex_t p2;
+ vx_vertex_t p3;
+} vx_triangle_t;
+
+typedef struct vx_hash_table_node {
+ struct vx_hash_table_node* next;
+ struct vx_hash_table_node* prev;
+ void* data;
+} vx_hash_table_node_t;
+
+typedef struct vx_hash_table {
+ vx_hash_table_node_t** elements;
+ size_t size;
+} vx_hash_table_t;
+
+vx_hash_table_t* vx__hash_table_alloc(size_t size)
+{
+ vx_hash_table_t* table = VX_MALLOC(vx_hash_table_t, 1);
+ if (!table) { return NULL; }
+ table->size = size;
+ table->elements = VX_MALLOC(vx_hash_table_node_t*, size);
+ if (!table->elements) { return NULL; }
+ for (size_t i = 0; i < table->size; ++i) {
+ table->elements[i] = NULL;
+ }
+ return table;
+}
+
+void vx__hash_table_free(vx_hash_table_t* table, bool freedata)
+{
+ for (size_t i = 0; i < table->size; ++i) {
+ vx_hash_table_node_t* node = table->elements[i];
+
+ if (node) {
+ if (node->next) {
+ while (node->next) {
+ node = node->next;
+ if (freedata) {
+ VX_FREE(node->prev->data);
+ }
+ VX_FREE(node->prev);
+ }
+ VX_FREE(node);
+ } else {
+ VX_FREE(node->data);
+ VX_FREE(node);
+ }
+ }
+ }
+
+ VX_FREE(table->elements);
+ VX_FREE(table);
+}
+
+bool vx__hash_table_insert(vx_hash_table_t* table,
+ size_t hash,
+ void* data,
+ bool (*compfunc)(void* d1, void* d2))
+{
+ if (!table->elements[hash]) {
+ table->elements[hash] = VX_MALLOC(vx_hash_table_node_t, 1);
+ table->elements[hash]->prev = NULL;
+ table->elements[hash]->next = NULL;
+ table->elements[hash]->data = data;
+ } else {
+ vx_hash_table_node_t* node = table->elements[hash];
+
+ if (compfunc && compfunc(node->data, data)) {
+ return false;
+ }
+
+ while (node->next) {
+ node = node->next;
+ if (compfunc && compfunc(node->data, data)) {
+ return false;
+ }
+ }
+
+ vx_hash_table_node_t* nnode = VX_MALLOC(vx_hash_table_node_t, 1);
+
+ nnode->prev = node;
+ nnode->next = NULL;
+ nnode->data = data;
+ node->next = nnode;
+ }
+ return true;
+}
+
+void vx_mesh_free(vx_mesh_t* m)
+{
+ VX_FREE(m->vertices);
+ m->vertices = NULL;
+ m->nvertices = 0;
+ VX_FREE(m->indices);
+ m->indices = NULL;
+ m->nindices = 0;
+ if (m->normals) { VX_FREE(m->normals); }
+ VX_FREE(m);
+}
+
+vx_mesh_t* vx_mesh_alloc(int nvertices, int nindices)
+{
+ vx_mesh_t* m = VX_MALLOC(vx_mesh_t, 1);
+ if (!m) { return NULL; }
+ m->indices = VX_CALLOC(unsigned int, nindices);
+ if (!m->indices) { return NULL; }
+ m->vertices = VX_CALLOC(vx_vertex_t, nvertices);
+ if (!m->vertices) { return NULL; }
+ m->normals = NULL;
+ m->nindices = nindices;
+ m->nvertices = nvertices;
+ return m;
+}
+
+float vx__map_to_voxel(float position, float voxelSize, bool min)
+{
+ float vox = (position + (position < 0.f ? -1.f : 1.f) * voxelSize * 0.5f) / voxelSize;
+ return (min ? floor(vox) : ceil(vox)) * voxelSize;
+}
+
+vx_vertex_t vx__vertex_cross(vx_vertex_t* v1, vx_vertex_t* v2)
+{
+ vx_vertex_t cross;
+ cross.x = v1->y * v2->z - v1->z * v2->y;
+ cross.y = v1->z * v2->x - v1->x * v2->z;
+ cross.z = v1->x * v2->y - v1->y * v2->x;
+ return cross;
+}
+
+bool vx__vertex_equals(vx_vertex_t* v1, vx_vertex_t* v2) {
+ return fabs(v1->x - v2->x) < VOXELIZER_EPSILON &&
+ fabs(v1->y - v2->y) < VOXELIZER_EPSILON &&
+ fabs(v1->z - v2->z) < VOXELIZER_EPSILON;
+}
+
+bool vx__vertex_comp_func(void* a, void* b)
+{
+ return vx__vertex_equals((vx_vertex_t*) a, (vx_vertex_t*) b);
+}
+
+void vx__vertex_sub(vx_vertex_t* a, vx_vertex_t* b)
+{
+ a->x -= b->x;
+ a->y -= b->y;
+ a->z -= b->z;
+}
+
+void vx__vertex_add(vx_vertex_t* a, vx_vertex_t* b)
+{
+ a->x += b->x;
+ a->y += b->y;
+ a->z += b->z;
+}
+
+void vx__vertex_multiply(vx_vertex_t* a, float v)
+{
+ a->x *= v;
+ a->y *= v;
+ a->z *= v;
+}
+
+float vx__vertex_dot(vx_vertex_t* v1, vx_vertex_t* v2)
+{
+ return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
+}
+
+int vx__plane_box_overlap(vx_vertex_t* normal,
+ float d,
+ vx_vertex_t* halfboxsize)
+{
+ vx_vertex_t vmin, vmax;
+
+ for (int dim = 0; dim <= 2; dim++) {
+ if (normal->v[dim] > 0.0f) {
+ vmin.v[dim] = -halfboxsize->v[dim];
+ vmax.v[dim] = halfboxsize->v[dim];
+ } else {
+ vmin.v[dim] = halfboxsize->v[dim];
+ vmax.v[dim] = -halfboxsize->v[dim];
+ }
+ }
+
+ if (vx__vertex_dot(normal, &vmin) + d > 0.0f) {
+ return false;
+ }
+
+ if (vx__vertex_dot(normal, &vmax) + d >= 0.0f) {
+ return true;
+ }
+
+ return false;
+}
+
+#define AXISTEST_X01(a, b, fa, fb) \
+ p1 = a * v1.y - b * v1.z; \
+ p3 = a * v3.y - b * v3.z; \
+ if (p1 < p3) { \
+ min = p1; max = p3; \
+ } else { \
+ min = p3; max = p1; \
+ } \
+ rad = fa * halfboxsize.y + fb * halfboxsize.z; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ } \
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p1 = a * v1.y - b * v1.z; \
+ p2 = a * v2.y - b * v2.z; \
+ if (p1 < p2) { \
+ min = p1; max = p2; \
+ } else { \
+ min = p2; max = p1; \
+ } \
+ rad = fa * halfboxsize.y + fb * halfboxsize.z; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ } \
+
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p1 = -a * v1.x + b * v1.z; \
+ p3 = -a * v3.x + b * v3.z; \
+ if (p1 < p3) { \
+ min = p1; max = p3; \
+ } else { \
+ min = p3; max = p1; \
+ } \
+ rad = fa * halfboxsize.x + fb * halfboxsize.z; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ } \
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p1 = -a * v1.x + b * v1.z; \
+ p2 = -a * v2.x + b * v2.z; \
+ if (p1 < p2) { \
+ min = p1; max = p2; \
+ } else { \
+ min = p2; max = p1; \
+ } \
+ rad = fa * halfboxsize.x + fb * halfboxsize.z; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ }
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p2 = a * v2.x - b * v2.y; \
+ p3 = a * v3.x - b * v3.y; \
+ if (p3 < p2) { \
+ min = p3; max = p2; \
+ } else { \
+ min = p2; max = p3; \
+ } \
+ rad = fa * halfboxsize.x + fb * halfboxsize.y; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ }
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p1 = a * v1.x - b * v1.y; \
+ p2 = a * v2.x - b * v2.y; \
+ if (p1 < p2) { \
+ min = p1; max = p2; \
+ } else { \
+ min = p2; max = p1; \
+ } \
+ rad = fa * halfboxsize.x + fb * halfboxsize.y; \
+ if (min > rad || max < -rad) { \
+ return false; \
+ }
+
+int vx__triangle_box_overlap(vx_vertex_t boxcenter,
+ vx_vertex_t halfboxsize,
+ vx_triangle_t triangle)
+{
+ vx_vertex_t v1, v2, v3, normal, e1, e2, e3;
+ float min, max, d, p1, p2, p3, rad, fex, fey, fez;
+
+ v1 = triangle.p1;
+ v2 = triangle.p2;
+ v3 = triangle.p3;
+
+ vx__vertex_sub(&v1, &boxcenter);
+ vx__vertex_sub(&v2, &boxcenter);
+ vx__vertex_sub(&v3, &boxcenter);
+
+ e1 = v2;
+ e2 = v3;
+ e3 = v1;
+
+ vx__vertex_sub(&e1, &v1);
+ vx__vertex_sub(&e2, &v2);
+ vx__vertex_sub(&e3, &v3);
+
+ fex = fabs(e1.x);
+ fey = fabs(e1.y);
+ fez = fabs(e1.z);
+
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z12(e1.y, e1.x, fey, fex);
+
+ fex = fabs(e2.x);
+ fey = fabs(e2.y);
+ fez = fabs(e2.z);
+
+ AXISTEST_X01(e2.z, e2.y, fez, fey);
+ AXISTEST_Y02(e2.z, e2.x, fez, fex);
+ AXISTEST_Z0(e2.y, e2.x, fey, fex);
+
+ fex = fabs(e3.x);
+ fey = fabs(e3.y);
+ fez = fabs(e3.z);
+
+ AXISTEST_X2(e3.z, e3.y, fez, fey);
+ AXISTEST_Y1(e3.z, e3.x, fez, fex);
+ AXISTEST_Z12(e3.y, e3.x, fey, fex);
+
+ VX_FINDMINMAX(v1.x, v2.x, v3.x, min, max);
+ if (min > halfboxsize.x || max < -halfboxsize.x) {
+ return false;
+ }
+
+ VX_FINDMINMAX(v1.y, v2.y, v3.y, min, max);
+ if (min > halfboxsize.y || max < -halfboxsize.y) {
+ return false;
+ }
+
+ VX_FINDMINMAX(v1.z, v2.z, v3.z, min, max);
+ if (min > halfboxsize.z || max < -halfboxsize.z) {
+ return false;
+ }
+
+ normal = vx__vertex_cross(&e1, &e2);
+ d = -vx__vertex_dot(&normal, &v1);
+
+ if (!vx__plane_box_overlap(&normal, d, &halfboxsize)) {
+ return false;
+ }
+
+ return true;
+}
+
+#undef AXISTEST_X2
+#undef AXISTEST_X01
+#undef AXISTEST_Y1
+#undef AXISTEST_Y02
+#undef AXISTEST_Z0
+#undef AXISTEST_Z12
+
+float vx__triangle_area(vx_triangle_t* triangle) {
+ vx_vertex_t ab = triangle->p2;
+ vx_vertex_t ac = triangle->p3;
+
+ vx__vertex_sub(&ab, &triangle->p1);
+ vx__vertex_sub(&ac, &triangle->p1);
+
+ float a0 = ab.y * ac.z - ab.z * ac.y;
+ float a1 = ab.z * ac.x - ab.x * ac.z;
+ float a2 = ab.x * ac.y - ab.y * ac.x;
+
+ return sqrtf(powf(a0, 2.f) + powf(a1, 2.f) + powf(a2, 2.f)) * 0.5f;
+}
+
+void vx__aabb_init(vx_aabb_t* aabb)
+{
+ aabb->max.x = aabb->max.y = aabb->max.z = -INFINITY;
+ aabb->min.x = aabb->min.y = aabb->min.z = INFINITY;
+}
+
+vx_aabb_t vx__triangle_aabb(vx_triangle_t* triangle)
+{
+ vx_aabb_t aabb;
+
+ vx__aabb_init(&aabb);
+
+ aabb.max.x = VX_MAX(aabb.max.x, triangle->p1.x); aabb.max.x = VX_MAX(aabb.max.x,
+ triangle->p2.x); aabb.max.x = VX_MAX(aabb.max.x, triangle->p3.x);
+ aabb.max.y = VX_MAX(aabb.max.y, triangle->p1.y); aabb.max.y = VX_MAX(aabb.max.y,
+ triangle->p2.y); aabb.max.y = VX_MAX(aabb.max.y, triangle->p3.y);
+ aabb.max.z = VX_MAX(aabb.max.z, triangle->p1.z); aabb.max.z = VX_MAX(aabb.max.z,
+ triangle->p2.z); aabb.max.z = VX_MAX(aabb.max.z, triangle->p3.z);
+
+ aabb.min.x = VX_MIN(aabb.min.x, triangle->p1.x); aabb.min.x = VX_MIN(aabb.min.x,
+ triangle->p2.x); aabb.min.x = VX_MIN(aabb.min.x, triangle->p3.x);
+ aabb.min.y = VX_MIN(aabb.min.y, triangle->p1.y); aabb.min.y = VX_MIN(aabb.min.y,
+ triangle->p2.y); aabb.min.y = VX_MIN(aabb.min.y, triangle->p3.y);
+ aabb.min.z = VX_MIN(aabb.min.z, triangle->p1.z); aabb.min.z = VX_MIN(aabb.min.z,
+ triangle->p2.z); aabb.min.z = VX_MIN(aabb.min.z, triangle->p3.z);
+
+ return aabb;
+}
+
+vx_vertex_t vx__aabb_center(vx_aabb_t* a)
+{
+ vx_vertex_t boxcenter = a->min;
+ vx__vertex_add(&boxcenter, &a->max);
+ vx__vertex_multiply(&boxcenter, 0.5f);
+
+ return boxcenter;
+}
+
+vx_vertex_t vx__aabb_half_size(vx_aabb_t* a)
+{
+ vx_vertex_t size;
+
+ size.x = fabs(a->max.x - a->min.x) * 0.5f;
+ size.y = fabs(a->max.y - a->min.y) * 0.5f;
+ size.z = fabs(a->max.z - a->min.z) * 0.5f;
+
+ return size;
+}
+
+vx_aabb_t vx__aabb_merge(vx_aabb_t* a, vx_aabb_t* b)
+{
+ vx_aabb_t merge;
+
+ merge.min.x = VX_MIN(a->min.x, b->min.x);
+ merge.min.y = VX_MIN(a->min.y, b->min.y);
+ merge.min.z = VX_MIN(a->min.z, b->min.z);
+
+ merge.max.x = VX_MAX(a->max.x, b->max.x);
+ merge.max.y = VX_MAX(a->max.y, b->max.y);
+ merge.max.z = VX_MAX(a->max.z, b->max.z);
+
+ return merge;
+}
+
+size_t vx__vertex_hash(vx_vertex_t pos, size_t n)
+{
+ size_t a = (size_t)(pos.x * 73856093);
+ size_t b = (size_t)(pos.y * 19349663);
+ size_t c = (size_t)(pos.z * 83492791);
+
+ return (a ^ b ^ c) % n;
+}
+
+void vx__add_voxel(vx_mesh_t* mesh,
+ vx_vertex_t* pos,
+ float* vertices)
+{
+ for (size_t i = 0; i < 8; ++i) {
+ size_t index = i+mesh->nvertices;
+
+ mesh->vertices[index].x = vertices[i*3+0] + pos->x;
+ mesh->vertices[index].y = vertices[i*3+1] + pos->y;
+ mesh->vertices[index].z = vertices[i*3+2] + pos->z;
+ }
+
+ int j = -1;
+ for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
+ if (i % 6 == 0) {
+ j++;
+ }
+ mesh->normalindices[i+mesh->nindices] = vx_normal_indices[j];
+ }
+
+ for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
+ mesh->indices[i+mesh->nindices] = vx_voxel_indices[i] + mesh->nvertices;
+ }
+
+ mesh->nindices += VOXELIZER_INDICES_SIZE;
+ mesh->nvertices += 8;
+}
+
+vx_mesh_t* vx_voxelize(vx_mesh_t* m,
+ float voxelsizex,
+ float voxelsizey,
+ float voxelsizez,
+ float precision)
+{
+ vx_mesh_t* outmesh = NULL;
+ vx_hash_table_t* table = NULL;
+ size_t voxels = 0;
+
+ float halfsizex = voxelsizex * 0.5f;
+ float halfsizey = voxelsizey * 0.5f;
+ float halfsizez = voxelsizez * 0.5f;
+
+ table = vx__hash_table_alloc(VOXELIZER_HASH_TABLE_SIZE);
+
+ for (int i = 0; i < m->nindices; i += 3) {
+ vx_triangle_t triangle;
+
+ VX_ASSERT(m->indices[i+0] < m->nvertices);
+ VX_ASSERT(m->indices[i+1] < m->nvertices);
+ VX_ASSERT(m->indices[i+2] < m->nvertices);
+
+ triangle.p1 = m->vertices[m->indices[i+0]];
+ triangle.p2 = m->vertices[m->indices[i+1]];
+ triangle.p3 = m->vertices[m->indices[i+2]];
+
+ if (vx__triangle_area(&triangle) < VOXELIZER_EPSILON) {
+ // triangle with 0 area
+ continue;
+ }
+
+ vx_aabb_t aabb = vx__triangle_aabb(&triangle);
+
+ aabb.min.x = vx__map_to_voxel(aabb.min.x, voxelsizex, true);
+ aabb.min.y = vx__map_to_voxel(aabb.min.y, voxelsizey, true);
+ aabb.min.z = vx__map_to_voxel(aabb.min.z, voxelsizez, true);
+
+ aabb.max.x = vx__map_to_voxel(aabb.max.x, voxelsizex, false);
+ aabb.max.y = vx__map_to_voxel(aabb.max.y, voxelsizey, false);
+ aabb.max.z = vx__map_to_voxel(aabb.max.z, voxelsizez, false);
+
+ for (float x = aabb.min.x; x < aabb.max.x; x += voxelsizex) {
+ for (float y = aabb.min.y; y < aabb.max.y; y += voxelsizey) {
+ for (float z = aabb.min.z; z < aabb.max.z; z += voxelsizez) {
+ vx_aabb_t saabb;
+
+ saabb.min.x = x - halfsizex;
+ saabb.min.y = y - halfsizey;
+ saabb.min.z = z - halfsizez;
+ saabb.max.x = x + halfsizex;
+ saabb.max.y = y + halfsizey;
+ saabb.max.z = z + halfsizez;
+
+ vx_vertex_t boxcenter = vx__aabb_center(&saabb);
+ vx_vertex_t halfsize = vx__aabb_half_size(&saabb);
+
+ // HACK: some holes might appear, this
+ // precision factor reduces the artifact
+ halfsize.x += precision;
+ halfsize.y += precision;
+ halfsize.z += precision;
+
+ if (vx__triangle_box_overlap(boxcenter, halfsize, triangle)) {
+ vx_vertex_t* nodedata = VX_MALLOC(vx_vertex_t, 1);
+ *nodedata = boxcenter;
+
+ size_t hash = vx__vertex_hash(boxcenter, VOXELIZER_HASH_TABLE_SIZE);
+
+ bool insert = vx__hash_table_insert(table,
+ hash,
+ nodedata,
+ vx__vertex_comp_func);
+
+ if (insert) {
+ voxels++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ outmesh = VX_MALLOC(vx_mesh_t, 1);
+ size_t nvertices = voxels * 8;
+ size_t nindices = voxels * VOXELIZER_INDICES_SIZE;
+ outmesh->nnormals = VOXELIZER_NORMAL_INDICES_SIZE;
+ outmesh->vertices = VX_CALLOC(vx_vertex_t, nvertices);
+ outmesh->normals = VX_CALLOC(vx_vertex_t, 6);
+ outmesh->indices = VX_CALLOC(unsigned int, nindices);
+ outmesh->normalindices = VX_CALLOC(unsigned int, nindices);
+ outmesh->nindices = 0;
+ outmesh->nvertices = 0;
+
+ memcpy(outmesh->normals, vx_normals, 18 * sizeof(float));
+
+ float vertices[24] = {
+ -halfsizex, halfsizey, halfsizez,
+ -halfsizex, -halfsizey, halfsizez,
+ halfsizex, -halfsizey, halfsizez,
+ halfsizex, halfsizey, halfsizez,
+ -halfsizex, halfsizey, -halfsizez,
+ -halfsizex, -halfsizey, -halfsizez,
+ halfsizex, -halfsizey, -halfsizez,
+ halfsizex, halfsizey, -halfsizez,
+ };
+
+ for (size_t i = 0; i < table->size; ++i) {
+ if (table->elements[i] != NULL) {
+ vx_hash_table_node_t* node = table->elements[i];
+
+ if (!node) {
+ continue;
+ }
+
+ vx_vertex_t* p = (vx_vertex_t*) node->data;
+ vx__add_voxel(outmesh, p, vertices);
+
+ while (node->next) {
+ node = node->next;
+ p = (vx_vertex_t*) node->data;
+ vx__add_voxel(outmesh, p, vertices);
+ }
+ }
+ }
+
+ vx__hash_table_free(table, true);
+
+ return outmesh;
+}
+
+#undef VOXELIZER_EPSILON
+#undef VOXELIZER_INDICES_SIZE
+#undef VOXELIZER_HASH_TABLE_SIZE
+
+#endif // VX_VOXELIZER_IMPLEMENTATION