Skip to content

Commit

Permalink
Removed memory duplication and memcpy with animations
Browse files Browse the repository at this point in the history
previously the bonematrix array was stored per mesh even though this is duplicated. now points back to the model.
this saves memory and removes a memcpy.
  • Loading branch information
JettMonstersGoBoom committed Dec 22, 2024
1 parent dc202e8 commit 0bc4ede
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 63 deletions.
4 changes: 3 additions & 1 deletion src/raylib.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,9 @@ typedef struct Mesh {
float *animNormals; // Animated normals (after bones transformations)
unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)
float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)
Matrix *boneMatrices; // Bones animated transformation matrices
int boneCount; // Number of bones
Matrix *boneMatricesPtr; // POINTER to Models bones transformation matrices
// DO NOT FREE THIS

// OpenGL identifiers
unsigned int vaoId; // OpenGL Vertex Array Object id
Expand Down Expand Up @@ -414,6 +415,7 @@ typedef struct Model {
// Animation data
int boneCount; // Number of bones
BoneInfo *bones; // Bones information (skeleton)
Matrix *boneMatrices; // Bones animated transformation matrices, moved these here to boost perf a little and remove wasted memory duplication
Transform *bindPose; // Bones base transformation (pose)
} Model;

Expand Down
79 changes: 17 additions & 62 deletions src/rmodels.c
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ void UnloadModel(Model model)
// Unload animation data
RL_FREE(model.bones);
RL_FREE(model.bindPose);

RL_FREE(model.boneMatrices);
TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
}

Expand Down Expand Up @@ -1508,9 +1508,9 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)

#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Upload Bone Transforms
if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatricesPtr)
{
rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatricesPtr, mesh.boneCount);
}
#endif
//-----------------------------------------------------
Expand Down Expand Up @@ -1754,9 +1754,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i

#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Upload Bone Transforms
if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatricesPtr)
{
rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatricesPtr, mesh.boneCount);
}
#endif

Expand Down Expand Up @@ -1932,7 +1932,6 @@ void UnloadMesh(Mesh mesh)
RL_FREE(mesh.animNormals);
RL_FREE(mesh.boneWeights);
RL_FREE(mesh.boneIds);
RL_FREE(mesh.boneMatrices);
}

// Export mesh data to file
Expand Down Expand Up @@ -2270,22 +2269,6 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
{
if (frame >= anim.frameCount) frame = frame%anim.frameCount;

// Get first mesh which have bones
int firstMeshWithBones = -1;

for (int i = 0; i < model.meshCount; i++)
{
if (model.meshes[i].boneMatrices)
{
assert(model.meshes[i].boneCount == anim.boneCount);
if (firstMeshWithBones == -1)
{
firstMeshWithBones = i;
break;
}
}
}

// Update all bones and boneMatrices of first mesh with bones.
for (int boneId = 0; boneId < anim.boneCount; boneId++)
{
Expand All @@ -2312,22 +2295,7 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
MatrixScale(boneScale.x, boneScale.y, boneScale.z));

model.meshes[firstMeshWithBones].boneMatrices[boneId] = boneMatrix;
}

// Update remaining meshes with bones
// NOTE: Using deep copy because shallow copy results in double free with 'UnloadModel()'
if (firstMeshWithBones != -1)
{
for (int i = firstMeshWithBones + 1; i < model.meshCount; i++)
{
if (model.meshes[i].boneMatrices)
{
memcpy(model.meshes[i].boneMatrices,
model.meshes[firstMeshWithBones].boneMatrices,
model.meshes[i].boneCount * sizeof(model.meshes[i].boneMatrices[0]));
}
}
model.boneMatrices[boneId] = boneMatrix;
}
}
}
Expand Down Expand Up @@ -2372,7 +2340,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
// Early stop when no transformation will be applied
if (boneWeight == 0.0f) continue;
animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
animVertex = Vector3Transform(animVertex,model.boneMatrices[boneId]);
mesh.animVertices[vCounter] += animVertex.x*boneWeight;
mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
Expand All @@ -2383,7 +2351,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
if (mesh.normals != NULL)
{
animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
animNormal = Vector3Transform(animNormal,model.meshes[m].boneMatrices[boneId]);
animNormal = Vector3Transform(animNormal,model.boneMatrices[boneId]);
mesh.animNormals[vCounter] += animNormal.x*boneWeight;
mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
Expand Down Expand Up @@ -4807,16 +4775,10 @@ static Model LoadIQM(const char *fileName)
}

BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);

for (int i = 0; i < model.meshCount; i++)
model.boneMatrices = RL_CALLOC(model.boneCount,sizeof(Matrix));
for (int j = 0; j < model.boneCount; j++)
{
model.meshes[i].boneCount = model.boneCount;
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));

for (int j = 0; j < model.meshes[i].boneCount; j++)
{
model.meshes[i].boneMatrices[j] = MatrixIdentity();
}
model.boneMatrices[j] = MatrixIdentity();
}

UnloadFileData(fileData);
Expand Down Expand Up @@ -5907,14 +5869,10 @@ static Model LoadGLTF(const char *fileName)
}

// Bone Transform Matrices
model.meshes[meshIndex].boneCount = model.boneCount;
model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));

for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
{
model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
}
if (model.boneMatrices==NULL)
model.boneMatrices = RL_CALLOC(model.boneCount, sizeof(Matrix));

model.meshes[meshIndex].boneMatricesPtr = model.boneMatrices;
meshIndex++; // Move to next mesh
}

Expand Down Expand Up @@ -6687,12 +6645,9 @@ static Model LoadM3D(const char *fileName)
memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));

model.meshes[i].boneCount = model.boneCount;
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
for (j = 0; j < model.meshes[i].boneCount; j++)
{
model.meshes[i].boneMatrices[j] = MatrixIdentity();
}
if (model.boneMatrices==NULL)
model.boneMatrices = RL_CALLOC(model.boneCount, sizeof(Matrix));

Check failure

Code scanning / CodeQL

Uncontrolled allocation size High

This allocation size is derived from
user input (string read by fread)
and could allocate arbitrary amounts of memory.
model.meshes[i].boneMatricesPtr = model.boneMatrices;
}
}

Expand Down

0 comments on commit 0bc4ede

Please sign in to comment.