mirror of https://github.com/raysan5/raylib
REVIEWED: Decouple `DrawMesh()` and `DrawMeshInstanced()` #1958
This commit is contained in:
parent
cac856119c
commit
b7ae0df3d9
301
src/models.c
301
src/models.c
|
@ -972,12 +972,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
|
||||
|
@ -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,51 +1051,16 @@ 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)
|
||||
{
|
||||
// Create instances buffer
|
||||
instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
|
||||
// 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);
|
||||
|
||||
// Fill buffer with instances transformations as float16 arrays
|
||||
for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
|
||||
// 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());
|
||||
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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]);
|
||||
|
||||
// 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());
|
||||
|
||||
// Get model-view matrix
|
||||
matModelView = MatrixMultiply(matModel, matView);
|
||||
}
|
||||
// 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)));
|
||||
|
@ -1210,16 +1162,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
|
||||
if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
|
||||
else rlDrawVertexArray(0, mesh.vertexCount);
|
||||
}
|
||||
|
||||
// Unbind all binded texture maps
|
||||
|
@ -1243,18 +1188,224 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
|||
// Disable shader program
|
||||
rlDisableShader();
|
||||
|
||||
if (instancing)
|
||||
// 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)
|
||||
{
|
||||
// Remove instance transforms buffer
|
||||
rlUnloadVertexBuffer(instancesVboId);
|
||||
RL_FREE(instanceTransforms);
|
||||
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
|
||||
};
|
||||
|
||||
rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
|
||||
}
|
||||
else
|
||||
|
||||
// Upload to shader material.colSpecular (if location available)
|
||||
if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
|
||||
{
|
||||
// Restore rlgl internal modelview and projection matrices
|
||||
rlSetMatrixModelview(matView);
|
||||
rlSetMatrixProjection(matProjection);
|
||||
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)));
|
||||
//-----------------------------------------------------
|
||||
|
||||
// Bind active texture maps (if available)
|
||||
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
||||
{
|
||||
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);
|
||||
|
||||
rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 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]);
|
||||
|
||||
// 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]);
|
||||
|
||||
if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -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]);
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
int eyesCount = 1;
|
||||
if (rlIsStereoRenderEnabled()) eyesCount = 2;
|
||||
|
||||
for (int eye = 0; eye < eyesCount; eye++)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Send combined model-view-projection matrix to shader
|
||||
rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
|
||||
|
||||
// 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
|
||||
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();
|
||||
|
||||
// Remove instance transforms buffer
|
||||
rlUnloadVertexBuffer(instancesVboId);
|
||||
RL_FREE(instanceTransforms);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue