diff options
| author | Ray <[email protected]> | 2022-08-20 14:01:54 +0200 |
|---|---|---|
| committer | Ray <[email protected]> | 2022-08-20 14:01:54 +0200 |
| commit | 4ee5fdf6192166ecb3fc5f020fac9077c05add29 (patch) | |
| tree | 682ad9189d7581b1a018a75199553b457a1c583a /src/rmodels.c | |
| parent | 35c777ef2ccdad0b3a94b508ec13df5f6cd9ea49 (diff) | |
| download | raylib-4ee5fdf6192166ecb3fc5f020fac9077c05add29.tar.gz raylib-4ee5fdf6192166ecb3fc5f020fac9077c05add29.zip | |
ADDED: Support M3D model file format (meshes and materials) #2648
Diffstat (limited to 'src/rmodels.c')
| -rw-r--r-- | src/rmodels.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/rmodels.c b/src/rmodels.c index ee8b2117..7b2b19a2 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -12,6 +12,7 @@ * #define SUPPORT_FILEFORMAT_IQM * #define SUPPORT_FILEFORMAT_GLTF * #define SUPPORT_FILEFORMAT_VOX +* #define SUPPORT_FILEFORMAT_M3D * Selected desired fileformats to be supported for model data loading. * * #define SUPPORT_MESH_GENERATION @@ -86,6 +87,19 @@ #include "external/vox_loader.h" // VOX file format loading (MagikaVoxel) #endif +#if defined(SUPPORT_FILEFORMAT_M3D) + #define M3D_MALLOC RL_MALLOC + #define M3D_REALLOC RL_REALLOC + #define M3D_FREE RL_FREE + + // Let the M3D loader know about stb_image is used in this project, + // to allow it to use on textures loading + #include "external/stb_image.h" + + #define M3D_IMPLEMENTATION + #include "external/m3d.h" // Model3D file format loading +#endif + #if defined(SUPPORT_MESH_GENERATION) #define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T))) #define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1)) @@ -141,6 +155,9 @@ static Model LoadGLTF(const char *fileName); // Load GLTF mesh data #if defined(SUPPORT_FILEFORMAT_VOX) static Model LoadVOX(const char *filename); // Load VOX mesh data #endif +#if defined(SUPPORT_FILEFORMAT_M3D) +static Model LoadM3D(const char *filename); // Load M3D mesh data +#endif //---------------------------------------------------------------------------------- // Module Functions Definition @@ -5101,4 +5118,156 @@ static Model LoadVOX(const char *fileName) } #endif +#if defined(SUPPORT_FILEFORMAT_M3D) +// Hook LoadFileData()/UnloadFileData() calls to M3D loaders +unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, len); } +void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); } + +// Load M3D mesh data +static Model LoadM3D(const char *fileName) +{ + Model model = { 0 }; + + m3d_t *m3d = NULL; + m3dp_t *prop = NULL; + unsigned int bytesRead = 0; + unsigned char *fileData = LoadFileData(fileName, &bytesRead); + int i, j, k, l, mi = -2; + + if (fileData != NULL) + { + m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL); + + if (!m3d || (m3d->errcode != M3D_SUCCESS)) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data", fileName); + return model; + } + else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial); + + if (m3d->nummaterial > 0) + { + model.meshCount = model.materialCount = m3d->nummaterial; + TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount); + } + else + { + model.meshCount = model.materialCount = 1; + TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material"); + } + + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); + model.materials = (Material *)RL_CALLOC(model.meshCount + 1, sizeof(Material)); + + // Map no material to index 0 with default shader, everything else materialid + 1 + model.materials[0] = LoadMaterialDefault(); + model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; + + for (i = l = 0, k = -1; i < m3d->numface; i++, l++) + { + // Materials are grouped together + if (mi != m3d->face[i].materialid) + { + k++; + mi = m3d->face[i].materialid; + + for (j = i, l = 0; (j < m3d->numface) && (mi == m3d->face[j].materialid); j++, l++); + + model.meshes[k].vertexCount = l*3; + model.meshes[k].triangleCount = l; + model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); + model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float)); + model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float)); + model.meshMaterial[k] = mi + 1; + l = 0; + } + + // Process meshes per material, add triangles + model.meshes[k].vertices[l * 9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x; + model.meshes[k].vertices[l * 9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y; + model.meshes[k].vertices[l * 9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z; + model.meshes[k].vertices[l * 9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x; + model.meshes[k].vertices[l * 9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y; + model.meshes[k].vertices[l * 9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z; + model.meshes[k].vertices[l * 9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x; + model.meshes[k].vertices[l * 9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y; + model.meshes[k].vertices[l * 9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z; + + if (m3d->face[i].texcoord[0] != M3D_UNDEF) + { + model.meshes[k].texcoords[l * 6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u; + model.meshes[k].texcoords[l * 6 + 1] = m3d->tmap[m3d->face[i].texcoord[0]].v; + model.meshes[k].texcoords[l * 6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u; + model.meshes[k].texcoords[l * 6 + 3] = m3d->tmap[m3d->face[i].texcoord[1]].v; + model.meshes[k].texcoords[l * 6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u; + model.meshes[k].texcoords[l * 6 + 5] = m3d->tmap[m3d->face[i].texcoord[2]].v; + } + + if (m3d->face[i].normal[0] != M3D_UNDEF) + { + model.meshes[k].normals[l * 9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x; + model.meshes[k].normals[l * 9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y; + model.meshes[k].normals[l * 9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z; + model.meshes[k].normals[l * 9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x; + model.meshes[k].normals[l * 9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y; + model.meshes[k].normals[l * 9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z; + model.meshes[k].normals[l * 9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x; + model.meshes[k].normals[l * 9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y; + model.meshes[k].normals[l * 9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z; + } + } + + for (i = 0; i < m3d->nummaterial; i++) + { + model.materials[i + 1] = LoadMaterialDefault(); + model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; + + for (j = 0; j < m3d->material[i].numprop; j++) + { + prop = &m3d->material[i].prop[j]; + + switch (prop->type) + { + case m3dp_Kd: + { + memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4); + model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f; + } break; + case m3dp_Ks: + { + memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4); + model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = 0.0f; + } break; + case m3dp_Ke: + { + memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4); + model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f; + } break; + case m3dp_Pm: + { + model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum; + } break; + case m3dp_Pr: + { + model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum; + } break; + case m3dp_Ps: + { + model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE; + model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum; + } break; + default: break; + } + } + } + + m3d_free(m3d); + UnloadFileData(fileData); + } + + return model; +} +#endif + #endif // SUPPORT_MODULE_RMODELS |
