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