From a422d2fc8b633ba14bba922f9a74c1be6a72ce39 Mon Sep 17 00:00:00 2001 From: procfxgen Date: Fri, 10 Sep 2021 15:24:01 +0200 Subject: [PATCH] Vox loaded (#1981) * new models_magicavoxel_loading example * Portable header-only file "magicavoxel_loader.h" for MagicaVoxel loader example. * models_magicavoxel_loading example added to CMakeLists.txt and Makefile * fix models_magicavoxel_loading example for linux. * * vox_loader into "src/external/vox_loader.h" * vox file support for "models.c" * updated example "models/models_magicavoxel_loading.c" * * Fix Vox_FreeArrays (removed memory leak) * * removed magicavoxel_loader.h * * Revert vs2019 solution * * vox_loader.h -> Support custom memory allocators * vox_loader.h -> Reverse Y<>Z for left to right handed system * models/models_magicavoxel_loading.c -> fix model center * * vox_loader.h -> Removed Raylib dependencies * * Changed Vox_LoadFileName to Vox_LoadFromMemory --- examples/models/models_magicavoxel_loading.c | 12 +- src/external/vox_loader.h | 169 ++++++++++--------- src/models.c | 36 +++- 3 files changed, 125 insertions(+), 92 deletions(-) diff --git a/examples/models/models_magicavoxel_loading.c b/examples/models/models_magicavoxel_loading.c index bb1389d6c..fd268f079 100644 --- a/examples/models/models_magicavoxel_loading.c +++ b/examples/models/models_magicavoxel_loading.c @@ -51,16 +51,14 @@ int main(void) t1 = GetTime() * 1000.0; TraceLog(LOG_INFO, TextFormat("Vox <%s> loaded in %f ms", GetFileName(szVoxFiles[i]), t1 - t0)); - //Compute model matrix + //Compute model's center matrix BoundingBox bb = GetModelBoundingBox(models[i]); Vector3 center; - center.x = -(((bb.max.x - bb.min.x) / 2)); - center.y = -(((bb.max.y - bb.min.y) / 2)); - center.z = -(((bb.max.z - bb.min.z) / 2)); + center.x = bb.min.x + (((bb.max.x - bb.min.x) / 2)); + center.z = bb.min.z + (((bb.max.z - bb.min.z) / 2)); - Matrix matP = MatrixTranslate(center.x, center.z, 0); - Matrix matR = MatrixRotateX(90 * DEG2RAD); - models[i].transform = MatrixMultiply(matP, matR); + Matrix matP = MatrixTranslate(-center.x, 0, -center.z); + models[i].transform = matP; } diff --git a/src/external/vox_loader.h b/src/external/vox_loader.h index 2650b7129..6bbf6799b 100644 --- a/src/external/vox_loader.h +++ b/src/external/vox_loader.h @@ -22,7 +22,7 @@ THE SOFTWARE. - vox_loader - v1.00 + vox_loader - v1.01 no warranty implied; use at your own risk Do this: @@ -34,10 +34,13 @@ #include ... #include ... #define VOX_LOADER_INCLUDE__H - #include "magicavoxel_loader.h" + #include "vox_loader.h" revision history: 1.00 (2021-09-03) first released version + 1.01 (2021-09-07) Support custom memory allocators + Removed Raylib dependencies + Changed Vox_LoadFileName to Vox_LoadFromMemory */ @@ -53,10 +56,21 @@ revision history: extern "C" { #endif -#define VOX_SUCCESS (0) -#define VOX_ERROR_FILE_NOT_FOUND (-1) -#define VOX_ERROR_INVALID_FORMAT (-2) -#define VOX_ERROR_FILE_VERSION_TOO_OLD (-3) + #define VOX_SUCCESS (0) + #define VOX_ERROR_FILE_NOT_FOUND (-1) + #define VOX_ERROR_INVALID_FORMAT (-2) + #define VOX_ERROR_FILE_VERSION_TOO_OLD (-3) + + // VoxColor, 4 components, R8G8B8A8 (32bit) + typedef struct { + unsigned char r, g, b, a; + } VoxColor; + + // VoxVector3, 3 components + typedef struct { + float x, y, z; + } VoxVector3; + typedef struct { @@ -66,13 +80,13 @@ extern "C" { typedef struct { - Vector3* array; + VoxVector3* array; int used, size; } ArrayVector3; typedef struct { - Color* array; + VoxColor* array; int used, size; } ArrayColor; @@ -118,13 +132,13 @@ extern "C" { ArrayColor colors; //Palette for voxels - Color palette[256]; + VoxColor palette[256]; } VoxArray3D; // Functions - extern int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray); + extern int Vox_LoadFromMemory(const unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray); extern void Vox_FreeArrays(VoxArray3D* voxarray); @@ -155,7 +169,7 @@ extern "C" { void initArrayInt(ArrayInt* a, int initialSize) { - a->array = MemAlloc(initialSize * sizeof(int)); + a->array = VOX_MALLOC(initialSize * sizeof(int)); a->used = 0; a->size = initialSize; } @@ -165,14 +179,14 @@ void insertArrayInt(ArrayInt* a, int element) if (a->used == a->size) { a->size *= 2; - a->array = MemRealloc(a->array, a->size * sizeof(int)); + a->array = VOX_REALLOC(a->array, a->size * sizeof(int)); } a->array[a->used++] = element; } void freeArrayInt(ArrayInt* a) { - MemFree(a->array); + VOX_FREE(a->array); a->array = NULL; a->used = a->size = 0; } @@ -183,7 +197,7 @@ void freeArrayInt(ArrayInt* a) void initArrayUShort(ArrayUShort* a, int initialSize) { - a->array = MemAlloc(initialSize * sizeof(unsigned short)); + a->array = VOX_MALLOC(initialSize * sizeof(unsigned short)); a->used = 0; a->size = initialSize; } @@ -193,14 +207,14 @@ void insertArrayUShort(ArrayUShort* a, unsigned short element) if (a->used == a->size) { a->size *= 2; - a->array = MemRealloc(a->array, a->size * sizeof(unsigned short)); + a->array = VOX_REALLOC(a->array, a->size * sizeof(unsigned short)); } a->array[a->used++] = element; } void freeArrayUShort(ArrayUShort* a) { - MemFree(a->array); + VOX_FREE(a->array); a->array = NULL; a->used = a->size = 0; } @@ -212,24 +226,24 @@ void freeArrayUShort(ArrayUShort* a) void initArrayVector3(ArrayVector3* a, int initialSize) { - a->array = MemAlloc(initialSize * sizeof(Vector3)); + a->array = VOX_MALLOC(initialSize * sizeof(VoxVector3)); a->used = 0; a->size = initialSize; } -void insertArrayVector3(ArrayVector3* a, Vector3 element) +void insertArrayVector3(ArrayVector3* a, VoxVector3 element) { if (a->used == a->size) { a->size *= 2; - a->array = MemRealloc(a->array, a->size * sizeof(Vector3)); + a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxVector3)); } a->array[a->used++] = element; } void freeArrayVector3(ArrayVector3* a) { - MemFree(a->array); + VOX_FREE(a->array); a->array = NULL; a->used = a->size = 0; } @@ -240,24 +254,24 @@ void freeArrayVector3(ArrayVector3* a) void initArrayColor(ArrayColor* a, int initialSize) { - a->array = MemAlloc(initialSize * sizeof(Color)); + a->array = VOX_MALLOC(initialSize * sizeof(VoxColor)); a->used = 0; a->size = initialSize; } -void insertArrayColor(ArrayColor* a, Color element) +void insertArrayColor(ArrayColor* a, VoxColor element) { if (a->used == a->size) { a->size *= 2; - a->array = MemRealloc(a->array, a->size * sizeof(Color)); + a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxColor)); } a->array[a->used++] = element; } void freeArrayColor(ArrayColor* a) { - MemFree(a->array); + VOX_FREE(a->array); a->array = NULL; a->used = a->size = 0; } @@ -300,7 +314,7 @@ const int fv[6][4] = { {4, 6, 7, 5 } };//+Z -const Vector3 SolidVertex[] = { +const VoxVector3 SolidVertex[] = { {0, 0, 0}, //0 {1, 0, 0}, //1 {0, 1, 0}, //2 @@ -315,7 +329,7 @@ const Vector3 SolidVertex[] = { // Allocated VoxArray3D size -void Vox_AllocArray(VoxArray3D* voxarray, int _sx, int _sy, int _sz) +void Vox_AllocArray(VoxArray3D* pvoxarray, int _sx, int _sy, int _sz) { int sx = _sx + ((CHUNKSIZE - (_sx % CHUNKSIZE)) % CHUNKSIZE); int sy = _sy + ((CHUNKSIZE - (_sy % CHUNKSIZE)) % CHUNKSIZE); @@ -325,50 +339,50 @@ void Vox_AllocArray(VoxArray3D* voxarray, int _sx, int _sy, int _sz) int chy = sy >> CHUNKSIZE_OPSHIFT; //Chunks Count in Y int chz = sz >> CHUNKSIZE_OPSHIFT; //Chunks Count in Z - //VoxArray3D* parray = (VoxArray3D*)MemAlloc(sizeof(VoxArray3D)); - voxarray->sizeX = sx; - voxarray->sizeY = sy; - voxarray->sizeZ = sz; + //VoxArray3D* parray = (VoxArray3D*)VOX_MALLOC(sizeof(VoxArray3D)); + pvoxarray->sizeX = sx; + pvoxarray->sizeY = sy; + pvoxarray->sizeZ = sz; - voxarray->chunksSizeX = chx; - voxarray->chunksSizeY = chy; - voxarray->chunksSizeZ = chz; + pvoxarray->chunksSizeX = chx; + pvoxarray->chunksSizeY = chy; + pvoxarray->chunksSizeZ = chz; - voxarray->ChunkFlattenOffset = (chy * chz); //m_arrayChunks[(x * (sy*sz)) + (z * sy) + y] + pvoxarray->ChunkFlattenOffset = (chy * chz); //m_arrayChunks[(x * (sy*sz)) + (z * sy) + y] //Alloc chunks array int size = sizeof(CubeChunk3D) * chx * chy * chz; - voxarray->m_arrayChunks = MemAlloc(size); - voxarray->arrayChunksSize = size; + pvoxarray->m_arrayChunks = VOX_MALLOC(size); + pvoxarray->arrayChunksSize = size; //Init chunks array size = chx * chy * chz; - voxarray->chunksTotal = size; - voxarray->chunksAllocated = 0; + pvoxarray->chunksTotal = size; + pvoxarray->chunksAllocated = 0; for (int i = 0; i < size; i++) { - voxarray->m_arrayChunks[i].m_array = 0; - voxarray->m_arrayChunks[i].arraySize = 0; + pvoxarray->m_arrayChunks[i].m_array = 0; + pvoxarray->m_arrayChunks[i].arraySize = 0; } } // Set voxel ID from its position into VoxArray3D -void Vox_SetVoxel(VoxArray3D* voxarray, int x, int y, int z, unsigned char id) +void Vox_SetVoxel(VoxArray3D* pvoxarray, int x, int y, int z, unsigned char id) { //Get chunk from array pos int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; - int offset = (chX * voxarray->ChunkFlattenOffset) + (chZ * voxarray->chunksSizeY) + chY; + int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; //if (offset > voxarray->arrayChunksSize) //{ // TraceLog(LOG_ERROR, "Out of array"); //} - CubeChunk3D* chunk = &voxarray->m_arrayChunks[offset]; + CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; //Set Chunk chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); @@ -378,11 +392,11 @@ void Vox_SetVoxel(VoxArray3D* voxarray, int x, int y, int z, unsigned char id) if (chunk->m_array == 0) { int size = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE; - chunk->m_array = MemAlloc(size); + chunk->m_array = VOX_MALLOC(size); chunk->arraySize = size; - //memset(chunk->m_array, 0, size); + memset(chunk->m_array, 0, size); - voxarray->chunksAllocated++; + pvoxarray->chunksAllocated++; } offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY; @@ -397,12 +411,12 @@ void Vox_SetVoxel(VoxArray3D* voxarray, int x, int y, int z, unsigned char id) } // Get voxel ID from its position into VoxArray3D -unsigned char Vox_GetVoxel(VoxArray3D* voxarray, int x, int y, int z) +unsigned char Vox_GetVoxel(VoxArray3D* pvoxarray, int x, int y, int z) { if (x < 0 || y < 0 || z < 0) return 0; - if (x >= voxarray->sizeX || y >= voxarray->sizeY || z >= voxarray->sizeZ) + if (x >= pvoxarray->sizeX || y >= pvoxarray->sizeY || z >= pvoxarray->sizeZ) return 0; @@ -410,14 +424,14 @@ unsigned char Vox_GetVoxel(VoxArray3D* voxarray, int x, int y, int z) int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE; int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE; int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE; - int offset = (chX * voxarray->ChunkFlattenOffset) + (chZ * voxarray->chunksSizeY) + chY; + int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY; //if (offset > voxarray->arrayChunksSize) //{ // TraceLog(LOG_ERROR, "Out of array"); //} - CubeChunk3D* chunk = &voxarray->m_arrayChunks[offset]; + CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset]; //Set Chunk chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE); @@ -481,10 +495,10 @@ unsigned char Vox_CalcFacesVisible(VoxArray3D* pvoxArray, int cx, int cy, int cz } // Get a vertex position from a voxel's corner -Vector3 Vox_GetVertexPosition(int _wcx, int _wcy, int _wcz, int _nNumVertex) +VoxVector3 Vox_GetVertexPosition(int _wcx, int _wcy, int _wcz, int _nNumVertex) { float scale = 0.25; - Vector3 vtx = SolidVertex[_nNumVertex]; + VoxVector3 vtx = SolidVertex[_nNumVertex]; vtx.x = (vtx.x + _wcx) * scale; vtx.y = (vtx.y + _wcy) * scale; vtx.z = (vtx.z + _wcz) * scale; @@ -501,7 +515,7 @@ void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID) return; int i, j; - Vector3 vertComputed[8]; + VoxVector3 vertComputed[8]; int bVertexComputed[8]; memset(vertComputed, 0, sizeof(vertComputed)); memset(bVertexComputed, 0, sizeof(bVertexComputed)); @@ -542,7 +556,7 @@ void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID) insertArrayVector3(&pvoxArray->vertices, vertComputed[v2]); insertArrayVector3(&pvoxArray->vertices, vertComputed[v3]); - Color col = pvoxArray->palette[matID]; + VoxColor col = pvoxArray->palette[matID]; insertArrayColor(&pvoxArray->colors, col); insertArrayColor(&pvoxArray->colors, col); @@ -566,7 +580,7 @@ void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID) } // MagicaVoxel *.vox file format Loader -int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) +int Vox_LoadFromMemory(const unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray) { ////////////////////////////////////////////////// @@ -576,24 +590,17 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) unsigned long signature; - unsigned int readed = 0; - unsigned char* fileData; - fileData = LoadFileData(pszfileName, &readed); - if (fileData == 0) - { - return VOX_ERROR_FILE_NOT_FOUND; - } + unsigned char* fileData = pvoxData; unsigned char* fileDataPtr = fileData; - unsigned char* endfileDataPtr = fileData + readed; + unsigned char* endfileDataPtr = fileData + voxDataSize; signature = *((unsigned long *)fileDataPtr); fileDataPtr += sizeof(unsigned long); if (signature != 0x20584F56) //56 4F 58 20 { - //TraceLog(LOG_ERROR, "Not an MagicaVoxel File format"); - return VOX_ERROR_INVALID_FORMAT; + return VOX_ERROR_INVALID_FORMAT; //"Not an MagicaVoxel File format" } unsigned long version; @@ -603,8 +610,7 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) if (version < 150) { - //TraceLog(LOG_ERROR, "MagicaVoxel version too old"); - return VOX_ERROR_FILE_VERSION_TOO_OLD; + return VOX_ERROR_FILE_VERSION_TOO_OLD; //"MagicaVoxel version too old" } @@ -651,7 +657,7 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) fileDataPtr += sizeof(unsigned long); //Alloc vox array - Vox_AllocArray(voxarray, sizeX, sizeY, sizeZ); + Vox_AllocArray(pvoxarray, sizeX, sizeZ, sizeY); //Reverse Y<>Z for left to right handed system } else if (strcmp(szChunkName, "XYZI") == 0) { @@ -669,14 +675,14 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) vz = *((unsigned char*)fileDataPtr++); vi = *((unsigned char*)fileDataPtr++); - Vox_SetVoxel(voxarray, vx, vy, vz, vi); + Vox_SetVoxel(pvoxarray, vx, vz, pvoxarray->sizeZ-vy-1, vi); //Reverse Y<>Z for left to right handed system numVoxels--; } } else if (strcmp(szChunkName, "RGBA") == 0) { - Color col; + VoxColor col; //(each pixel: 1 byte x 4 : r, g, b, a ) x 256 for (int i = 0; i < 256 - 1; i++) @@ -686,7 +692,7 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) col.b = *((unsigned char*)fileDataPtr++); col.a = *((unsigned char*)fileDataPtr++); - voxarray->palette[i + 1] = col; + pvoxarray->palette[i + 1] = col; } } @@ -696,6 +702,7 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) } } + //TraceLog(LOG_INFO, TextFormat("Vox Size : %dx%dx%d", sizeX, sizeY, sizeZ)); //TraceLog(LOG_INFO, TextFormat("Vox Chunks Count : %d/%d", pvoxArray->chunksAllocated, pvoxArray->chunksTotal)); @@ -708,22 +715,22 @@ int Vox_LoadFileName(const char* pszfileName, VoxArray3D* voxarray) //TraceLog(LOG_INFO, TextFormat("Building VOX Mesh : %s", pszfileName)); // Init Arrays - initArrayVector3(&voxarray->vertices, 3 * 1024); - initArrayUShort(&voxarray->indices, 3 * 1024); - initArrayColor(&voxarray->colors, 3 * 1024); + initArrayVector3(&pvoxarray->vertices, 3 * 1024); + initArrayUShort(&pvoxarray->indices, 3 * 1024); + initArrayColor(&pvoxarray->colors, 3 * 1024); // Create vertices and indices buffers int x, y, z; - for (x = 0; x <= voxarray->sizeX; x++) + for (x = 0; x <= pvoxarray->sizeX; x++) { - for (z = 0; z <= voxarray->sizeZ; z++) + for (z = 0; z <= pvoxarray->sizeZ; z++) { - for (y = 0; y <= voxarray->sizeY; y++) + for (y = 0; y <= pvoxarray->sizeY; y++) { - unsigned char matID = Vox_GetVoxel(voxarray, x, y, z); + unsigned char matID = Vox_GetVoxel(pvoxarray, x, y, z); if (matID != 0) - Vox_Build_Voxel(voxarray, x, y, z, matID); + Vox_Build_Voxel(pvoxarray, x, y, z, matID); } } } @@ -744,11 +751,11 @@ void Vox_FreeArrays(VoxArray3D* voxarray) if (chunk->m_array != 0) { chunk->arraySize = 0; - MemFree(chunk->m_array); + VOX_FREE(chunk->m_array); } } - MemFree(voxarray->m_arrayChunks); + VOX_FREE(voxarray->m_arrayChunks); voxarray->m_arrayChunks = 0; voxarray->arrayChunksSize = 0; diff --git a/src/models.c b/src/models.c index ab3d0dd0b..d645a4f68 100644 --- a/src/models.c +++ b/src/models.c @@ -74,7 +74,19 @@ #endif #if defined(SUPPORT_FILEFORMAT_VOX) - // TODO: Support custom memory allocators + // Allow custom memory allocators + #ifndef VOX_MALLOC + #define VOX_MALLOC RL_MALLOC + #endif + #ifndef VOX_CALLOC + #define VOX_CALLOC RL_CALLOC + #endif + #ifndef VOX_REALLOC + #define VOX_REALLOC RL_REALLOC + #endif + #ifndef VOX_FREE + #define VOX_FREE RL_FREE + #endif #define VOX_LOADER_IMPLEMENTATION #include "external/vox_loader.h" // vox file format loading (MagikaVoxel) @@ -5529,24 +5541,38 @@ static void GetGLTFPrimitiveCount(cgltf_node *node, int *outCount) #endif #if defined(SUPPORT_FILEFORMAT_VOX) -// Load VOX (MagikaVoxel) mesh data +// Load VOX (MagicaVoxel) mesh data static Model LoadVOX(const char *fileName) { Model model = { 0 }; int nbvertices = 0; int meshescount = 0; + unsigned int readed = 0; + unsigned char* fileData; + //Read vox file into buffer + fileData = LoadFileData(fileName, &readed); + if (fileData == 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName); + return model; + } + + //Read and build voxarray description VoxArray3D voxarray = { 0 }; - int ret = Vox_LoadFileName(fileName, &voxarray); + int ret = Vox_LoadFromMemory(fileData, readed, &voxarray); if (ret != VOX_SUCCESS) { + // Error + UnloadFileData(fileData); + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName); return model; } else { - // Compute meshes count + // Success: Compute meshes count nbvertices = voxarray.vertices.used; meshescount = 1 + (nbvertices/65536); @@ -5611,7 +5637,9 @@ static Model LoadVOX(const char *fileName) pcolors += verticesMax; } + //Free buffers Vox_FreeArrays(&voxarray); + UnloadFileData(fileData); return model; }