From 3013d45de1ff7db8dd782577e70178f590f91fa8 Mon Sep 17 00:00:00 2001 From: Thibault Leclercq Date: Fri, 13 Oct 2023 21:17:30 +0200 Subject: [PATCH] implement feature --- src/config.h | 1 + src/raylib.h | 2 + src/rcore.c | 2 + src/rlgl.h | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/rmodels.c | 80 ++++++++++++++----------- 5 files changed, 211 insertions(+), 35 deletions(-) diff --git a/src/config.h b/src/config.h index 7886aeeba..347d32ddf 100644 --- a/src/config.h +++ b/src/config.h @@ -116,6 +116,7 @@ #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE "instanceTransform" // Bound by default to shader location: 6 #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix diff --git a/src/raylib.h b/src/raylib.h index c03e0a576..078ccf96b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -371,6 +371,7 @@ typedef struct MaterialMap { // Material, includes shader and maps typedef struct Material { Shader shader; // Material shader + Shader shaderInstanced; // Material shader MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS) float params[4]; // Material generic parameters (if required) } Material; @@ -753,6 +754,7 @@ typedef enum { SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color + SHADER_LOC_VERTEX_INSTANCE, // Shader location: vertex attribute: instance (transform) SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection diff --git a/src/rcore.c b/src/rcore.c index e7868ebb8..02abeb5f1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -896,6 +896,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + shader.locs[SHADER_LOC_VERTEX_INSTANCE] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE); // Get handles to GLSL uniform locations (vertex shader) shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP); @@ -931,6 +932,7 @@ bool IsShaderReady(Shader shader) // shader.locs[SHADER_LOC_VERTEX_NORMAL] // shader.locs[SHADER_LOC_VERTEX_TANGENT] // shader.locs[SHADER_LOC_VERTEX_COLOR] // Set by default internal shader + // shader.locs[SHADER_LOC_VERTEX_INSTANCE] // Set by default internal shader instanced // Vertex shader uniform locations (default) // shader.locs[SHADER_LOC_MATRIX_MVP] // Set by default internal shader diff --git a/src/rlgl.h b/src/rlgl.h index 40e7b4785..d269de1ae 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -467,6 +467,7 @@ typedef enum { RL_SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal RL_SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent RL_SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color + RL_SHADER_LOC_VERTEX_INSTANCE, // Shader location: vertex attribute: instance (transform) RL_SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection RL_SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) RL_SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection @@ -664,6 +665,8 @@ RLAPI int rlGetFramebufferHeight(void); // Get default framebuff RLAPI unsigned int rlGetTextureIdDefault(void); // Get default texture id RLAPI unsigned int rlGetShaderIdDefault(void); // Get default shader id RLAPI int *rlGetShaderLocsDefault(void); // Get default shader locations +RLAPI unsigned int rlGetShaderInstancedIdDefault(void); // Get default shader instanced id +RLAPI int *rlGetShaderInstancedLocsDefault(void); // Get default shader instanced locations // Render batch management // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode @@ -978,6 +981,10 @@ typedef struct rlglData { unsigned int defaultFShaderId; // Default fragment shader id (used by default shader program) unsigned int defaultShaderId; // Default shader program id, supports vertex color and diffuse texture int *defaultShaderLocs; // Default shader locations pointer to be used on rendering + unsigned int defaultVShaderInstancedId; // Default vertex shader instanced id (used by default shader instanced program) + unsigned int defaultFShaderInstancedId; // Default fragment shader instanced id (used by default shader instanced program) + unsigned int defaultShaderInstancedId; // Default shader instanced program id, supports vertex color and diffuse texture + int *defaultShaderInstancedLocs; // Default shader instanced locations pointer to be used on rendering unsigned int currentShaderId; // Current shader id to be used on rendering (by default, defaultShaderId) int *currentShaderLocs; // Current shader locations pointer to be used on rendering (by default, defaultShaderLocs) @@ -1055,6 +1062,8 @@ static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void rlLoadShaderDefault(void); // Load default shader static void rlUnloadShaderDefault(void); // Unload default shader +static void rlLoadShaderInstancedDefault(void); // Load default shaderInstanced +static void rlUnloadShaderInstancedDefault(void); // Unload default shaderInstanced #if defined(RLGL_SHOW_GL_DETAILS_INFO) static char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name #endif // RLGL_SHOW_GL_DETAILS_INFO @@ -2093,6 +2102,7 @@ void rlglInit(int width, int height) // Init default Shader (customized for GL 3.3 and ES2) // Loaded: RLGL.State.defaultShaderId + RLGL.State.defaultShaderLocs rlLoadShaderDefault(); + rlLoadShaderInstancedDefault(); RLGL.State.currentShaderId = RLGL.State.defaultShaderId; RLGL.State.currentShaderLocs = RLGL.State.defaultShaderLocs; @@ -2159,6 +2169,7 @@ void rlglClose(void) rlUnloadRenderBatch(RLGL.defaultBatch); rlUnloadShaderDefault(); // Unload default shader + rlUnloadShaderInstancedDefault(); // Unload default shader glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); @@ -2524,6 +2535,26 @@ int *rlGetShaderLocsDefault(void) return locs; } +// Get default shader instanced id +unsigned int rlGetShaderInstancedIdDefault(void) +{ + unsigned int id = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + id = RLGL.State.defaultShaderInstancedId; +#endif + return id; +} + +// Get default shader instanced locs +int *rlGetShaderInstancedLocsDefault(void) +{ + int *locs = NULL; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + locs = RLGL.State.defaultShaderInstancedLocs; +#endif + return locs; +} + // Render batch management //------------------------------------------------------------------------------------------------ // Load render batch @@ -4662,6 +4693,136 @@ static void rlUnloadShaderDefault(void) TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId); } +// Load default instanced shader (just vertex positioning and texture coloring) +static void rlLoadShaderInstancedDefault(void) +{ + RLGL.State.defaultShaderInstancedLocs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); + + // NOTE: All locations must be reseted to -1 (no location) + for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) RLGL.State.defaultShaderInstancedLocs[i] = -1; + + // Vertex shader directly defined, no external file required + const char *defaultVShaderInstancedCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "attribute mat4 instanceTransform; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "in mat4 instanceTransform; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) (on some browsers) + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "attribute mat4 instanceTransform; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#endif + "uniform mat4 mvp; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " gl_Position = mvp*instanceTransform*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // Fragment shader directly defined, no external file required + const char *defaultFShaderInstancedCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "out vec4 finalColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif + + // NOTE: Compiled vertex/fragment shaders are not deleted, + // they are kept for re-use as default shaders in case some shader loading fails + RLGL.State.defaultVShaderInstancedId = rlCompileShader(defaultVShaderInstancedCode, GL_VERTEX_SHADER); // Compile default vertex shader + RLGL.State.defaultFShaderInstancedId = rlCompileShader(defaultFShaderInstancedCode, GL_FRAGMENT_SHADER); // Compile default fragment shader + + RLGL.State.defaultShaderInstancedId = rlLoadShaderProgram(RLGL.State.defaultVShaderInstancedId, RLGL.State.defaultFShaderInstancedId); + + if (RLGL.State.defaultShaderInstancedId > 0) + { + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default instanced shader loaded successfully", RLGL.State.defaultShaderInstancedId); + + // Set default shader locations: attributes locations + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_VERTEX_POSITION] = glGetAttribLocation(RLGL.State.defaultShaderInstancedId, "vertexPosition"); + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShaderInstancedId, "vertexTexCoord"); + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShaderInstancedId, "vertexColor"); + + // For instanced rendering + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_VERTEX_INSTANCE] = glGetAttribLocation(RLGL.State.defaultShaderInstancedId, "instanceTransform"); + + // Set default shader locations: uniform locations + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShaderInstancedId, "mvp"); + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderInstancedId, "colDiffuse"); + RLGL.State.defaultShaderInstancedLocs[RL_SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderInstancedId, "texture0"); + } + else TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to load default instanced shader", RLGL.State.defaultShaderInstancedId); +} + +// Unload default instanced shader +// NOTE: Unloads: RLGL.State.defaultShaderInstancedId, RLGL.State.defaultShaderInstancedLocs +static void rlUnloadShaderInstancedDefault(void) +{ + glUseProgram(0); + + glDetachShader(RLGL.State.defaultShaderInstancedId, RLGL.State.defaultVShaderInstancedId); + glDetachShader(RLGL.State.defaultShaderInstancedId, RLGL.State.defaultFShaderInstancedId); + glDeleteShader(RLGL.State.defaultVShaderInstancedId); + glDeleteShader(RLGL.State.defaultFShaderInstancedId); + + glDeleteProgram(RLGL.State.defaultShaderInstancedId); + + RL_FREE(RLGL.State.defaultShaderInstancedLocs); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default instanced shader unloaded successfully", RLGL.State.defaultShaderInstancedId); +} + #if defined(RLGL_SHOW_GL_DETAILS_INFO) // Get compressed format official GL identifier name static char *rlGetCompressedFormatName(int format) diff --git a/src/rmodels.c b/src/rmodels.c index a11ecf799..438ee687c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1539,12 +1539,12 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i unsigned int instancesVboId = 0; // Bind shader program - rlEnableShader(material.shader.id); + rlEnableShader(material.shaderInstanced.id); // Send required data to shader (matrices, values) //----------------------------------------------------- // Upload to shader material.colDiffuse - if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1) + if (material.shaderInstanced.locs[SHADER_LOC_COLOR_DIFFUSE] != -1) { float values[4] = { (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f, @@ -1553,11 +1553,11 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f }; - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1); + rlSetUniform(material.shaderInstanced.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) + if (material.shaderInstanced.locs[SHADER_LOC_COLOR_SPECULAR] != -1) { float values[4] = { (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f, @@ -1566,7 +1566,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f }; - rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); + rlSetUniform(material.shaderInstanced.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1); } // Get a copy of current matrices to work with, @@ -1580,8 +1580,11 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i 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); + if (material.shaderInstanced.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shaderInstanced.locs[SHADER_LOC_MATRIX_VIEW], matView); + if (material.shaderInstanced.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shaderInstanced.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection); + + // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL (identity in case of instanced rendering) + rlSetUniformMatrix(material.shaderInstanced.locs[SHADER_LOC_MATRIX_MODEL], MatrixIdentity()); // Create instances buffer instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16)); @@ -1598,12 +1601,12 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // 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 + // Instances transformation matrices are send to shader attribute location: SHADER_LOC_VERTEX_INSTANCE 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); + rlEnableVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_INSTANCE] + i); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_INSTANCE] + i, 4, RL_FLOAT, 0, sizeof(Matrix), (void *)(i*sizeof(Vector4))); + rlSetVertexAttributeDivisor(material.shaderInstanced.locs[SHADER_LOC_VERTEX_INSTANCE] + i, 1); } rlDisableVertexBuffer(); @@ -1614,7 +1617,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i 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))); + if (material.shaderInstanced.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shaderInstanced.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); //----------------------------------------------------- // Bind active texture maps (if available) @@ -1631,7 +1634,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i (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); + rlSetUniform(material.shaderInstanced.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1); } } @@ -1641,62 +1644,62 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i { // 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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_TEXCOORD01]); - if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) + if (material.shaderInstanced.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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.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 (material.shaderInstanced.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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.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_VEC4, 4); - rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + rlSetVertexAttributeDefault(material.shaderInstanced.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4); + rlDisableVertexAttribute(material.shaderInstanced.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) + if (material.shaderInstanced.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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.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) + if (material.shaderInstanced.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]); + rlSetVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); } // WARNING: Disable vertex attribute color input if mesh can not provide that data (despite location being enabled in shader) - if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shaderInstanced.locs[SHADER_LOC_VERTEX_COLOR]); int eyeCount = 1; if (rlIsStereoRenderEnabled()) eyeCount = 2; @@ -1714,7 +1717,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i } // Send combined model-view-projection matrix to shader - rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection); + rlSetUniformMatrix(material.shaderInstanced.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection); // Draw mesh instanced if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances); @@ -1927,6 +1930,9 @@ Material LoadMaterialDefault(void) material.shader.id = rlGetShaderIdDefault(); material.shader.locs = rlGetShaderLocsDefault(); + material.shaderInstanced.id = rlGetShaderInstancedIdDefault(); + material.shaderInstanced.locs = rlGetShaderInstancedLocsDefault(); + // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap) material.maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; //material.maps[MATERIAL_MAP_NORMAL].texture; // NOTE: By default, not set @@ -1941,8 +1947,9 @@ Material LoadMaterialDefault(void) // Check if a material is ready bool IsMaterialReady(Material material) { - return ((material.maps != NULL) && // Validate material contain some map - (material.shader.id > 0)); // Validate material shader is valid + return ((material.maps != NULL) && // Validate material contain some map + (material.shader.id > 0) && // Validate material shader is valid + (material.shaderInstanced.id > 0)) ; // Validate material shader instanced is valid } // Unload material from memory @@ -1951,6 +1958,9 @@ void UnloadMaterial(Material material) // Unload material shader (avoid unloading default shader, managed by raylib) if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader); + // Unload material shader (avoid unloading default shader, managed by raylib) + if (material.shaderInstanced.id != rlGetShaderInstancedIdDefault()) UnloadShader(material.shaderInstanced); + // Unload loaded texture maps (avoid unloading default texture, managed by raylib) if (material.maps != NULL) {