diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index 8ce6a44f..59655714 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -28,7 +28,6 @@ int main() camera.fovy = 45.0f; camera.type = CAMERA_PERSPECTIVE; - Texture2D bill = LoadTexture("resources/billboard.png"); // Our texture billboard Vector3 billPosition = { 0.0f, 2.0f, 0.0f }; // Position where draw billboard @@ -52,11 +51,11 @@ int main() ClearBackground(RAYWHITE); BeginMode3D(camera); - - DrawBillboard(camera, bill, billPosition, 2.0f, WHITE); DrawGrid(10, 1.0f); // Draw a grid - + + DrawBillboard(camera, bill, billPosition, 2.0f, WHITE); + EndMode3D(); DrawFPS(10, 10); diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c new file mode 100644 index 00000000..21fd30d5 --- /dev/null +++ b/examples/models/models_rlgl_solar_system.c @@ -0,0 +1,156 @@ +/******************************************************************************************* +* +* raylib [models] example - rlgl module usage with push/pop matrix transformations +* +* This example has been created using raylib 2.2 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2018 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "rlgl.h" + + +void DrawSphereBasic(Color color); // Draw sphere without any matrix transformation + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + const float sunRadius = 4.0f; + const float earthRadius = 0.6f; + const float earthOrbitRadius = 8.0f; + const float moonRadius = 0.16f; + const float moonOrbitRadius = 1.5f; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl module usage with push/pop matrix transformations"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 16.0f, 16.0f, 16.0f }; + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.fovy = 45.0f; + camera.type = CAMERA_PERSPECTIVE; + + SetCameraMode(camera, CAMERA_FREE); + + float rotationSpeed = 0.2f; // General system rotation speed + + float earthRotation = 0.0f; // Rotation of earth around itself (days) in degrees + float earthOrbitRotation = 0.0f; // Rotation of earth around the Sun (years) in degrees + float moonRotation = 0.0f; // Rotation of moon around itself + float moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + + earthRotation += (5.0f*rotationSpeed); + earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed); + moonRotation += (2.0f*rotationSpeed); + moonOrbitRotation += (8.0f*rotationSpeed); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + rlPushMatrix(); + rlScalef(sunRadius, sunRadius, sunRadius); // Scale Sun + DrawSphereBasic(GOLD); // Draw the Sun + rlPopMatrix(); + + rlPushMatrix(); + rlRotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Earth orbit around Sun + rlTranslatef(earthOrbitRadius, 0.0f, 0.0f); // Translation for Earth orbit + rlRotatef(-earthOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Earth orbit around Sun inverted + + rlPushMatrix(); + rlRotatef(earthRotation, 0.25, 1.0, 0.0); // Rotation for Earth itself + rlScalef(earthRadius, earthRadius, earthRadius);// Scale Earth + + DrawSphereBasic(BLUE); // Draw the Earth + rlPopMatrix(); + + rlRotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth + rlTranslatef(moonOrbitRadius, 0.0f, 0.0f); // Translation for Moon orbit + rlRotatef(-moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth inverted + rlRotatef(moonRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon itself + rlScalef(moonRadius, moonRadius, moonRadius); // Scale Moon + + DrawSphereBasic(LIGHTGRAY); // Draw the Moon + rlPopMatrix(); + + // Some reference elements (not affected by previous matrix transformations) + DrawCircle3D((Vector3){ 0.0f, 0.0f, 0.0f }, earthOrbitRadius, (Vector3){ 1, 0, 0 }, 90.0f, LIME); + DrawGrid(20, 1.0f); + + EndMode3D(); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +// Draw sphere without any matrix transformation +// NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f +void DrawSphereBasic(Color color) +{ + int rings = 16; + int slices = 16; + + rlBegin(RL_TRIANGLES); + rlColor4ub(color.r, color.g, color.b, color.a); + + for (int i = 0; i < (rings + 2); i++) + { + for (int j = 0; j < slices; j++) + { + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + } + } + rlEnd(); +} \ No newline at end of file diff --git a/examples/models/models_rlgl_solar_system.png b/examples/models/models_rlgl_solar_system.png new file mode 100644 index 00000000..576510c4 Binary files /dev/null and b/examples/models/models_rlgl_solar_system.png differ diff --git a/examples/shapes/shapes_basic_shapes.c b/examples/shapes/shapes_basic_shapes.c index 4b7cc261..67eea9d5 100644 --- a/examples/shapes/shapes_basic_shapes.c +++ b/examples/shapes/shapes_basic_shapes.c @@ -39,26 +39,27 @@ int main() DrawText("some basic shapes available on raylib", 20, 20, 20, DARKGRAY); - DrawLine(18, 42, screenWidth - 18, 42, BLACK); - DrawCircle(screenWidth/4, 120, 35, DARKBLUE); - DrawCircleGradient(screenWidth/4, 220, 60, GREEN, SKYBLUE); - DrawCircleLines(screenWidth/4, 340, 80, DARKBLUE); DrawRectangle(screenWidth/4*2 - 60, 100, 120, 60, RED); + DrawRectangleLines(screenWidth/4*2 - 40, 320, 80, 60, ORANGE); // NOTE: Uses QUADS internally, not lines DrawRectangleGradientH(screenWidth/4*2 - 90, 170, 180, 130, MAROON, GOLD); - DrawRectangleLines(screenWidth/4*2 - 40, 320, 80, 60, ORANGE); DrawTriangle((Vector2){screenWidth/4*3, 80}, (Vector2){screenWidth/4*3 - 60, 150}, (Vector2){screenWidth/4*3 + 60, 150}, VIOLET); + DrawPoly((Vector2){screenWidth/4*3, 320}, 6, 80, 0, BROWN); + + DrawCircleGradient(screenWidth/4, 220, 60, GREEN, SKYBLUE); + + // NOTE: We draw all LINES based shapes together to optimize internal drawing, + // this way, all LINES are rendered in a single draw pass + DrawLine(18, 42, screenWidth - 18, 42, BLACK); + DrawCircleLines(screenWidth/4, 340, 80, DARKBLUE); DrawTriangleLines((Vector2){screenWidth/4*3, 160}, (Vector2){screenWidth/4*3 - 20, 230}, (Vector2){screenWidth/4*3 + 20, 230}, DARKBLUE); - - DrawPoly((Vector2){screenWidth/4*3, 320}, 6, 80, 0, BROWN); - EndDrawing(); //---------------------------------------------------------------------------------- } diff --git a/src/config.h b/src/config.h index bec0c5fc..baafb934 100644 --- a/src/config.h +++ b/src/config.h @@ -25,7 +25,7 @@ * **********************************************************************************************/ -#define RAYLIB_VERSION "2.1-dev" +#define RAYLIB_VERSION "2.2-dev" // Edit to control what features Makefile'd raylib is compiled with #if defined(RAYLIB_CMAKE) diff --git a/src/rlgl.h b/src/rlgl.h index f2134e70..5ead869f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -102,18 +102,19 @@ // Defines and Macros //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - // NOTE: This is the maximum amount of lines, triangles and quads per frame, be careful! - #define MAX_LINES_BATCH 8192 - #define MAX_TRIANGLES_BATCH 4096 - #define MAX_QUADS_BATCH 8192 + // 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) - // NOTE: Reduce memory sizes for embedded systems (RPI and HTML5) + // 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_LINES_BATCH 1024 // Critical for wire shapes (sphere) - #define MAX_TRIANGLES_BATCH 2048 // Critical for some shapes (sphere) - #define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad + #define MAX_BATCH_ELEMENTS 2048 #endif +#define MAX_BATCH_BUFFERING 1 // Max number of buffers for batching (multi-buffering) +#define MAX_MATRIX_STACK_SIZE 32 // Max size of Matrix stack +#define MAX_DRAWCALL_REGISTERED 256 // Max draws by state changes (mode, texture) + // Texture parameters (equivalent to OpenGL defines) #define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S #define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T @@ -431,7 +432,7 @@ void rlClearScreenBuffers(void); // Clear used screen buf //------------------------------------------------------------------------------------ void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures) -void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads) +void rlglDraw(void); // Update and draw default internal buffers int rlGetVersion(void); // Returns current OpenGL version bool rlCheckBufferLimit(int type, int vCount); // Check internal buffer overflow for a given number of vertex @@ -593,11 +594,6 @@ int GetPixelDataSize(int width, int height, int format);// Get pixel data size i //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MATRIX_STACK_SIZE 16 // Matrix stack max size -#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes -#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations) - // NOTE: Every vertex are 3 floats (12 bytes) - #ifndef GL_SHADING_LANGUAGE_VERSION #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #endif @@ -692,29 +688,24 @@ typedef struct DynamicBuffer { } DynamicBuffer; // Draw call type -// NOTE: Used to track required draw-calls, organized by texture typedef struct DrawCall { - int vertexCount; - GLuint vaoId; - GLuint textureId; - GLuint shaderId; - - Matrix projection; - Matrix modelview; - - // TODO: Store additional draw state data - //int blendMode; - //Guint fboId; + int mode; // Drawing mode: LINES, TRIANGLES, QUADS + int vertexCount; // Number of vertex of the draw + //GLuint vaoId; // Vertex Array id to be used on the draw + //GLuint shaderId; // Shader id to be used on the draw + GLuint textureId; // Texture id to be used on the draw + //Matrix projection; // Projection matrix for this draw + //Matrix modelview; // Modelview matrix for this draw } DrawCall; #if defined(SUPPORT_VR_SIMULATOR) // VR Stereo rendering configuration for simulator typedef struct VrStereoConfig { - RenderTexture2D stereoFbo; // VR stereo rendering framebuffer - Shader distortionShader; // VR stereo rendering distortion shader - Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports - Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices - Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices + RenderTexture2D stereoFbo; // VR stereo rendering framebuffer + Shader distortionShader; // VR stereo rendering distortion shader + Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports + Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices + Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices } VrStereoConfig; #endif @@ -801,31 +792,28 @@ typedef struct VrStereoConfig { #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -static Matrix stack[MATRIX_STACK_SIZE]; +static Matrix stack[MAX_MATRIX_STACK_SIZE] = { 0 }; static int stackCounter = 0; static Matrix modelview = { 0 }; static Matrix projection = { 0 }; static Matrix *currentMatrix = NULL; static int currentMatrixMode = -1; - -static int currentDrawMode = -1; - static float currentDepth = -1.0f; -static DynamicBuffer lines = { 0 }; // Default dynamic buffer for lines data -static DynamicBuffer triangles = { 0 }; // Default dynamic buffer for triangles data -static DynamicBuffer quads = { 0 }; // Default dynamic buffer for quads data (used to draw textures) +// Default dynamic buffer for elements data +// NOTE: A multi-buffering system is supported +static DynamicBuffer vertexData[MAX_BATCH_BUFFERING] = { 0 }; +static int currentBuffer = 0; + +// Transform matrix to be used with rlTranslate, rlRotate, rlScale +static Matrix transformMatrix = { 0 }; +static bool useTransformMatrix = false; // Default buffers draw calls static DrawCall *draws = NULL; static int drawsCounter = 0; -// Temp vertex buffer to be used with rlTranslate, rlRotate, rlScale -static Vector3 *tempBuffer = NULL; -static int tempBufferCount = 0; -static bool useTempBuffer = false; - // Shaders static unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) static unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) @@ -844,10 +832,10 @@ static bool texCompASTCSupported = false; // ASTC texture compression support #if defined(SUPPORT_VR_SIMULATOR) // VR global variables -static VrStereoConfig vrConfig; // VR stereo configuration for simulator -static bool vrSimulatorReady = false; // VR simulator ready flag -static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag - // NOTE: This flag is useful to render data over stereo image (i.e. FPS) +static VrStereoConfig vrConfig; // VR stereo configuration for simulator +static bool vrSimulatorReady = false; // VR simulator ready flag +static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag + // NOTE: This flag is useful to render data over stereo image (i.e. FPS) #endif // defined(SUPPORT_VR_SIMULATOR) #endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -894,7 +882,7 @@ static Shader LoadShaderDefault(void); // Load default shader (just vertex 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 (lines, triangles, quads) +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 @@ -963,30 +951,36 @@ void rlMatrixMode(int mode) currentMatrixMode = mode; } -// Push the current matrix to stack +// Push the current matrix into stack void rlPushMatrix(void) { - if (stackCounter == MATRIX_STACK_SIZE - 1) + if (stackCounter >= MAX_MATRIX_STACK_SIZE) TraceLog(LOG_ERROR, "Matrix stack overflow"); + + if (currentMatrixMode == RL_MODELVIEW) { - TraceLog(LOG_ERROR, "Stack Buffer Overflow (MAX %i Matrix)", MATRIX_STACK_SIZE); + useTransformMatrix = true; + currentMatrix = &transformMatrix; } stack[stackCounter] = *currentMatrix; - rlLoadIdentity(); // TODO: Review matrix stack logic! stackCounter++; - - if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true; } // Pop lattest inserted matrix from stack void rlPopMatrix(void) -{ +{ if (stackCounter > 0) { Matrix mat = stack[stackCounter - 1]; *currentMatrix = mat; stackCounter--; } + + if ((stackCounter == 0) && (currentMatrixMode == RL_MODELVIEW)) + { + currentMatrix = &modelview; + useTransformMatrix = false; + } } // Reset current matrix to identity matrix @@ -1095,108 +1089,63 @@ void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); } // Initialize drawing mode (how to organize vertex) void rlBegin(int mode) { - // Draw mode can only be RL_LINES, RL_TRIANGLES and RL_QUADS - currentDrawMode = 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 (draws[drawsCounter - 1].mode != mode) + { + if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++; + if (drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); + + draws[drawsCounter - 1].mode = mode; + draws[drawsCounter - 1].vertexCount = 0; + draws[drawsCounter - 1].textureId = whiteTexture; + } } // Finish vertex providing void rlEnd(void) { - if (useTempBuffer) + // Make sure current draws[i].vertexCount is multiple of 4, to align with index processing + // NOTE: It implies adding some extra vertex at the end of the draw, those vertex will be + // processed but are placed in a single point to not result in a fragment output... + // TODO: System could be improved (a bit) just storing every draw alignment value + // and adding it to vertexOffset on drawing... maybe in a future... + int vertexToAlign = draws[drawsCounter - 1].vertexCount%4; + for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1); + + // Make sure vertexCount is the same for vertices, texcoords, colors and normals + // 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 (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].cCounter) { - // NOTE: In this case, *currentMatrix is already transposed because transposing has been applied - // independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1) - // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1 - - // Apply transformation matrix to all temp vertices - for (int i = 0; i < tempBufferCount; i++) tempBuffer[i] = Vector3Transform(tempBuffer[i], *currentMatrix); - - // Deactivate tempBuffer usage to allow rlVertex3f do its job - useTempBuffer = false; - - // Copy all transformed vertices to right VAO - for (int i = 0; i < tempBufferCount; i++) rlVertex3f(tempBuffer[i].x, tempBuffer[i].y, tempBuffer[i].z); + int addColors = vertexData[currentBuffer].vCounter - vertexData[currentBuffer].cCounter; - // Reset temp buffer - tempBufferCount = 0; + for (int i = 0; i < addColors; i++) + { + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter] = vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter - 4]; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 1] = vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter - 3]; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 2] = vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter - 2]; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 3] = vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter - 1]; + vertexData[currentBuffer].cCounter++; + } } - - // Make sure vertexCount is the same for vertices-texcoords-normals-colors - // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls. - switch (currentDrawMode) + + // Make sure texcoords count match vertex count + if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].tcCounter) { - case RL_LINES: - { - if (lines.vCounter != lines.cCounter) - { - int addColors = lines.vCounter - lines.cCounter; - - for (int i = 0; i < addColors; i++) - { - lines.colors[4*lines.cCounter] = lines.colors[4*lines.cCounter - 4]; - lines.colors[4*lines.cCounter + 1] = lines.colors[4*lines.cCounter - 3]; - lines.colors[4*lines.cCounter + 2] = lines.colors[4*lines.cCounter - 2]; - lines.colors[4*lines.cCounter + 3] = lines.colors[4*lines.cCounter - 1]; + int addTexCoords = vertexData[currentBuffer].vCounter - vertexData[currentBuffer].tcCounter; - lines.cCounter++; - } - } - } break; - case RL_TRIANGLES: - { - if (triangles.vCounter != triangles.cCounter) - { - int addColors = triangles.vCounter - triangles.cCounter; - - for (int i = 0; i < addColors; i++) - { - triangles.colors[4*triangles.cCounter] = triangles.colors[4*triangles.cCounter - 4]; - triangles.colors[4*triangles.cCounter + 1] = triangles.colors[4*triangles.cCounter - 3]; - triangles.colors[4*triangles.cCounter + 2] = triangles.colors[4*triangles.cCounter - 2]; - triangles.colors[4*triangles.cCounter + 3] = triangles.colors[4*triangles.cCounter - 1]; - - triangles.cCounter++; - } - } - } break; - case RL_QUADS: + for (int i = 0; i < addTexCoords; i++) { - // Make sure colors count match vertex count - if (quads.vCounter != quads.cCounter) - { - int addColors = quads.vCounter - quads.cCounter; - - for (int i = 0; i < addColors; i++) - { - quads.colors[4*quads.cCounter] = quads.colors[4*quads.cCounter - 4]; - quads.colors[4*quads.cCounter + 1] = quads.colors[4*quads.cCounter - 3]; - quads.colors[4*quads.cCounter + 2] = quads.colors[4*quads.cCounter - 2]; - quads.colors[4*quads.cCounter + 3] = quads.colors[4*quads.cCounter - 1]; - - quads.cCounter++; - } - } - - // Make sure texcoords count match vertex count - if (quads.vCounter != quads.tcCounter) - { - int addTexCoords = quads.vCounter - quads.tcCounter; - - for (int i = 0; i < addTexCoords; i++) - { - quads.texcoords[2*quads.tcCounter] = 0.0f; - quads.texcoords[2*quads.tcCounter + 1] = 0.0f; - - quads.tcCounter++; - } - } - - // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P - - } break; - default: break; + vertexData[currentBuffer].texcoords[2*vertexData[currentBuffer].tcCounter] = 0.0f; + vertexData[currentBuffer].texcoords[2*vertexData[currentBuffer].tcCounter + 1] = 0.0f; + vertexData[currentBuffer].tcCounter++; + } } + // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P + // 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) @@ -1204,84 +1153,36 @@ void rlEnd(void) // Verify internal buffers limits // NOTE: This check is combined with usage of rlCheckBufferLimit() - if ((lines.vCounter/2 >= (MAX_LINES_BATCH - 2)) || - (triangles.vCounter/3 >= (MAX_TRIANGLES_BATCH - 3)) || - (quads.vCounter/4 >= (MAX_QUADS_BATCH - 4))) + if ((vertexData[currentBuffer].vCounter/4) >= (MAX_BATCH_ELEMENTS - 4)) { // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(), // we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call! // Also noted that if we had multiple matrix pushed, it will require "stackCounter" pops before launching the draw - - // TODO: Undoubtely, current rlPushMatrix/rlPopMatrix should be redesigned... or removed... it's not working properly - rlPopMatrix(); rlglDraw(); } } // Define one vertex (position) +// NOTE: Vertex position data is the basic information required for drawing void rlVertex3f(float x, float y, float z) { - // NOTE: Temp buffer is processed and resetted at rlEnd() - // Between rlBegin() and rlEnd() can not be more than TEMP_VERTEX_BUFFER_SIZE rlVertex3f() calls - if (useTempBuffer && (tempBufferCount < TEMP_VERTEX_BUFFER_SIZE)) - { - tempBuffer[tempBufferCount].x = x; - tempBuffer[tempBufferCount].y = y; - tempBuffer[tempBufferCount].z = z; - tempBufferCount++; - } - else + Vector3 vec = { x, y, z }; + + // Transform provided vector if required + if (useTransformMatrix) vec = Vector3Transform(vec, transformMatrix); + + // Verify that MAX_BATCH_ELEMENTS limit not reached + if (vertexData[currentBuffer].vCounter/4 < MAX_BATCH_ELEMENTS) { - switch (currentDrawMode) - { - case RL_LINES: - { - // Verify that MAX_LINES_BATCH limit not reached - if (lines.vCounter/2 < MAX_LINES_BATCH) - { - lines.vertices[3*lines.vCounter] = x; - lines.vertices[3*lines.vCounter + 1] = y; - lines.vertices[3*lines.vCounter + 2] = z; - - lines.vCounter++; - } - else TraceLog(LOG_ERROR, "MAX_LINES_BATCH overflow"); - - } break; - case RL_TRIANGLES: - { - // Verify that MAX_TRIANGLES_BATCH limit not reached - if (triangles.vCounter/3 < MAX_TRIANGLES_BATCH) - { - triangles.vertices[3*triangles.vCounter] = x; - triangles.vertices[3*triangles.vCounter + 1] = y; - triangles.vertices[3*triangles.vCounter + 2] = z; - - triangles.vCounter++; - } - else TraceLog(LOG_ERROR, "MAX_TRIANGLES_BATCH overflow"); - - } break; - case RL_QUADS: - { - // Verify that MAX_QUADS_BATCH limit not reached - if (quads.vCounter/4 < MAX_QUADS_BATCH) - { - quads.vertices[3*quads.vCounter] = x; - quads.vertices[3*quads.vCounter + 1] = y; - quads.vertices[3*quads.vCounter + 2] = z; - - quads.vCounter++; + vertexData[currentBuffer].vertices[3*vertexData[currentBuffer].vCounter] = vec.x; + vertexData[currentBuffer].vertices[3*vertexData[currentBuffer].vCounter + 1] = vec.y; + vertexData[currentBuffer].vertices[3*vertexData[currentBuffer].vCounter + 2] = vec.z; + vertexData[currentBuffer].vCounter++; - draws[drawsCounter - 1].vertexCount++; - } - else TraceLog(LOG_ERROR, "MAX_QUADS_BATCH overflow"); - - } break; - default: break; - } + draws[drawsCounter - 1].vertexCount++; } + else TraceLog(LOG_ERROR, "MAX_BATCH_ELEMENTS overflow"); } // Define one vertex (position) @@ -1300,13 +1201,9 @@ void rlVertex2i(int x, int y) // NOTE: Texture coordinates are limited to QUADS only void rlTexCoord2f(float x, float y) { - if (currentDrawMode == RL_QUADS) - { - quads.texcoords[2*quads.tcCounter] = x; - quads.texcoords[2*quads.tcCounter + 1] = y; - - quads.tcCounter++; - } + vertexData[currentBuffer].texcoords[2*vertexData[currentBuffer].tcCounter] = x; + vertexData[currentBuffer].texcoords[2*vertexData[currentBuffer].tcCounter + 1] = y; + vertexData[currentBuffer].tcCounter++; } // Define one vertex (normal) @@ -1319,40 +1216,11 @@ void rlNormal3f(float x, float y, float z) // Define one vertex (color) void rlColor4ub(byte x, byte y, byte z, byte w) { - switch (currentDrawMode) - { - case RL_LINES: - { - lines.colors[4*lines.cCounter] = x; - lines.colors[4*lines.cCounter + 1] = y; - lines.colors[4*lines.cCounter + 2] = z; - lines.colors[4*lines.cCounter + 3] = w; - - lines.cCounter++; - - } break; - case RL_TRIANGLES: - { - triangles.colors[4*triangles.cCounter] = x; - triangles.colors[4*triangles.cCounter + 1] = y; - triangles.colors[4*triangles.cCounter + 2] = z; - triangles.colors[4*triangles.cCounter + 3] = w; - - triangles.cCounter++; - - } break; - case RL_QUADS: - { - quads.colors[4*quads.cCounter] = x; - quads.colors[4*quads.cCounter + 1] = y; - quads.colors[4*quads.cCounter + 2] = z; - quads.colors[4*quads.cCounter + 3] = w; - - quads.cCounter++; - - } break; - default: break; - } + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter] = x; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 1] = y; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 2] = z; + vertexData[currentBuffer].colors[4*vertexData[currentBuffer].cCounter + 3] = w; + vertexData[currentBuffer].cCounter++; } // Define one vertex (color) @@ -1385,8 +1253,7 @@ void rlEnableTexture(unsigned int id) if (draws[drawsCounter - 1].textureId != id) { if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++; - - if (drawsCounter >= MAX_DRAWS_BY_TEXTURE) rlglDraw(); + if (drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw(); draws[drawsCounter - 1].textureId = id; draws[drawsCounter - 1].vertexCount = 0; @@ -1403,7 +1270,7 @@ void rlDisableTexture(void) #else // NOTE: If quads batch limit is reached, // we force a draw call and next batch starts - if (quads.vCounter/4 >= MAX_QUADS_BATCH) rlglDraw(); + if (vertexData[currentBuffer].vCounter/4 >= MAX_BATCH_ELEMENTS) rlglDraw(); #endif } @@ -1747,7 +1614,6 @@ void rlglInit(int width, int height) // Init default white texture unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) - whiteTexture = rlLoadTexture(pixels, 1, 1, UNCOMPRESSED_R8G8B8A8, 1); if (whiteTexture != 0) TraceLog(LOG_INFO, "[TEX ID %i] Base white texture loaded successfully", whiteTexture); @@ -1757,34 +1623,30 @@ void rlglInit(int width, int height) defaultShader = LoadShaderDefault(); currentShader = defaultShader; - // Init default vertex arrays buffers (lines, triangles, quads) + // Init default vertex arrays buffers LoadBuffersDefault(); - - // Init temp vertex buffer, used when transformation required (translate, rotate, scale) - tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE); - - for (int i = 0; i < TEMP_VERTEX_BUFFER_SIZE; i++) tempBuffer[i] = Vector3Zero(); + + // Init transformations matrix accumulator + transformMatrix = MatrixIdentity(); // Init draw calls tracking system - draws = (DrawCall *)malloc(sizeof(DrawCall)*MAX_DRAWS_BY_TEXTURE); + draws = (DrawCall *)malloc(sizeof(DrawCall)*MAX_DRAWCALL_REGISTERED); - for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++) + for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++) { + draws[i].mode = RL_QUADS; draws[i].vertexCount = 0; - draws[i].vaoId = 0; - draws[i].shaderId = 0; - draws[i].textureId = 0; - - draws[i].projection = MatrixIdentity(); - draws[i].modelview = MatrixIdentity(); + //draws[i].vaoId = 0; + //draws[i].shaderId = 0; + draws[i].textureId = whiteTexture; + //draws[i].projection = MatrixIdentity(); + //draws[i].modelview = MatrixIdentity(); } drawsCounter = 1; - draws[0].textureId = whiteTexture; // Set default draw texture id - currentDrawMode = RL_TRIANGLES; // Set default draw mode // Init internal matrix stack (emulating OpenGL 1.1) - for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); + for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); // Init internal projection and modelview matrices projection = MatrixIdentity(); @@ -1832,24 +1694,19 @@ void rlglClose(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UnloadShaderDefault(); // Unload default shader - UnloadBuffersDefault(); // Unload default buffers (lines, triangles, quads) + UnloadBuffersDefault(); // Unload default buffers glDeleteTextures(1, &whiteTexture); // Unload default texture TraceLog(LOG_INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); free(draws); - free(tempBuffer); #endif } -// Drawing batches: triangles, quads, lines +// Update and draw internal buffers void rlglDraw(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: In a future version, models could be stored in a stack... - //for (int i = 0; i < modelsCount; i++) rlDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform); - - // NOTE: Default buffers upload and draw UpdateBuffersDefault(); DrawBuffersDefault(); // NOTE: Stereo rendering is checked inside #endif @@ -1862,7 +1719,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 @@ -1878,13 +1735,7 @@ bool rlCheckBufferLimit(int type, int vCount) { bool overflow = false; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - switch (type) - { - case RL_LINES: overflow = ((lines.vCounter + vCount)/2 >= MAX_LINES_BATCH); break; - case RL_TRIANGLES: overflow = ((triangles.vCounter + vCount)/3 >= MAX_TRIANGLES_BATCH); break; - case RL_QUADS: overflow = ((quads.vCounter + vCount)/4 >= MAX_QUADS_BATCH); break; - default: break; - } + if ((vertexData[currentBuffer].vCounter + vCount)/4 >= MAX_BATCH_ELEMENTS) overflow = true; #endif return overflow; } @@ -2098,6 +1949,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi } // Update already loaded texture in GPU with new data +// TODO: We don't know safely if internal texture format is the expected one... void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data) { glBindTexture(GL_TEXTURE_2D, id); @@ -2881,25 +2733,6 @@ void *rlReadTexturePixels(Texture2D texture) return pixels; } -/* -// TODO: Record draw calls to be processed in batch -// NOTE: Global state must be kept -void rlRecordDraw(void) -{ - // TODO: Before adding a new draw, check if anything changed from last stored draw -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - draws[drawsCounter].vertexCount = currentState.vertexCount; - draws[drawsCounter].vaoId = currentState.vaoId; // lines.id, trangles.id, quads.id? - draws[drawsCounter].textureId = currentState.textureId; // whiteTexture? - draws[drawsCounter].shaderId = currentState.shaderId; // defaultShader.id - draws[drawsCounter].projection = projection; - draws[drawsCounter].modelview = modelview; - - drawsCounter++; -#endif -} -*/ - //---------------------------------------------------------------------------------- // Module Functions Definition - Shaders Functions // NOTE: Those functions are exposed directly to the user in raylib.h @@ -2934,12 +2767,12 @@ Shader GetShaderDefault(void) // NOTE: text chars array should be freed manually char *LoadText(const char *fileName) { - FILE *textFile; + FILE *textFile = NULL; char *text = NULL; if (fileName != NULL) { - textFile = fopen(fileName,"r"); + textFile = fopen(fileName,"rt"); if (textFile != NULL) { @@ -2950,7 +2783,8 @@ char *LoadText(const char *fileName) if (size > 0) { text = (char *)malloc(sizeof(char)*(size + 1)); - fread(text, sizeof(char), size, textFile); + int count = fread(text, sizeof(char), size, textFile); + text[count] = '\0'; } fclose(textFile); @@ -3833,7 +3667,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad // Load default shader (just vertex positioning and texture coloring) -// NOTE: This shader program is used for batch buffers (lines, triangles, quads) +// NOTE: This shader program is used for internal buffers static Shader LoadShaderDefault(void) { Shader shader = { 0 }; @@ -3974,171 +3808,93 @@ static void UnloadShaderDefault(void) glDeleteProgram(defaultShader.id); } -// Load default internal buffers (lines, triangles, quads) +// Load default internal buffers static void LoadBuffersDefault(void) { - // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads) + // Initialize CPU (RAM) arrays (vertex position, texcoord, color data and indexes) //-------------------------------------------------------------------------------------------- - - // Lines - Initialize arrays (vertex position and color data) - lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line - lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line - lines.texcoords = NULL; - lines.indices = NULL; - - for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0f; - for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0; - - lines.vCounter = 0; - lines.cCounter = 0; - lines.tcCounter = 0; - - // Triangles - Initialize arrays (vertex position and color data) - triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle - triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle - triangles.texcoords = NULL; - triangles.indices = NULL; - - for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0f; - for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0; - - triangles.vCounter = 0; - triangles.cCounter = 0; - triangles.tcCounter = 0; - - // Quads - Initialize arrays (vertex position, texcoord, color data and indexes) - quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad - quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad - quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad + for (int i = 0; i < MAX_BATCH_BUFFERING; i++) + { + vertexData[i].vertices = (float *)malloc(sizeof(float)*3*4*MAX_BATCH_ELEMENTS); // 3 float by vertex, 4 vertex by quad + vertexData[i].texcoords = (float *)malloc(sizeof(float)*2*4*MAX_BATCH_ELEMENTS); // 2 float by texcoord, 4 texcoord by quad + vertexData[i].colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS); // 4 float by color, 4 colors by quad #if defined(GRAPHICS_API_OPENGL_33) - quads.indices = (unsigned int *)malloc(sizeof(unsigned int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) + vertexData[i].indices = (unsigned int *)malloc(sizeof(unsigned int)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) #elif defined(GRAPHICS_API_OPENGL_ES2) - quads.indices = (unsigned short *)malloc(sizeof(unsigned short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) + vertexData[i].indices = (unsigned short *)malloc(sizeof(unsigned short)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices) #endif - for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f; - for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0f; - for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0; + for (int j = 0; j < (3*4*MAX_BATCH_ELEMENTS); j++) vertexData[i].vertices[j] = 0.0f; + for (int j = 0; j < (2*4*MAX_BATCH_ELEMENTS); j++) vertexData[i].texcoords[j] = 0.0f; + for (int j = 0; j < (4*4*MAX_BATCH_ELEMENTS); j++) vertexData[i].colors[j] = 0; - int k = 0; + int k = 0; - // Indices can be initialized right now - for (int i = 0; i < (6*MAX_QUADS_BATCH); i+=6) - { - quads.indices[i] = 4*k; - quads.indices[i+1] = 4*k+1; - quads.indices[i+2] = 4*k+2; - quads.indices[i+3] = 4*k; - quads.indices[i+4] = 4*k+2; - quads.indices[i+5] = 4*k+3; - - k++; - } + // Indices can be initialized right now + for (int j = 0; j < (6*MAX_BATCH_ELEMENTS); j += 6) + { + vertexData[i].indices[j] = 4*k; + vertexData[i].indices[j + 1] = 4*k + 1; + vertexData[i].indices[j + 2] = 4*k + 2; + vertexData[i].indices[j + 3] = 4*k; + vertexData[i].indices[j + 4] = 4*k + 2; + vertexData[i].indices[j + 5] = 4*k + 3; + + k++; + } - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; + vertexData[i].vCounter = 0; + vertexData[i].tcCounter = 0; + vertexData[i].cCounter = 0; + } - TraceLog(LOG_INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)"); + TraceLog(LOG_INFO, "Internal buffers initialized successfully (CPU)"); //-------------------------------------------------------------------------------------------- - // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads) - // NOTE: Default buffers are linked to use currentShader (defaultShader) + // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs //-------------------------------------------------------------------------------------------- - - // Upload and link lines vertex buffers - if (vaoSupported) - { - // Initialize Lines VAO - glGenVertexArrays(1, &lines.vaoId); - glBindVertexArray(lines.vaoId); - } - - // Lines - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(2, &lines.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(2, &lines.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", lines.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", lines.vboId[0], lines.vboId[1]); - - // Upload and link triangles vertex buffers - if (vaoSupported) + for (int i = 0; i < MAX_BATCH_BUFFERING; i++) { - // Initialize Triangles VAO - glGenVertexArrays(1, &triangles.vaoId); - glBindVertexArray(triangles.vaoId); - } - - // Triangles - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(1, &triangles.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &triangles.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", triangles.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (triangles)", triangles.vboId[0], triangles.vboId[1]); - - // Upload and link quads vertex buffers - if (vaoSupported) - { - // Initialize Quads VAO - glGenVertexArrays(1, &quads.vaoId); - glBindVertexArray(quads.vaoId); - } + if (vaoSupported) + { + // Initialize Quads VAO + glGenVertexArrays(1, &vertexData[i].vaoId); + glBindVertexArray(vertexData[i].vaoId); + } - // Quads - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(1, &quads.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex texcoord buffer (shader-location = 1) - glGenBuffers(1, &quads.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_TEXCOORD01]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &quads.vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - // Fill index buffer - glGenBuffers(1, &quads.vboId[3]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); + // Quads - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) + glGenBuffers(1, &vertexData[i].vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[i].vboId[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, vertexData[i].vertices, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); + glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); + + // Vertex texcoord buffer (shader-location = 1) + glGenBuffers(1, &vertexData[i].vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[i].vboId[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, vertexData[i].texcoords, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_TEXCOORD01]); + glVertexAttribPointer(currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); + + // Vertex color buffer (shader-location = 3) + glGenBuffers(1, &vertexData[i].vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[i].vboId[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS, vertexData[i].colors, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); + glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + + // Fill index buffer + glGenBuffers(1, &vertexData[i].vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexData[i].vboId[3]); #if defined(GRAPHICS_API_OPENGL_33) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_BATCH_ELEMENTS, vertexData[i].indices, GL_STATIC_DRAW); #elif defined(GRAPHICS_API_OPENGL_ES2) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, vertexData[i].indices, GL_STATIC_DRAW); #endif - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", quads.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quads.vboId[0], quads.vboId[1], quads.vboId[2], quads.vboId[3]); + } + + TraceLog(LOG_INFO, "Internal buffers uploaded successfully (GPU)"); // Unbind the current VAO if (vaoSupported) glBindVertexArray(0); @@ -4150,74 +3906,48 @@ static void LoadBuffersDefault(void) // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) static void UpdateBuffersDefault(void) { - // Update lines vertex buffers - if (lines.vCounter > 0) - { - // Activate Lines VAO - if (vaoSupported) glBindVertexArray(lines.vaoId); - - // Lines - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*lines.vCounter, lines.vertices); // target - offset (in bytes) - size (in bytes) - data pointer - - // Lines - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*lines.cCounter, lines.colors); - } - - // Update triangles vertex buffers - if (triangles.vCounter > 0) - { - // Activate Triangles VAO - if (vaoSupported) glBindVertexArray(triangles.vaoId); - - // Triangles - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*triangles.vCounter, triangles.vertices); - - // Triangles - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*triangles.cCounter, triangles.colors); - } - - // Update quads vertex buffers - if (quads.vCounter > 0) + // Update vertex buffers data + if (vertexData[currentBuffer].vCounter > 0) { - // Activate Quads VAO - if (vaoSupported) glBindVertexArray(quads.vaoId); - - // Quads - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices); - - // Quads - texture coordinates buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords); - - // Quads - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*quads.vCounter, quads.colors); - - // Another option would be using buffer mapping... - //quads.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - // Now we can modify vertices - //glUnmapBuffer(GL_ARRAY_BUFFER); + // Activate elements VAO + if (vaoSupported) glBindVertexArray(vertexData[currentBuffer].vaoId); + + // Vertex positions buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].vertices); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer + + // Texture coordinates buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[1]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].texcoords); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer + + // Colors buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[2]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].colors); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, vertexData[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. + // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer(). + // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new + // allocated pointer immediately even if GPU is still working with the previous data. + + // Another option: map the buffer object into client's memory + // Probably this code could be moved somewhere else... + // vertexData[currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + // if(vertexData[currentBuffer].vertices) + // { + // Update vertex data + // } + // glUnmapBuffer(GL_ARRAY_BUFFER); + + // Unbind the current VAO + if (vaoSupported) glBindVertexArray(0); } - //-------------------------------------------------------------- - - // Unbind the current VAO - if (vaoSupported) glBindVertexArray(0); } // Draw default internal buffers vertex data -// NOTE: We draw in this order: lines, triangles, quads static void DrawBuffersDefault(void) { Matrix matProjection = projection; @@ -4230,13 +3960,14 @@ static void DrawBuffersDefault(void) for (int eye = 0; eye < eyesCount; eye++) { - #if defined(SUPPORT_VR_SIMULATOR) +#if defined(SUPPORT_VR_SIMULATOR) if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); - #endif +#endif - // Set current shader and upload current MVP matrix - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) + // Draw quads buffers + if (vertexData[currentBuffer].vCounter > 0) { + // Set current shader and upload current MVP matrix glUseProgram(currentShader.id); // Create modelview-projection matrix @@ -4247,117 +3978,50 @@ static void DrawBuffersDefault(void) glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0); // NOTE: Additional map textures not considered for default buffers drawing - } - - // Draw lines buffers - if (lines.vCounter > 0) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, whiteTexture); + + int vertexOffset = 0; - if (vaoSupported) - { - glBindVertexArray(lines.vaoId); - } + if (vaoSupported) glBindVertexArray(vertexData[currentBuffer].vaoId); else { // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - } - - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - // Draw triangles buffers - if (triangles.vCounter > 0) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(triangles.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - } - - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - // Draw quads buffers - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; - - if (vaoSupported) - { - glBindVertexArray(quads.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[0]); glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[1]); glVertexAttribPointer(currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_TEXCOORD01]); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[2]); glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexData[currentBuffer].vboId[3]); } + glActiveTexture(GL_TEXTURE0); + for (int i = 0; i < drawsCounter; i++) { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads*6 index by Quad - - //TraceLog(LOG_DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - // 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 - #if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); - #elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); - #endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(LOG_INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! + if ((draws[i].mode == RL_LINES) || (draws[i].mode == RL_TRIANGLES)) glDrawArrays(draws[i].mode, vertexOffset, 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, draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); +#elif defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); +#endif + } - indicesOffset += draws[i].vertexCount/4*6; + vertexOffset += draws[i].vertexCount; } if (!vaoSupported) @@ -4375,13 +4039,9 @@ static void DrawBuffersDefault(void) } // Reset vertex counters for next frame - lines.vCounter = 0; - lines.cCounter = 0; - triangles.vCounter = 0; - triangles.cCounter = 0; - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; + vertexData[currentBuffer].vCounter = 0; + vertexData[currentBuffer].tcCounter = 0; + vertexData[currentBuffer].cCounter = 0; // Reset depth for next draw currentDepth = -1.0f; @@ -4391,9 +4051,14 @@ static void DrawBuffersDefault(void) modelview = matModelView; // Reset draws counter - drawsCounter = 1; - draws[0].textureId = whiteTexture; + draws[0].mode = RL_QUADS; draws[0].vertexCount = 0; + draws[0].textureId = whiteTexture; + drawsCounter = 1; + + // Change to next buffer in the list + currentBuffer++; + if (currentBuffer >= MAX_BATCH_BUFFERING) currentBuffer = 0; } // Unload default internal buffers vertex data from CPU and GPU @@ -4408,35 +4073,23 @@ static void UnloadBuffersDefault(void) glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - // Delete VBOs from GPU (VRAM) - glDeleteBuffers(1, &lines.vboId[0]); - glDeleteBuffers(1, &lines.vboId[1]); - glDeleteBuffers(1, &triangles.vboId[0]); - glDeleteBuffers(1, &triangles.vboId[1]); - glDeleteBuffers(1, &quads.vboId[0]); - glDeleteBuffers(1, &quads.vboId[1]); - glDeleteBuffers(1, &quads.vboId[2]); - glDeleteBuffers(1, &quads.vboId[3]); - - if (vaoSupported) + for (int i = 0; i < MAX_BATCH_BUFFERING; i++) { - // Delete VAOs from GPU (VRAM) - glDeleteVertexArrays(1, &lines.vaoId); - glDeleteVertexArrays(1, &triangles.vaoId); - glDeleteVertexArrays(1, &quads.vaoId); - } + // Delete VBOs from GPU (VRAM) + glDeleteBuffers(1, &vertexData[i].vboId[0]); + glDeleteBuffers(1, &vertexData[i].vboId[1]); + glDeleteBuffers(1, &vertexData[i].vboId[2]); + glDeleteBuffers(1, &vertexData[i].vboId[3]); - // Free vertex arrays memory from CPU (RAM) - free(lines.vertices); - free(lines.colors); - - free(triangles.vertices); - free(triangles.colors); + // Delete VAOs from GPU (VRAM) + if (vaoSupported) glDeleteVertexArrays(1, &vertexData[i].vaoId); - free(quads.vertices); - free(quads.texcoords); - free(quads.colors); - free(quads.indices); + // Free vertex arrays memory from CPU (RAM) + free(vertexData[i].vertices); + free(vertexData[i].texcoords); + free(vertexData[i].colors); + free(vertexData[i].indices); + } } // Renders a 1x1 XY quad in NDC