|
@@ -130,7 +130,7 @@
|
|
#define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
|
|
#define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
|
|
#endif
|
|
#endif
|
|
#ifndef MAX_MESH_VERTEX_BUFFERS
|
|
#ifndef MAX_MESH_VERTEX_BUFFERS
|
|
- #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
|
|
|
|
|
|
+ #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
|
|
#endif
|
|
#endif
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
@@ -1248,11 +1248,13 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
|
mesh->vaoId = 0; // Vertex Array Object
|
|
mesh->vaoId = 0; // Vertex Array Object
|
|
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions
|
|
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions
|
|
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords
|
|
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords
|
|
- mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals
|
|
|
|
- mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors
|
|
|
|
- mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents
|
|
|
|
- mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2
|
|
|
|
- mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices
|
|
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices
|
|
|
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
|
mesh->vaoId = rlLoadVertexArray();
|
|
mesh->vaoId = rlLoadVertexArray();
|
|
@@ -1338,6 +1340,38 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
|
rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2);
|
|
rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2);
|
|
rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
|
|
rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (mesh->boneIds != NULL)
|
|
|
|
+ {
|
|
|
|
+ // Enable vertex attribute: boneIds (shader-location = 6)
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
|
|
|
|
+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Default vertex attribute: boneIds
|
|
|
|
+ // WARNING: Default value provided to shader if location available
|
|
|
|
+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4);
|
|
|
|
+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (mesh->boneWeights != NULL)
|
|
|
|
+ {
|
|
|
|
+ // Enable vertex attribute: boneWeights (shader-location = 7)
|
|
|
|
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);
|
|
|
|
+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Default vertex attribute: boneWeights
|
|
|
|
+ // WARNING: Default value provided to shader if location available
|
|
|
|
+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);
|
|
|
|
+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
|
|
|
|
+ }
|
|
|
|
|
|
if (mesh->indices != NULL)
|
|
if (mesh->indices != NULL)
|
|
{
|
|
{
|
|
@@ -1451,6 +1485,13 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
|
|
|
|
|
// Upload model normal matrix (if locations available)
|
|
// Upload model normal matrix (if locations available)
|
|
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
|
|
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
|
|
|
|
+
|
|
|
|
+ // Upload Bone Transforms
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
|
|
|
|
+ {
|
|
|
|
+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
|
|
|
|
+ }
|
|
|
|
+
|
|
//-----------------------------------------------------
|
|
//-----------------------------------------------------
|
|
|
|
|
|
// Bind active texture maps (if available)
|
|
// Bind active texture maps (if available)
|
|
@@ -1529,6 +1570,22 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
|
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
|
|
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
|
|
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
|
|
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
|
|
|
|
+ {
|
|
|
|
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
|
|
|
|
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
|
|
|
|
+ {
|
|
|
|
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
|
|
|
|
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
|
|
|
|
+ }
|
|
|
|
|
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
|
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
|
|
}
|
|
}
|
|
@@ -1671,6 +1728,13 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
|
|
|
|
|
|
// Upload model normal matrix (if locations available)
|
|
// Upload model normal matrix (if locations available)
|
|
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
|
|
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
|
|
|
|
+
|
|
|
|
+ // Upload Bone Transforms
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
|
|
|
|
+ {
|
|
|
|
+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
|
|
|
|
+ }
|
|
|
|
+
|
|
//-----------------------------------------------------
|
|
//-----------------------------------------------------
|
|
|
|
|
|
// Bind active texture maps (if available)
|
|
// Bind active texture maps (if available)
|
|
@@ -1747,6 +1811,22 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
|
|
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
|
|
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
|
|
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
|
|
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
|
|
|
|
+ {
|
|
|
|
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
|
|
|
|
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
|
|
|
|
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
|
|
|
|
+ {
|
|
|
|
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
|
|
|
|
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
|
|
|
|
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
|
|
|
|
+ }
|
|
|
|
|
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
|
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
|
|
}
|
|
}
|
|
@@ -1825,6 +1905,7 @@ void UnloadMesh(Mesh mesh)
|
|
RL_FREE(mesh.animNormals);
|
|
RL_FREE(mesh.animNormals);
|
|
RL_FREE(mesh.boneWeights);
|
|
RL_FREE(mesh.boneWeights);
|
|
RL_FREE(mesh.boneIds);
|
|
RL_FREE(mesh.boneIds);
|
|
|
|
+ RL_FREE(mesh.boneMatrices);
|
|
}
|
|
}
|
|
|
|
|
|
// Export mesh data to file
|
|
// Export mesh data to file
|
|
@@ -2255,6 +2336,50 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame)
|
|
|
|
+{
|
|
|
|
+ if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
|
|
|
|
+ {
|
|
|
|
+ if (frame >= anim.frameCount) frame = frame%anim.frameCount;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < model.meshCount; i++)
|
|
|
|
+ {
|
|
|
|
+ if (model.meshes[i].boneMatrices)
|
|
|
|
+ {
|
|
|
|
+ assert(model.meshes[i].boneCount == anim.boneCount);
|
|
|
|
+
|
|
|
|
+ for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++)
|
|
|
|
+ {
|
|
|
|
+ Vector3 inTranslation = model.bindPose[boneId].translation;
|
|
|
|
+ Quaternion inRotation = model.bindPose[boneId].rotation;
|
|
|
|
+ Vector3 inScale = model.bindPose[boneId].scale;
|
|
|
|
+
|
|
|
|
+ Vector3 outTranslation = anim.framePoses[frame][boneId].translation;
|
|
|
|
+ Quaternion outRotation = anim.framePoses[frame][boneId].rotation;
|
|
|
|
+ Vector3 outScale = anim.framePoses[frame][boneId].scale;
|
|
|
|
+
|
|
|
|
+ Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), QuaternionInvert(inRotation));
|
|
|
|
+ Quaternion invRotation = QuaternionInvert(inRotation);
|
|
|
|
+ Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale);
|
|
|
|
+
|
|
|
|
+ Vector3 boneTranslation = Vector3Add(
|
|
|
|
+ Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation),
|
|
|
|
+ outRotation), outTranslation);
|
|
|
|
+ Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation);
|
|
|
|
+ Vector3 boneScale = Vector3Multiply(outScale, invScale);
|
|
|
|
+
|
|
|
|
+ Matrix boneMatrix = MatrixMultiply(MatrixMultiply(
|
|
|
|
+ QuaternionToMatrix(boneRotation),
|
|
|
|
+ MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
|
|
|
|
+ MatrixScale(boneScale.x, boneScale.y, boneScale.z));
|
|
|
|
+
|
|
|
|
+ model.meshes[i].boneMatrices[boneId] = boneMatrix;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
// Unload animation array data
|
|
// Unload animation array data
|
|
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
|
|
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
|
|
{
|
|
{
|
|
@@ -4671,6 +4796,17 @@ static Model LoadIQM(const char *fileName)
|
|
}
|
|
}
|
|
|
|
|
|
BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
|
|
BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < model.meshCount; i++)
|
|
|
|
+ {
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
UnloadFileData(fileData);
|
|
UnloadFileData(fileData);
|
|
|
|
|
|
@@ -5754,6 +5890,15 @@ static Model LoadGLTF(const char *fileName)
|
|
{
|
|
{
|
|
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
|
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // 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();
|
|
|
|
+ }
|
|
|
|
|
|
meshIndex++; // Move to next mesh
|
|
meshIndex++; // Move to next mesh
|
|
}
|
|
}
|
|
@@ -6522,6 +6667,13 @@ 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].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));
|
|
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();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|