diff --git a/src/rlgl.h b/src/rlgl.h index 548709cf..c2473ee9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -128,31 +128,45 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - // This is the maximum amount of elements (quads) per batch - // NOTE: Be careful with text, every letter maps to a quad - #define MAX_BATCH_ELEMENTS 8192 -#elif defined(GRAPHICS_API_OPENGL_ES2) - // We reduce memory sizes for embedded systems (RPI and HTML5) - // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care... - #define MAX_BATCH_ELEMENTS 2048 +// Default internal render batch limits +#ifndef DEFAULT_BATCH_BUFFER_ELEMENTS + #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // This is the maximum amount of elements (quads) per batch + // NOTE: Be careful with text, every letter maps to a quad + #define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 + #elif defined(GRAPHICS_API_OPENGL_ES2) + // We reduce memory sizes for embedded systems (RPI and HTML5) + // NOTE: On HTML5 (emscripten) this is allocated on heap, + // by default it's only 16MB!...just take care... + #define DEFAULT_BATCH_BUFFER_ELEMENTS 2048 + #endif +#endif +#ifndef DEFAULT_BATCH_BUFFERS + #define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) +#endif +#ifndef DEFAULT_BATCH_DRAWCALLS + #define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) #endif -#ifndef MAX_BATCH_BUFFERING - #define MAX_BATCH_BUFFERING 1 // Max number of buffers for batching (multi-buffering) +// Internal Matrix stack +#ifndef MAX_MATRIX_STACK_SIZE + #define MAX_MATRIX_STACK_SIZE 32 // Maximum size of Matrix stack #endif -#define MAX_MATRIX_STACK_SIZE 32 // Max size of Matrix stack -#define MAX_DRAWCALL_REGISTERED 256 // Max draws by state changes (mode, texture) // Shader and material limits -#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct -#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct +#ifndef MAX_SHADER_LOCATIONS + #define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +#endif +#ifndef MAX_MATERIAL_MAPS + #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported +#endif -#ifndef RL_NEAR_CULL_DISTANCE - #define RL_NEAR_CULL_DISTANCE 0.01 // Default near cull distance +// Projection matrix culling +#ifndef RL_CULL_DISTANCE_NEAR + #define RL_CULL_DISTANCE_NEAR 0.01 // Default near cull distance #endif -#ifndef RL_FAR_CULL_DISTANCE - #define RL_FAR_CULL_DISTANCE 1000.0 // Default far cull distance +#ifndef RL_CULL_DISTANCE_FAR + #define RL_CULL_DISTANCE_FAR 1000.0 // Default far cull distance #endif // Texture parameters (equivalent to OpenGL defines) @@ -263,10 +277,6 @@ typedef unsigned char byte; unsigned int *vboId; // OpenGL Vertex Buffer Objects id (7 types of vertex data) } Mesh; - // Shader and material limits - #define MAX_SHADER_LOCATIONS 32 - #define MAX_MATERIAL_MAPS 12 - // Shader type (generic) typedef struct Shader { unsigned int id; // Shader program id @@ -758,36 +768,52 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data //---------------------------------------------------------------------------------- // Dynamic vertex buffers (position + texcoords + colors + indices arrays) -typedef struct DynamicBuffer { - int vCounter; // vertex position counter to process (and draw) from full buffer - int tcCounter; // vertex texcoord counter to process (and draw) from full buffer - int cCounter; // vertex color counter to process (and draw) from full buffer - - float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) - float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) +typedef struct VertexBuffer { + int elementsCount; // Number of elements in the buffer (QUADS) + + int vCounter; // Vertex position counter to process (and draw) from full buffer + int tcCounter; // Vertex texcoord counter to process (and draw) from full buffer + int cCounter; // Vertex color counter to process (and draw) from full buffer + + float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - unsigned int *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad) + unsigned int *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) #elif defined(GRAPHICS_API_OPENGL_ES2) - unsigned short *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad) + unsigned short *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) #endif unsigned int vaoId; // OpenGL Vertex Array Object id unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) -} DynamicBuffer; +} VertexBuffer; // Draw call type +// NOTE: Only texture changes register a new draw, other state-change-related elements are not +// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any +// of those state-change happens (this is done in core module) typedef struct DrawCall { int mode; // Drawing mode: LINES, TRIANGLES, QUADS int vertexCount; // Number of vertex of the draw int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) - //unsigned int vaoId; // Vertex array id to be used on the draw - //unsigned int shaderId; // Shader id to be used on the draw + //unsigned int vaoId; // Vertex array id to be used on the draw + //unsigned int shaderId; // Shader id to be used on the draw unsigned int textureId; // Texture id to be used on the draw //Matrix projection; // Projection matrix for this draw //Matrix modelview; // Modelview matrix for this draw } DrawCall; +// RenderBatch type +typedef struct RenderBatch { + int buffersCount; // Number of vertex buffers (multi-buffering support) + int currentBuffer; // Current buffer tracking in case of multi-buffering + VertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data + + DrawCall *draws; // Draw calls array + int drawsCounter; // Draw calls counter + float currentDepth; // Current depth value for next draw +} RenderBatch; + #if defined(SUPPORT_VR_SIMULATOR) // VR Stereo rendering configuration for simulator typedef struct VrStereoConfig { @@ -801,21 +827,19 @@ typedef struct VrStereoConfig { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) typedef struct rlglData { + RenderBatch *currentBatch; // Current render batch + RenderBatch defaultBatch; // Default internal render batch + struct { int currentMatrixMode; // Current matrix mode Matrix *currentMatrix; // Current matrix pointer Matrix modelview; // Default modelview matrix Matrix projection; // Default projection matrix Matrix transform; // Transform matrix to be used with rlTranslate, rlRotate, rlScale - bool doTransform; // Use transform matrix against vertex (if required) + bool transformRequired; // Require transform matrix application to current draw-call vertex (if required) Matrix stack[MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop int stackCounter; // Matrix stack counter - DynamicBuffer vertexData[MAX_BATCH_BUFFERING];// Default dynamic buffer for elements data - int currentBuffer; // Current buffer tracking, multi-buffering system is supported - DrawCall *draws; // Draw calls array - int drawsCounter; // Draw calls counter - Texture2D shapesTexture; // Texture used on shapes drawing (usually a white) Rectangle shapesTextureRec; // Texture source rectangle used on shapes drawing unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader) @@ -823,7 +847,6 @@ typedef struct rlglData { unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) Shader defaultShader; // Basic shader, support vertex color and diffuse texture Shader currentShader; // Shader to be used on rendering (by default, defaultShader) - float currentDepth; // Current depth value int framebufferWidth; // Default framebuffer width int framebufferHeight; // Default framebuffer height @@ -879,14 +902,16 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; // Entry point poin static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program -static Shader LoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring) -static void SetShaderDefaultLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) -static void UnloadShaderDefault(void); // Unload default shader +static Shader LoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring) +static void SetShaderDefaultLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) +static void UnloadShaderDefault(void); // Unload default shader -static void LoadBuffersDefault(void); // Load default internal buffers -static void UpdateBuffersDefault(void); // Update default internal buffers (VAOs/VBOs) with vertex data -static void DrawBuffersDefault(void); // Draw default internal buffers vertex data -static void UnloadBuffersDefault(void); // Unload default internal buffers vertex data from CPU and GPU +static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements); // Load a render batch system +static void UnloadRenderBatch(RenderBatch batch); // Unload render batch system +static void DrawRenderBatch(RenderBatch *batch); // Draw render batch data (Update->Draw->Reset) +static void SetRenderBatchActive(RenderBatch *batch); // Set the active render batch for rlgl +static void SetRenderBatchDefault(void); // Set default render batch for rlgl +//static bool CheckRenderBatchLimit(RenderBatch batch, int vCount); // Check render batch vertex buffer limits static void GenDrawCube(void); // Generate and draw cube static void GenDrawQuad(void); // Generate and draw quad @@ -958,7 +983,7 @@ void rlPushMatrix(void) if (RLGL.State.currentMatrixMode == RL_MODELVIEW) { - RLGL.State.doTransform = true; + RLGL.State.transformRequired = true; RLGL.State.currentMatrix = &RLGL.State.transform; } @@ -979,7 +1004,7 @@ void rlPopMatrix(void) if ((RLGL.State.stackCounter == 0) && (RLGL.State.currentMatrixMode == RL_MODELVIEW)) { RLGL.State.currentMatrix = &RLGL.State.modelview; - RLGL.State.doTransform = false; + RLGL.State.transformRequired = false; } } @@ -1091,36 +1116,36 @@ void rlBegin(int mode) { // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode != mode) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode != mode) { - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount > 0) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) { - // Make sure current RLGL.State.draws[i].vertexCount is aligned a multiple of 4, + // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_LINES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount : RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4); - else if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_TRIANGLES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4))); + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); - else RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = 0; + else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; - if (rlCheckBufferLimit(RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment)) rlglDraw(); + if (rlCheckBufferLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) rlglDraw(); else { - RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; - RLGL.State.drawsCounter++; + RLGL.currentBatch->drawsCounter++; } } - if (RLGL.State.drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); + if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlglDraw(); - RLGL.State.draws[RLGL.State.drawsCounter - 1].mode = mode; - RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount = 0; - RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId = RLGL.State.defaultTextureId; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode = mode; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = RLGL.State.defaultTextureId; } } @@ -1131,30 +1156,30 @@ void rlEnd(void) // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls // Make sure colors count match vertex count - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter != RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter) + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter) { - int addColors = RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter; + int addColors = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter; for (int i = 0; i < addColors; i++) { - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 4]; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 1] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 3]; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 2] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 2]; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 3] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 1]; - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 4]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 1] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 3]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 2] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 2]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 3] = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter - 1]; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++; } } // Make sure texcoords count match vertex count - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter != RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter) + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter) { - int addTexCoords = RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter; + int addTexCoords = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter; for (int i = 0; i < addTexCoords; i++) { - RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter] = 0.0f; - RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter + 1] = 0.0f; - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = 0.0f; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = 0.0f; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++; } } @@ -1163,11 +1188,11 @@ void rlEnd(void) // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values, // as well as depth buffer bit-depth (16bit or 24bit or 32bit) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) - RLGL.State.currentDepth += (1.0f/20000.0f); + RLGL.currentBatch->currentDepth += (1.0f/20000.0f); // Verify internal buffers limits // NOTE: This check is combined with usage of rlCheckBufferLimit() - if ((RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter) >= (MAX_BATCH_ELEMENTS*4 - 4)) + if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter) >= (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4 - 4)) { // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(), // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call! @@ -1184,40 +1209,40 @@ void rlVertex3f(float x, float y, float z) Vector3 vec = { x, y, z }; // Transform provided vector if required - if (RLGL.State.doTransform) vec = Vector3Transform(vec, RLGL.State.transform); + if (RLGL.State.transformRequired) vec = Vector3Transform(vec, RLGL.State.transform); - // Verify that MAX_BATCH_ELEMENTS limit not reached - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4)) + // Verify that current vertex buffer elements limit has not been reached + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) { - RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter] = vec.x; - RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + 1] = vec.y; - RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + 2] = vec.z; - RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter] = vec.x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 1] = vec.y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 2] = vec.z; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter++; - RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount++; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount++; } - else TRACELOG(LOG_ERROR, "RLGL: Batch elements overflow (MAX_BATCH_ELEMENTS)"); + else TRACELOG(LOG_ERROR, "RLGL: Batch elements overflow"); } // Define one vertex (position) void rlVertex2f(float x, float y) { - rlVertex3f(x, y, RLGL.State.currentDepth); + rlVertex3f(x, y, RLGL.currentBatch->currentDepth); } // Define one vertex (position) void rlVertex2i(int x, int y) { - rlVertex3f((float)x, (float)y, RLGL.State.currentDepth); + rlVertex3f((float)x, (float)y, RLGL.currentBatch->currentDepth); } // Define one vertex (texture coordinate) // NOTE: Texture coordinates are limited to QUADS only void rlTexCoord2f(float x, float y) { - RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter] = x; - RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter + 1] = y; - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++; } // Define one vertex (normal) @@ -1230,11 +1255,11 @@ void rlNormal3f(float x, float y, float z) // Define one vertex (color) void rlColor4ub(byte x, byte y, byte z, byte w) { - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter] = x; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 1] = y; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 2] = z; - RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 3] = w; - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter++; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter] = x; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 1] = y; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 2] = z; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 3] = w; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++; } // Define one vertex (color) @@ -1264,35 +1289,35 @@ void rlEnableTexture(unsigned int id) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId != id) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId != id) { - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount > 0) + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) { - // Make sure current RLGL.State.draws[i].vertexCount is aligned a multiple of 4, + // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // that way, following QUADS drawing will keep aligned with index processing // It implies adding some extra alignment vertex at the end of the draw, // those vertex are not processed but they are considered as an additional offset // for the next set of vertex to be drawn - if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_LINES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount : RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4); - else if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_TRIANGLES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4))); + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); - else RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = 0; + else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; - if (rlCheckBufferLimit(RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment)) rlglDraw(); + if (rlCheckBufferLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) rlglDraw(); else { - RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; - RLGL.State.drawsCounter++; + RLGL.currentBatch->drawsCounter++; } } - if (RLGL.State.drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); + if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlglDraw(); - RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId = id; - RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount = 0; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = id; + RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; } #endif } @@ -1306,7 +1331,7 @@ void rlDisableTexture(void) #else // NOTE: If quads batch limit is reached, // we force a draw call and next batch starts - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter >= (MAX_BATCH_ELEMENTS*4)) rlglDraw(); + if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter >= (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) rlglDraw(); #endif } @@ -1691,33 +1716,14 @@ void rlglInit(int width, int height) RLGL.State.currentShader = RLGL.State.defaultShader; // Init default vertex arrays buffers - LoadBuffersDefault(); - - // Init transformations matrix accumulator - RLGL.State.transform = MatrixIdentity(); + RLGL.defaultBatch = LoadRenderBatch(DEFAULT_BATCH_BUFFERS, DEFAULT_BATCH_BUFFER_ELEMENTS); + RLGL.currentBatch = &RLGL.defaultBatch; - // Init draw calls tracking system - RLGL.State.draws = (DrawCall *)RL_MALLOC(sizeof(DrawCall)*MAX_DRAWCALL_REGISTERED); - - for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++) - { - RLGL.State.draws[i].mode = RL_QUADS; - RLGL.State.draws[i].vertexCount = 0; - RLGL.State.draws[i].vertexAlignment = 0; - //RLGL.State.draws[i].vaoId = 0; - //RLGL.State.draws[i].shaderId = 0; - RLGL.State.draws[i].textureId = RLGL.State.defaultTextureId; - //RLGL.State.draws[i].RLGL.State.projection = MatrixIdentity(); - //RLGL.State.draws[i].RLGL.State.modelview = MatrixIdentity(); - } - - RLGL.State.drawsCounter = 1; // Reset draws counter - RLGL.State.currentDepth = -1.0f; // Reset depth value - - // Init RLGL.State.stack matrices (emulating OpenGL 1.1) + // Init stack matrices (emulating OpenGL 1.1) for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity(); - // Init RLGL.State.projection and RLGL.State.modelview matrices + // Init internal matrices + RLGL.State.transform = MatrixIdentity(); RLGL.State.projection = MatrixIdentity(); RLGL.State.modelview = MatrixIdentity(); RLGL.State.currentMatrix = &RLGL.State.modelview; @@ -1766,13 +1772,12 @@ void rlglInit(int width, int height) void rlglClose(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - UnloadShaderDefault(); // Unload default shader - UnloadBuffersDefault(); // Unload default buffers + UnloadRenderBatch(RLGL.defaultBatch); + + UnloadShaderDefault(); // Unload default shader glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded default texture data from VRAM (GPU)", RLGL.State.defaultTextureId); - - RL_FREE(RLGL.State.draws); #endif } @@ -1780,12 +1785,7 @@ void rlglClose(void) void rlglDraw(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Only process data if we have data to process - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0) - { - UpdateBuffersDefault(); - DrawBuffersDefault(); // NOTE: Stereo rendering is checked inside - } + DrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside #endif } @@ -1796,7 +1796,7 @@ int rlGetVersion(void) return OPENGL_11; #elif defined(GRAPHICS_API_OPENGL_21) #if defined(__APPLE__) - return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX + return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX #else return OPENGL_21; #endif @@ -1812,7 +1812,7 @@ bool rlCheckBufferLimit(int vCount) { bool overflow = false; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + vCount) >= (MAX_BATCH_ELEMENTS*4)) overflow = true; + if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + vCount) >= (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) overflow = true; #endif return overflow; } @@ -3796,8 +3796,7 @@ void EndVrDrawing(void) rlDisableTexture(); // Update and draw render texture fbo with distortion to backbuffer - UpdateBuffersDefault(); - DrawBuffersDefault(); + DrawRenderBatch(RLGL.currentBatch); // Restore RLGL.State.defaultShader RLGL.State.currentShader = RLGL.State.defaultShader; @@ -3859,7 +3858,6 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad unsigned int program = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - GLint success = 0; program = glCreateProgram(); @@ -4056,44 +4054,50 @@ static void UnloadShaderDefault(void) glDeleteProgram(RLGL.State.defaultShader.id); } -// Load default internal buffers -static void LoadBuffersDefault(void) +// Load render batch +static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements) { - // Initialize CPU (RAM) arrays (vertex position, texcoord, color data and indexes) + RenderBatch batch = { 0 }; + + // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) //-------------------------------------------------------------------------------------------- - for (int i = 0; i < MAX_BATCH_BUFFERING; i++) + batch.vertexBuffer = (VertexBuffer *)RL_MALLOC(sizeof(VertexBuffer)*numBuffers); + + for (int i = 0; i < numBuffers; i++) { - RLGL.State.vertexData[i].vertices = (float *)RL_MALLOC(sizeof(float)*3*4*MAX_BATCH_ELEMENTS); // 3 float by vertex, 4 vertex by quad - RLGL.State.vertexData[i].texcoords = (float *)RL_MALLOC(sizeof(float)*2*4*MAX_BATCH_ELEMENTS); // 2 float by texcoord, 4 texcoord by quad - RLGL.State.vertexData[i].colors = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS); // 4 float by color, 4 colors by quad + batch.vertexBuffer[i].elementsCount = bufferElements; + + batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(sizeof(float)*3*4*bufferElements); // 3 float by vertex, 4 vertex by quad + batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(sizeof(float)*2*4*bufferElements); // 2 float by texcoord, 4 texcoord by quad + batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*4*4*bufferElements); // 4 float by color, 4 colors by quad #if defined(GRAPHICS_API_OPENGL_33) - RLGL.State.vertexData[i].indices = (unsigned int *)RL_MALLOC(sizeof(unsigned int)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) + batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(sizeof(unsigned int)*6*bufferElements); // 6 int by quad (indices) #elif defined(GRAPHICS_API_OPENGL_ES2) - RLGL.State.vertexData[i].indices = (unsigned short *)RL_MALLOC(sizeof(unsigned short)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) + batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(sizeof(unsigned short)*6*bufferElements); // 6 int by quad (indices) #endif - for (int j = 0; j < (3*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].vertices[j] = 0.0f; - for (int j = 0; j < (2*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].texcoords[j] = 0.0f; - for (int j = 0; j < (4*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].colors[j] = 0; + for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f; + for (int j = 0; j < (2*4*bufferElements); j++) batch.vertexBuffer[i].texcoords[j] = 0.0f; + for (int j = 0; j < (4*4*bufferElements); j++) batch.vertexBuffer[i].colors[j] = 0; int k = 0; // Indices can be initialized right now - for (int j = 0; j < (6*MAX_BATCH_ELEMENTS); j += 6) + for (int j = 0; j < (6*bufferElements); j += 6) { - RLGL.State.vertexData[i].indices[j] = 4*k; - RLGL.State.vertexData[i].indices[j + 1] = 4*k + 1; - RLGL.State.vertexData[i].indices[j + 2] = 4*k + 2; - RLGL.State.vertexData[i].indices[j + 3] = 4*k; - RLGL.State.vertexData[i].indices[j + 4] = 4*k + 2; - RLGL.State.vertexData[i].indices[j + 5] = 4*k + 3; + batch.vertexBuffer[i].indices[j] = 4*k; + batch.vertexBuffer[i].indices[j + 1] = 4*k + 1; + batch.vertexBuffer[i].indices[j + 2] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 3] = 4*k; + batch.vertexBuffer[i].indices[j + 4] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 5] = 4*k + 3; k++; } - RLGL.State.vertexData[i].vCounter = 0; - RLGL.State.vertexData[i].tcCounter = 0; - RLGL.State.vertexData[i].cCounter = 0; + batch.vertexBuffer[i].vCounter = 0; + batch.vertexBuffer[i].tcCounter = 0; + batch.vertexBuffer[i].cCounter = 0; } TRACELOG(LOG_INFO, "RLGL: Internal vertex buffers initialized successfully in RAM (CPU)"); @@ -4101,79 +4105,103 @@ static void LoadBuffersDefault(void) // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs //-------------------------------------------------------------------------------------------- - for (int i = 0; i < MAX_BATCH_BUFFERING; i++) + for (int i = 0; i < numBuffers; i++) { if (RLGL.ExtSupported.vao) { // Initialize Quads VAO - glGenVertexArrays(1, &RLGL.State.vertexData[i].vaoId); - glBindVertexArray(RLGL.State.vertexData[i].vaoId); + glGenVertexArrays(1, &batch.vertexBuffer[i].vaoId); + glBindVertexArray(batch.vertexBuffer[i].vaoId); } // Quads - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) - glGenBuffers(1, &RLGL.State.vertexData[i].vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].vertices, GL_DYNAMIC_DRAW); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*bufferElements, batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); // Vertex texcoord buffer (shader-location = 1) - glGenBuffers(1, &RLGL.State.vertexData[i].vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].texcoords, GL_DYNAMIC_DRAW); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*bufferElements, batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &RLGL.State.vertexData[i].vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].colors, GL_DYNAMIC_DRAW); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*bufferElements, batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); // Fill index buffer - glGenBuffers(1, &RLGL.State.vertexData[i].vboId[3]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[3]); + glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); #if defined(GRAPHICS_API_OPENGL_33) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].indices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*bufferElements, batch.vertexBuffer[i].indices, GL_STATIC_DRAW); #elif defined(GRAPHICS_API_OPENGL_ES2) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].indices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*bufferElements, batch.vertexBuffer[i].indices, GL_STATIC_DRAW); #endif } - TRACELOG(LOG_INFO, "RLGL: Internal vertex buffers uploaded successfully to VRAM (GPU)"); + TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully"); // Unbind the current VAO if (RLGL.ExtSupported.vao) glBindVertexArray(0); //-------------------------------------------------------------------------------------------- + + // Init draw calls tracking system + //-------------------------------------------------------------------------------------------- + batch.draws = (DrawCall *)RL_MALLOC(sizeof(DrawCall)*DEFAULT_BATCH_DRAWCALLS); + + for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++) + { + batch.draws[i].mode = RL_QUADS; + batch.draws[i].vertexCount = 0; + batch.draws[i].vertexAlignment = 0; + //batch.draws[i].vaoId = 0; + //batch.draws[i].shaderId = 0; + batch.draws[i].textureId = RLGL.State.defaultTextureId; + //batch.draws[i].RLGL.State.projection = MatrixIdentity(); + //batch.draws[i].RLGL.State.modelview = MatrixIdentity(); + } + + batch.drawsCounter = 1; // Reset draws counter + batch.currentDepth = -1.0f; // Reset depth value + //-------------------------------------------------------------------------------------------- + + return batch; } -// Update default internal buffers (VAOs/VBOs) with vertex array data -// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) -// TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) -static void UpdateBuffersDefault(void) +// Draw render batch +// NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer) +static void DrawRenderBatch(RenderBatch *batch) { - // Update vertex buffers data - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0) + // Update batch vertex buffers + //------------------------------------------------------------------------------------------------------------ + // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) + // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) + if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0) { // Activate elements VAO - if (RLGL.ExtSupported.vao) glBindVertexArray(RLGL.State.vertexData[RLGL.State.currentBuffer].vaoId); + if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); // Vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[0]); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].vertices); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].vertices); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer // Texture coordinates buffer - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[1]); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].texcoords); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer // Colors buffer - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[2]); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].colors); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].colors); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer // NOTE: glMapBuffer() causes sync issue. // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. @@ -4183,8 +4211,8 @@ static void UpdateBuffersDefault(void) // Another option: map the buffer object into client's memory // Probably this code could be moved somewhere else... - // RLGL.State.vertexData[RLGL.State.currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - // if (RLGL.State.vertexData[RLGL.State.currentBuffer].vertices) + // batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + // if (batch->vertexBuffer[batch->currentBuffer].vertices) // { // Update vertex data // } @@ -4193,11 +4221,10 @@ static void UpdateBuffersDefault(void) // Unbind the current VAO if (RLGL.ExtSupported.vao) glBindVertexArray(0); } -} - -// Draw default internal buffers vertex data -static void DrawBuffersDefault(void) -{ + //------------------------------------------------------------------------------------------------------------ + + // Draw batch vertex buffers (considering VR stereo if required) + //------------------------------------------------------------------------------------------------------------ Matrix matProjection = RLGL.State.projection; Matrix matModelView = RLGL.State.modelview; @@ -4213,7 +4240,7 @@ static void DrawBuffersDefault(void) #endif // Draw buffers - if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0) + if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0) { // Set current shader and upload current MVP matrix glUseProgram(RLGL.State.currentShader.id); @@ -4233,51 +4260,51 @@ static void DrawBuffersDefault(void) int vertexOffset = 0; - if (RLGL.ExtSupported.vao) glBindVertexArray(RLGL.State.vertexData[RLGL.State.currentBuffer].vaoId); + if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); else { // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]); // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); } glActiveTexture(GL_TEXTURE0); - for (int i = 0; i < RLGL.State.drawsCounter; i++) + for (int i = 0; i < batch->drawsCounter; i++) { - glBindTexture(GL_TEXTURE_2D, RLGL.State.draws[i].textureId); + glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId); // TODO: Find some way to bind additional textures --> Use global texture IDs? Register them on draw[i]? //if (RLGL.State.currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureUnit1_id); } //if (RLGL.State.currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureUnit2_id); } - if ((RLGL.State.draws[i].mode == RL_LINES) || (RLGL.State.draws[i].mode == RL_TRIANGLES)) glDrawArrays(RLGL.State.draws[i].mode, vertexOffset, RLGL.State.draws[i].vertexCount); + if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount); else { #if defined(GRAPHICS_API_OPENGL_33) // We need to define the number of indices to be processed: quadsCount*6 // NOTE: The final parameter tells the GPU the offset in bytes from the // start of the index buffer to the location of the first index to process - glDrawElements(GL_TRIANGLES, RLGL.State.draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); + glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); #elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, RLGL.State.draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*vertexOffset/4*6)); + glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*vertexOffset/4*6)); #endif } - vertexOffset += (RLGL.State.draws[i].vertexCount + RLGL.State.draws[i].vertexAlignment); + vertexOffset += (batch->draws[i].vertexCount + batch->draws[i].vertexAlignment); } if (!RLGL.ExtSupported.vao) @@ -4293,36 +4320,40 @@ static void DrawBuffersDefault(void) glUseProgram(0); // Unbind shader program } - + //------------------------------------------------------------------------------------------------------------ + + // Reset batch buffers + //------------------------------------------------------------------------------------------------------------ // Reset vertex counters for next frame - RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter = 0; - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter = 0; - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter = 0; + batch->vertexBuffer[batch->currentBuffer].vCounter = 0; + batch->vertexBuffer[batch->currentBuffer].tcCounter = 0; + batch->vertexBuffer[batch->currentBuffer].cCounter = 0; // Reset depth for next draw - RLGL.State.currentDepth = -1.0f; + batch->currentDepth = -1.0f; // Restore projection/modelview matrices RLGL.State.projection = matProjection; RLGL.State.modelview = matModelView; - // Reset RLGL.State.draws array - for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++) + // Reset RLGL.currentBatch->draws array + for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++) { - RLGL.State.draws[i].mode = RL_QUADS; - RLGL.State.draws[i].vertexCount = 0; - RLGL.State.draws[i].textureId = RLGL.State.defaultTextureId; + batch->draws[i].mode = RL_QUADS; + batch->draws[i].vertexCount = 0; + batch->draws[i].textureId = RLGL.State.defaultTextureId; } - RLGL.State.drawsCounter = 1; + batch->drawsCounter = 1; + //------------------------------------------------------------------------------------------------------------ - // Change to next buffer in the list - RLGL.State.currentBuffer++; - if (RLGL.State.currentBuffer >= MAX_BATCH_BUFFERING) RLGL.State.currentBuffer = 0; + // Change to next buffer in the list (in case of multi-buffering) + batch->currentBuffer++; + if (batch->currentBuffer >= batch->buffersCount) batch->currentBuffer = 0; } // Unload default internal buffers vertex data from CPU and GPU -static void UnloadBuffersDefault(void) +static void UnloadRenderBatch(RenderBatch batch) { // Unbind everything if (RLGL.ExtSupported.vao) glBindVertexArray(0); @@ -4333,23 +4364,42 @@ static void UnloadBuffersDefault(void) glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - for (int i = 0; i < MAX_BATCH_BUFFERING; i++) + // Unload all vertex buffers data + for (int i = 0; i < batch.buffersCount; i++) { // Delete VBOs from GPU (VRAM) - glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[0]); - glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[1]); - glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[2]); - glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[3]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[1]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[2]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[3]); // Delete VAOs from GPU (VRAM) - if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &RLGL.State.vertexData[i].vaoId); + if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &batch.vertexBuffer[i].vaoId); // Free vertex arrays memory from CPU (RAM) - RL_FREE(RLGL.State.vertexData[i].vertices); - RL_FREE(RLGL.State.vertexData[i].texcoords); - RL_FREE(RLGL.State.vertexData[i].colors); - RL_FREE(RLGL.State.vertexData[i].indices); + RL_FREE(batch.vertexBuffer[i].vertices); + RL_FREE(batch.vertexBuffer[i].texcoords); + RL_FREE(batch.vertexBuffer[i].colors); + RL_FREE(batch.vertexBuffer[i].indices); } + + // Unload arrays + RL_FREE(batch.vertexBuffer); + RL_FREE(batch.draws); +} + +// Set the active render batch for rlgl +static void SetRenderBatchActive(RenderBatch *batch) +{ + DrawRenderBatch(RLGL.currentBatch); + RLGL.currentBatch = batch; +} + +// Set default render batch for rlgl +static void SetRenderBatchDefault(void) +{ + DrawRenderBatch(RLGL.currentBatch); + RLGL.currentBatch = &RLGL.defaultBatch; } // Renders a 1x1 XY quad in NDC