Browse Source

Support instancing in OpenGL ES 2.0 if available

Checking for extension and enabling it if available
Ray 4 years ago
parent
commit
aba69146f2
1 changed files with 99 additions and 84 deletions
  1. 99 84
      src/rlgl.h

+ 99 - 84
src/rlgl.h

@@ -892,11 +892,12 @@ typedef struct rlglData {
 
     } State;            // Renderer state
     struct {
-        bool vao;                           // VAO support (OpenGL ES2 could not support VAO extension)
-        bool texNPOT;                       // NPOT textures full support
-        bool texDepth;                      // Depth textures supported
-        bool texFloat32;                    // float textures support (32 bit per channel)
-        bool texCompDXT;                    // DDS texture compression support
+        bool vao;                           // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object)
+        bool instancing;                    // Instancing supported
+        bool texNPOT;                       // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot)
+        bool texDepth;                      // Depth textures supported (GL_ARB_depth_texture, GL_WEBGL_depth_texture)
+        bool texFloat32;                    // float textures support (32 bit per channel) (GL_OES_texture_float)
+        bool texCompDXT;                    // DDS texture compression support (GL_EXT_texture_compression_s3tc)
         bool texCompETC1;                   // ETC1 texture compression support
         bool texCompETC2;                   // ETC2/EAC texture compression support
         bool texCompPVRT;                   // PVR texture compression support
@@ -930,9 +931,14 @@ static rlglData RLGL = { 0 };
 
 #if defined(GRAPHICS_API_OPENGL_ES2)
 // NOTE: VAO functionality is exposed through extensions (OES)
-static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays;        // Entry point pointer to function glGenVertexArrays()
-static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray;        // Entry point pointer to function glBindVertexArray()
-static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays;  // Entry point pointer to function glDeleteVertexArrays()
+static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
+static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
+static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
+
+// NOTE: Instancing functionality could also be available through extension
+static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL;
+static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL;
+static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL;
 #endif
 
 //----------------------------------------------------------------------------------
@@ -1617,10 +1623,9 @@ void rlglInit(int width, int height)
     GLint numExt = 0;
 
 #if defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_21)
-    // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
+    // OpenGL 3.3 extensions supported by default (core)
     RLGL.ExtSupported.vao = true;
-
-    // Multiple texture extensions supported by default
+    RLGL.ExtSupported.instancing = true;
     RLGL.ExtSupported.texNPOT = true;
     RLGL.ExtSupported.texFloat32 = true;
     RLGL.ExtSupported.texDepth = true;
@@ -1685,7 +1690,17 @@ void rlglInit(int width, int height)
 
             if ((glGenVertexArrays != NULL) && (glBindVertexArray != NULL) && (glDeleteVertexArrays != NULL)) RLGL.ExtSupported.vao = true;
         }
-
+        
+        // Check instanced rendering support
+        if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) 
+        {
+            glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)eglGetProcAddress("glDrawArraysInstancedANGLE");
+            glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)eglGetProcAddress("glDrawElementsInstancedANGLE");
+            glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)eglGetProcAddress("glVertexAttribDivisorANGLE");
+            
+            if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
+        }
+        
         // Check NPOT textures support
         // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
         if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) RLGL.ExtSupported.texNPOT = true;
