diff options
Diffstat (limited to '')
| -rw-r--r-- | raylib/src/external/vox_loader.h | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/raylib/src/external/vox_loader.h b/raylib/src/external/vox_loader.h new file mode 100644 index 0000000..0d328c0 --- /dev/null +++ b/raylib/src/external/vox_loader.h | |||
| @@ -0,0 +1,727 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2021 Johann Nadalutti. | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in | ||
| 14 | all copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | THE SOFTWARE. | ||
| 23 | |||
| 24 | |||
| 25 | vox_loader - v1.01 | ||
| 26 | no warranty implied; use at your own risk | ||
| 27 | |||
| 28 | Do this: | ||
| 29 | #define VOX_LOADER_INCLUDE__H | ||
| 30 | before you include this file in* one* C or C++ file to create the implementation. | ||
| 31 | |||
| 32 | // i.e. it should look like this: | ||
| 33 | #include ... | ||
| 34 | #include ... | ||
| 35 | #include ... | ||
| 36 | #define VOX_LOADER_INCLUDE__H | ||
| 37 | #include "vox_loader.h" | ||
| 38 | |||
| 39 | revision history: | ||
| 40 | 1.00 (2021-09-03) first released version | ||
| 41 | 1.01 (2021-09-07) Support custom memory allocators | ||
| 42 | Removed Raylib dependencies | ||
| 43 | Changed Vox_LoadFileName to Vox_LoadFromMemory | ||
| 44 | 1.02 (2021-09-10) @raysan5: Reviewed some formating | ||
| 45 | 1.03 (2021-10-02) @catmanl: Reduce warnings on gcc | ||
| 46 | 1.04 (2021-10-17) @warzes: Fixing the error of loading VOX models | ||
| 47 | |||
| 48 | */ | ||
| 49 | |||
| 50 | #ifndef VOX_LOADER_H | ||
| 51 | #define VOX_LOADER_H | ||
| 52 | |||
| 53 | // Allow custom memory allocators | ||
| 54 | #ifndef VOX_MALLOC | ||
| 55 | #define VOX_MALLOC(sz) malloc(sz) | ||
| 56 | #endif | ||
| 57 | #ifndef VOX_CALLOC | ||
| 58 | #define VOX_CALLOC(n,sz) calloc(n,sz) | ||
| 59 | #endif | ||
| 60 | #ifndef VOX_REALLOC | ||
| 61 | #define VOX_REALLOC(n,sz) realloc(n,sz) | ||
| 62 | #endif | ||
| 63 | #ifndef VOX_FREE | ||
| 64 | #define VOX_FREE(p) free(p) | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #define VOX_SUCCESS (0) | ||
| 68 | #define VOX_ERROR_FILE_NOT_FOUND (-1) | ||
| 69 | #define VOX_ERROR_INVALID_FORMAT (-2) | ||
| 70 | #define VOX_ERROR_FILE_VERSION_NOT_MATCH (-3) | ||
| 71 | |||
| 72 | // VoxColor, 4 components, R8G8B8A8 (32bit) | ||
| 73 | typedef struct { | ||
| 74 | unsigned char r, g, b, a; | ||
| 75 | } VoxColor; | ||
| 76 | |||
| 77 | // VoxVector3, 3 components | ||
| 78 | typedef struct { | ||
| 79 | float x, y, z; | ||
| 80 | } VoxVector3; | ||
| 81 | |||
| 82 | typedef struct { | ||
| 83 | VoxVector3* array; | ||
| 84 | int used, size; | ||
| 85 | } ArrayVector3; | ||
| 86 | |||
| 87 | typedef struct { | ||
| 88 | VoxColor* array; | ||
| 89 | int used, size; | ||
| 90 | } ArrayColor; | ||
| 91 | |||
| 92 | typedef struct { | ||
| 93 | unsigned short* array; | ||
| 94 | int used, size; | ||
| 95 | } ArrayUShort; | ||
| 96 | |||
| 97 | // A chunk that contain voxels | ||
| 98 | typedef struct { | ||
| 99 | unsigned char* m_array; //If Sparse != null | ||
| 100 | int arraySize; //Size for m_array in bytes (DEBUG ONLY) | ||
| 101 | } CubeChunk3D; | ||
| 102 | |||
| 103 | // Array for voxels | ||
| 104 | // Array is divised into chunks of CHUNKSIZE*CHUNKSIZE*CHUNKSIZE voxels size | ||
| 105 | typedef struct { | ||
| 106 | // Array size in voxels | ||
| 107 | int sizeX; | ||
| 108 | int sizeY; | ||
| 109 | int sizeZ; | ||
| 110 | |||
| 111 | // Chunks size into array (array is divised into chunks) | ||
| 112 | int chunksSizeX; | ||
| 113 | int chunksSizeY; | ||
| 114 | int chunksSizeZ; | ||
| 115 | |||
| 116 | // Chunks array | ||
| 117 | CubeChunk3D* m_arrayChunks; | ||
| 118 | int arrayChunksSize; // Size for m_arrayChunks in bytes (DEBUG ONLY) | ||
| 119 | |||
| 120 | int ChunkFlattenOffset; | ||
| 121 | int chunksAllocated; | ||
| 122 | int chunksTotal; | ||
| 123 | |||
| 124 | // Arrays for mesh build | ||
| 125 | ArrayVector3 vertices; | ||
| 126 | ArrayVector3 normals; | ||
| 127 | ArrayUShort indices; | ||
| 128 | ArrayColor colors; | ||
| 129 | |||
| 130 | //Palette for voxels | ||
| 131 | VoxColor palette[256]; | ||
| 132 | |||
| 133 | } VoxArray3D; | ||
| 134 | |||
| 135 | #if defined(__cplusplus) | ||
| 136 | extern "C" { // Prevents name mangling of functions | ||
| 137 | #endif | ||
| 138 | |||
| 139 | // Functions | ||
| 140 | int Vox_LoadFromMemory(unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray); | ||
| 141 | void Vox_FreeArrays(VoxArray3D* voxarray); | ||
| 142 | |||
| 143 | #ifdef __cplusplus | ||
| 144 | } | ||
| 145 | #endif | ||
| 146 | |||
| 147 | #endif // VOX_LOADER_H | ||
| 148 | //// end header file ///////////////////////////////////////////////////// | ||
| 149 | |||
| 150 | |||
| 151 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 152 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 153 | // Implementation | ||
| 154 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 155 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 156 | |||
| 157 | #ifdef VOX_LOADER_IMPLEMENTATION | ||
| 158 | |||
| 159 | #include <string.h> | ||
| 160 | #include <stdlib.h> | ||
| 161 | |||
| 162 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 163 | // ArrayUShort helper | ||
| 164 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 165 | |||
| 166 | static void initArrayUShort(ArrayUShort* a, int initialSize) | ||
| 167 | { | ||
| 168 | a->array = VOX_MALLOC(initialSize * sizeof(unsigned short)); | ||
| 169 | a->used = 0; | ||
| 170 | a->size = initialSize; | ||
| 171 | } | ||
| 172 | |||
| 173 | static void insertArrayUShort(ArrayUShort* a, unsigned short element) | ||
| 174 | { | ||
| 175 | if (a->used == a->size) | ||
| 176 | { | ||
| 177 | a->size *= 2; | ||
| 178 | a->array = VOX_REALLOC(a->array, a->size * sizeof(unsigned short)); | ||
| 179 | } | ||
| 180 | a->array[a->used++] = element; | ||
| 181 | } | ||
| 182 | |||
| 183 | static void freeArrayUShort(ArrayUShort* a) | ||
| 184 | { | ||
| 185 | VOX_FREE(a->array); | ||
| 186 | a->array = NULL; | ||
| 187 | a->used = a->size = 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 192 | // ArrayVector3 helper | ||
| 193 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 194 | |||
| 195 | static void initArrayVector3(ArrayVector3* a, int initialSize) | ||
| 196 | { | ||
| 197 | a->array = VOX_MALLOC(initialSize * sizeof(VoxVector3)); | ||
| 198 | a->used = 0; | ||
| 199 | a->size = initialSize; | ||
| 200 | } | ||
| 201 | |||
| 202 | static void insertArrayVector3(ArrayVector3* a, VoxVector3 element) | ||
| 203 | { | ||
| 204 | if (a->used == a->size) | ||
| 205 | { | ||
| 206 | a->size *= 2; | ||
| 207 | a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxVector3)); | ||
| 208 | } | ||
| 209 | a->array[a->used++] = element; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void freeArrayVector3(ArrayVector3* a) | ||
| 213 | { | ||
| 214 | VOX_FREE(a->array); | ||
| 215 | a->array = NULL; | ||
| 216 | a->used = a->size = 0; | ||
| 217 | } | ||
| 218 | |||
| 219 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 220 | // ArrayColor helper | ||
| 221 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 222 | |||
| 223 | static void initArrayColor(ArrayColor* a, int initialSize) | ||
| 224 | { | ||
| 225 | a->array = VOX_MALLOC(initialSize * sizeof(VoxColor)); | ||
| 226 | a->used = 0; | ||
| 227 | a->size = initialSize; | ||
| 228 | } | ||
| 229 | |||
| 230 | static void insertArrayColor(ArrayColor* a, VoxColor element) | ||
| 231 | { | ||
| 232 | if (a->used == a->size) | ||
| 233 | { | ||
| 234 | a->size *= 2; | ||
| 235 | a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxColor)); | ||
| 236 | } | ||
| 237 | a->array[a->used++] = element; | ||
| 238 | } | ||
| 239 | |||
| 240 | static void freeArrayColor(ArrayColor* a) | ||
| 241 | { | ||
| 242 | VOX_FREE(a->array); | ||
| 243 | a->array = NULL; | ||
| 244 | a->used = a->size = 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | |||
| 248 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 249 | // Vox Loader | ||
| 250 | ///////////////////////////////////////////////////////////////////////////////////////////// | ||
| 251 | |||
| 252 | #define CHUNKSIZE 16 // chunk size (CHUNKSIZE*CHUNKSIZE*CHUNKSIZE) in voxels | ||
| 253 | #define CHUNKSIZE_OPSHIFT 4 // 1<<4=16 -> Warning depend of CHUNKSIZE | ||
| 254 | #define CHUNK_FLATTENOFFSET_OPSHIFT 8 // Warning depend of CHUNKSIZE | ||
| 255 | |||
| 256 | // | ||
| 257 | // used right handed system and CCW face | ||
| 258 | // | ||
| 259 | // indexes for voxelcoords, per face orientation | ||
| 260 | // | ||
| 261 | |||
| 262 | //# Y | ||
| 263 | //# | | ||
| 264 | //# o----X | ||
| 265 | //# / | ||
| 266 | //# Z 2------------3 | ||
| 267 | //# /| /| | ||
| 268 | //# 6------------7 | | ||
| 269 | //# | | | | | ||
| 270 | //# |0 ----------|- 1 | ||
| 271 | //# |/ |/ | ||
| 272 | //# 4------------5 | ||
| 273 | |||
| 274 | // | ||
| 275 | // CCW | ||
| 276 | const int fv[6][4] = { | ||
| 277 | {0, 2, 6, 4 }, //-X | ||
| 278 | {5, 7, 3, 1 }, //+X | ||
| 279 | {0, 4, 5, 1 }, //-y | ||
| 280 | {6, 2, 3, 7 }, //+y | ||
| 281 | {1, 3, 2, 0 }, //-Z | ||
| 282 | {4, 6, 7, 5 } //+Z | ||
| 283 | }; | ||
| 284 | |||
| 285 | const VoxVector3 SolidVertex[] = { | ||
| 286 | {0, 0, 0}, //0 | ||
| 287 | {1, 0, 0}, //1 | ||
| 288 | {0, 1, 0}, //2 | ||
| 289 | {1, 1, 0}, //3 | ||
| 290 | {0, 0, 1}, //4 | ||
| 291 | {1, 0, 1}, //5 | ||
| 292 | {0, 1, 1}, //6 | ||
| 293 | {1, 1, 1} //7 | ||
| 294 | }; | ||
| 295 | |||
| 296 | const VoxVector3 FacesPerSideNormal[] = { | ||
| 297 | { -1, 0, 0 }, //-X | ||
| 298 | {1, 0, 0 }, //+X | ||
| 299 | {0,-1, 0}, //-Y | ||
| 300 | {0, 1, 0}, //+Y | ||
| 301 | {0, 0, -1}, //-Z | ||
| 302 | {0, 0, 1}, //+Z | ||
| 303 | }; | ||
| 304 | |||
| 305 | |||
| 306 | // Allocated VoxArray3D size | ||
| 307 | static void Vox_AllocArray(VoxArray3D* pvoxarray, int _sx, int _sy, int _sz) | ||
| 308 | { | ||
| 309 | int sx = _sx + ((CHUNKSIZE - (_sx % CHUNKSIZE)) % CHUNKSIZE); | ||
| 310 | int sy = _sy + ((CHUNKSIZE - (_sy % CHUNKSIZE)) % CHUNKSIZE); | ||
| 311 | int sz = _sz + ((CHUNKSIZE - (_sz % CHUNKSIZE)) % CHUNKSIZE); | ||
| 312 | |||
| 313 | int chx = sx >> CHUNKSIZE_OPSHIFT; //Chunks Count in X | ||
| 314 | int chy = sy >> CHUNKSIZE_OPSHIFT; //Chunks Count in Y | ||
| 315 | int chz = sz >> CHUNKSIZE_OPSHIFT; //Chunks Count in Z | ||
| 316 | |||
| 317 | //VoxArray3D* parray = (VoxArray3D*)VOX_MALLOC(sizeof(VoxArray3D)); | ||
| 318 | pvoxarray->sizeX = sx; | ||
| 319 | pvoxarray->sizeY = sy; | ||
| 320 | pvoxarray->sizeZ = sz; | ||
| 321 | |||
| 322 | pvoxarray->chunksSizeX = chx; | ||
| 323 | pvoxarray->chunksSizeY = chy; | ||
| 324 | pvoxarray->chunksSizeZ = chz; | ||
| 325 | |||
| 326 | pvoxarray->ChunkFlattenOffset = (chy * chz); //m_arrayChunks[(x * (sy*sz)) + (z * sy) + y] | ||
| 327 | |||
| 328 | // Alloc chunks array | ||
| 329 | int size = sizeof(CubeChunk3D) * chx * chy * chz; | ||
| 330 | pvoxarray->m_arrayChunks = VOX_MALLOC(size); | ||
| 331 | pvoxarray->arrayChunksSize = size; | ||
| 332 | |||
| 333 | // Init chunks array | ||
| 334 | size = chx * chy * chz; | ||
| 335 | pvoxarray->chunksTotal = size; | ||
| 336 | pvoxarray->chunksAllocated = 0; | ||
| 337 | |||
| 338 | for (int i = 0; i < size; i++) | ||
| 339 | { | ||
| 340 | pvoxarray->m_arrayChunks[i].m_array = 0; | ||
| 341 | pvoxarray->m_arrayChunks[i].arraySize = 0; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | // Set voxel ID from its position into VoxArray3D | ||
| 346 | static void Vox_SetVoxel(VoxArray3D* pvoxarray, int x, int y, int z, unsigned char id) | ||
| 347 | { | ||
| 348 | // Get chunk from array pos | ||
| 349 | int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; | ||
| 350 | int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; | ||
| 351 | int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; | ||
| 352 | int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; | ||
| 353 | |||
| 354 | //if (offset > voxarray->arrayChunksSize) | ||
| 355 | //{ | ||
| 356 | // TraceLog(LOG_ERROR, "Out of array"); | ||
| 357 | //} | ||
| 358 | |||
| 359 | CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; | ||
| 360 | |||
| 361 | // Set Chunk | ||
| 362 | chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); | ||
| 363 | chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE); | ||
| 364 | chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE); | ||
| 365 | |||
| 366 | if (chunk->m_array == 0) | ||
| 367 | { | ||
| 368 | int size = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE; | ||
| 369 | chunk->m_array = VOX_MALLOC(size); | ||
| 370 | chunk->arraySize = size; | ||
| 371 | memset(chunk->m_array, 0, size); | ||
| 372 | |||
| 373 | pvoxarray->chunksAllocated++; | ||
| 374 | } | ||
| 375 | |||
| 376 | offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY; | ||
| 377 | |||
| 378 | //if (offset > chunk->arraySize) | ||
| 379 | //{ | ||
| 380 | // TraceLog(LOG_ERROR, "Out of array"); | ||
| 381 | //} | ||
| 382 | |||
| 383 | chunk->m_array[offset] = id; | ||
| 384 | } | ||
| 385 | |||
| 386 | // Get voxel ID from its position into VoxArray3D | ||
| 387 | static unsigned char Vox_GetVoxel(VoxArray3D* pvoxarray, int x, int y, int z) | ||
| 388 | { | ||
| 389 | if (x < 0 || y < 0 || z < 0) return 0; | ||
| 390 | |||
| 391 | if (x >= pvoxarray->sizeX || y >= pvoxarray->sizeY || z >= pvoxarray->sizeZ) return 0; | ||
| 392 | |||
| 393 | // Get chunk from array pos | ||
| 394 | int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; | ||
| 395 | int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; | ||
| 396 | int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; | ||
| 397 | int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; | ||
| 398 | |||
| 399 | //if (offset > voxarray->arrayChunksSize) | ||
| 400 | //{ | ||
| 401 | // TraceLog(LOG_ERROR, "Out of array"); | ||
| 402 | //} | ||
| 403 | |||
| 404 | CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; | ||
| 405 | |||
| 406 | // Set Chunk | ||
| 407 | chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); | ||
| 408 | chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE); | ||
| 409 | chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE); | ||
| 410 | |||
| 411 | if (chunk->m_array == 0) | ||
| 412 | { | ||
| 413 | return 0; | ||
| 414 | } | ||
| 415 | |||
| 416 | offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY; | ||
| 417 | |||
| 418 | //if (offset > chunk->arraySize) | ||
| 419 | //{ | ||
| 420 | // TraceLog(LOG_ERROR, "Out of array"); | ||
| 421 | //} | ||
| 422 | return chunk->m_array[offset]; | ||
| 423 | |||
| 424 | } | ||
| 425 | |||
| 426 | // Calc visibles faces from a voxel position | ||
| 427 | static unsigned char Vox_CalcFacesVisible(VoxArray3D* pvoxArray, int cx, int cy, int cz) | ||
| 428 | { | ||
| 429 | unsigned char idXm1 = Vox_GetVoxel(pvoxArray, cx - 1, cy, cz); | ||
| 430 | unsigned char idXp1 = Vox_GetVoxel(pvoxArray, cx + 1, cy, cz); | ||
| 431 | |||
| 432 | unsigned char idYm1 = Vox_GetVoxel(pvoxArray, cx, cy - 1, cz); | ||
| 433 | unsigned char idYp1 = Vox_GetVoxel(pvoxArray, cx, cy + 1, cz); | ||
| 434 | |||
| 435 | unsigned char idZm1 = Vox_GetVoxel(pvoxArray, cx, cy, cz - 1); | ||
| 436 | unsigned char idZp1 = Vox_GetVoxel(pvoxArray, cx, cy, cz + 1); | ||
| 437 | |||
| 438 | unsigned char byVFMask = 0; | ||
| 439 | |||
| 440 | //#-x | ||
| 441 | if (idXm1 == 0) byVFMask |= (1 << 0); | ||
| 442 | |||
| 443 | //#+x | ||
| 444 | if (idXp1 == 0) byVFMask |= (1 << 1); | ||
| 445 | |||
| 446 | //#-y | ||
| 447 | if (idYm1 == 0) byVFMask |= (1 << 2); | ||
| 448 | |||
| 449 | //#+y | ||
| 450 | if (idYp1 == 0) byVFMask |= (1 << 3); | ||
| 451 | |||
| 452 | //#-z | ||
| 453 | if (idZm1 == 0) byVFMask |= (1 << 4); | ||
| 454 | |||
| 455 | //#+z | ||
| 456 | if (idZp1 == 0) byVFMask |= (1 << 5); | ||
| 457 | |||
| 458 | return byVFMask; | ||
| 459 | } | ||
| 460 | |||
| 461 | // Get a vertex position from a voxel's corner | ||
| 462 | static VoxVector3 Vox_GetVertexPosition(int _wcx, int _wcy, int _wcz, int _nNumVertex) | ||
| 463 | { | ||
| 464 | float scale = 0.25; | ||
| 465 | |||
| 466 | VoxVector3 vtx = SolidVertex[_nNumVertex]; | ||
| 467 | vtx.x = (vtx.x + _wcx) * scale; | ||
| 468 | vtx.y = (vtx.y + _wcy) * scale; | ||
| 469 | vtx.z = (vtx.z + _wcz) * scale; | ||
| 470 | |||
| 471 | return vtx; | ||
| 472 | } | ||
| 473 | |||
| 474 | // Build a voxel vertices/colors/indices | ||
| 475 | static void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID) | ||
| 476 | { | ||
| 477 | unsigned char byVFMask = Vox_CalcFacesVisible(pvoxArray, x, y, z); | ||
| 478 | |||
| 479 | if (byVFMask == 0) return; | ||
| 480 | |||
| 481 | int i, j; | ||
| 482 | VoxVector3 vertComputed[8]; | ||
| 483 | int bVertexComputed[8]; | ||
| 484 | memset(vertComputed, 0, sizeof(vertComputed)); | ||
| 485 | memset(bVertexComputed, 0, sizeof(bVertexComputed)); | ||
| 486 | |||
| 487 | //For each Cube's faces | ||
| 488 | for (i = 0; i < 6; i++) // 6 faces | ||
| 489 | { | ||
| 490 | if ((byVFMask & (1 << i)) != 0) //If face is visible | ||
| 491 | { | ||
| 492 | for (j = 0; j < 4; j++) // 4 corners | ||
| 493 | { | ||
| 494 | int nNumVertex = fv[i][j]; //Face,Corner | ||
| 495 | if (bVertexComputed[nNumVertex] == 0) //if never calc | ||
| 496 | { | ||
| 497 | bVertexComputed[nNumVertex] = 1; | ||
| 498 | vertComputed[nNumVertex] = Vox_GetVertexPosition(x, y, z, nNumVertex); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | //Add face | ||
| 505 | for (i = 0; i < 6; i++)// 6 faces | ||
| 506 | { | ||
| 507 | if ((byVFMask & (1 << i)) == 0) | ||
| 508 | continue; //Face invisible | ||
| 509 | |||
| 510 | int v0 = fv[i][0]; //Face, Corner | ||
| 511 | int v1 = fv[i][1]; //Face, Corner | ||
| 512 | int v2 = fv[i][2]; //Face, Corner | ||
| 513 | int v3 = fv[i][3]; //Face, Corner | ||
| 514 | |||
| 515 | //Arrays | ||
| 516 | int idx = pvoxArray->vertices.used; | ||
| 517 | insertArrayVector3(&pvoxArray->vertices, vertComputed[v0]); | ||
| 518 | insertArrayVector3(&pvoxArray->vertices, vertComputed[v1]); | ||
| 519 | insertArrayVector3(&pvoxArray->vertices, vertComputed[v2]); | ||
| 520 | insertArrayVector3(&pvoxArray->vertices, vertComputed[v3]); | ||
| 521 | |||
| 522 | insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); | ||
| 523 | insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); | ||
| 524 | insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); | ||
| 525 | insertArrayVector3(&pvoxArray->normals, FacesPerSideNormal[i]); | ||
| 526 | |||
| 527 | VoxColor col = pvoxArray->palette[matID]; | ||
| 528 | |||
| 529 | insertArrayColor(&pvoxArray->colors, col); | ||
| 530 | insertArrayColor(&pvoxArray->colors, col); | ||
| 531 | insertArrayColor(&pvoxArray->colors, col); | ||
| 532 | insertArrayColor(&pvoxArray->colors, col); | ||
| 533 | |||
| 534 | |||
| 535 | //v0 - v1 - v2, v0 - v2 - v3 | ||
| 536 | insertArrayUShort(&pvoxArray->indices, idx + 0); | ||
| 537 | insertArrayUShort(&pvoxArray->indices, idx + 2); | ||
| 538 | insertArrayUShort(&pvoxArray->indices, idx + 1); | ||
| 539 | |||
| 540 | insertArrayUShort(&pvoxArray->indices, idx + 0); | ||
| 541 | insertArrayUShort(&pvoxArray->indices, idx + 3); | ||
| 542 | insertArrayUShort(&pvoxArray->indices, idx + 2); | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | // MagicaVoxel *.vox file format Loader | ||
| 547 | int Vox_LoadFromMemory(unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray) | ||
| 548 | { | ||
| 549 | ////////////////////////////////////////////////// | ||
| 550 | // Read VOX file | ||
| 551 | // 4 bytes: magic number ('V' 'O' 'X' 'space') | ||
| 552 | // 4 bytes: version number (current version is 150) | ||
| 553 | |||
| 554 | // @raysan5: Reviewed (unsigned long) -> (unsigned int), possible issue with Ubuntu 18.04 64bit | ||
| 555 | |||
| 556 | // @raysan5: reviewed signature loading | ||
| 557 | |||
| 558 | unsigned char* fileData = pvoxData; | ||
| 559 | unsigned char* fileDataPtr = fileData; | ||
| 560 | unsigned char* endfileDataPtr = fileData + voxDataSize; | ||
| 561 | |||
| 562 | if (strncmp((char*)fileDataPtr, "VOX ", 4) != 0) | ||
| 563 | { | ||
| 564 | return VOX_ERROR_INVALID_FORMAT; //"Not an MagicaVoxel File format" | ||
| 565 | } | ||
| 566 | |||
| 567 | fileDataPtr += 4; | ||
| 568 | |||
| 569 | // @raysan5: reviewed version loading | ||
| 570 | unsigned int version = 0; | ||
| 571 | version = ((unsigned int*)fileDataPtr)[0]; | ||
| 572 | fileDataPtr += 4; | ||
| 573 | |||
| 574 | if (version != 150 && version != 200) | ||
| 575 | { | ||
| 576 | return VOX_ERROR_FILE_VERSION_NOT_MATCH; //"MagicaVoxel version doesn't match" | ||
| 577 | } | ||
| 578 | |||
| 579 | |||
| 580 | // header | ||
| 581 | //4 bytes: chunk id | ||
| 582 | //4 bytes: size of chunk contents (n) | ||
| 583 | //4 bytes: total size of children chunks(m) | ||
| 584 | |||
| 585 | //// chunk content | ||
| 586 | //n bytes: chunk contents | ||
| 587 | |||
| 588 | //// children chunks : m bytes | ||
| 589 | //{ child chunk 0 } | ||
| 590 | //{ child chunk 1 } | ||
| 591 | unsigned int sizeX, sizeY, sizeZ; | ||
| 592 | sizeX = sizeY = sizeZ = 0; | ||
| 593 | unsigned int numVoxels = 0; | ||
| 594 | |||
| 595 | while (fileDataPtr < endfileDataPtr) | ||
| 596 | { | ||
| 597 | char szChunkName[5]; | ||
| 598 | memcpy(szChunkName, fileDataPtr, 4); | ||
| 599 | szChunkName[4] = 0; | ||
| 600 | fileDataPtr += 4; | ||
| 601 | |||
| 602 | unsigned int chunkSize = *((unsigned int*)fileDataPtr); | ||
| 603 | fileDataPtr += sizeof(unsigned int); | ||
| 604 | |||
| 605 | //unsigned long chunkTotalChildSize = *((unsigned long*)fileDataPtr); | ||
| 606 | fileDataPtr += sizeof(unsigned int); | ||
| 607 | |||
| 608 | if (strcmp(szChunkName, "SIZE") == 0) | ||
| 609 | { | ||
| 610 | //(4 bytes x 3 : x, y, z ) | ||
| 611 | sizeX = *((unsigned int*)fileDataPtr); | ||
| 612 | fileDataPtr += sizeof(unsigned int); | ||
| 613 | |||
| 614 | sizeY = *((unsigned int*)fileDataPtr); | ||
| 615 | fileDataPtr += sizeof(unsigned int); | ||
| 616 | |||
| 617 | sizeZ = *((unsigned int*)fileDataPtr); | ||
| 618 | fileDataPtr += sizeof(unsigned int); | ||
| 619 | |||
| 620 | //Alloc vox array | ||
| 621 | Vox_AllocArray(pvoxarray, sizeX, sizeZ, sizeY); //Reverse Y<>Z for left to right handed system | ||
| 622 | } | ||
| 623 | else if (strcmp(szChunkName, "XYZI") == 0) | ||
| 624 | { | ||
| 625 | unsigned char vx, vy, vz, vi; | ||
| 626 | |||
| 627 | //(numVoxels : 4 bytes ) | ||
| 628 | //(each voxel: 1 byte x 4 : x, y, z, colorIndex ) x numVoxels | ||
| 629 | numVoxels = *((unsigned int*)fileDataPtr); | ||
| 630 | fileDataPtr += sizeof(unsigned int); | ||
| 631 | |||
| 632 | while (numVoxels > 0) | ||
| 633 | { | ||
| 634 | vx = *((unsigned char*)fileDataPtr++); | ||
| 635 | vy = *((unsigned char*)fileDataPtr++); | ||
| 636 | vz = *((unsigned char*)fileDataPtr++); | ||
| 637 | vi = *((unsigned char*)fileDataPtr++); | ||
| 638 | |||
| 639 | Vox_SetVoxel(pvoxarray, vx, vz, pvoxarray->sizeZ-vy-1, vi); //Reverse Y<>Z for left to right handed system | ||
| 640 | |||
| 641 | numVoxels--; | ||
| 642 | } | ||
| 643 | } | ||
| 644 | else if (strcmp(szChunkName, "RGBA") == 0) | ||
| 645 | { | ||
| 646 | VoxColor col; | ||
| 647 | |||
| 648 | //(each pixel: 1 byte x 4 : r, g, b, a ) x 256 | ||
| 649 | for (int i = 0; i < 256 - 1; i++) | ||
| 650 | { | ||
| 651 | col.r = *((unsigned char*)fileDataPtr++); | ||
| 652 | col.g = *((unsigned char*)fileDataPtr++); | ||
| 653 | col.b = *((unsigned char*)fileDataPtr++); | ||
| 654 | col.a = *((unsigned char*)fileDataPtr++); | ||
| 655 | |||
| 656 | pvoxarray->palette[i + 1] = col; | ||
| 657 | } | ||
| 658 | |||
| 659 | } | ||
| 660 | else | ||
| 661 | { | ||
| 662 | fileDataPtr += chunkSize; | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | ////////////////////////////////////////////////////////// | ||
| 667 | // Building Mesh | ||
| 668 | // TODO compute globals indices array | ||
| 669 | |||
| 670 | // Init Arrays | ||
| 671 | initArrayVector3(&pvoxarray->vertices, 3 * 1024); | ||
| 672 | initArrayVector3(&pvoxarray->normals, 3 * 1024); | ||
| 673 | initArrayUShort(&pvoxarray->indices, 3 * 1024); | ||
| 674 | initArrayColor(&pvoxarray->colors, 3 * 1024); | ||
| 675 | |||
| 676 | // Create vertices and indices buffers | ||
| 677 | int x, y, z; | ||
| 678 | |||
| 679 | for (x = 0; x <= pvoxarray->sizeX; x++) | ||
| 680 | { | ||
| 681 | for (z = 0; z <= pvoxarray->sizeZ; z++) | ||
| 682 | { | ||
| 683 | for (y = 0; y <= pvoxarray->sizeY; y++) | ||
| 684 | { | ||
| 685 | unsigned char matID = Vox_GetVoxel(pvoxarray, x, y, z); | ||
| 686 | if (matID != 0) | ||
| 687 | Vox_Build_Voxel(pvoxarray, x, y, z, matID); | ||
| 688 | } | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | return VOX_SUCCESS; | ||
| 693 | } | ||
| 694 | |||
| 695 | void Vox_FreeArrays(VoxArray3D* voxarray) | ||
| 696 | { | ||
| 697 | // Free chunks | ||
| 698 | if (voxarray->m_arrayChunks != 0) | ||
| 699 | { | ||
| 700 | for (int i = 0; i < voxarray->chunksTotal; i++) | ||
| 701 | { | ||
| 702 | CubeChunk3D* chunk = &voxarray->m_arrayChunks[i]; | ||
| 703 | if (chunk->m_array != 0) | ||
| 704 | { | ||
| 705 | chunk->arraySize = 0; | ||
| 706 | VOX_FREE(chunk->m_array); | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | VOX_FREE(voxarray->m_arrayChunks); | ||
| 711 | voxarray->m_arrayChunks = 0; | ||
| 712 | voxarray->arrayChunksSize = 0; | ||
| 713 | |||
| 714 | voxarray->chunksSizeX = voxarray->chunksSizeY = voxarray->chunksSizeZ = 0; | ||
| 715 | voxarray->chunksTotal = 0; | ||
| 716 | voxarray->chunksAllocated = 0; | ||
| 717 | voxarray->ChunkFlattenOffset = 0; | ||
| 718 | voxarray->sizeX = voxarray->sizeY = voxarray->sizeZ = 0; | ||
| 719 | } | ||
| 720 | |||
| 721 | // Free arrays | ||
| 722 | freeArrayVector3(&voxarray->vertices); | ||
| 723 | freeArrayUShort(&voxarray->indices); | ||
| 724 | freeArrayColor(&voxarray->colors); | ||
| 725 | } | ||
| 726 | |||
| 727 | #endif //VOX_LOADER_IMPLEMENTATION | ||
