summaryrefslogtreecommitdiffhomepage
path: root/src/models.c
diff options
context:
space:
mode:
authorRay <[email protected]>2021-08-27 12:13:44 +0200
committerRay <[email protected]>2021-08-27 12:13:44 +0200
commitb7ae0df3d99e750922183ff7f06227981822e6b4 (patch)
tree0005ab281e042fad2e91f80ea711f2757918f68a /src/models.c
parentcac856119c23898579fc237703a8ff3bda207dc6 (diff)
downloadraylib-b7ae0df3d99e750922183ff7f06227981822e6b4.tar.gz
raylib-b7ae0df3d99e750922183ff7f06227981822e6b4.zip
REVIEWED: Decouple `DrawMesh()` and `DrawMeshInstanced()` #1958
Diffstat (limited to 'src/models.c')
-rw-r--r--src/models.c285
1 files changed, 218 insertions, 67 deletions
diff --git a/src/models.c b/src/models.c
index bd200d5f..411538d1 100644
--- a/src/models.c
+++ b/src/models.c
@@ -973,12 +973,6 @@ void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset
// Draw a 3d mesh with material and transform
void DrawMesh(Mesh mesh, Material material, Matrix transform)
{
- DrawMeshInstanced(mesh, material, &transform, 1);
-}
-
-// Draw multiple mesh instances with material and different transforms
-void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances)
-{
#if defined(GRAPHICS_API_OPENGL_11)
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
@@ -993,7 +987,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
rlPushMatrix();
- rlMultMatrixf(MatrixToFloat(transforms[0]));
+ rlMultMatrixf(MatrixToFloat(transform));
rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
material.maps[MATERIAL_MAP_DIFFUSE].color.g,
material.maps[MATERIAL_MAP_DIFFUSE].color.b,
@@ -1012,13 +1006,6 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
- // Check instancing
- bool instancing = false;
- if (instances < 1) return;
- else if (instances > 1) instancing = true;
- float16 *instanceTransforms = NULL;
- unsigned int instancesVboId = 0;
-
// Bind shader program
rlEnableShader(material.shader.id);
@@ -1064,52 +1051,232 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
- if (instancing)
+ // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL
+ if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform);
+
+ // Accumulate several model transformations:
+ // transform: model transformation provided (includes DrawModel() params combined with model.transform)
+ // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
+ matModel = MatrixMultiply(transform, rlGetMatrixTransform());
+
+ // Get model-view matrix
+ matModelView = MatrixMultiply(matModel, matView);
+
+ // 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)));
+ //-----------------------------------------------------
+
+ // Bind active texture maps (if available)
+ for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
{
- // Create instances buffer
- instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
+ if (material.maps[i].texture.id > 0)
+ {
+ // Select current shader texture slot
+ rlActiveTextureSlot(i);
+
+ // Enable texture for active slot
+ if ((i == MATERIAL_MAP_IRRADIANCE) ||
+ (i == MATERIAL_MAP_PREFILTER) ||
+ (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
+ else rlEnableTexture(material.maps[i].texture.id);
- // Fill buffer with instances transformations as float16 arrays
- for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
+ rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
+ }
+ }
- // Enable mesh VAO to attach new buffer
- rlEnableVertexArray(mesh.vaoId);
+ // Try binding vertex array objects (VAO)
+ // or use VBOs if not possible
+ if (!rlEnableVertexArray(mesh.vaoId))
+ {
+ // Bind mesh VBO data: vertex position (shader-location = 0)
+ rlEnableVertexBuffer(mesh.vboId[0]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
- // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData().
- // It isn't clear which would be reliably faster in all cases and on all platforms,
- // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
- // no faster, since we're transferring all the transform matrices anyway
- instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
+ // Bind mesh VBO data: vertex texcoords (shader-location = 1)
+ rlEnableVertexBuffer(mesh.vboId[1]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
- // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL
- for (unsigned int i = 0; i < 4; i++)
+ if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
{
- rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i);
- rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
- rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 1);
+ // Bind mesh VBO data: vertex normals (shader-location = 2)
+ rlEnableVertexBuffer(mesh.vboId[2]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
}
- rlDisableVertexBuffer();
- rlDisableVertexArray();
+ // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
+ {
+ if (mesh.vboId[3] != 0)
+ {
+ rlEnableVertexBuffer(mesh.vboId[3]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+ }
+ else
+ {
+ // Set default value for unused attribute
+ // NOTE: Required when using default shader and no VAO support
+ float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC2, 4);
+ rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+ }
+ }
+
+ // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[4]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
+ }
- // Accumulate internal matrix transform (push/pop) and view matrix
- // NOTE: In this case, model instance transformation must be computed in the shader
- matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
+ // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[5]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
+ }
+
+ if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
}
- else
+
+ int eyesCount = 1;
+ if (rlIsStereoRenderEnabled()) eyesCount = 2;
+
+ for (int eye = 0; eye < eyesCount; eye++)
{
- // Model transformation matrix is send to shader uniform location: SHADER_LOC_MATRIX_MODEL
- if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transforms[0]);
+ // Calculate model-view-projection matrix (MVP)
+ Matrix matModelViewProjection = MatrixIdentity();
+ if (eyesCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
+ else
+ {
+ // Setup current eye viewport (half screen width)
+ rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
+ matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
+ }
- // Accumulate several model transformations:
- // transforms[0]: model transformation provided (includes DrawModel() params combined with model.transform)
- // rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
- matModel = MatrixMultiply(transforms[0], rlGetMatrixTransform());
+ // Send combined model-view-projection matrix to shader
+ rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
+
+ // Draw mesh
+ if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
+ else rlDrawVertexArray(0, mesh.vertexCount);
+ }
+
+ // Unbind all binded texture maps
+ for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+ {
+ // Select current shader texture slot
+ rlActiveTextureSlot(i);
+
+ // Disable texture for active slot
+ if ((i == MATERIAL_MAP_IRRADIANCE) ||
+ (i == MATERIAL_MAP_PREFILTER) ||
+ (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
+ else rlDisableTexture();
+ }
+
+ // Disable all possible vertex array objects (or VBOs)
+ rlDisableVertexArray();
+ rlDisableVertexBuffer();
+ rlDisableVertexBufferElement();
+
+ // Disable shader program
+ rlDisableShader();
+
+ // Restore rlgl internal modelview and projection matrices
+ rlSetMatrixModelview(matView);
+ rlSetMatrixProjection(matProjection);
+#endif
+}
+
+// Draw multiple mesh instances with material and different transforms
+void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ // Instancing required variables
+ float16 *instanceTransforms = NULL;
+ unsigned int instancesVboId = 0;
+
+ // Bind shader program
+ rlEnableShader(material.shader.id);
+
+ // Send required data to shader (matrices, values)
+ //-----------------------------------------------------
+ // Upload to shader material.colDiffuse
+ if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
+ {
+ float values[4] = {
+ (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
+ (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
+ (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
+ (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
+ };
- // Get model-view matrix
- matModelView = MatrixMultiply(matModel, matView);
+ rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
}
+ // Upload to shader material.colSpecular (if location available)
+ if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
+ {
+ float values[4] = {
+ (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
+ (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
+ (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
+ (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
+ };
+
+ rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
+ }
+
+ // Get a copy of current matrices to work with,
+ // just in case stereo render is required and we need to modify them
+ // NOTE: At this point the modelview matrix just contains the view matrix (camera)
+ // That's because BeginMode3D() sets it and there is no model-drawing function
+ // that modifies it, all use rlPushMatrix() and rlPopMatrix()
+ Matrix matModel = MatrixIdentity();
+ Matrix matView = rlGetMatrixModelview();
+ Matrix matModelView = MatrixIdentity();
+ Matrix matProjection = rlGetMatrixProjection();
+
+ // Upload view and projection matrices (if locations available)
+ if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
+ if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
+
+ // Create instances buffer
+ instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
+
+ // Fill buffer with instances transformations as float16 arrays
+ for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
+
+ // Enable mesh VAO to attach new buffer
+ rlEnableVertexArray(mesh.vaoId);
+
+ // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData().
+ // It isn't clear which would be reliably faster in all cases and on all platforms,
+ // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
+ // no faster, since we're transferring all the transform matrices anyway
+ instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
+
+ // Instances transformation matrices are send to shader attribute location: SHADER_LOC_MATRIX_MODEL
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
+ rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_MATRIX_MODEL] + i, 1);
+ }
+
+ rlDisableVertexBuffer();
+ rlDisableVertexArray();
+
+ // Accumulate internal matrix transform (push/pop) and view matrix
+ // NOTE: In this case, model instance transformation must be computed in the shader
+ matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
+
// 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)));
//-----------------------------------------------------
@@ -1210,16 +1377,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
// Send combined model-view-projection matrix to shader
rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
- if (instancing) // Draw mesh instanced
- {
- if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
- else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
- }
- else // Draw mesh
- {
- if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
- else rlDrawVertexArray(0, mesh.vertexCount);
- }
+ // Draw mesh instanced
+ if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
+ else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
}
// Unbind all binded texture maps
@@ -1243,18 +1403,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
// Disable shader program
rlDisableShader();
- if (instancing)
- {
- // Remove instance transforms buffer
- rlUnloadVertexBuffer(instancesVboId);
- RL_FREE(instanceTransforms);
- }
- else
- {
- // Restore rlgl internal modelview and projection matrices
- rlSetMatrixModelview(matView);
- rlSetMatrixProjection(matProjection);
- }
+ // Remove instance transforms buffer
+ rlUnloadVertexBuffer(instancesVboId);
+ RL_FREE(instanceTransforms);
#endif
}