|
|
@ -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,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 |
|
|
|
} |
|
|
|
|
|
|
|