diff options
Diffstat (limited to 'examples/voxelize/voxelizer.h')
-rw-r--r-- | examples/voxelize/voxelizer.h | 764 |
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 |