@@ -2925,95 +2940,95 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
 // Draw a 3d mesh with material and transform
 void rlDrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int count)
 {
-#if defined(GRAPHICS_API_OPENGL_33)
-    // Bind shader program
-    glUseProgram(material.shader.id);
-
-    // Upload to shader material.colDiffuse
-    if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
-        glUniform4f(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], (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);
-
-    // Upload to shader material.colSpecular (if available)
-    if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
-        glUniform4f(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
-                                                               (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
-                                                               (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
-                                                               (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f);
-
-    // Bind active texture maps (if available)
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    if (RLGL.ExtSupported.instancing)
     {
-        if (material.maps[i].texture.id > 0)
+        // Bind shader program
+        glUseProgram(material.shader.id);
+
+        // Upload to shader material.colDiffuse
+        if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
+            glUniform4f(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], (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);
+
+        // Upload to shader material.colSpecular (if available)
+        if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
+            glUniform4f(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
+                                                                   (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
+                                                                   (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
+                                                                   (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f);
+
+        // Bind active texture maps (if available)
+        for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
         {
-            glActiveTexture(GL_TEXTURE0 + i);
-            if ((i == MATERIAL_MAP_IRRADIANCE) || (i == MATERIAL_MAP_PREFILTER) || (i == MATERIAL_MAP_CUBEMAP))
-                glBindTexture(GL_TEXTURE_CUBE_MAP, material.maps[i].texture.id);
-            else glBindTexture(GL_TEXTURE_2D, material.maps[i].texture.id);
+            if (material.maps[i].texture.id > 0)
+            {
+                glActiveTexture(GL_TEXTURE0 + i);
+                if ((i == MATERIAL_MAP_IRRADIANCE) || (i == MATERIAL_MAP_PREFILTER) || (i == MATERIAL_MAP_CUBEMAP))
+                    glBindTexture(GL_TEXTURE_CUBE_MAP, material.maps[i].texture.id);
+                else glBindTexture(GL_TEXTURE_2D, material.maps[i].texture.id);
 
-            glUniform1i(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], i);
+                glUniform1i(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], i);
+            }
         }
-    }
 
-    // Bind vertex array objects (or VBOs)
-    glBindVertexArray(mesh.vaoId);
+        // Bind vertex array objects (or VBOs)
+        glBindVertexArray(mesh.vaoId);
 
-    // At this point the modelview matrix just contains the view matrix (camera)
-    // For instanced shaders "mvp" is not premultiplied by any instance transform, only RLGL.State.transform
-    glUniformMatrix4fv(material.shader.locs[SHADER_LOC_MATRIX_MVP], 1, false,
-                       MatrixToFloat(MatrixMultiply(MatrixMultiply(RLGL.State.transform, RLGL.State.modelview), RLGL.State.projection)));
+        // At this point the modelview matrix just contains the view matrix (camera)
+        // For instanced shaders "mvp" is not premultiplied by any instance transform, only RLGL.State.transform
+        glUniformMatrix4fv(material.shader.locs[SHADER_LOC_MATRIX_MVP], 1, false,
+                           MatrixToFloat(MatrixMultiply(MatrixMultiply(RLGL.State.transform, RLGL.State.modelview), RLGL.State.projection)));
 
-    float16* instanceTransforms = RL_MALLOC(count*sizeof(float16));
+        float16* instanceTransforms = RL_MALLOC(count*sizeof(float16));
 
-    for (int i = 0; i < count; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
+        for (int i = 0; i < count; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
 
-    // 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, and
-    // anecdotally glMapBuffer seems very slow (syncs) while glBufferSubData seems no faster
-    // since we're transferring all the transform matrices anyway.
-    unsigned int instancesB = 0;
-    glGenBuffers(1, &instancesB);
-    glBindBuffer(GL_ARRAY_BUFFER, instancesB);
-    glBufferData(GL_ARRAY_BUFFER, count*sizeof(float16), instanceTransforms, GL_STATIC_DRAW);
+        // 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, and
+        // anecdotally glMapBuffer seems very slow (syncs) while glBufferSubData seems no faster
+        // since we're transferring all the transform matrices anyway.
+        unsigned int instancesB = 0;
+        glGenBuffers(1, &instancesB);
+        glBindBuffer(GL_ARRAY_BUFFER, instancesB);
+        glBufferData(GL_ARRAY_BUFFER, count*sizeof(float16), instanceTransforms, GL_STATIC_DRAW);
 
-    // Instances are put in SHADER_LOC_MATRIX_MODEL attribute location with space for 4x Vector4, eg:
-    // layout (location = 12) in mat4 instance;
-    unsigned int instanceA = material.shader.locs[SHADER_LOC_MATRIX_MODEL];
+        // Instances are put in SHADER_LOC_MATRIX_MODEL attribute location with space for 4x Vector4, eg:
+        // layout (location = 12) in mat4 instance;
+        unsigned int instanceA = material.shader.locs[SHADER_LOC_MATRIX_MODEL];
 
-    for (unsigned int i = 0; i < 4; i++)
-    {
-        glEnableVertexAttribArray(instanceA+i);
-        glVertexAttribPointer(instanceA + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
-        glVertexAttribDivisor(instanceA + i, 1);
-    }
-
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
+        for (unsigned int i = 0; i < 4; i++)
+        {
+            glEnableVertexAttribArray(instanceA+i);
+            glVertexAttribPointer(instanceA + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix), (void *)(i*sizeof(Vector4)));
+            glVertexAttribDivisor(instanceA + i, 1);
+        }
 
-    // Draw call!
-    if (mesh.indices != NULL) glDrawElementsInstanced(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0, count);
-    else glDrawArraysInstanced(GL_TRIANGLES, 0, mesh.vertexCount, count);
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-    glDeleteBuffers(1, &instancesB);
-    RL_FREE(instanceTransforms);
+        // Draw instanced
+        if (mesh.indices != NULL) glDrawElementsInstanced(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0, count);
+        else glDrawArraysInstanced(GL_TRIANGLES, 0, mesh.vertexCount, count);
 
-    // Unbind all binded texture maps
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-    {
-        glActiveTexture(GL_TEXTURE0 + i);       // Set shader active texture
-        if ((i == MATERIAL_MAP_IRRADIANCE) || (i == MATERIAL_MAP_PREFILTER) || (i == MATERIAL_MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
-        else glBindTexture(GL_TEXTURE_2D, 0);   // Unbind current active texture
-    }
+        glDeleteBuffers(1, &instancesB);
+        RL_FREE(instanceTransforms);
 
-    // Unind vertex array objects (or VBOs)
-    glBindVertexArray(0);
+        // Unbind all binded texture maps
+        for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+        {
+            glActiveTexture(GL_TEXTURE0 + i);       // Set shader active texture
+            if ((i == MATERIAL_MAP_IRRADIANCE) || (i == MATERIAL_MAP_PREFILTER) || (i == MATERIAL_MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+            else glBindTexture(GL_TEXTURE_2D, 0);   // Unbind current active texture
+        }
 
-    // Unbind shader program
-    glUseProgram(0);
+        // Unind vertex array objects (or VBOs)
+        glBindVertexArray(0);
 
-#else
-    TRACELOG(LOG_WARNING, "VAO: Instanced rendering requires GRAPHICS_API_OPENGL_33");
+        // Unbind shader program
+        glUseProgram(0);
+    }
 #endif
 }