diff --git a/src/models.c b/src/models.c index 0cce4f2c3..8f76e4bb7 100644 --- a/src/models.c +++ b/src/models.c @@ -959,10 +959,14 @@ void SetModelMeshMaterial(Model *model, int meshId, int materialId) } // Load model animations from file -ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) +ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount) { #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number #define IQM_VERSION 2 // only IQM version 2 supported + + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); + unsigned char *fileDataPtr = fileData; typedef struct IQMHeader { char magic[16]; @@ -995,72 +999,66 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) unsigned int flags; } IQMAnim; - FILE *iqmFile = NULL; - IQMHeader iqm; - - iqmFile = fopen(filename,"rb"); - - if (!iqmFile) - { - TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", filename); - return NULL; - } + // In case file can not be read, return an empty model + if (fileDataPtr == NULL) return NULL; // Read IQM header - fread(&iqm, sizeof(IQMHeader), 1, iqmFile); + IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; - if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) + if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", filename); - fclose(iqmFile); + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); return NULL; } - if (iqm.version != IQM_VERSION) + if (iqmHeader->version != IQM_VERSION) { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version incorrect", filename); - fclose(iqmFile); + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); return NULL; } // Get bones data - IQMPose *poses = RL_MALLOC(iqm.num_poses*sizeof(IQMPose)); - fseek(iqmFile, iqm.ofs_poses, SEEK_SET); - fread(poses, iqm.num_poses*sizeof(IQMPose), 1, iqmFile); + IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose)); + //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET); + //fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile); + memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose)); // Get animations data - *animCount = iqm.num_anims; - IQMAnim *anim = RL_MALLOC(iqm.num_anims*sizeof(IQMAnim)); - fseek(iqmFile, iqm.ofs_anims, SEEK_SET); - fread(anim, iqm.num_anims*sizeof(IQMAnim), 1, iqmFile); - ModelAnimation *animations = RL_MALLOC(iqm.num_anims*sizeof(ModelAnimation)); + *animCount = iqmHeader->num_anims; + IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim)); + //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET); + //fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile); + memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim)); + + ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation)); // frameposes - unsigned short *framedata = RL_MALLOC(iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short)); - fseek(iqmFile, iqm.ofs_frames, SEEK_SET); - fread(framedata, iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short), 1, iqmFile); + unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); + //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET); + //fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile); + memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short)); - for (unsigned int a = 0; a < iqm.num_anims; a++) + for (unsigned int a = 0; a < iqmHeader->num_anims; a++) { animations[a].frameCount = anim[a].num_frames; - animations[a].boneCount = iqm.num_poses; - animations[a].bones = RL_MALLOC(iqm.num_poses*sizeof(BoneInfo)); + animations[a].boneCount = iqmHeader->num_poses; + animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo)); animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *)); //animations[a].framerate = anim.framerate; // TODO: Use framerate? - for (unsigned int j = 0; j < iqm.num_poses; j++) + for (unsigned int j = 0; j < iqmHeader->num_poses; j++) { strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); animations[a].bones[j].parent = poses[j].parent; } - for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqm.num_poses*sizeof(Transform)); + for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform)); - int dcounter = anim[a].first_frame*iqm.num_framechannels; + int dcounter = anim[a].first_frame*iqmHeader->num_framechannels; for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) { - for (unsigned int i = 0; i < iqm.num_poses; i++) + for (unsigned int i = 0; i < iqmHeader->num_poses; i++) { animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0]; @@ -1161,13 +1159,13 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) } } } + + RL_FREE(fileData); RL_FREE(framedata); RL_FREE(poses); RL_FREE(anim); - fclose(iqmFile); - return animations; } @@ -3042,12 +3040,16 @@ static Model LoadOBJ(const char *fileName) // Load IQM mesh data static Model LoadIQM(const char *fileName) { - #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number - #define IQM_VERSION 2 // only IQM version 2 supported + #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number + #define IQM_VERSION 2 // only IQM version 2 supported #define BONE_NAME_LENGTH 32 // BoneInfo name string length #define MESH_NAME_LENGTH 32 // Mesh name string length #define MATERIAL_NAME_LENGTH 32 // Material name string length + + unsigned int fileSize = 0; + unsigned char *fileData = LoadFileData(fileName, &fileSize); + unsigned char *fileDataPtr = fileData; // IQM file structs //----------------------------------------------------------------------------------- @@ -3134,13 +3136,10 @@ static Model LoadIQM(const char *fileName) Model model = { 0 }; - FILE *iqmFile = NULL; - IQMHeader iqm; - - IQMMesh *imesh; - IQMTriangle *tri; - IQMVertexArray *va; - IQMJoint *ijoint; + IQMMesh *imesh = NULL; + IQMTriangle *tri = NULL; + IQMVertexArray *va = NULL; + IQMJoint *ijoint = NULL; float *vertex = NULL; float *normal = NULL; @@ -3148,36 +3147,33 @@ static Model LoadIQM(const char *fileName) char *blendi = NULL; unsigned char *blendw = NULL; - iqmFile = fopen(fileName, "rb"); - - if (iqmFile == NULL) - { - TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open IQM file", fileName); - return model; - } + // In case file can not be read, return an empty model + if (fileDataPtr == NULL) return model; - fread(&iqm, sizeof(IQMHeader), 1, iqmFile); // Read IQM header + // Read IQM header + IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr; - if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) + if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) { TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); - fclose(iqmFile); return model; } - if (iqm.version != IQM_VERSION) + if (iqmHeader->version != IQM_VERSION) { - TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqm.version); - fclose(iqmFile); + TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); return model; } + + //fileDataPtr += sizeof(IQMHeader); // Move file data pointer // Meshes data processing - imesh = RL_MALLOC(sizeof(IQMMesh)*iqm.num_meshes); - fseek(iqmFile, iqm.ofs_meshes, SEEK_SET); - fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile); + imesh = RL_MALLOC(sizeof(IQMMesh)*iqmHeader->num_meshes); + //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET); + //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile); + memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh)); - model.meshCount = iqm.num_meshes; + model.meshCount = iqmHeader->num_meshes; model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); model.materialCount = model.meshCount; @@ -3189,11 +3185,13 @@ static Model LoadIQM(const char *fileName) for (int i = 0; i < model.meshCount; i++) { - fseek(iqmFile, iqm.ofs_text + imesh[i].name, SEEK_SET); - fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); + //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET); + //fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); + memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char)); - fseek(iqmFile, iqm.ofs_text + imesh[i].material, SEEK_SET); - fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile); + //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET); + //fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile); + memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char)); model.materials[i] = LoadMaterialDefault(); @@ -3220,9 +3218,10 @@ static Model LoadIQM(const char *fileName) } // Triangles data processing - tri = RL_MALLOC(iqm.num_triangles*sizeof(IQMTriangle)); - fseek(iqmFile, iqm.ofs_triangles, SEEK_SET); - fread(tri, iqm.num_triangles*sizeof(IQMTriangle), 1, iqmFile); + tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle)); + //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET); + //fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile); + memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle)); for (int m = 0; m < model.meshCount; m++) { @@ -3239,21 +3238,23 @@ static Model LoadIQM(const char *fileName) } // Vertex arrays data processing - va = RL_MALLOC(iqm.num_vertexarrays*sizeof(IQMVertexArray)); - fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET); - fread(va, iqm.num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile); + va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); + //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET); + //fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile); + memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray)); - for (unsigned int i = 0; i < iqm.num_vertexarrays; i++) + for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++) { switch (va[i].type) { case IQM_POSITION: { - vertex = RL_MALLOC(iqm.num_vertexes*3*sizeof(float)); - fseek(iqmFile, va[i].offset, SEEK_SET); - fread(vertex, iqm.num_vertexes*3*sizeof(float), 1, iqmFile); + vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); + memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); - for (unsigned int m = 0; m < iqm.num_meshes; m++) + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) { int vCounter = 0; for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) @@ -3266,11 +3267,12 @@ static Model LoadIQM(const char *fileName) } break; case IQM_NORMAL: { - normal = RL_MALLOC(iqm.num_vertexes*3*sizeof(float)); - fseek(iqmFile, va[i].offset, SEEK_SET); - fread(normal, iqm.num_vertexes*3*sizeof(float), 1, iqmFile); + normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile); + memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float)); - for (unsigned int m = 0; m < iqm.num_meshes; m++) + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) { int vCounter = 0; for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++) @@ -3283,11 +3285,12 @@ static Model LoadIQM(const char *fileName) } break; case IQM_TEXCOORD: { - text = RL_MALLOC(iqm.num_vertexes*2*sizeof(float)); - fseek(iqmFile, va[i].offset, SEEK_SET); - fread(text, iqm.num_vertexes*2*sizeof(float), 1, iqmFile); + text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile); + memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float)); - for (unsigned int m = 0; m < iqm.num_meshes; m++) + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) { int vCounter = 0; for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++) @@ -3299,11 +3302,12 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDINDEXES: { - blendi = RL_MALLOC(iqm.num_vertexes*4*sizeof(char)); - fseek(iqmFile, va[i].offset, SEEK_SET); - fread(blendi, iqm.num_vertexes*4*sizeof(char), 1, iqmFile); + blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile); + memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char)); - for (unsigned int m = 0; m < iqm.num_meshes; m++) + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) { int boneCounter = 0; for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) @@ -3315,11 +3319,12 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDWEIGHTS: { - blendw = RL_MALLOC(iqm.num_vertexes*4*sizeof(unsigned char)); - fseek(iqmFile, va[i].offset, SEEK_SET); - fread(blendw, iqm.num_vertexes*4*sizeof(unsigned char), 1, iqmFile); + blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile); + memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char)); - for (unsigned int m = 0; m < iqm.num_meshes; m++) + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) { int boneCounter = 0; for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) @@ -3333,20 +3338,22 @@ static Model LoadIQM(const char *fileName) } // Bones (joints) data processing - ijoint = RL_MALLOC(iqm.num_joints*sizeof(IQMJoint)); - fseek(iqmFile, iqm.ofs_joints, SEEK_SET); - fread(ijoint, iqm.num_joints*sizeof(IQMJoint), 1, iqmFile); + ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint)); + //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET); + //fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile); + memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint)); - model.boneCount = iqm.num_joints; - model.bones = RL_MALLOC(iqm.num_joints*sizeof(BoneInfo)); - model.bindPose = RL_MALLOC(iqm.num_joints*sizeof(Transform)); + model.boneCount = iqmHeader->num_joints; + model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo)); + model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform)); - for (unsigned int i = 0; i < iqm.num_joints; i++) + for (unsigned int i = 0; i < iqmHeader->num_joints; i++) { // Bones model.bones[i].parent = ijoint[i].parent; - fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET); - fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile); + //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET); + //fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile); + memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char)); // Bind pose (base pose) model.bindPose[i].translation.x = ijoint[i].translate[0]; @@ -3375,7 +3382,8 @@ static Model LoadIQM(const char *fileName) } } - fclose(iqmFile); + RL_FREE(fileData); + RL_FREE(imesh); RL_FREE(tri); RL_FREE(va); @@ -3490,7 +3498,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co int width, height; unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4); - free(data); + RL_FREE(data); rimage.data = raw; rimage.width = width; @@ -3524,7 +3532,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co int width, height; unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4); - free(data); + RL_FREE(data); rimage.data = raw; rimage.width = width; @@ -3688,14 +3696,14 @@ static Model LoadGLTF(const char *fileName) { cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; model.meshes[primitiveIndex].vertexCount = (int)acc->count; - model.meshes[primitiveIndex].vertices = RL_MALLOC(sizeof(float)*model.meshes[primitiveIndex].vertexCount*3); + model.meshes[primitiveIndex].vertices = RL_MALLOC(model.meshes[primitiveIndex].vertexCount*3*sizeof(float)); LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].vertices) } else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal) { cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; - model.meshes[primitiveIndex].normals = RL_MALLOC(sizeof(float)*acc->count*3); + model.meshes[primitiveIndex].normals = RL_MALLOC(acc->count*3*sizeof(float)); LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].normals) } @@ -3705,7 +3713,7 @@ static Model LoadGLTF(const char *fileName) if (acc->component_type == cgltf_component_type_r_32f) { - model.meshes[primitiveIndex].texcoords = RL_MALLOC(sizeof(float)*acc->count*2); + model.meshes[primitiveIndex].texcoords = RL_MALLOC(acc->count*2*sizeof(float)); LOAD_ACCESSOR(float, 2, acc, model.meshes[primitiveIndex].texcoords) } else @@ -3723,7 +3731,7 @@ static Model LoadGLTF(const char *fileName) if (acc->component_type == cgltf_component_type_r_16u) { model.meshes[primitiveIndex].triangleCount = (int)acc->count/3; - model.meshes[primitiveIndex].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[primitiveIndex].triangleCount*3); + model.meshes[primitiveIndex].indices = RL_MALLOC(model.meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short)); LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[primitiveIndex].indices) } else