1 /**********************************************************************************************
2 *
3 * rlgl v3.7 - raylib OpenGL abstraction layer
4 *
5 * rlgl is a wrapper for multiple OpenGL versions (1.1, 2.1, 3.3 Core, ES 2.0) to
6 * pseudo-OpenGL 1.1 style functions (rlVertex, rlTranslate, rlRotate...).
7 *
8 * When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal
9 * VBO buffers (and VAOs if available). It requires calling 3 functions:
10 * rlglInit() - Initialize internal buffers and auxiliary resources
11 * rlglClose() - De-initialize internal buffers data and other auxiliar resources
12 *
13 * CONFIGURATION:
14 *
15 * #define GRAPHICS_API_OPENGL_11
16 * #define GRAPHICS_API_OPENGL_21
17 * #define GRAPHICS_API_OPENGL_33
18 * #define GRAPHICS_API_OPENGL_ES2
19 * Use selected OpenGL graphics backend, should be supported by platform
20 * Those preprocessor defines are only used on rlgl module, if OpenGL version is
21 * required by any other module, use rlGetVersion() to check it
22 *
23 * #define RLGL_IMPLEMENTATION
24 * Generates the implementation of the library into the included file.
25 * If not defined, the library is in header only mode and can be included in other headers
26 * or source files without problems. But only ONE file should hold the implementation.
27 *
28 * #define RLGL_STANDALONE
29 * Use rlgl as standalone library (no raylib dependency)
30 *
31 * #define SUPPORT_GL_DETAILS_INFO
32 * Show OpenGL extensions and capabilities detailed logs on init
33 *
34 * DEPENDENCIES:
35 * raymath - 3D math functionality (Vector3, Matrix, Quaternion)
36 * GLAD - OpenGL extensions loading (OpenGL 3.3 Core only)
37 *
38 *
39 * LICENSE: zlib/libpng
40 *
41 * Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
42 *
43 * This software is provided "as-is", without any express or implied warranty. In no event
44 * will the authors be held liable for any damages arising from the use of this software.
45 *
46 * Permission is granted to anyone to use this software for any purpose, including commercial
47 * applications, and to alter it and redistribute it freely, subject to the following restrictions:
48 *
49 * 1. The origin of this software must not be misrepresented; you must not claim that you
50 * wrote the original software. If you use this software in a product, an acknowledgment
51 * in the product documentation would be appreciated but is not required.
52 *
53 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
54 * as being the original software.
55 *
56 * 3. This notice may not be removed or altered from any source distribution.
57 *
58 **********************************************************************************************/
59
60 #ifndef RLGL_H
61 #define RLGL_H
62
63 #if defined(RLGL_STANDALONE)
64 #define RAYMATH_STANDALONE
65 #define RAYMATH_HEADER_ONLY
66
67 #define RLAPI // We are building or using rlgl as a static library (or Linux shared library)
68
69 #if defined(_WIN32)
70 #if defined(BUILD_LIBTYPE_SHARED)
71 #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
72 #elif defined(USE_LIBTYPE_SHARED)
73 #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
74 #endif
75 #endif
76
77 // Support TRACELOG macros
78 #if !defined(TRACELOG)
79 #define TRACELOG(level, ...) (void)0
80 #define TRACELOGD(...) (void)0
81 #endif
82
83 // Allow custom memory allocators
84 #ifndef RL_MALLOC
85 #define RL_MALLOC(sz) malloc(sz)
86 #endif
87 #ifndef RL_CALLOC
88 #define RL_CALLOC(n,sz) calloc(n,sz)
89 #endif
90 #ifndef RL_REALLOC
91 #define RL_REALLOC(n,sz) realloc(n,sz)
92 #endif
93 #ifndef RL_FREE
94 #define RL_FREE(p) free(p)
95 #endif
96 #else
97 #include "raylib.h" // Required for: Shader, Texture2D
98 #endif
99
100 #include "raymath.h" // Required for: Vector3, Matrix
101
102 // Security check in case no GRAPHICS_API_OPENGL_* defined
103 #if !defined(GRAPHICS_API_OPENGL_11) && \
104 !defined(GRAPHICS_API_OPENGL_21) && \
105 !defined(GRAPHICS_API_OPENGL_33) && \
106 !defined(GRAPHICS_API_OPENGL_ES2)
107 #define GRAPHICS_API_OPENGL_33
108 #endif
109
110 // Security check in case multiple GRAPHICS_API_OPENGL_* defined
111 #if defined(GRAPHICS_API_OPENGL_11)
112 #if defined(GRAPHICS_API_OPENGL_21)
113 #undef GRAPHICS_API_OPENGL_21
114 #endif
115 #if defined(GRAPHICS_API_OPENGL_33)
116 #undef GRAPHICS_API_OPENGL_33
117 #endif
118 #if defined(GRAPHICS_API_OPENGL_ES2)
119 #undef GRAPHICS_API_OPENGL_ES2
120 #endif
121 #endif
122
123 // OpenGL 2.1 uses most of OpenGL 3.3 Core functionality
124 // WARNING: Specific parts are checked with #if defines
125 #if defined(GRAPHICS_API_OPENGL_21)
126 #define GRAPHICS_API_OPENGL_33
127 #endif
128
129 #define SUPPORT_RENDER_TEXTURES_HINT
130
131 //----------------------------------------------------------------------------------
132 // Defines and Macros
133 //----------------------------------------------------------------------------------
134 // Default internal render batch limits
135 #ifndef DEFAULT_BATCH_BUFFER_ELEMENTS
136 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
137 // This is the maximum amount of elements (quads) per batch
138 // NOTE: Be careful with text, every letter maps to a quad
139 #define DEFAULT_BATCH_BUFFER_ELEMENTS 8192
140 #endif
141 #if defined(GRAPHICS_API_OPENGL_ES2)
142 // We reduce memory sizes for embedded systems (RPI and HTML5)
143 // NOTE: On HTML5 (emscripten) this is allocated on heap,
144 // by default it's only 16MB!...just take care...
145 #define DEFAULT_BATCH_BUFFER_ELEMENTS 2048
146 #endif
147 #endif
148 #ifndef DEFAULT_BATCH_BUFFERS
149 #define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
150 #endif
151 #ifndef DEFAULT_BATCH_DRAWCALLS
152 #define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
153 #endif
154 #ifndef MAX_BATCH_ACTIVE_TEXTURES
155 #define MAX_BATCH_ACTIVE_TEXTURES 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
156 #endif
157
158 // Internal Matrix stack
159 #ifndef MAX_MATRIX_STACK_SIZE
160 #define MAX_MATRIX_STACK_SIZE 32 // Maximum size of Matrix stack
161 #endif
162
163 // Vertex buffers id limit
164 #ifndef MAX_MESH_VERTEX_BUFFERS
165 #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
166 #endif
167
168 // Shader and material limits
169 #ifndef MAX_SHADER_LOCATIONS
170 #define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
171 #endif
172 #ifndef MAX_MATERIAL_MAPS
173 #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
174 #endif
175
176 // Projection matrix culling
177 #ifndef RL_CULL_DISTANCE_NEAR
178 #define RL_CULL_DISTANCE_NEAR 0.01 // Default near cull distance
179 #endif
180 #ifndef RL_CULL_DISTANCE_FAR
181 #define RL_CULL_DISTANCE_FAR 1000.0 // Default far cull distance
182 #endif
183
184 // Texture parameters (equivalent to OpenGL defines)
185 #define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S
186 #define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T
187 #define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER
188 #define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER
189
190 #define RL_TEXTURE_FILTER_NEAREST 0x2600 // GL_NEAREST
191 #define RL_TEXTURE_FILTER_LINEAR 0x2601 // GL_LINEAR
192 #define RL_TEXTURE_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST
193 #define RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR
194 #define RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST
195 #define RL_TEXTURE_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR
196 #define RL_TEXTURE_FILTER_ANISOTROPIC 0x3000 // Anisotropic filter (custom identifier)
197
198 #define RL_TEXTURE_WRAP_REPEAT 0x2901 // GL_REPEAT
199 #define RL_TEXTURE_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE
200 #define RL_TEXTURE_WRAP_MIRROR_REPEAT 0x8370 // GL_MIRRORED_REPEAT
201 #define RL_TEXTURE_WRAP_MIRROR_CLAMP 0x8742 // GL_MIRROR_CLAMP_EXT
202
203 // Matrix modes (equivalent to OpenGL)
204 #define RL_MODELVIEW 0x1700 // GL_MODELVIEW
205 #define RL_PROJECTION 0x1701 // GL_PROJECTION
206 #define RL_TEXTURE 0x1702 // GL_TEXTURE
207
208 // Primitive assembly draw modes
209 #define RL_LINES 0x0001 // GL_LINES
210 #define RL_TRIANGLES 0x0004 // GL_TRIANGLES
211 #define RL_QUADS 0x0007 // GL_QUADS
212
213 // GL equivalent data types
214 #define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE
215 #define RL_FLOAT 0x1406 // GL_FLOAT
216
217 //----------------------------------------------------------------------------------
218 // Types and Structures Definition
219 //----------------------------------------------------------------------------------
220 typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion;
221
222 typedef enum {
223 RL_ATTACHMENT_COLOR_CHANNEL0 = 0,
224 RL_ATTACHMENT_COLOR_CHANNEL1,
225 RL_ATTACHMENT_COLOR_CHANNEL2,
226 RL_ATTACHMENT_COLOR_CHANNEL3,
227 RL_ATTACHMENT_COLOR_CHANNEL4,
228 RL_ATTACHMENT_COLOR_CHANNEL5,
229 RL_ATTACHMENT_COLOR_CHANNEL6,
230 RL_ATTACHMENT_COLOR_CHANNEL7,
231 RL_ATTACHMENT_DEPTH = 100,
232 RL_ATTACHMENT_STENCIL = 200,
233 } FramebufferAttachType;
234
235 typedef enum {
236 RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0,
237 RL_ATTACHMENT_CUBEMAP_NEGATIVE_X,
238 RL_ATTACHMENT_CUBEMAP_POSITIVE_Y,
239 RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y,
240 RL_ATTACHMENT_CUBEMAP_POSITIVE_Z,
241 RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z,
242 RL_ATTACHMENT_TEXTURE2D = 100,
243 RL_ATTACHMENT_RENDERBUFFER = 200,
244 } FramebufferAttachTextureType;
245
246 // Dynamic vertex buffers (position + texcoords + colors + indices arrays)
247 typedef struct VertexBuffer {
248 int elementsCount; // Number of elements in the buffer (QUADS)
249
250 int vCounter; // Vertex position counter to process (and draw) from full buffer
251 int tcCounter; // Vertex texcoord counter to process (and draw) from full buffer
252 int cCounter; // Vertex color counter to process (and draw) from full buffer
253
254 float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
255 float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
256 unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
257 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
258 unsigned int *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
259 #endif
260 #if defined(GRAPHICS_API_OPENGL_ES2)
261 unsigned short *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
262 #endif
263 unsigned int vaoId; // OpenGL Vertex Array Object id
264 unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data)
265 } VertexBuffer;
266
267 // Draw call type
268 // NOTE: Only texture changes register a new draw, other state-change-related elements are not
269 // used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
270 // of those state-change happens (this is done in core module)
271 typedef struct DrawCall {
272 int mode; // Drawing mode: LINES, TRIANGLES, QUADS
273 int vertexCount; // Number of vertex of the draw
274 int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES)
275 //unsigned int vaoId; // Vertex array id to be used on the draw -> Using RLGL.currentBatch->vertexBuffer.vaoId
276 //unsigned int shaderId; // Shader id to be used on the draw -> Using RLGL.currentShader.id
277 unsigned int textureId; // Texture id to be used on the draw -> Use to create new draw call if changes
278
279 //Matrix projection; // Projection matrix for this draw -> Using RLGL.projection by default
280 //Matrix modelview; // Modelview matrix for this draw -> Using RLGL.modelview by default
281 } DrawCall;
282
283 // RenderBatch type
284 typedef struct RenderBatch {
285 int buffersCount; // Number of vertex buffers (multi-buffering support)
286 int currentBuffer; // Current buffer tracking in case of multi-buffering
287 VertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data
288
289 DrawCall *draws; // Draw calls array, depends on textureId
290 int drawsCounter; // Draw calls counter
291 float currentDepth; // Current depth value for next draw
292 } RenderBatch;
293
294 // Shader attribute data types
295 typedef enum {
296 SHADER_ATTRIB_FLOAT = 0,
297 SHADER_ATTRIB_VEC2,
298 SHADER_ATTRIB_VEC3,
299 SHADER_ATTRIB_VEC4
300 } ShaderAttributeDataType;
301
302 #if defined(RLGL_STANDALONE)
303 #ifndef __cplusplus
304 // Boolean type
305 typedef enum { false, true } bool;
306 #endif
307
308 // Color type, RGBA (32bit)
309 typedef struct Color {
310 unsigned char r;
311 unsigned char g;
312 unsigned char b;
313 unsigned char a;
314 } Color;
315
316 // Texture type
317 // NOTE: Data stored in GPU memory
318 typedef struct Texture2D {
319 unsigned int id; // OpenGL texture id
320 int width; // Texture base width
321 int height; // Texture base height
322 int mipmaps; // Mipmap levels, 1 by default
323 int format; // Data format (PixelFormat)
324 } Texture2D;
325
326 // Shader type (generic)
327 typedef struct Shader {
328 unsigned int id; // Shader program id
329 int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
330 } Shader;
331
332 // TraceLog message types
333 typedef enum {
334 LOG_ALL,
335 LOG_TRACE,
336 LOG_DEBUG,
337 LOG_INFO,
338 LOG_WARNING,
339 LOG_ERROR,
340 LOG_FATAL,
341 LOG_NONE
342 } TraceLogLevel;
343
344 // Texture formats (support depends on OpenGL version)
345 typedef enum {
346 PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
347 PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
348 PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp
349 PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp
350 PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
351 PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
352 PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp
353 PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float)
354 PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float)
355 PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float)
356 PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
357 PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
358 PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp
359 PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp
360 PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp
361 PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp
362 PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
363 PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp
364 PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp
365 PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
366 PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp
367 } PixelFormat;
368
369 // Texture parameters: filter mode
370 // NOTE 1: Filtering considers mipmaps if available in the texture
371 // NOTE 2: Filter is accordingly set for minification and magnification
372 typedef enum {
373 TEXTURE_FILTER_POINT = 0, // No filter, just pixel aproximation
374 TEXTURE_FILTER_BILINEAR, // Linear filtering
375 TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
376 TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
377 TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x
378 TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x
379 } TextureFilter;
380
381 // Texture parameters: wrap mode
382 typedef enum {
383 TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode
384 TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode
385 TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode
386 TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode
387 } TextureWrap;
388
389 // Color blending modes (pre-defined)
390 typedef enum {
391 BLEND_ALPHA = 0, // Blend textures considering alpha (default)
392 BLEND_ADDITIVE, // Blend textures adding colors
393 BLEND_MULTIPLIED, // Blend textures multiplying colors
394 BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
395 BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
396 BLEND_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom())
397 } BlendMode;
398
399 // Shader location point type
400 typedef enum {
401 SHADER_LOC_VERTEX_POSITION = 0,
402 SHADER_LOC_VERTEX_TEXCOORD01,
403 SHADER_LOC_VERTEX_TEXCOORD02,
404 SHADER_LOC_VERTEX_NORMAL,
405 SHADER_LOC_VERTEX_TANGENT,
406 SHADER_LOC_VERTEX_COLOR,
407 SHADER_LOC_MATRIX_MVP,
408 SHADER_LOC_MATRIX_MODEL,
409 SHADER_LOC_MATRIX_VIEW,
410 SHADER_LOC_MATRIX_NORMAL,
411 SHADER_LOC_MATRIX_PROJECTION,
412 SHADER_LOC_VECTOR_VIEW,
413 SHADER_LOC_COLOR_DIFFUSE,
414 SHADER_LOC_COLOR_SPECULAR,
415 SHADER_LOC_COLOR_AMBIENT,
416 SHADER_LOC_MAP_ALBEDO, // SHADER_LOC_MAP_DIFFUSE
417 SHADER_LOC_MAP_METALNESS, // SHADER_LOC_MAP_SPECULAR
418 SHADER_LOC_MAP_NORMAL,
419 SHADER_LOC_MAP_ROUGHNESS,
420 SHADER_LOC_MAP_OCCLUSION,
421 SHADER_LOC_MAP_EMISSION,
422 SHADER_LOC_MAP_HEIGHT,
423 SHADER_LOC_MAP_CUBEMAP,
424 SHADER_LOC_MAP_IRRADIANCE,
425 SHADER_LOC_MAP_PREFILTER,
426 SHADER_LOC_MAP_BRDF
427 } ShaderLocationIndex;
428
429 #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO
430 #define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS
431
432 // Shader uniform data types
433 typedef enum {
434 SHADER_UNIFORM_FLOAT = 0,
435 SHADER_UNIFORM_VEC2,
436 SHADER_UNIFORM_VEC3,
437 SHADER_UNIFORM_VEC4,
438 SHADER_UNIFORM_INT,
439 SHADER_UNIFORM_IVEC2,
440 SHADER_UNIFORM_IVEC3,
441 SHADER_UNIFORM_IVEC4,
442 SHADER_UNIFORM_SAMPLER2D
443 } ShaderUniformDataType;
444 #endif
445
446 #if defined(__cplusplus)
447 extern "C" { // Prevents name mangling of functions
448 #endif
449
450 //------------------------------------------------------------------------------------
451 // Functions Declaration - Matrix operations
452 //------------------------------------------------------------------------------------
453 RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed
454 RLAPI void rlPushMatrix(void); // Push the current matrix to stack
455 RLAPI void rlPopMatrix(void); // Pop lattest inserted matrix from stack
456 RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix
457 RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
458 RLAPI void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix
459 RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
460 RLAPI void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix
461 RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar);
462 RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar);
463 RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area
464
465 //------------------------------------------------------------------------------------
466 // Functions Declaration - Vertex level operations
467 //------------------------------------------------------------------------------------
468 RLAPI void rlBegin(int mode); // Initialize drawing mode (how to organize vertex)
469 RLAPI void rlEnd(void); // Finish vertex providing
470 RLAPI void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int
471 RLAPI void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float
472 RLAPI void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float
473 RLAPI void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float
474 RLAPI void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float
475 RLAPI void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Define one vertex (color) - 4 byte
476 RLAPI void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float
477 RLAPI void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float
478
479 //------------------------------------------------------------------------------------
480 // Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
481 // NOTE: This functions are used to completely abstract raylib code from OpenGL layer,
482 // some of them are direct wrappers over OpenGL calls, some others are custom
483 //------------------------------------------------------------------------------------
484
485 // Vertex buffers state
486 RLAPI bool rlEnableVertexArray(unsigned int vaoId); // Enable vertex array (VAO, if supported)
487 RLAPI void rlDisableVertexArray(void); // Disable vertex array (VAO, if supported)
488 RLAPI void rlEnableVertexBuffer(unsigned int id); // Enable vertex buffer (VBO)
489 RLAPI void rlDisableVertexBuffer(void); // Disable vertex buffer (VBO)
490 RLAPI void rlEnableVertexBufferElement(unsigned int id);// Enable vertex buffer element (VBO element)
491 RLAPI void rlDisableVertexBufferElement(void); // Disable vertex buffer element (VBO element)
492 RLAPI void rlEnableVertexAttribute(unsigned int index); // Enable vertex attribute index
493 RLAPI void rlDisableVertexAttribute(unsigned int index);// Disable vertex attribute index
494 #if defined(GRAPHICS_API_OPENGL_11)
495 RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer);
496 RLAPI void rlDisableStatePointer(int vertexAttribType);
497 #endif
498
499 // Textures state
500 RLAPI void rlActiveTextureSlot(int slot); // Select and active a texture slot
501 RLAPI void rlEnableTexture(unsigned int id); // Enable texture
502 RLAPI void rlDisableTexture(void); // Disable texture
503 RLAPI void rlEnableTextureCubemap(unsigned int id); // Enable texture cubemap
504 RLAPI void rlDisableTextureCubemap(void); // Disable texture cubemap
505 RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
506
507 // Shader state
508 RLAPI void rlEnableShader(unsigned int id); // Enable shader program
509 RLAPI void rlDisableShader(void); // Disable shader program
510
511 // Framebuffer state
512 RLAPI void rlEnableFramebuffer(unsigned int id); // Enable render texture (fbo)
513 RLAPI void rlDisableFramebuffer(void); // Disable render texture (fbo), return to default framebuffer
514
515 // General render state
516 RLAPI void rlEnableDepthTest(void); // Enable depth test
517 RLAPI void rlDisableDepthTest(void); // Disable depth test
518 RLAPI void rlEnableDepthMask(void); // Enable depth write
519 RLAPI void rlDisableDepthMask(void); // Disable depth write
520 RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling
521 RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling
522 RLAPI void rlEnableScissorTest(void); // Enable scissor test
523 RLAPI void rlDisableScissorTest(void); // Disable scissor test
524 RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
525 RLAPI void rlEnableWireMode(void); // Enable wire mode
526 RLAPI void rlDisableWireMode(void); // Disable wire mode
527 RLAPI void rlSetLineWidth(float width); // Set the line drawing width
528 RLAPI float rlGetLineWidth(void); // Get the line drawing width
529 RLAPI void rlEnableSmoothLines(void); // Enable line aliasing
530 RLAPI void rlDisableSmoothLines(void); // Disable line aliasing
531 RLAPI void rlEnableStereoRender(void); // Enable stereo rendering
532 RLAPI void rlDisableStereoRender(void); // Disable stereo rendering
533 RLAPI bool rlIsStereoRenderEnabled(void); // Check if stereo render is enabled
534
535 RLAPI void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Clear color buffer with color
536 RLAPI void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
537 RLAPI void rlCheckErrors(void); // Check and log OpenGL error codes
538 RLAPI void rlSetBlendMode(int mode); // Set blending mode
539 RLAPI void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation); // Set blending mode factor and equation (using OpenGL factors)
540
541 //------------------------------------------------------------------------------------
542 // Functions Declaration - rlgl functionality
543 //------------------------------------------------------------------------------------
544 // rlgl initialization functions
545 RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
546 RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
547 RLAPI void rlLoadExtensions(void* loader); // Load OpenGL extensions (loader function pointer required)
548 RLAPI int rlGetVersion(void); // Returns current OpenGL version
549 RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width
550 RLAPI int rlGetFramebufferHeight(void); // Get default framebuffer height
551
552 RLAPI Shader rlGetShaderDefault(void); // Get default shader
553 RLAPI Texture2D rlGetTextureDefault(void); // Get default texture
554
555 // Render batch management
556 // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
557 // but this render batch API is exposed in case of custom batches are required
558 RLAPI RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements); // Load a render batch system
559 RLAPI void rlUnloadRenderBatch(RenderBatch batch); // Unload render batch system
560 RLAPI void rlDrawRenderBatch(RenderBatch *batch); // Draw render batch data (Update->Draw->Reset)
561 RLAPI void rlSetRenderBatchActive(RenderBatch *batch); // Set the active render batch for rlgl (NULL for default internal)
562 RLAPI void rlDrawRenderBatchActive(void); // Update and draw internal render batch
563 RLAPI bool rlCheckRenderBatchLimit(int vCount); // Check internal buffer overflow for a given number of vertex
564 RLAPI void rlSetTexture(unsigned int id); // Set current texture for render batch and check buffers limits
565
566 //------------------------------------------------------------------------------------------------------------------------
567
568 // Vertex buffers management
569 RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported
570 RLAPI unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic); // Load a vertex buffer attribute
571 RLAPI unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic); // Load a new attributes element buffer
572 RLAPI void rlUpdateVertexBuffer(int bufferId, void *data, int dataSize, int offset); // Update GPU buffer with new data
573 RLAPI void rlUnloadVertexArray(unsigned int vaoId);
574 RLAPI void rlUnloadVertexBuffer(unsigned int vboId);
575 RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer);
576 RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor);
577 RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value
578 RLAPI void rlDrawVertexArray(int offset, int count);
579 RLAPI void rlDrawVertexArrayElements(int offset, int count, void *buffer);
580 RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances);
581 RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances);
582
583 // Textures management
584 RLAPI unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
585 RLAPI unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo)
586 RLAPI unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap
587 RLAPI void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update GPU texture with new data
588 RLAPI void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats
589 RLAPI void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory
590 RLAPI void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
591 RLAPI void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data
592 RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
593
594 // Framebuffer management (fbo)
595 RLAPI unsigned int rlLoadFramebuffer(int width, int height); // Load an empty framebuffer
596 RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
597 RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete
598 RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU
599
600 // Shaders management
601 RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings
602 RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: GL_VERTEX_SHADER, GL_FRAGMENT_SHADER)
603 RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program
604 RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program
605 RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform
606 RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute
607 RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform
608 RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix
609 RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler
610 RLAPI void rlSetShader(Shader shader); // Set shader currently active
611
612 // Matrix state management
613 RLAPI Matrix rlGetMatrixModelview(void); // Get internal modelview matrix
614 RLAPI Matrix rlGetMatrixProjection(void); // Get internal projection matrix
615 RLAPI Matrix rlGetMatrixTransform(void); // Get internal accumulated transform matrix
616 RLAPI Matrix rlGetMatrixProjectionStereo(int eye); // Get internal projection matrix for stereo render (selected eye)
617 RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye); // Get internal view offset matrix for stereo render (selected eye)
618 RLAPI void rlSetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
619 RLAPI void rlSetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
620 RLAPI void rlSetMatrixProjectionStereo(Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering
621 RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering
622
623 // Quick and dirty cube/quad buffers load->draw->unload
624 RLAPI void rlLoadDrawCube(void); // Load and draw a cube
625 RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
626 #if defined(__cplusplus)
627 }
628 #endif
629
630 #endif // RLGL_H
631
632 /***********************************************************************************
633 *
634 * RLGL IMPLEMENTATION
635 *
636 ************************************************************************************/
637
638 #if defined(RLGL_IMPLEMENTATION)
639
640 #if !defined(RLGL_STANDALONE)
641 // Check if config flags have been externally provided on compilation line
642 #if !defined(EXTERNAL_CONFIG_FLAGS)
643 #include "config.h" // Defines module configuration flags
644 #endif
645 #include "raymath.h" // Required for: Vector3 and Matrix functions
646 #endif
647
648 #include <stdlib.h> // Required for: malloc(), free()
649 #include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
650
651 #if defined(GRAPHICS_API_OPENGL_11)
652 #if defined(__APPLE__)
653 #include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
654 #include <OpenGL/glext.h>
655 #else
656 // APIENTRY for OpenGL function pointer declarations is required
657 #ifndef APIENTRY
658 #if defined(_WIN32)
659 #define APIENTRY __stdcall
660 #else
661 #define APIENTRY
662 #endif
663 #endif
664 // WINGDIAPI definition. Some Windows OpenGL headers need it
665 #if !defined(WINGDIAPI) && defined(_WIN32)
666 #define WINGDIAPI __declspec(dllimport)
667 #endif
668
669 #include <GL/gl.h> // OpenGL 1.1 library
670 #endif
671 #endif
672
673 #if defined(GRAPHICS_API_OPENGL_33)
674 #if defined(__APPLE__)
675 #include <OpenGL/gl3.h> // OpenGL 3 library for OSX
676 #include <OpenGL/gl3ext.h> // OpenGL 3 extensions library for OSX
677 #else
678 #define GLAD_REALLOC RL_REALLOC
679 #define GLAD_FREE RL_FREE
680
681 #define GLAD_IMPLEMENTATION
682 #if defined(RLGL_STANDALONE)
683 #include "glad.h" // GLAD extensions loading library, includes OpenGL headers
684 #else
685 #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers
686 #endif
687 #endif
688 #endif
689
690 #if defined(GRAPHICS_API_OPENGL_ES2)
691 #define GL_GLEXT_PROTOTYPES
692 #include <EGL/egl.h> // EGL library
693 #include <GLES2/gl2.h> // OpenGL ES 2.0 library
694 #include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library
695
696 // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
697 // provided headers (despite being defined in official Khronos GLES2 headers)
698 #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
699 typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
700 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
701 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
702 #endif
703 #endif
704
705 //----------------------------------------------------------------------------------
706 // Defines and Macros
707 //----------------------------------------------------------------------------------
708 #ifndef GL_SHADING_LANGUAGE_VERSION
709 #define GL_SHADING_LANGUAGE_VERSION 0x8B8C
710 #endif
711
712 #ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
713 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
714 #endif
715 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
716 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
717 #endif
718 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
719 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
720 #endif
721 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
722 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
723 #endif
724 #ifndef GL_ETC1_RGB8_OES
725 #define GL_ETC1_RGB8_OES 0x8D64
726 #endif
727 #ifndef GL_COMPRESSED_RGB8_ETC2
728 #define GL_COMPRESSED_RGB8_ETC2 0x9274
729 #endif
730 #ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
731 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
732 #endif
733 #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
734 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
735 #endif
736 #ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
737 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
738 #endif
739 #ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR
740 #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0
741 #endif
742 #ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR
743 #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7
744 #endif
745
746 #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
747 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
748 #endif
749 #ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
750 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
751 #endif
752
753 #if defined(GRAPHICS_API_OPENGL_11)
754 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
755 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
756 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
757 #endif
758
759 #if defined(GRAPHICS_API_OPENGL_21)
760 #define GL_LUMINANCE 0x1909
761 #define GL_LUMINANCE_ALPHA 0x190A
762 #endif
763
764 #if defined(GRAPHICS_API_OPENGL_ES2)
765 #define glClearDepth glClearDepthf
766 #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
767 #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
768 #endif
769
770 // Default shader vertex attribute names to set location points
771 #ifndef DEFAULT_SHADER_ATTRIB_NAME_POSITION
772 #define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
773 #endif
774 #ifndef DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD
775 #define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
776 #endif
777 #ifndef DEFAULT_SHADER_ATTRIB_NAME_NORMAL
778 #define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
779 #endif
780 #ifndef DEFAULT_SHADER_ATTRIB_NAME_COLOR
781 #define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
782 #endif
783 #ifndef DEFAULT_SHADER_ATTRIB_NAME_TANGENT
784 #define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
785 #endif
786 #ifndef DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2
787 #define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
788 #endif
789
790 //----------------------------------------------------------------------------------
791 // Types and Structures Definition
792 //----------------------------------------------------------------------------------
793 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
794 typedef struct rlglData {
795 RenderBatch *currentBatch; // Current render batch
796 RenderBatch defaultBatch; // Default internal render batch
797
798 struct {
799 int currentMatrixMode; // Current matrix mode
800 Matrix *currentMatrix; // Current matrix pointer
801 Matrix modelview; // Default modelview matrix
802 Matrix projection; // Default projection matrix
803 Matrix transform; // Transform matrix to be used with rlTranslate, rlRotate, rlScale
804 bool transformRequired; // Require transform matrix application to current draw-call vertex (if required)
805 Matrix stack[MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop
806 int stackCounter; // Matrix stack counter
807
808 unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader)
809 unsigned int activeTextureId[MAX_BATCH_ACTIVE_TEXTURES]; // Active texture ids to be enabled on batch drawing (0 active by default)
810 unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program)
811 unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program)
812 Shader defaultShader; // Basic shader, support vertex color and diffuse texture
813 Shader currentShader; // Shader to be used on rendering (by default, defaultShader)
814
815 bool stereoRender; // Stereo rendering flag
816 Matrix projectionStereo[2]; // VR stereo rendering eyes projection matrices
817 Matrix viewOffsetStereo[2]; // VR stereo rendering eyes view offset matrices
818
819 int currentBlendMode; // Blending mode active
820 int glBlendSrcFactor; // Blending source factor
821 int glBlendDstFactor; // Blending destination factor
822 int glBlendEquation; // Blending equation
823
824 int framebufferWidth; // Default framebuffer width
825 int framebufferHeight; // Default framebuffer height
826
827 } State; // Renderer state
828 struct {
829 bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object)
830 bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays)
831 bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot)
832 bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_WEBGL_depth_texture, GL_OES_depth_texture)
833 bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float)
834 bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, GL_WEBKIT_WEBGL_compressed_texture_s3tc)
835 bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1)
836 bool texCompETC2; // ETC2/EAC texture compression support (GL_ARB_ES3_compatibility)
837 bool texCompPVRT; // PVR texture compression support (GL_IMG_texture_compression_pvrtc)
838 bool texCompASTC; // ASTC texture compression support (GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr)
839 bool texMirrorClamp; // Clamp mirror wrap mode supported (GL_EXT_texture_mirror_clamp)
840 bool texAnisoFilter; // Anisotropic texture filtering support (GL_EXT_texture_filter_anisotropic)
841
842 float maxAnisotropyLevel; // Maximum anisotropy level supported (minimum is 2.0f)
843 int maxDepthBits; // Maximum bits for depth component
844
845 } ExtSupported; // Extensions supported flags
846 } rlglData;
847 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
848
849 //----------------------------------------------------------------------------------
850 // Global Variables Definition
851 //----------------------------------------------------------------------------------
852 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
853 static rlglData RLGL = { 0 };
854 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
855
856 #if defined(GRAPHICS_API_OPENGL_ES2)
857 // NOTE: VAO functionality is exposed through extensions (OES)
858 static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
859 static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
860 static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
861
862 // NOTE: Instancing functionality could also be available through extension
863 static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL;
864 static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL;
865 static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL;
866 #endif
867
868 //----------------------------------------------------------------------------------
869 // Module specific Functions Declaration
870 //----------------------------------------------------------------------------------
871 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
872 static void rlLoadShaderDefault(void); // Load default shader (RLGL.State.defaultShader)
873 static void rlUnloadShaderDefault(void); // Unload default shader (RLGL.State.defaultShader)
874 #if defined(SUPPORT_GL_DETAILS_INFO)
875 static char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name
876 #endif // SUPPORT_GL_DETAILS_INFO
877 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
878 #if defined(GRAPHICS_API_OPENGL_11)
879 static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side
880 static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side
881 #endif
882 static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
883
884 //----------------------------------------------------------------------------------
885 // Module Functions Definition - Matrix operations
886 //----------------------------------------------------------------------------------
887
888 #if defined(GRAPHICS_API_OPENGL_11)
889 // Fallback to OpenGL 1.1 function calls
890 //---------------------------------------
rlMatrixMode(int mode)891 void rlMatrixMode(int mode)
892 {
893 switch (mode)
894 {
895 case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break;
896 case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break;
897 case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break;
898 default: break;
899 }
900 }
901
rlFrustum(double left,double right,double bottom,double top,double znear,double zfar)902 void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar)
903 {
904 glFrustum(left, right, bottom, top, znear, zfar);
905 }
906
rlOrtho(double left,double right,double bottom,double top,double znear,double zfar)907 void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
908 {
909 glOrtho(left, right, bottom, top, znear, zfar);
910 }
911
rlPushMatrix(void)912 void rlPushMatrix(void) { glPushMatrix(); }
rlPopMatrix(void)913 void rlPopMatrix(void) { glPopMatrix(); }
rlLoadIdentity(void)914 void rlLoadIdentity(void) { glLoadIdentity(); }
rlTranslatef(float x,float y,float z)915 void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); }
rlRotatef(float angleDeg,float x,float y,float z)916 void rlRotatef(float angleDeg, float x, float y, float z) { glRotatef(angleDeg, x, y, z); }
rlScalef(float x,float y,float z)917 void rlScalef(float x, float y, float z) { glScalef(x, y, z); }
rlMultMatrixf(float * matf)918 void rlMultMatrixf(float *matf) { glMultMatrixf(matf); }
919 #endif
920 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
921 // Choose the current matrix to be transformed
rlMatrixMode(int mode)922 void rlMatrixMode(int mode)
923 {
924 if (mode == RL_PROJECTION) RLGL.State.currentMatrix = &RLGL.State.projection;
925 else if (mode == RL_MODELVIEW) RLGL.State.currentMatrix = &RLGL.State.modelview;
926 //else if (mode == RL_TEXTURE) // Not supported
927
928 RLGL.State.currentMatrixMode = mode;
929 }
930
931 // Push the current matrix into RLGL.State.stack
rlPushMatrix(void)932 void rlPushMatrix(void)
933 {
934 if (RLGL.State.stackCounter >= MAX_MATRIX_STACK_SIZE) TRACELOG(LOG_ERROR, "RLGL: Matrix stack overflow (MAX_MATRIX_STACK_SIZE)");
935
936 if (RLGL.State.currentMatrixMode == RL_MODELVIEW)
937 {
938 RLGL.State.transformRequired = true;
939 RLGL.State.currentMatrix = &RLGL.State.transform;
940 }
941
942 RLGL.State.stack[RLGL.State.stackCounter] = *RLGL.State.currentMatrix;
943 RLGL.State.stackCounter++;
944 }
945
946 // Pop lattest inserted matrix from RLGL.State.stack
rlPopMatrix(void)947 void rlPopMatrix(void)
948 {
949 if (RLGL.State.stackCounter > 0)
950 {
951 Matrix mat = RLGL.State.stack[RLGL.State.stackCounter - 1];
952 *RLGL.State.currentMatrix = mat;
953 RLGL.State.stackCounter--;
954 }
955
956 if ((RLGL.State.stackCounter == 0) && (RLGL.State.currentMatrixMode == RL_MODELVIEW))
957 {
958 RLGL.State.currentMatrix = &RLGL.State.modelview;
959 RLGL.State.transformRequired = false;
960 }
961 }
962
963 // Reset current matrix to identity matrix
rlLoadIdentity(void)964 void rlLoadIdentity(void)
965 {
966 *RLGL.State.currentMatrix = MatrixIdentity();
967 }
968
969 // Multiply the current matrix by a translation matrix
rlTranslatef(float x,float y,float z)970 void rlTranslatef(float x, float y, float z)
971 {
972 Matrix matTranslation = MatrixTranslate(x, y, z);
973
974 // NOTE: We transpose matrix with multiplication order
975 *RLGL.State.currentMatrix = MatrixMultiply(matTranslation, *RLGL.State.currentMatrix);
976 }
977
978 // Multiply the current matrix by a rotation matrix
rlRotatef(float angleDeg,float x,float y,float z)979 void rlRotatef(float angleDeg, float x, float y, float z)
980 {
981 Matrix matRotation = MatrixIdentity();
982
983 Vector3 axis = (Vector3){ x, y, z };
984 matRotation = MatrixRotate(Vector3Normalize(axis), angleDeg*DEG2RAD);
985
986 // NOTE: We transpose matrix with multiplication order
987 *RLGL.State.currentMatrix = MatrixMultiply(matRotation, *RLGL.State.currentMatrix);
988 }
989
990 // Multiply the current matrix by a scaling matrix
rlScalef(float x,float y,float z)991 void rlScalef(float x, float y, float z)
992 {
993 Matrix matScale = MatrixScale(x, y, z);
994
995 // NOTE: We transpose matrix with multiplication order
996 *RLGL.State.currentMatrix = MatrixMultiply(matScale, *RLGL.State.currentMatrix);
997 }
998
999 // Multiply the current matrix by another matrix
rlMultMatrixf(float * matf)1000 void rlMultMatrixf(float *matf)
1001 {
1002 // Matrix creation from array
1003 Matrix mat = { matf[0], matf[4], matf[8], matf[12],
1004 matf[1], matf[5], matf[9], matf[13],
1005 matf[2], matf[6], matf[10], matf[14],
1006 matf[3], matf[7], matf[11], matf[15] };
1007
1008 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, mat);
1009 }
1010
1011 // Multiply the current matrix by a perspective matrix generated by parameters
rlFrustum(double left,double right,double bottom,double top,double znear,double zfar)1012 void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar)
1013 {
1014 Matrix matPerps = MatrixFrustum(left, right, bottom, top, znear, zfar);
1015
1016 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matPerps);
1017 }
1018
1019 // Multiply the current matrix by an orthographic matrix generated by parameters
rlOrtho(double left,double right,double bottom,double top,double znear,double zfar)1020 void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
1021 {
1022 // NOTE: If left-right and top-botton values are equal it could create
1023 // a division by zero on MatrixOrtho(), response to it is platform/compiler dependant
1024 Matrix matOrtho = MatrixOrtho(left, right, bottom, top, znear, zfar);
1025
1026 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matOrtho);
1027 }
1028 #endif
1029
1030 // Set the viewport area (transformation from normalized device coordinates to window coordinates)
rlViewport(int x,int y,int width,int height)1031 void rlViewport(int x, int y, int width, int height)
1032 {
1033 glViewport(x, y, width, height);
1034 }
1035
1036 //----------------------------------------------------------------------------------
1037 // Module Functions Definition - Vertex level operations
1038 //----------------------------------------------------------------------------------
1039 #if defined(GRAPHICS_API_OPENGL_11)
1040 // Fallback to OpenGL 1.1 function calls
1041 //---------------------------------------
rlBegin(int mode)1042 void rlBegin(int mode)
1043 {
1044 switch (mode)
1045 {
1046 case RL_LINES: glBegin(GL_LINES); break;
1047 case RL_TRIANGLES: glBegin(GL_TRIANGLES); break;
1048 case RL_QUADS: glBegin(GL_QUADS); break;
1049 default: break;
1050 }
1051 }
1052
rlEnd()1053 void rlEnd() { glEnd(); }
rlVertex2i(int x,int y)1054 void rlVertex2i(int x, int y) { glVertex2i(x, y); }
rlVertex2f(float x,float y)1055 void rlVertex2f(float x, float y) { glVertex2f(x, y); }
rlVertex3f(float x,float y,float z)1056 void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); }
rlTexCoord2f(float x,float y)1057 void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); }
rlNormal3f(float x,float y,float z)1058 void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); }
rlColor4ub(unsigned char r,unsigned char g,unsigned char b,unsigned char a)1059 void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glColor4ub(r, g, b, a); }
rlColor3f(float x,float y,float z)1060 void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); }
rlColor4f(float x,float y,float z,float w)1061 void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); }
1062 #endif
1063 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1064 // Initialize drawing mode (how to organize vertex)
rlBegin(int mode)1065 void rlBegin(int mode)
1066 {
1067 // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS
1068 // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer
1069 if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode != mode)
1070 {
1071 if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0)
1072 {
1073 // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4,
1074 // that way, following QUADS drawing will keep aligned with index processing
1075 // It implies adding some extra alignment vertex at the end of the draw,
1076 // those vertex are not processed but they are considered as an additional offset
1077 // for the next set of vertex to be drawn
1078 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);
1079 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)));
1080 else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0;
1081
1082 if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment))
1083 {
1084 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1085 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1086 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1087
1088 RLGL.currentBatch->drawsCounter++;
1089 }
1090 }
1091
1092 if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch);
1093
1094 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode = mode;
1095 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0;
1096 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = RLGL.State.defaultTextureId;
1097 }
1098 }
1099
1100 // Finish vertex providing
rlEnd(void)1101 void rlEnd(void)
1102 {
1103 // Make sure vertexCount is the same for vertices, texcoords, colors and normals
1104 // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls
1105
1106 // Make sure colors count match vertex count
1107 if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter)
1108 {
1109 int addColors = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter;
1110
1111 for (int i = 0; i < addColors; i++)
1112 {
1113 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];
1114 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];
1115 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];
1116 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];
1117 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++;
1118 }
1119 }
1120
1121 // Make sure texcoords count match vertex count
1122 if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter != RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter)
1123 {
1124 int addTexCoords = RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter;
1125
1126 for (int i = 0; i < addTexCoords; i++)
1127 {
1128 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = 0.0f;
1129 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = 0.0f;
1130 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++;
1131 }
1132 }
1133
1134 // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P
1135
1136 // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
1137 // as well as depth buffer bit-depth (16bit or 24bit or 32bit)
1138 // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
1139 RLGL.currentBatch->currentDepth += (1.0f/20000.0f);
1140
1141 // Verify internal buffers limits
1142 // NOTE: This check is combined with usage of rlCheckRenderBatchLimit()
1143 if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter) >=
1144 (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4 - 4))
1145 {
1146 // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlDrawRenderBatch(),
1147 // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call!
1148 // If we have multiple matrix pushed, it will require "RLGL.State.stackCounter" pops before launching the draw
1149 for (int i = RLGL.State.stackCounter; i >= 0; i--) rlPopMatrix();
1150 rlDrawRenderBatch(RLGL.currentBatch);
1151 }
1152 }
1153
1154 // Define one vertex (position)
1155 // NOTE: Vertex position data is the basic information required for drawing
rlVertex3f(float x,float y,float z)1156 void rlVertex3f(float x, float y, float z)
1157 {
1158 Vector3 vec = { x, y, z };
1159
1160 // Transform provided vector if required
1161 if (RLGL.State.transformRequired) vec = Vector3Transform(vec, RLGL.State.transform);
1162
1163 // Verify that current vertex buffer elements limit has not been reached
1164 if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4))
1165 {
1166 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter] = vec.x;
1167 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 1] = vec.y;
1168 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 2] = vec.z;
1169 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter++;
1170
1171 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount++;
1172 }
1173 else TRACELOG(LOG_ERROR, "RLGL: Batch elements overflow");
1174 }
1175
1176 // Define one vertex (position)
rlVertex2f(float x,float y)1177 void rlVertex2f(float x, float y)
1178 {
1179 rlVertex3f(x, y, RLGL.currentBatch->currentDepth);
1180 }
1181
1182 // Define one vertex (position)
rlVertex2i(int x,int y)1183 void rlVertex2i(int x, int y)
1184 {
1185 rlVertex3f((float)x, (float)y, RLGL.currentBatch->currentDepth);
1186 }
1187
1188 // Define one vertex (texture coordinate)
1189 // NOTE: Texture coordinates are limited to QUADS only
rlTexCoord2f(float x,float y)1190 void rlTexCoord2f(float x, float y)
1191 {
1192 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter] = x;
1193 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter + 1] = y;
1194 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter++;
1195 }
1196
1197 // Define one vertex (normal)
1198 // NOTE: Normals limited to TRIANGLES only?
rlNormal3f(float x,float y,float z)1199 void rlNormal3f(float x, float y, float z)
1200 {
1201 // TODO: Normals usage...
1202 }
1203
1204 // Define one vertex (color)
rlColor4ub(unsigned char x,unsigned char y,unsigned char z,unsigned char w)1205 void rlColor4ub(unsigned char x, unsigned char y, unsigned char z, unsigned char w)
1206 {
1207 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter] = x;
1208 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 1] = y;
1209 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 2] = z;
1210 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter + 3] = w;
1211 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter++;
1212 }
1213
1214 // Define one vertex (color)
rlColor4f(float r,float g,float b,float a)1215 void rlColor4f(float r, float g, float b, float a)
1216 {
1217 rlColor4ub((unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), (unsigned char)(a*255));
1218 }
1219
1220 // Define one vertex (color)
rlColor3f(float x,float y,float z)1221 void rlColor3f(float x, float y, float z)
1222 {
1223 rlColor4ub((unsigned char)(x*255), (unsigned char)(y*255), (unsigned char)(z*255), 255);
1224 }
1225
1226 #endif
1227
1228 //--------------------------------------------------------------------------------------
1229 // Module Functions Definition - OpenGL style functions (common to 1.1, 3.3+, ES2)
1230 //--------------------------------------------------------------------------------------
1231
1232 // Set current texture to use
rlSetTexture(unsigned int id)1233 void rlSetTexture(unsigned int id)
1234 {
1235 if (id == 0)
1236 {
1237 #if defined(GRAPHICS_API_OPENGL_11)
1238 rlDisableTexture();
1239 #else
1240 // NOTE: If quads batch limit is reached, we force a draw call and next batch starts
1241 if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter >=
1242 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)
1243 {
1244 rlDrawRenderBatch(RLGL.currentBatch);
1245 }
1246 #endif
1247 }
1248 else
1249 {
1250 #if defined(GRAPHICS_API_OPENGL_11)
1251 rlEnableTexture(id);
1252 #else
1253 if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId != id)
1254 {
1255 if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0)
1256 {
1257 // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4,
1258 // that way, following QUADS drawing will keep aligned with index processing
1259 // It implies adding some extra alignment vertex at the end of the draw,
1260 // those vertex are not processed but they are considered as an additional offset
1261 // for the next set of vertex to be drawn
1262 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);
1263 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)));
1264 else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0;
1265
1266 if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment))
1267 {
1268 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1269 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1270 RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment;
1271
1272 RLGL.currentBatch->drawsCounter++;
1273 }
1274 }
1275
1276 if (RLGL.currentBatch->drawsCounter >= DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch);
1277
1278 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = id;
1279 RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0;
1280 }
1281 #endif
1282 }
1283 }
1284
1285 // Select and active a texture slot
rlActiveTextureSlot(int slot)1286 void rlActiveTextureSlot(int slot)
1287 {
1288 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1289 glActiveTexture(GL_TEXTURE0 + slot);
1290 #endif
1291 }
1292
1293 // Enable texture
rlEnableTexture(unsigned int id)1294 void rlEnableTexture(unsigned int id)
1295 {
1296 #if defined(GRAPHICS_API_OPENGL_11)
1297 glEnable(GL_TEXTURE_2D);
1298 #endif
1299 glBindTexture(GL_TEXTURE_2D, id);
1300 }
1301
1302 // Disable texture
rlDisableTexture(void)1303 void rlDisableTexture(void)
1304 {
1305 #if defined(GRAPHICS_API_OPENGL_11)
1306 glDisable(GL_TEXTURE_2D);
1307 #endif
1308 glBindTexture(GL_TEXTURE_2D, 0);
1309 }
1310
1311 // Enable texture cubemap
rlEnableTextureCubemap(unsigned int id)1312 void rlEnableTextureCubemap(unsigned int id)
1313 {
1314 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1315 glEnable(GL_TEXTURE_CUBE_MAP); // Core in OpenGL 1.4
1316 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
1317 #endif
1318 }
1319
1320 // Disable texture cubemap
rlDisableTextureCubemap(void)1321 void rlDisableTextureCubemap(void)
1322 {
1323 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1324 glDisable(GL_TEXTURE_CUBE_MAP);
1325 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1326 #endif
1327 }
1328
1329 // Set texture parameters (wrap mode/filter mode)
rlTextureParameters(unsigned int id,int param,int value)1330 void rlTextureParameters(unsigned int id, int param, int value)
1331 {
1332 glBindTexture(GL_TEXTURE_2D, id);
1333
1334 switch (param)
1335 {
1336 case RL_TEXTURE_WRAP_S:
1337 case RL_TEXTURE_WRAP_T:
1338 {
1339 if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP)
1340 {
1341 #if !defined(GRAPHICS_API_OPENGL_11)
1342 if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_2D, param, value);
1343 else TRACELOG(LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
1344 #endif
1345 }
1346 else glTexParameteri(GL_TEXTURE_2D, param, value);
1347
1348 } break;
1349 case RL_TEXTURE_MAG_FILTER:
1350 case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
1351 case RL_TEXTURE_FILTER_ANISOTROPIC:
1352 {
1353 #if !defined(GRAPHICS_API_OPENGL_11)
1354 if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
1355 else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
1356 {
1357 TRACELOG(LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropyLevel);
1358 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
1359 }
1360 else TRACELOG(LOG_WARNING, "GL: Anisotropic filtering not supported");
1361 #endif
1362 } break;
1363 default: break;
1364 }
1365
1366 glBindTexture(GL_TEXTURE_2D, 0);
1367 }
1368
1369 // Enable shader program
rlEnableShader(unsigned int id)1370 void rlEnableShader(unsigned int id)
1371 {
1372 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
1373 glUseProgram(id);
1374 #endif
1375 }
1376
1377 // Disable shader program
rlDisableShader(void)1378 void rlDisableShader(void)
1379 {
1380 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
1381 glUseProgram(0);
1382 #endif
1383 }
1384
1385 // Enable rendering to texture (fbo)
rlEnableFramebuffer(unsigned int id)1386 void rlEnableFramebuffer(unsigned int id)
1387 {
1388 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
1389 glBindFramebuffer(GL_FRAMEBUFFER, id);
1390 #endif
1391 }
1392
1393 // Disable rendering to texture
rlDisableFramebuffer(void)1394 void rlDisableFramebuffer(void)
1395 {
1396 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
1397 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1398 #endif
1399 }
1400
1401 // Enable depth test
rlEnableDepthTest(void)1402 void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); }
1403
1404 // Disable depth test
rlDisableDepthTest(void)1405 void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); }
1406
1407 // Enable depth write
rlEnableDepthMask(void)1408 void rlEnableDepthMask(void) { glDepthMask(GL_TRUE); }
1409
1410 // Disable depth write
rlDisableDepthMask(void)1411 void rlDisableDepthMask(void) { glDepthMask(GL_FALSE); }
1412
1413 // Enable backface culling
rlEnableBackfaceCulling(void)1414 void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); }
1415
1416 // Disable backface culling
rlDisableBackfaceCulling(void)1417 void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); }
1418
1419 // Enable scissor test
rlEnableScissorTest(void)1420 void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); }
1421
1422 // Disable scissor test
rlDisableScissorTest(void)1423 void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); }
1424
1425 // Scissor test
rlScissor(int x,int y,int width,int height)1426 void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); }
1427
1428 // Enable wire mode
rlEnableWireMode(void)1429 void rlEnableWireMode(void)
1430 {
1431 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
1432 // NOTE: glPolygonMode() not available on OpenGL ES
1433 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1434 #endif
1435 }
1436
1437 // Disable wire mode
rlDisableWireMode(void)1438 void rlDisableWireMode(void)
1439 {
1440 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
1441 // NOTE: glPolygonMode() not available on OpenGL ES
1442 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1443 #endif
1444 }
1445 // Set the line drawing width
rlSetLineWidth(float width)1446 void rlSetLineWidth(float width)
1447 {
1448 glLineWidth(width);
1449 }
1450
1451 // Get the line drawing width
rlGetLineWidth(void)1452 float rlGetLineWidth(void)
1453 {
1454 float width = 0;
1455 glGetFloatv(GL_LINE_WIDTH, &width);
1456 return width;
1457 }
1458
1459 // Enable line aliasing
rlEnableSmoothLines(void)1460 void rlEnableSmoothLines(void)
1461 {
1462 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11)
1463 glEnable(GL_LINE_SMOOTH);
1464 #endif
1465 }
1466
1467 // Disable line aliasing
rlDisableSmoothLines(void)1468 void rlDisableSmoothLines(void)
1469 {
1470 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11)
1471 glDisable(GL_LINE_SMOOTH);
1472 #endif
1473 }
1474
1475 // Enable stereo rendering
rlEnableStereoRender(void)1476 void rlEnableStereoRender(void)
1477 {
1478 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
1479 RLGL.State.stereoRender = true;
1480 #endif
1481 }
1482
1483 // Disable stereo rendering
rlDisableStereoRender(void)1484 void rlDisableStereoRender(void)
1485 {
1486 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
1487 RLGL.State.stereoRender = false;
1488 #endif
1489 }
1490
1491 // Check if stereo render is enabled
rlIsStereoRenderEnabled(void)1492 bool rlIsStereoRenderEnabled(void)
1493 {
1494 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
1495 return RLGL.State.stereoRender;
1496 #else
1497 return false;
1498 #endif
1499 }
1500
1501 // Clear color buffer with color
rlClearColor(unsigned char r,unsigned char g,unsigned char b,unsigned char a)1502 void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
1503 {
1504 // Color values clamp to 0.0f(0) and 1.0f(255)
1505 float cr = (float)r/255;
1506 float cg = (float)g/255;
1507 float cb = (float)b/255;
1508 float ca = (float)a/255;
1509
1510 glClearColor(cr, cg, cb, ca);
1511 }
1512
1513 // Clear used screen buffers (color and depth)
rlClearScreenBuffers(void)1514 void rlClearScreenBuffers(void)
1515 {
1516 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D)
1517 //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
1518 }
1519
1520 // Check and log OpenGL error codes
rlCheckErrors()1521 void rlCheckErrors()
1522 {
1523 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1524 int check = 1;
1525 while (check)
1526 {
1527 const GLenum err = glGetError();
1528 switch (err)
1529 {
1530 case GL_NO_ERROR: check = 0; break;
1531 case 0x0500: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_ENUM"); break;
1532 case 0x0501: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_VALUE"); break;
1533 case 0x0502: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_OPERATION"); break;
1534 case 0x0503: TRACELOG(LOG_WARNING, "GL: Error detected: GL_STACK_OVERFLOW"); break;
1535 case 0x0504: TRACELOG(LOG_WARNING, "GL: Error detected: GL_STACK_UNDERFLOW"); break;
1536 case 0x0505: TRACELOG(LOG_WARNING, "GL: Error detected: GL_OUT_OF_MEMORY"); break;
1537 case 0x0506: TRACELOG(LOG_WARNING, "GL: Error detected: GL_INVALID_FRAMEBUFFER_OPERATION"); break;
1538 default: TRACELOG(LOG_WARNING, "GL: Error detected: Unknown error code: %x", err); break;
1539 }
1540 }
1541 #endif
1542 }
1543
1544 // Set blend mode
rlSetBlendMode(int mode)1545 void rlSetBlendMode(int mode)
1546 {
1547 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1548 if (RLGL.State.currentBlendMode != mode)
1549 {
1550 rlDrawRenderBatch(RLGL.currentBatch);
1551
1552 switch (mode)
1553 {
1554 case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break;
1555 case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendEquation(GL_FUNC_ADD); break;
1556 case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break;
1557 case BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); break;
1558 case BLEND_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break;
1559 case BLEND_CUSTOM: glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); break;
1560 default: break;
1561 }
1562
1563 RLGL.State.currentBlendMode = mode;
1564 }
1565 #endif
1566 }
1567
1568 // Set blending mode factor and equation
rlSetBlendFactors(int glSrcFactor,int glDstFactor,int glEquation)1569 void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation)
1570 {
1571 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1572 RLGL.State.glBlendSrcFactor = glSrcFactor;
1573 RLGL.State.glBlendDstFactor = glDstFactor;
1574 RLGL.State.glBlendEquation = glEquation;
1575 #endif
1576 }
1577
1578 //----------------------------------------------------------------------------------
1579 // Module Functions Definition - rlgl functionality
1580 //----------------------------------------------------------------------------------
1581
1582 // Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
rlglInit(int width,int height)1583 void rlglInit(int width, int height)
1584 {
1585 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1586 // Init default white texture
1587 unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
1588 RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
1589
1590 if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId);
1591 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture");
1592
1593 // Init default Shader (customized for GL 3.3 and ES2)
1594 rlLoadShaderDefault(); // RLGL.State.defaultShader
1595 RLGL.State.currentShader = RLGL.State.defaultShader;
1596
1597 // Init default vertex arrays buffers
1598 RLGL.defaultBatch = rlLoadRenderBatch(DEFAULT_BATCH_BUFFERS, DEFAULT_BATCH_BUFFER_ELEMENTS);
1599 RLGL.currentBatch = &RLGL.defaultBatch;
1600
1601 // Init stack matrices (emulating OpenGL 1.1)
1602 for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity();
1603
1604 // Init internal matrices
1605 RLGL.State.transform = MatrixIdentity();
1606 RLGL.State.projection = MatrixIdentity();
1607 RLGL.State.modelview = MatrixIdentity();
1608 RLGL.State.currentMatrix = &RLGL.State.modelview;
1609 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
1610
1611 // Initialize OpenGL default states
1612 //----------------------------------------------------------
1613 // Init state: Depth test
1614 glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
1615 glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
1616
1617 // Init state: Blending mode
1618 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
1619 glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
1620
1621 // Init state: Culling
1622 // NOTE: All shapes/models triangles are drawn CCW
1623 glCullFace(GL_BACK); // Cull the back face (default)
1624 glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
1625 glEnable(GL_CULL_FACE); // Enable backface culling
1626
1627 // Init state: Cubemap seamless
1628 #if defined(GRAPHICS_API_OPENGL_33)
1629 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
1630 #endif
1631
1632 #if defined(GRAPHICS_API_OPENGL_11)
1633 // Init state: Color hints (deprecated in OpenGL 3.0+)
1634 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
1635 glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
1636 #endif
1637
1638 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1639 // Store screen size into global variables
1640 RLGL.State.framebufferWidth = width;
1641 RLGL.State.framebufferHeight = height;
1642
1643 TRACELOG(LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
1644 //----------------------------------------------------------
1645 #endif
1646
1647 // Init state: Color/Depth buffers clear
1648 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
1649 glClearDepth(1.0f); // Set clear depth value (default)
1650 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
1651 }
1652
1653 // Vertex Buffer Object deinitialization (memory free)
rlglClose(void)1654 void rlglClose(void)
1655 {
1656 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1657 rlUnloadRenderBatch(RLGL.defaultBatch);
1658
1659 rlUnloadShaderDefault(); // Unload default shader
1660
1661 glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
1662 TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
1663 #endif
1664 }
1665
1666 // Load OpenGL extensions
1667 // NOTE: External loader function could be passed as a pointer
rlLoadExtensions(void * loader)1668 void rlLoadExtensions(void *loader)
1669 {
1670 #if defined(GRAPHICS_API_OPENGL_33) // Also defined for GRAPHICS_API_OPENGL_21
1671 // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
1672 #if !defined(__APPLE__)
1673 if (!gladLoadGLLoader((GLADloadproc)loader)) TRACELOG(LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
1674 else TRACELOG(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
1675 #endif
1676
1677 // Get number of supported extensions
1678 GLint numExt = 0;
1679 glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
1680 TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt);
1681
1682 #if defined(SUPPORT_GL_DETAILS_INFO)
1683 // Get supported extensions list
1684 // WARNING: glGetStringi() not available on OpenGL 2.1
1685 char **extList = RL_MALLOC(sizeof(char *)*numExt);
1686 TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
1687 for (int i = 0; i < numExt; i++)
1688 {
1689 extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
1690 TRACELOG(LOG_INFO, " %s", extList[i]);
1691 }
1692 RL_FREE(extList); // Free extensions pointers
1693 #endif
1694
1695 // Register supported extensions flags
1696 // OpenGL 3.3 extensions supported by default (core)
1697 RLGL.ExtSupported.vao = true;
1698 RLGL.ExtSupported.instancing = true;
1699 RLGL.ExtSupported.texNPOT = true;
1700 RLGL.ExtSupported.texFloat32 = true;
1701 RLGL.ExtSupported.texDepth = true;
1702 RLGL.ExtSupported.maxDepthBits = 32;
1703 RLGL.ExtSupported.texAnisoFilter = true;
1704 RLGL.ExtSupported.texMirrorClamp = true;
1705 #if !defined(__APPLE__)
1706 // NOTE: With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans
1707 if (GLAD_GL_EXT_texture_compression_s3tc) RLGL.ExtSupported.texCompDXT = true; // Texture compression: DXT
1708 if (GLAD_GL_ARB_ES3_compatibility) RLGL.ExtSupported.texCompETC2 = true; // Texture compression: ETC2/EAC
1709 #endif
1710 #endif // GRAPHICS_API_OPENGL_33
1711
1712 #if defined(GRAPHICS_API_OPENGL_ES2)
1713 // Get supported extensions list
1714 GLint numExt = 0;
1715 const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
1716 const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
1717
1718 // NOTE: We have to duplicate string because glGetString() returns a const string
1719 int len = strlen(extensions) + 1;
1720 char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char));
1721 strcpy(extensionsDup, extensions);
1722 extList[numExt] = extensionsDup;
1723
1724 for (int i = 0; i < len; i++)
1725 {
1726 if (extensionsDup[i] == ' ')
1727 {
1728 extensionsDup[i] = '\0';
1729 numExt++;
1730 extList[numExt] = &extensionsDup[i + 1];
1731 }
1732 }
1733
1734 TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt);
1735
1736 #if defined(SUPPORT_GL_DETAILS_INFO)
1737 TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
1738 for (int i = 0; i < numExt; i++) TRACELOG(LOG_INFO, " %s", extList[i]);
1739 #endif
1740
1741 // Check required extensions
1742 for (int i = 0; i < numExt; i++)
1743 {
1744 // Check VAO support
1745 // NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature
1746 if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0)
1747 {
1748 // The extension is supported by our hardware and driver, try to get related functions pointers
1749 // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
1750 glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
1751 glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
1752 glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
1753 //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted
1754
1755 if ((glGenVertexArrays != NULL) && (glBindVertexArray != NULL) && (glDeleteVertexArrays != NULL)) RLGL.ExtSupported.vao = true;
1756 }
1757
1758 // Check instanced rendering support
1759 if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // Web ANGLE
1760 {
1761 glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)eglGetProcAddress("glDrawArraysInstancedANGLE");
1762 glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)eglGetProcAddress("glDrawElementsInstancedANGLE");
1763 glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)eglGetProcAddress("glVertexAttribDivisorANGLE");
1764
1765 if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
1766 }
1767 else
1768 {
1769 if ((strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) && // Standard EXT
1770 (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0))
1771 {
1772 glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)eglGetProcAddress("glDrawArraysInstancedEXT");
1773 glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)eglGetProcAddress("glDrawElementsInstancedEXT");
1774 glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)eglGetProcAddress("glVertexAttribDivisorEXT");
1775
1776 if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
1777 }
1778 }
1779
1780 // Check NPOT textures support
1781 // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
1782 if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) RLGL.ExtSupported.texNPOT = true;
1783
1784 // Check texture float support
1785 if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true;
1786
1787 // Check depth texture support
1788 if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) ||
1789 (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true;
1790
1791 if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24;
1792 if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32;
1793
1794 // Check texture compression support: DXT
1795 if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
1796 (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
1797 (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) RLGL.ExtSupported.texCompDXT = true;
1798
1799 // Check texture compression support: ETC1
1800 if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) ||
1801 (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) RLGL.ExtSupported.texCompETC1 = true;
1802
1803 // Check texture compression support: ETC2/EAC
1804 if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) RLGL.ExtSupported.texCompETC2 = true;
1805
1806 // Check texture compression support: PVR
1807 if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) RLGL.ExtSupported.texCompPVRT = true;
1808
1809 // Check texture compression support: ASTC
1810 if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) RLGL.ExtSupported.texCompASTC = true;
1811
1812 // Check anisotropic texture filter support
1813 if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) RLGL.ExtSupported.texAnisoFilter = true;
1814
1815 // Check clamp mirror wrap mode support
1816 if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) RLGL.ExtSupported.texMirrorClamp = true;
1817 }
1818
1819 // Free extensions pointers
1820 RL_FREE(extList);
1821 RL_FREE(extensionsDup); // Duplicated string must be deallocated
1822 #endif // GRAPHICS_API_OPENGL_ES2
1823
1824 // Check OpenGL information and capabilities
1825 //------------------------------------------------------------------------------
1826 // Show current OpenGL and GLSL version
1827 TRACELOG(LOG_INFO, "GL: OpenGL device information:");
1828 TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR));
1829 TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER));
1830 TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION));
1831 TRACELOG(LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
1832
1833 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1834 // NOTE: Anisotropy levels capability is an extension
1835 #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
1836 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
1837 #endif
1838 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel);
1839
1840 #if defined(SUPPORT_GL_DETAILS_INFO)
1841 // Show some OpenGL GPU capabilities
1842 TRACELOG(LOG_INFO, "GL: OpenGL capabilities:");
1843 GLint capability = 0;
1844 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &capability);
1845 TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_SIZE: %i", capability);
1846 glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &capability);
1847 TRACELOG(LOG_INFO, " GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i", capability);
1848 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &capability);
1849 TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_IMAGE_UNITS: %i", capability);
1850 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &capability);
1851 TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIBS: %i", capability);
1852 #if !defined(GRAPHICS_API_OPENGL_ES2)
1853 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &capability);
1854 TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_BLOCK_SIZE: %i", capability);
1855 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &capability);
1856 TRACELOG(LOG_INFO, " GL_MAX_DRAW_BUFFERS: %i", capability);
1857 if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_MAX_ANISOTROPY: %.0f", RLGL.ExtSupported.maxAnisotropyLevel);
1858 #endif
1859 glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &capability);
1860 TRACELOG(LOG_INFO, " GL_NUM_COMPRESSED_TEXTURE_FORMATS: %i", capability);
1861 GLint format[32] = { 0 };
1862 glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
1863 for (int i = 0; i < capability; i++) TRACELOG(LOG_INFO, " %s", rlGetCompressedFormatName(format[i]));
1864
1865 /*
1866 // Following capabilities are only supported by OpenGL 4.3 or greater
1867 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability);
1868 TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability);
1869 glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability);
1870 TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability);
1871 */
1872 #else // SUPPORT_GL_DETAILS_INFO
1873
1874 // Show some basic info about GL supported features
1875 #if defined(GRAPHICS_API_OPENGL_ES2)
1876 if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully");
1877 else TRACELOG(LOG_WARNING, "GL: VAO extension not found, VAO not supported");
1878 if (RLGL.ExtSupported.texNPOT) TRACELOG(LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported");
1879 else TRACELOG(LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)");
1880 #endif
1881 if (RLGL.ExtSupported.texCompDXT) TRACELOG(LOG_INFO, "GL: DXT compressed textures supported");
1882 if (RLGL.ExtSupported.texCompETC1) TRACELOG(LOG_INFO, "GL: ETC1 compressed textures supported");
1883 if (RLGL.ExtSupported.texCompETC2) TRACELOG(LOG_INFO, "GL: ETC2/EAC compressed textures supported");
1884 if (RLGL.ExtSupported.texCompPVRT) TRACELOG(LOG_INFO, "GL: PVRT compressed textures supported");
1885 if (RLGL.ExtSupported.texCompASTC) TRACELOG(LOG_INFO, "GL: ASTC compressed textures supported");
1886 #endif // SUPPORT_GL_DETAILS_INFO
1887
1888 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
1889 }
1890
1891 // Returns current OpenGL version
rlGetVersion(void)1892 int rlGetVersion(void)
1893 {
1894 #if defined(GRAPHICS_API_OPENGL_11)
1895 return OPENGL_11;
1896 #endif
1897 #if defined(GRAPHICS_API_OPENGL_21)
1898 #if defined(__APPLE__)
1899 return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX
1900 #else
1901 return OPENGL_21;
1902 #endif
1903 #elif defined(GRAPHICS_API_OPENGL_33)
1904 return OPENGL_33;
1905 #endif
1906 #if defined(GRAPHICS_API_OPENGL_ES2)
1907 return OPENGL_ES_20;
1908 #endif
1909 }
1910
1911 // Get default framebuffer width
rlGetFramebufferWidth(void)1912 int rlGetFramebufferWidth(void)
1913 {
1914 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1915 return RLGL.State.framebufferWidth;
1916 #else
1917 return 0;
1918 #endif
1919 }
1920
1921 // Get default framebuffer height
rlGetFramebufferHeight(void)1922 int rlGetFramebufferHeight(void)
1923 {
1924 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1925 return RLGL.State.framebufferHeight;
1926 #else
1927 return 0;
1928 #endif
1929 }
1930
1931 // Get default internal shader (simple texture + tint color)
rlGetShaderDefault(void)1932 Shader rlGetShaderDefault(void)
1933 {
1934 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1935 return RLGL.State.defaultShader;
1936 #else
1937 Shader shader = { 0 };
1938 return shader;
1939 #endif
1940 }
1941
1942 // Get default internal texture (white texture)
rlGetTextureDefault(void)1943 Texture2D rlGetTextureDefault(void)
1944 {
1945 Texture2D texture = { 0 };
1946 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1947 texture.id = RLGL.State.defaultTextureId;
1948 texture.width = 1;
1949 texture.height = 1;
1950 texture.mipmaps = 1;
1951 texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1952 #endif
1953 return texture;
1954 }
1955
1956 // Render batch management
1957 //------------------------------------------------------------------------------------------------
1958 // Load render batch
rlLoadRenderBatch(int numBuffers,int bufferElements)1959 RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
1960 {
1961 RenderBatch batch = { 0 };
1962
1963 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1964 // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
1965 //--------------------------------------------------------------------------------------------
1966 batch.vertexBuffer = (VertexBuffer *)RL_MALLOC(sizeof(VertexBuffer)*numBuffers);
1967
1968 for (int i = 0; i < numBuffers; i++)
1969 {
1970 batch.vertexBuffer[i].elementsCount = bufferElements;
1971
1972 batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad
1973 batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad
1974 batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(bufferElements*4*4*sizeof(unsigned char)); // 4 float by color, 4 colors by quad
1975 #if defined(GRAPHICS_API_OPENGL_33)
1976 batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices)
1977 #endif
1978 #if defined(GRAPHICS_API_OPENGL_ES2)
1979 batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(bufferElements*6*sizeof(unsigned short)); // 6 int by quad (indices)
1980 #endif
1981
1982 for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f;
1983 for (int j = 0; j < (2*4*bufferElements); j++) batch.vertexBuffer[i].texcoords[j] = 0.0f;
1984 for (int j = 0; j < (4*4*bufferElements); j++) batch.vertexBuffer[i].colors[j] = 0;
1985
1986 int k = 0;
1987
1988 // Indices can be initialized right now
1989 for (int j = 0; j < (6*bufferElements); j += 6)
1990 {
1991 batch.vertexBuffer[i].indices[j] = 4*k;
1992 batch.vertexBuffer[i].indices[j + 1] = 4*k + 1;
1993 batch.vertexBuffer[i].indices[j + 2] = 4*k + 2;
1994 batch.vertexBuffer[i].indices[j + 3] = 4*k;
1995 batch.vertexBuffer[i].indices[j + 4] = 4*k + 2;
1996 batch.vertexBuffer[i].indices[j + 5] = 4*k + 3;
1997
1998 k++;
1999 }
2000
2001 batch.vertexBuffer[i].vCounter = 0;
2002 batch.vertexBuffer[i].tcCounter = 0;
2003 batch.vertexBuffer[i].cCounter = 0;
2004 }
2005
2006 TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)");
2007 //--------------------------------------------------------------------------------------------
2008
2009 // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs
2010 //--------------------------------------------------------------------------------------------
2011 for (int i = 0; i < numBuffers; i++)
2012 {
2013 if (RLGL.ExtSupported.vao)
2014 {
2015 // Initialize Quads VAO
2016 glGenVertexArrays(1, &batch.vertexBuffer[i].vaoId);
2017 glBindVertexArray(batch.vertexBuffer[i].vaoId);
2018 }
2019
2020 // Quads - Vertex buffers binding and attributes enable
2021 // Vertex position buffer (shader-location = 0)
2022 glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]);
2023 glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[0]);
2024 glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW);
2025 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION]);
2026 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
2027
2028 // Vertex texcoord buffer (shader-location = 1)
2029 glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]);
2030 glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[1]);
2031 glBufferData(GL_ARRAY_BUFFER, bufferElements*2*4*sizeof(float), batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW);
2032 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
2033 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
2034
2035 // Vertex color buffer (shader-location = 3)
2036 glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]);
2037 glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]);
2038 glBufferData(GL_ARRAY_BUFFER, bufferElements*4*4*sizeof(unsigned char), batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW);
2039 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR]);
2040 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
2041
2042 // Fill index buffer
2043 glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]);
2044 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]);
2045 #if defined(GRAPHICS_API_OPENGL_33)
2046 glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(int), batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
2047 #endif
2048 #if defined(GRAPHICS_API_OPENGL_ES2)
2049 glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(short), batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
2050 #endif
2051 }
2052
2053 TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)");
2054
2055 // Unbind the current VAO
2056 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2057 //--------------------------------------------------------------------------------------------
2058
2059 // Init draw calls tracking system
2060 //--------------------------------------------------------------------------------------------
2061 batch.draws = (DrawCall *)RL_MALLOC(DEFAULT_BATCH_DRAWCALLS*sizeof(DrawCall));
2062
2063 for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++)
2064 {
2065 batch.draws[i].mode = RL_QUADS;
2066 batch.draws[i].vertexCount = 0;
2067 batch.draws[i].vertexAlignment = 0;
2068 //batch.draws[i].vaoId = 0;
2069 //batch.draws[i].shaderId = 0;
2070 batch.draws[i].textureId = RLGL.State.defaultTextureId;
2071 //batch.draws[i].RLGL.State.projection = MatrixIdentity();
2072 //batch.draws[i].RLGL.State.modelview = MatrixIdentity();
2073 }
2074
2075 batch.buffersCount = numBuffers; // Record buffer count
2076 batch.drawsCounter = 1; // Reset draws counter
2077 batch.currentDepth = -1.0f; // Reset depth value
2078 //--------------------------------------------------------------------------------------------
2079 #endif
2080
2081 return batch;
2082 }
2083
2084 // Unload default internal buffers vertex data from CPU and GPU
rlUnloadRenderBatch(RenderBatch batch)2085 void rlUnloadRenderBatch(RenderBatch batch)
2086 {
2087 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2088 // Unbind everything
2089 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2090 glDisableVertexAttribArray(0);
2091 glDisableVertexAttribArray(1);
2092 glDisableVertexAttribArray(2);
2093 glDisableVertexAttribArray(3);
2094 glBindBuffer(GL_ARRAY_BUFFER, 0);
2095 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2096
2097 // Unload all vertex buffers data
2098 for (int i = 0; i < batch.buffersCount; i++)
2099 {
2100 // Delete VBOs from GPU (VRAM)
2101 glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]);
2102 glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[1]);
2103 glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[2]);
2104 glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[3]);
2105
2106 // Delete VAOs from GPU (VRAM)
2107 if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &batch.vertexBuffer[i].vaoId);
2108
2109 // Free vertex arrays memory from CPU (RAM)
2110 RL_FREE(batch.vertexBuffer[i].vertices);
2111 RL_FREE(batch.vertexBuffer[i].texcoords);
2112 RL_FREE(batch.vertexBuffer[i].colors);
2113 RL_FREE(batch.vertexBuffer[i].indices);
2114 }
2115
2116 // Unload arrays
2117 RL_FREE(batch.vertexBuffer);
2118 RL_FREE(batch.draws);
2119 #endif
2120 }
2121
2122 // Draw render batch
2123 // NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer)
rlDrawRenderBatch(RenderBatch * batch)2124 void rlDrawRenderBatch(RenderBatch *batch)
2125 {
2126 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2127 // Update batch vertex buffers
2128 //------------------------------------------------------------------------------------------------------------
2129 // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
2130 // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required)
2131 if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0)
2132 {
2133 // Activate elements VAO
2134 if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId);
2135
2136 // Vertex positions buffer
2137 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
2138 glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices);
2139 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer
2140
2141 // Texture coordinates buffer
2142 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]);
2143 glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*2*sizeof(float), batch->vertexBuffer[batch->currentBuffer].texcoords);
2144 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer
2145
2146 // Colors buffer
2147 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]);
2148 glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*4*sizeof(unsigned char), batch->vertexBuffer[batch->currentBuffer].colors);
2149 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer
2150
2151 // NOTE: glMapBuffer() causes sync issue.
2152 // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job.
2153 // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer().
2154 // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new
2155 // allocated pointer immediately even if GPU is still working with the previous data.
2156
2157 // Another option: map the buffer object into client's memory
2158 // Probably this code could be moved somewhere else...
2159 // batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
2160 // if (batch->vertexBuffer[batch->currentBuffer].vertices)
2161 // {
2162 // Update vertex data
2163 // }
2164 // glUnmapBuffer(GL_ARRAY_BUFFER);
2165
2166 // Unbind the current VAO
2167 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2168 }
2169 //------------------------------------------------------------------------------------------------------------
2170
2171 // Draw batch vertex buffers (considering VR stereo if required)
2172 //------------------------------------------------------------------------------------------------------------
2173 Matrix matProjection = RLGL.State.projection;
2174 Matrix matModelView = RLGL.State.modelview;
2175
2176 int eyesCount = 1;
2177 if (RLGL.State.stereoRender) eyesCount = 2;
2178
2179 for (int eye = 0; eye < eyesCount; eye++)
2180 {
2181 if (eyesCount == 2)
2182 {
2183 // Setup current eye viewport (half screen width)
2184 rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight);
2185
2186 // Set current eye view offset to modelview matrix
2187 rlSetMatrixModelview(MatrixMultiply(matModelView, RLGL.State.viewOffsetStereo[eye]));
2188 // Set current eye projection matrix
2189 rlSetMatrixProjection(RLGL.State.projectionStereo[eye]);
2190 }
2191
2192 // Draw buffers
2193 if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0)
2194 {
2195 // Set current shader and upload current MVP matrix
2196 glUseProgram(RLGL.State.currentShader.id);
2197
2198 // Create modelview-projection matrix and upload to shader
2199 Matrix matMVP = MatrixMultiply(RLGL.State.modelview, RLGL.State.projection);
2200 glUniformMatrix4fv(RLGL.State.currentShader.locs[SHADER_LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP));
2201
2202 if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId);
2203 else
2204 {
2205 // Bind vertex attrib: position (shader-location = 0)
2206 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
2207 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
2208 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_POSITION]);
2209
2210 // Bind vertex attrib: texcoord (shader-location = 1)
2211 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]);
2212 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
2213 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
2214
2215 // Bind vertex attrib: color (shader-location = 3)
2216 glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]);
2217 glVertexAttribPointer(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
2218 glEnableVertexAttribArray(RLGL.State.currentShader.locs[SHADER_LOC_VERTEX_COLOR]);
2219
2220 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]);
2221 }
2222
2223 // Setup some default shader values
2224 glUniform4f(RLGL.State.currentShader.locs[SHADER_LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f);
2225 glUniform1i(RLGL.State.currentShader.locs[SHADER_LOC_MAP_DIFFUSE], 0); // Active default sampler2D: texture0
2226
2227 // Activate additional sampler textures
2228 // Those additional textures will be common for all draw calls of the batch
2229 for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++)
2230 {
2231 if (RLGL.State.activeTextureId[i] > 0)
2232 {
2233 glActiveTexture(GL_TEXTURE0 + 1 + i);
2234 glBindTexture(GL_TEXTURE_2D, RLGL.State.activeTextureId[i]);
2235 }
2236 }
2237
2238 // Activate default sampler2D texture0 (one texture is always active for default batch shader)
2239 // NOTE: Batch system accumulates calls by texture0 changes, additional textures are enabled for all the draw calls
2240 glActiveTexture(GL_TEXTURE0);
2241
2242 for (int i = 0, vertexOffset = 0; i < batch->drawsCounter; i++)
2243 {
2244 // Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default
2245 glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId);
2246
2247 if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount);
2248 else
2249 {
2250 #if defined(GRAPHICS_API_OPENGL_33)
2251 // We need to define the number of indices to be processed: quadsCount*6
2252 // NOTE: The final parameter tells the GPU the offset in bytes from the
2253 // start of the index buffer to the location of the first index to process
2254 glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint)));
2255 #endif
2256 #if defined(GRAPHICS_API_OPENGL_ES2)
2257 glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(vertexOffset/4*6*sizeof(GLushort)));
2258 #endif
2259 }
2260
2261 vertexOffset += (batch->draws[i].vertexCount + batch->draws[i].vertexAlignment);
2262 }
2263
2264 if (!RLGL.ExtSupported.vao)
2265 {
2266 glBindBuffer(GL_ARRAY_BUFFER, 0);
2267 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2268 }
2269
2270 glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
2271 }
2272
2273 if (RLGL.ExtSupported.vao) glBindVertexArray(0); // Unbind VAO
2274
2275 glUseProgram(0); // Unbind shader program
2276 }
2277 //------------------------------------------------------------------------------------------------------------
2278
2279 // Reset batch buffers
2280 //------------------------------------------------------------------------------------------------------------
2281 // Reset vertex counters for next frame
2282 batch->vertexBuffer[batch->currentBuffer].vCounter = 0;
2283 batch->vertexBuffer[batch->currentBuffer].tcCounter = 0;
2284 batch->vertexBuffer[batch->currentBuffer].cCounter = 0;
2285
2286 // Reset depth for next draw
2287 batch->currentDepth = -1.0f;
2288
2289 // Restore projection/modelview matrices
2290 RLGL.State.projection = matProjection;
2291 RLGL.State.modelview = matModelView;
2292
2293 // Reset RLGL.currentBatch->draws array
2294 for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++)
2295 {
2296 batch->draws[i].mode = RL_QUADS;
2297 batch->draws[i].vertexCount = 0;
2298 batch->draws[i].textureId = RLGL.State.defaultTextureId;
2299 }
2300
2301 // Reset active texture units for next batch
2302 for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) RLGL.State.activeTextureId[i] = 0;
2303
2304 // Reset draws counter to one draw for the batch
2305 batch->drawsCounter = 1;
2306 //------------------------------------------------------------------------------------------------------------
2307
2308 // Change to next buffer in the list (in case of multi-buffering)
2309 batch->currentBuffer++;
2310 if (batch->currentBuffer >= batch->buffersCount) batch->currentBuffer = 0;
2311 #endif
2312 }
2313
2314 // Set the active render batch for rlgl
rlSetRenderBatchActive(RenderBatch * batch)2315 void rlSetRenderBatchActive(RenderBatch *batch)
2316 {
2317 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2318 rlDrawRenderBatch(RLGL.currentBatch);
2319
2320 if (batch != NULL) RLGL.currentBatch = batch;
2321 else RLGL.currentBatch = &RLGL.defaultBatch;
2322 #endif
2323 }
2324
2325 // Update and draw internal render batch
rlDrawRenderBatchActive(void)2326 void rlDrawRenderBatchActive(void)
2327 {
2328 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2329 rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside
2330 #endif
2331 }
2332
2333 // Check internal buffer overflow for a given number of vertex
2334 // and force a RenderBatch draw call if required
rlCheckRenderBatchLimit(int vCount)2335 bool rlCheckRenderBatchLimit(int vCount)
2336 {
2337 bool overflow = false;
2338
2339 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2340 if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + vCount) >=
2341 (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4))
2342 {
2343 overflow = true;
2344 rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside
2345 }
2346 #endif
2347
2348 return overflow;
2349 }
2350
2351 // Textures data management
2352 //-----------------------------------------------------------------------------------------
2353 // Convert image data to OpenGL texture (returns OpenGL valid Id)
rlLoadTexture(void * data,int width,int height,int format,int mipmapCount)2354 unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount)
2355 {
2356 glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
2357
2358 unsigned int id = 0;
2359
2360 // Check texture format support by OpenGL 1.1 (compressed textures not supported)
2361 #if defined(GRAPHICS_API_OPENGL_11)
2362 if (format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
2363 {
2364 TRACELOG(LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats");
2365 return id;
2366 }
2367 #else
2368 if ((!RLGL.ExtSupported.texCompDXT) && ((format == PIXELFORMAT_COMPRESSED_DXT1_RGB) || (format == PIXELFORMAT_COMPRESSED_DXT1_RGBA) ||
2369 (format == PIXELFORMAT_COMPRESSED_DXT3_RGBA) || (format == PIXELFORMAT_COMPRESSED_DXT5_RGBA)))
2370 {
2371 TRACELOG(LOG_WARNING, "GL: DXT compressed texture format not supported");
2372 return id;
2373 }
2374 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2375 if ((!RLGL.ExtSupported.texCompETC1) && (format == PIXELFORMAT_COMPRESSED_ETC1_RGB))
2376 {
2377 TRACELOG(LOG_WARNING, "GL: ETC1 compressed texture format not supported");
2378 return id;
2379 }
2380
2381 if ((!RLGL.ExtSupported.texCompETC2) && ((format == PIXELFORMAT_COMPRESSED_ETC2_RGB) || (format == PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA)))
2382 {
2383 TRACELOG(LOG_WARNING, "GL: ETC2 compressed texture format not supported");
2384 return id;
2385 }
2386
2387 if ((!RLGL.ExtSupported.texCompPVRT) && ((format == PIXELFORMAT_COMPRESSED_PVRT_RGB) || (format == PIXELFORMAT_COMPRESSED_PVRT_RGBA)))
2388 {
2389 TRACELOG(LOG_WARNING, "GL: PVRT compressed texture format not supported");
2390 return id;
2391 }
2392
2393 if ((!RLGL.ExtSupported.texCompASTC) && ((format == PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA) || (format == PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)))
2394 {
2395 TRACELOG(LOG_WARNING, "GL: ASTC compressed texture format not supported");
2396 return id;
2397 }
2398 #endif
2399 #endif // GRAPHICS_API_OPENGL_11
2400
2401 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2402
2403 glGenTextures(1, &id); // Generate texture id
2404
2405 glBindTexture(GL_TEXTURE_2D, id);
2406
2407 int mipWidth = width;
2408 int mipHeight = height;
2409 int mipOffset = 0; // Mipmap data offset
2410
2411 // Load the different mipmap levels
2412 for (int i = 0; i < mipmapCount; i++)
2413 {
2414 unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format);
2415
2416 unsigned int glInternalFormat, glFormat, glType;
2417 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
2418
2419 TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
2420
2421 if (glInternalFormat != -1)
2422 {
2423 if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, (unsigned char *)data + mipOffset);
2424 #if !defined(GRAPHICS_API_OPENGL_11)
2425 else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, (unsigned char *)data + mipOffset);
2426 #endif
2427
2428 #if defined(GRAPHICS_API_OPENGL_33)
2429 if (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
2430 {
2431 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
2432 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2433 }
2434 else if (format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA)
2435 {
2436 #if defined(GRAPHICS_API_OPENGL_21)
2437 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA };
2438 #elif defined(GRAPHICS_API_OPENGL_33)
2439 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
2440 #endif
2441 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2442 }
2443 #endif
2444 }
2445
2446 mipWidth /= 2;
2447 mipHeight /= 2;
2448 mipOffset += mipSize;
2449
2450 // Security check for NPOT textures
2451 if (mipWidth < 1) mipWidth = 1;
2452 if (mipHeight < 1) mipHeight = 1;
2453 }
2454
2455 // Texture parameters configuration
2456 // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
2457 #if defined(GRAPHICS_API_OPENGL_ES2)
2458 // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used
2459 if (RLGL.ExtSupported.texNPOT)
2460 {
2461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
2462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
2463 }
2464 else
2465 {
2466 // NOTE: If using negative texture coordinates (LoadOBJ()), it does not work!
2467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis
2468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis
2469 }
2470 #else
2471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
2472 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
2473 #endif
2474
2475 // Magnification and minification filters
2476 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
2477 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
2478
2479 #if defined(GRAPHICS_API_OPENGL_33)
2480 if (mipmapCount > 1)
2481 {
2482 // Activate Trilinear filtering if mipmaps are available
2483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2484 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2485 }
2486 #endif
2487
2488 // At this point we have the texture loaded in GPU and texture parameters configured
2489
2490 // NOTE: If mipmaps were not in data, they are not generated automatically
2491
2492 // Unbind current texture
2493 glBindTexture(GL_TEXTURE_2D, 0);
2494
2495 if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Texture loaded successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount);
2496 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load texture");
2497
2498 return id;
2499 }
2500
2501 // Load depth texture/renderbuffer (to be attached to fbo)
2502 // WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture/WEBGL_depth_texture extensions
rlLoadTextureDepth(int width,int height,bool useRenderBuffer)2503 unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
2504 {
2505 unsigned int id = 0;
2506
2507 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2508 // In case depth textures not supported, we force renderbuffer usage
2509 if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true;
2510
2511 // NOTE: We let the implementation to choose the best bit-depth
2512 // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F
2513 unsigned int glInternalFormat = GL_DEPTH_COMPONENT;
2514
2515 #if defined(GRAPHICS_API_OPENGL_ES2)
2516 if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES;
2517 else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES;
2518 else glInternalFormat = GL_DEPTH_COMPONENT16;
2519 #endif
2520
2521 if (!useRenderBuffer && RLGL.ExtSupported.texDepth)
2522 {
2523 glGenTextures(1, &id);
2524 glBindTexture(GL_TEXTURE_2D, id);
2525 glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
2526
2527 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2528 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2529 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2530 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2531
2532 glBindTexture(GL_TEXTURE_2D, 0);
2533
2534 TRACELOG(LOG_INFO, "TEXTURE: Depth texture loaded successfully");
2535 }
2536 else
2537 {
2538 // Create the renderbuffer that will serve as the depth attachment for the framebuffer
2539 // NOTE: A renderbuffer is simpler than a texture and could offer better performance on embedded devices
2540 glGenRenderbuffers(1, &id);
2541 glBindRenderbuffer(GL_RENDERBUFFER, id);
2542 glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height);
2543
2544 glBindRenderbuffer(GL_RENDERBUFFER, 0);
2545
2546 TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16);
2547 }
2548 #endif
2549
2550 return id;
2551 }
2552
2553 // Load texture cubemap
2554 // NOTE: Cubemap data is expected to be 6 images in a single data array (one after the other),
2555 // expected the following convention: +X, -X, +Y, -Y, +Z, -Z
rlLoadTextureCubemap(void * data,int size,int format)2556 unsigned int rlLoadTextureCubemap(void *data, int size, int format)
2557 {
2558 unsigned int id = 0;
2559
2560 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2561 unsigned int dataSize = rlGetPixelDataSize(size, size, format);
2562
2563 glGenTextures(1, &id);
2564 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
2565
2566 unsigned int glInternalFormat, glFormat, glType;
2567 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
2568
2569 if (glInternalFormat != -1)
2570 {
2571 // Load cubemap faces
2572 for (unsigned int i = 0; i < 6; i++)
2573 {
2574 if (data == NULL)
2575 {
2576 if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
2577 {
2578 if (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32)
2579 {
2580 // Instead of using a sized internal texture format (GL_RGB16F, GL_RGB32F), we let the driver to choose the better format for us (GL_RGB)
2581 if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
2582 else TRACELOG(LOG_WARNING, "TEXTURES: Cubemap requested format not supported");
2583 }
2584 else if ((format == PIXELFORMAT_UNCOMPRESSED_R32) || (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "TEXTURES: Cubemap requested format not supported");
2585 else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, NULL);
2586 }
2587 else TRACELOG(LOG_WARNING, "TEXTURES: Empty cubemap creation does not support compressed format");
2588 }
2589 else
2590 {
2591 if (format < PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, (unsigned char *)data + i*dataSize);
2592 else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, dataSize, (unsigned char *)data + i*dataSize);
2593 }
2594
2595 #if defined(GRAPHICS_API_OPENGL_33)
2596 if (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
2597 {
2598 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
2599 glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2600 }
2601 else if (format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA)
2602 {
2603 #if defined(GRAPHICS_API_OPENGL_21)
2604 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA };
2605 #elif defined(GRAPHICS_API_OPENGL_33)
2606 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
2607 #endif
2608 glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2609 }
2610 #endif
2611 }
2612 }
2613
2614 // Set cubemap texture sampling parameters
2615 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2616 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2617 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2618 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2619 #if defined(GRAPHICS_API_OPENGL_33)
2620 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0
2621 #endif
2622
2623 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
2624 #endif
2625
2626 if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Cubemap texture loaded successfully (%ix%i)", id, size, size);
2627 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load cubemap texture");
2628
2629 return id;
2630 }
2631
2632 // Update already loaded texture in GPU with new data
2633 // NOTE: We don't know safely if internal texture format is the expected one...
rlUpdateTexture(unsigned int id,int offsetX,int offsetY,int width,int height,int format,const void * data)2634 void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data)
2635 {
2636 glBindTexture(GL_TEXTURE_2D, id);
2637
2638 unsigned int glInternalFormat, glFormat, glType;
2639 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
2640
2641 if ((glInternalFormat != -1) && (format < PIXELFORMAT_COMPRESSED_DXT1_RGB))
2642 {
2643 glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, (unsigned char *)data);
2644 }
2645 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format);
2646 }
2647
2648 // Get OpenGL internal formats and data type from raylib PixelFormat
rlGetGlTextureFormats(int format,unsigned int * glInternalFormat,unsigned int * glFormat,unsigned int * glType)2649 void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType)
2650 {
2651 *glInternalFormat = -1;
2652 *glFormat = -1;
2653 *glType = -1;
2654
2655 switch (format)
2656 {
2657 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
2658 // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
2659 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break;
2660 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break;
2661 case PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
2662 case PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
2663 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
2664 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
2665 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
2666 #if !defined(GRAPHICS_API_OPENGL_11)
2667 case PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2668 case PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2669 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2670 #endif
2671 #elif defined(GRAPHICS_API_OPENGL_33)
2672 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break;
2673 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break;
2674 case PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
2675 case PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
2676 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
2677 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
2678 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
2679 case PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break;
2680 case PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break;
2681 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break;
2682 #endif
2683 #if !defined(GRAPHICS_API_OPENGL_11)
2684 case PIXELFORMAT_COMPRESSED_DXT1_RGB: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
2685 case PIXELFORMAT_COMPRESSED_DXT1_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
2686 case PIXELFORMAT_COMPRESSED_DXT3_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
2687 case PIXELFORMAT_COMPRESSED_DXT5_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
2688 case PIXELFORMAT_COMPRESSED_ETC1_RGB: if (RLGL.ExtSupported.texCompETC1) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
2689 case PIXELFORMAT_COMPRESSED_ETC2_RGB: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
2690 case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
2691 case PIXELFORMAT_COMPRESSED_PVRT_RGB: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
2692 case PIXELFORMAT_COMPRESSED_PVRT_RGBA: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
2693 case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
2694 case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
2695 #endif
2696 default: TRACELOG(LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break;
2697 }
2698 }
2699
2700 // Unload texture from GPU memory
rlUnloadTexture(unsigned int id)2701 void rlUnloadTexture(unsigned int id)
2702 {
2703 glDeleteTextures(1, &id);
2704 }
2705
2706 // Generate mipmap data for selected texture
rlGenerateMipmaps(Texture2D * texture)2707 void rlGenerateMipmaps(Texture2D *texture)
2708 {
2709 glBindTexture(GL_TEXTURE_2D, texture->id);
2710
2711 // Check if texture is power-of-two (POT)
2712 bool texIsPOT = false;
2713
2714 if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) &&
2715 ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true;
2716
2717 #if defined(GRAPHICS_API_OPENGL_11)
2718 if (texIsPOT)
2719 {
2720 // WARNING: Manual mipmap generation only works for RGBA 32bit textures!
2721 if (texture->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
2722 {
2723 // Retrieve texture data from VRAM
2724 void *texData = rlReadTexturePixels(*texture);
2725
2726 // NOTE: Texture data size is reallocated to fit mipmaps data
2727 // NOTE: CPU mipmap generation only supports RGBA 32bit data
2728 int mipmapCount = rlGenerateMipmapsData(texData, texture->width, texture->height);
2729
2730 int size = texture->width*texture->height*4;
2731 int offset = size;
2732
2733 int mipWidth = texture->width/2;
2734 int mipHeight = texture->height/2;
2735
2736 // Load the mipmaps
2737 for (int level = 1; level < mipmapCount; level++)
2738 {
2739 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)texData + offset);
2740
2741 size = mipWidth*mipHeight*4;
2742 offset += size;
2743
2744 mipWidth /= 2;
2745 mipHeight /= 2;
2746 }
2747
2748 texture->mipmaps = mipmapCount + 1;
2749 RL_FREE(texData); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
2750
2751 TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Mipmaps generated manually on CPU side, total: %i", texture->id, texture->mipmaps);
2752 }
2753 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps for provided texture format", texture->id);
2754 }
2755 #endif
2756 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2757 if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
2758 {
2759 //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
2760 glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
2761
2762 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2763 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps
2764
2765 #define MIN(a,b) (((a)<(b))?(a):(b))
2766 #define MAX(a,b) (((a)>(b))?(a):(b))
2767
2768 texture->mipmaps = 1 + (int)floor(log(MAX(texture->width, texture->height))/log(2));
2769 TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", texture->id, texture->mipmaps);
2770 }
2771 #endif
2772 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", texture->id);
2773
2774 glBindTexture(GL_TEXTURE_2D, 0);
2775 }
2776
2777
2778 // Read texture pixel data
rlReadTexturePixels(Texture2D texture)2779 void *rlReadTexturePixels(Texture2D texture)
2780 {
2781 void *pixels = NULL;
2782
2783 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2784 glBindTexture(GL_TEXTURE_2D, texture.id);
2785
2786 // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0)
2787 // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
2788 //int width, height, format;
2789 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
2790 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
2791 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
2792
2793 // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding.
2794 // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
2795 // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
2796 // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
2797 glPixelStorei(GL_PACK_ALIGNMENT, 1);
2798
2799 unsigned int glInternalFormat, glFormat, glType;
2800 rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType);
2801 unsigned int size = rlGetPixelDataSize(texture.width, texture.height, texture.format);
2802
2803 if ((glInternalFormat != -1) && (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB))
2804 {
2805 pixels = RL_MALLOC(size);
2806 glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels);
2807 }
2808 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", texture.id, texture.format);
2809
2810 glBindTexture(GL_TEXTURE_2D, 0);
2811 #endif
2812
2813 #if defined(GRAPHICS_API_OPENGL_ES2)
2814 // glGetTexImage() is not available on OpenGL ES 2.0
2815 // Texture width and height are required on OpenGL ES 2.0. There is no way to get it from texture id.
2816 // Two possible Options:
2817 // 1 - Bind texture to color fbo attachment and glReadPixels()
2818 // 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
2819 // We are using Option 1, just need to care for texture format on retrieval
2820 // NOTE: This behaviour could be conditioned by graphic driver...
2821 unsigned int fboId = rlLoadFramebuffer(texture.width, texture.height);
2822
2823 // TODO: Create depth texture/renderbuffer for fbo?
2824
2825 glBindFramebuffer(GL_FRAMEBUFFER, fboId);
2826 glBindTexture(GL_TEXTURE_2D, 0);
2827
2828 // Attach our texture to FBO
2829 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0);
2830
2831 // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format
2832 pixels = (unsigned char *)RL_MALLOC(rlGetPixelDataSize(texture.width, texture.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8));
2833 glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
2834
2835 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2836
2837 // Clean up temporal fbo
2838 rlUnloadFramebuffer(fboId);
2839 #endif
2840
2841 return pixels;
2842 }
2843
2844
2845 // Read screen pixel data (color buffer)
rlReadScreenPixels(int width,int height)2846 unsigned char *rlReadScreenPixels(int width, int height)
2847 {
2848 unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
2849
2850 // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
2851 // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly!
2852 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
2853
2854 // Flip image vertically!
2855 unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char));
2856
2857 for (int y = height - 1; y >= 0; y--)
2858 {
2859 for (int x = 0; x < (width*4); x++)
2860 {
2861 imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line
2862
2863 // Set alpha component value to 255 (no trasparent image retrieval)
2864 // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
2865 if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255;
2866 }
2867 }
2868
2869 RL_FREE(screenData);
2870
2871 return imgData; // NOTE: image data should be freed
2872 }
2873
2874 // Framebuffer management (fbo)
2875 //-----------------------------------------------------------------------------------------
2876 // Load a framebuffer to be used for rendering
2877 // NOTE: No textures attached
rlLoadFramebuffer(int width,int height)2878 unsigned int rlLoadFramebuffer(int width, int height)
2879 {
2880 unsigned int fboId = 0;
2881
2882 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
2883 glGenFramebuffers(1, &fboId); // Create the framebuffer object
2884 glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer
2885 #endif
2886
2887 return fboId;
2888 }
2889
2890 // Attach color buffer texture to an fbo (unloads previous attachment)
2891 // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture
rlFramebufferAttach(unsigned int fboId,unsigned int texId,int attachType,int texType,int mipLevel)2892 void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel)
2893 {
2894 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
2895 glBindFramebuffer(GL_FRAMEBUFFER, fboId);
2896
2897 switch (attachType)
2898 {
2899 case RL_ATTACHMENT_COLOR_CHANNEL0:
2900 case RL_ATTACHMENT_COLOR_CHANNEL1:
2901 case RL_ATTACHMENT_COLOR_CHANNEL2:
2902 case RL_ATTACHMENT_COLOR_CHANNEL3:
2903 case RL_ATTACHMENT_COLOR_CHANNEL4:
2904 case RL_ATTACHMENT_COLOR_CHANNEL5:
2905 case RL_ATTACHMENT_COLOR_CHANNEL6:
2906 case RL_ATTACHMENT_COLOR_CHANNEL7:
2907 {
2908 if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
2909 else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
2910 else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
2911
2912 } break;
2913 case RL_ATTACHMENT_DEPTH:
2914 {
2915 if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
2916 else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
2917
2918 } break;
2919 case RL_ATTACHMENT_STENCIL:
2920 {
2921 if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
2922 else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
2923
2924 } break;
2925 default: break;
2926 }
2927
2928 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2929 #endif
2930 }
2931
2932 // Verify render texture is complete
rlFramebufferComplete(unsigned int id)2933 bool rlFramebufferComplete(unsigned int id)
2934 {
2935 bool result = false;
2936
2937 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
2938 glBindFramebuffer(GL_FRAMEBUFFER, id);
2939
2940 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
2941
2942 if (status != GL_FRAMEBUFFER_COMPLETE)
2943 {
2944 switch (status)
2945 {
2946 case GL_FRAMEBUFFER_UNSUPPORTED: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer is unsupported", id); break;
2947 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete attachment", id); break;
2948 #if defined(GRAPHICS_API_OPENGL_ES2)
2949 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete dimensions", id); break;
2950 #endif
2951 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has a missing attachment", id); break;
2952 default: break;
2953 }
2954 }
2955
2956 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2957
2958 result = (status == GL_FRAMEBUFFER_COMPLETE);
2959 #endif
2960
2961 return result;
2962 }
2963
2964 // Unload framebuffer from GPU memory
2965 // NOTE: All attached textures/cubemaps/renderbuffers are also deleted
rlUnloadFramebuffer(unsigned int id)2966 void rlUnloadFramebuffer(unsigned int id)
2967 {
2968 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
2969
2970 // Query depth attachment to automatically delete texture/renderbuffer
2971 int depthType = 0, depthId = 0;
2972 glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type
2973 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType);
2974 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId);
2975
2976 unsigned int depthIdU = (unsigned int)depthId;
2977 if (depthType == GL_RENDERBUFFER) glDeleteRenderbuffers(1, &depthIdU);
2978 else if (depthType == GL_RENDERBUFFER) glDeleteTextures(1, &depthIdU);
2979
2980 // NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer,
2981 // the texture image is automatically detached from the currently bound framebuffer.
2982
2983 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2984 glDeleteFramebuffers(1, &id);
2985
2986 TRACELOG(LOG_INFO, "FBO: [ID %i] Unloaded framebuffer from VRAM (GPU)", id);
2987 #endif
2988 }
2989
2990 // Vertex data management
2991 //-----------------------------------------------------------------------------------------
2992 // Load a new attributes buffer
rlLoadVertexBuffer(void * buffer,int size,bool dynamic)2993 unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic)
2994 {
2995 unsigned int id = 0;
2996
2997 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2998 glGenBuffers(1, &id);
2999 glBindBuffer(GL_ARRAY_BUFFER, id);
3000 glBufferData(GL_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
3001 #endif
3002
3003 return id;
3004 }
3005
3006 // Load a new attributes element buffer
rlLoadVertexBufferElement(void * buffer,int size,bool dynamic)3007 unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic)
3008 {
3009 unsigned int id = 0;
3010
3011 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3012 glGenBuffers(1, &id);
3013 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
3014 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
3015 #endif
3016
3017 return id;
3018 }
3019
rlEnableVertexBuffer(unsigned int id)3020 void rlEnableVertexBuffer(unsigned int id)
3021 {
3022 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3023 glBindBuffer(GL_ARRAY_BUFFER, id);
3024 #endif
3025 }
3026
rlDisableVertexBuffer(void)3027 void rlDisableVertexBuffer(void)
3028 {
3029 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3030 glBindBuffer(GL_ARRAY_BUFFER, 0);
3031 #endif
3032 }
3033
rlEnableVertexBufferElement(unsigned int id)3034 void rlEnableVertexBufferElement(unsigned int id)
3035 {
3036 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3037 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
3038 #endif
3039 }
3040
rlDisableVertexBufferElement(void)3041 void rlDisableVertexBufferElement(void)
3042 {
3043 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3044 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
3045 #endif
3046 }
3047
3048 // Update GPU buffer with new data
3049 // NOTE: dataSize and offset must be provided in bytes
rlUpdateVertexBuffer(int bufferId,void * data,int dataSize,int offset)3050 void rlUpdateVertexBuffer(int bufferId, void *data, int dataSize, int offset)
3051 {
3052 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3053 glBindBuffer(GL_ARRAY_BUFFER, bufferId);
3054 glBufferSubData(GL_ARRAY_BUFFER, offset, dataSize, data);
3055 #endif
3056 }
3057
rlEnableVertexArray(unsigned int vaoId)3058 bool rlEnableVertexArray(unsigned int vaoId)
3059 {
3060 bool result = false;
3061 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3062 if (RLGL.ExtSupported.vao)
3063 {
3064 glBindVertexArray(vaoId);
3065 result = true;
3066 }
3067 #endif
3068 return result;
3069 }
3070
rlDisableVertexArray(void)3071 void rlDisableVertexArray(void)
3072 {
3073 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3074 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
3075 #endif
3076 }
3077
rlEnableVertexAttribute(unsigned int index)3078 void rlEnableVertexAttribute(unsigned int index)
3079 {
3080 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3081 glEnableVertexAttribArray(index);
3082 #endif
3083 }
3084
rlDisableVertexAttribute(unsigned int index)3085 void rlDisableVertexAttribute(unsigned int index)
3086 {
3087 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3088 glDisableVertexAttribArray(index);
3089 #endif
3090 }
3091
rlDrawVertexArray(int offset,int count)3092 void rlDrawVertexArray(int offset, int count)
3093 {
3094 glDrawArrays(GL_TRIANGLES, offset, count);
3095 }
3096
rlDrawVertexArrayElements(int offset,int count,void * buffer)3097 void rlDrawVertexArrayElements(int offset, int count, void *buffer)
3098 {
3099 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short*)buffer + offset);
3100 }
3101
rlDrawVertexArrayInstanced(int offset,int count,int instances)3102 void rlDrawVertexArrayInstanced(int offset, int count, int instances)
3103 {
3104 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3105 glDrawArraysInstanced(GL_TRIANGLES, 0, count, instances);
3106 #endif
3107 }
3108
rlDrawVertexArrayElementsInstanced(int offset,int count,void * buffer,int instances)3109 void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances)
3110 {
3111 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3112 glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short*)buffer + offset, instances);
3113 #endif
3114 }
3115
3116 #if defined(GRAPHICS_API_OPENGL_11)
rlEnableStatePointer(int vertexAttribType,void * buffer)3117 void rlEnableStatePointer(int vertexAttribType, void *buffer)
3118 {
3119 if (buffer != NULL) glEnableClientState(vertexAttribType);
3120 switch (vertexAttribType)
3121 {
3122 case GL_VERTEX_ARRAY: glVertexPointer(3, GL_FLOAT, 0, buffer); break;
3123 case GL_TEXTURE_COORD_ARRAY: glTexCoordPointer(2, GL_FLOAT, 0, buffer); break;
3124 case GL_NORMAL_ARRAY: if (buffer != NULL) glNormalPointer(GL_FLOAT, 0, buffer); break;
3125 case GL_COLOR_ARRAY: if (buffer != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer); break;
3126 //case GL_INDEX_ARRAY: if (buffer != NULL) glIndexPointer(GL_SHORT, 0, buffer); break; // Indexed colors
3127 default: break;
3128 }
3129 }
3130
rlDisableStatePointer(int vertexAttribType)3131 void rlDisableStatePointer(int vertexAttribType)
3132 {
3133 glDisableClientState(vertexAttribType);
3134 }
3135 #endif
3136
rlLoadVertexArray(void)3137 unsigned int rlLoadVertexArray(void)
3138 {
3139 unsigned int vaoId = 0;
3140 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3141 glGenVertexArrays(1, &vaoId);
3142 #endif
3143 return vaoId;
3144 }
3145
rlSetVertexAttribute(unsigned int index,int compSize,int type,bool normalized,int stride,void * pointer)3146 void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer)
3147 {
3148 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3149 glVertexAttribPointer(index, compSize, type, normalized, stride, pointer);
3150 #endif
3151 }
3152
rlSetVertexAttributeDivisor(unsigned int index,int divisor)3153 void rlSetVertexAttributeDivisor(unsigned int index, int divisor)
3154 {
3155 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3156 glVertexAttribDivisor(index, divisor);
3157 #endif
3158 }
3159
rlUnloadVertexArray(unsigned int vaoId)3160 void rlUnloadVertexArray(unsigned int vaoId)
3161 {
3162 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3163 if (RLGL.ExtSupported.vao)
3164 {
3165 glBindVertexArray(0);
3166 glDeleteVertexArrays(1, &vaoId);
3167 TRACELOG(LOG_INFO, "VAO: [ID %i] Unloaded vertex array data from VRAM (GPU)", vaoId);
3168 }
3169 #endif
3170 }
3171
rlUnloadVertexBuffer(unsigned int vboId)3172 void rlUnloadVertexBuffer(unsigned int vboId)
3173 {
3174 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3175 glDeleteBuffers(1, &vboId);
3176 //TRACELOG(LOG_INFO, "VBO: Unloaded vertex data from VRAM (GPU)");
3177 #endif
3178 }
3179
3180 // Shaders management
3181 //-----------------------------------------------------------------------------------------------
3182 // Load shader from code strings
3183 // NOTE: If shader string is NULL, using default vertex/fragment shaders
rlLoadShaderCode(const char * vsCode,const char * fsCode)3184 unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
3185 {
3186 unsigned int id = 0;
3187
3188 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3189 unsigned int vertexShaderId = RLGL.State.defaultVShaderId;
3190 unsigned int fragmentShaderId = RLGL.State.defaultFShaderId;
3191
3192 if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);
3193 if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER);
3194
3195 if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShader.id;
3196 else
3197 {
3198 id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId);
3199
3200 if (vertexShaderId != RLGL.State.defaultVShaderId)
3201 {
3202 // Detach shader before deletion to make sure memory is freed
3203 glDetachShader(id, vertexShaderId);
3204 glDeleteShader(vertexShaderId);
3205 }
3206 if (fragmentShaderId != RLGL.State.defaultFShaderId)
3207 {
3208 // Detach shader before deletion to make sure memory is freed
3209 glDetachShader(id, fragmentShaderId);
3210 glDeleteShader(fragmentShaderId);
3211 }
3212
3213 if (id == 0)
3214 {
3215 TRACELOG(LOG_WARNING, "SHADER: Failed to load custom shader code");
3216 id = RLGL.State.defaultShader.id;
3217 }
3218 }
3219
3220 // Get available shader uniforms
3221 // NOTE: This information is useful for debug...
3222 int uniformCount = -1;
3223
3224 glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount);
3225
3226 for (int i = 0; i < uniformCount; i++)
3227 {
3228 int namelen = -1;
3229 int num = -1;
3230 char name[256]; // Assume no variable names longer than 256
3231 GLenum type = GL_ZERO;
3232
3233 // Get the name of the uniforms
3234 glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name);
3235
3236 name[namelen] = 0;
3237
3238 TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name));
3239 }
3240 #endif
3241
3242 return id;
3243 }
3244
3245 // Compile custom shader and return shader id
rlCompileShader(const char * shaderCode,int type)3246 unsigned int rlCompileShader(const char *shaderCode, int type)
3247 {
3248 unsigned int shader = 0;
3249
3250 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3251 shader = glCreateShader(type);
3252 glShaderSource(shader, 1, &shaderCode, NULL);
3253
3254 GLint success = 0;
3255 glCompileShader(shader);
3256 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
3257
3258 if (success == GL_FALSE)
3259 {
3260 switch (type)
3261 {
3262 case GL_VERTEX_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break;
3263 case GL_FRAGMENT_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break;
3264 //case GL_GEOMETRY_SHADER:
3265 //case GL_COMPUTE_SHADER:
3266 default: break;
3267 }
3268
3269 int maxLength = 0;
3270 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
3271
3272 if (maxLength > 0)
3273 {
3274 int length = 0;
3275 char *log = RL_CALLOC(maxLength, sizeof(char));
3276 glGetShaderInfoLog(shader, maxLength, &length, log);
3277 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log);
3278 RL_FREE(log);
3279 }
3280 }
3281 else
3282 {
3283 switch (type)
3284 {
3285 case GL_VERTEX_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break;
3286 case GL_FRAGMENT_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break;
3287 //case GL_GEOMETRY_SHADER:
3288 //case GL_COMPUTE_SHADER:
3289 default: break;
3290 }
3291 }
3292 #endif
3293
3294 return shader;
3295 }
3296
3297 // Load custom shader strings and return program id
rlLoadShaderProgram(unsigned int vShaderId,unsigned int fShaderId)3298 unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
3299 {
3300 unsigned int program = 0;
3301
3302 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3303 GLint success = 0;
3304 program = glCreateProgram();
3305
3306 glAttachShader(program, vShaderId);
3307 glAttachShader(program, fShaderId);
3308
3309 // NOTE: Default attribute shader locations must be binded before linking
3310 glBindAttribLocation(program, 0, DEFAULT_SHADER_ATTRIB_NAME_POSITION);
3311 glBindAttribLocation(program, 1, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
3312 glBindAttribLocation(program, 2, DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
3313 glBindAttribLocation(program, 3, DEFAULT_SHADER_ATTRIB_NAME_COLOR);
3314 glBindAttribLocation(program, 4, DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
3315 glBindAttribLocation(program, 5, DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
3316
3317 // NOTE: If some attrib name is no found on the shader, it locations becomes -1
3318
3319 glLinkProgram(program);
3320
3321 // NOTE: All uniform variables are intitialised to 0 when a program links
3322
3323 glGetProgramiv(program, GL_LINK_STATUS, &success);
3324
3325 if (success == GL_FALSE)
3326 {
3327 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program);
3328
3329 int maxLength = 0;
3330 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
3331
3332 if (maxLength > 0)
3333 {
3334 int length = 0;
3335 char *log = RL_CALLOC(maxLength, sizeof(char));
3336 glGetProgramInfoLog(program, maxLength, &length, log);
3337 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
3338 RL_FREE(log);
3339 }
3340
3341 glDeleteProgram(program);
3342
3343 program = 0;
3344 }
3345 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program);
3346 #endif
3347 return program;
3348 }
3349
3350 // Unload shader program
rlUnloadShaderProgram(unsigned int id)3351 void rlUnloadShaderProgram(unsigned int id)
3352 {
3353 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3354 glDeleteProgram(id);
3355
3356 TRACELOG(LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id);
3357 #endif
3358 }
3359
3360 // Get shader location uniform
rlGetLocationUniform(unsigned int shaderId,const char * uniformName)3361 int rlGetLocationUniform(unsigned int shaderId, const char *uniformName)
3362 {
3363 int location = -1;
3364 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3365 location = glGetUniformLocation(shaderId, uniformName);
3366
3367 if (location == -1) TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName);
3368 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location);
3369 #endif
3370 return location;
3371 }
3372
3373 // Get shader location attribute
rlGetLocationAttrib(unsigned int shaderId,const char * attribName)3374 int rlGetLocationAttrib(unsigned int shaderId, const char *attribName)
3375 {
3376 int location = -1;
3377 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3378 location = glGetAttribLocation(shaderId, attribName);
3379
3380 if (location == -1) TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName);
3381 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location);
3382 #endif
3383 return location;
3384 }
3385
3386 // Set shader value uniform
rlSetUniform(int locIndex,const void * value,int uniformType,int count)3387 void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
3388 {
3389 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3390 switch (uniformType)
3391 {
3392 case SHADER_UNIFORM_FLOAT: glUniform1fv(locIndex, count, (float *)value); break;
3393 case SHADER_UNIFORM_VEC2: glUniform2fv(locIndex, count, (float *)value); break;
3394 case SHADER_UNIFORM_VEC3: glUniform3fv(locIndex, count, (float *)value); break;
3395 case SHADER_UNIFORM_VEC4: glUniform4fv(locIndex, count, (float *)value); break;
3396 case SHADER_UNIFORM_INT: glUniform1iv(locIndex, count, (int *)value); break;
3397 case SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break;
3398 case SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break;
3399 case SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break;
3400 case SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break;
3401 default: TRACELOG(LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized");
3402 }
3403 #endif
3404 }
3405
3406 // Set shader value attribute
rlSetVertexAttributeDefault(int locIndex,const void * value,int attribType,int count)3407 void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count)
3408 {
3409 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3410 switch (attribType)
3411 {
3412 case SHADER_ATTRIB_FLOAT: if (count == 1) glVertexAttrib1fv(locIndex, (float *)value); break;
3413 case SHADER_ATTRIB_VEC2: if (count == 2) glVertexAttrib2fv(locIndex, (float *)value); break;
3414 case SHADER_ATTRIB_VEC3: if (count == 3) glVertexAttrib3fv(locIndex, (float *)value); break;
3415 case SHADER_ATTRIB_VEC4: if (count == 4) glVertexAttrib4fv(locIndex, (float *)value); break;
3416 default: TRACELOG(LOG_WARNING, "SHADER: Failed to set attrib default value, data type not recognized");
3417 }
3418 #endif
3419 }
3420
3421 // Set shader value uniform matrix
rlSetUniformMatrix(int locIndex,Matrix mat)3422 void rlSetUniformMatrix(int locIndex, Matrix mat)
3423 {
3424 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3425 glUniformMatrix4fv(locIndex, 1, false, MatrixToFloat(mat));
3426 #endif
3427 }
3428
3429 // Set shader value uniform sampler
rlSetUniformSampler(int locIndex,unsigned int textureId)3430 void rlSetUniformSampler(int locIndex, unsigned int textureId)
3431 {
3432 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3433 // Check if texture is already active
3434 for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++) if (RLGL.State.activeTextureId[i] == textureId) return;
3435
3436 // Register a new active texture for the internal batch system
3437 // NOTE: Default texture is always activated as GL_TEXTURE0
3438 for (int i = 0; i < MAX_BATCH_ACTIVE_TEXTURES; i++)
3439 {
3440 if (RLGL.State.activeTextureId[i] == 0)
3441 {
3442 glUniform1i(locIndex, 1 + i); // Activate new texture unit
3443 RLGL.State.activeTextureId[i] = textureId; // Save texture id for binding on drawing
3444 break;
3445 }
3446 }
3447 #endif
3448 }
3449
3450 // Set shader currently active
rlSetShader(Shader shader)3451 void rlSetShader(Shader shader)
3452 {
3453 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3454 if (RLGL.State.currentShader.id != shader.id)
3455 {
3456 rlDrawRenderBatch(RLGL.currentBatch);
3457 RLGL.State.currentShader = shader;
3458 }
3459 #endif
3460 }
3461
3462 // Matrix state management
3463 //-----------------------------------------------------------------------------------------
3464 // Return internal modelview matrix
rlGetMatrixModelview(void)3465 Matrix rlGetMatrixModelview(void)
3466 {
3467 Matrix matrix = MatrixIdentity();
3468 #if defined(GRAPHICS_API_OPENGL_11)
3469 float mat[16];
3470 glGetFloatv(GL_MODELVIEW_MATRIX, mat);
3471 matrix.m0 = mat[0]; matrix.m1 = mat[1]; matrix.m2 = mat[2]; matrix.m3 = mat[3];
3472 matrix.m4 = mat[4]; matrix.m5 = mat[5]; matrix.m6 = mat[6]; matrix.m7 = mat[7];
3473 matrix.m8 = mat[8]; matrix.m9 = mat[9]; matrix.m10 = mat[10]; matrix.m11 = mat[11];
3474 matrix.m12 = mat[12]; matrix.m13 = mat[13]; matrix.m14 = mat[14]; matrix.m15 = mat[15];
3475 #else
3476 matrix = RLGL.State.modelview;
3477 #endif
3478 return matrix;
3479 }
3480
3481 // Return internal projection matrix
rlGetMatrixProjection(void)3482 Matrix rlGetMatrixProjection(void)
3483 {
3484 #if defined(GRAPHICS_API_OPENGL_11)
3485 float mat[16];
3486 glGetFloatv(GL_PROJECTION_MATRIX,mat);
3487 Matrix m;
3488 m.m0 = mat[0]; m.m1 = mat[1]; m.m2 = mat[2]; m.m3 = mat[3];
3489 m.m4 = mat[4]; m.m5 = mat[5]; m.m6 = mat[6]; m.m7 = mat[7];
3490 m.m8 = mat[8]; m.m9 = mat[9]; m.m10 = mat[10]; m.m11 = mat[11];
3491 m.m12 = mat[12]; m.m13 = mat[13]; m.m14 = mat[14]; m.m15 = mat[15];
3492 return m;
3493 #else
3494 return RLGL.State.projection;
3495 #endif
3496 }
3497
3498 // Get internal accumulated transform matrix
rlGetMatrixTransform(void)3499 Matrix rlGetMatrixTransform(void)
3500 {
3501 Matrix mat = MatrixIdentity();
3502 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3503 // TODO: Consider possible transform matrices in the RLGL.State.stack
3504 // Is this the right order? or should we start with the first stored matrix instead of the last one?
3505 //Matrix matStackTransform = MatrixIdentity();
3506 //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = MatrixMultiply(RLGL.State.stack[i], matStackTransform);
3507 mat = RLGL.State.transform;
3508 #endif
3509 return mat;
3510 }
3511
3512 // Get internal projection matrix for stereo render (selected eye)
rlGetMatrixProjectionStereo(int eye)3513 RLAPI Matrix rlGetMatrixProjectionStereo(int eye)
3514 {
3515 Matrix mat = MatrixIdentity();
3516 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3517 mat = RLGL.State.projectionStereo[eye];
3518 #endif
3519 return mat;
3520 }
3521
3522 // Get internal view offset matrix for stereo render (selected eye)
rlGetMatrixViewOffsetStereo(int eye)3523 RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye)
3524 {
3525 Matrix mat = MatrixIdentity();
3526 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3527 mat = RLGL.State.viewOffsetStereo[eye];
3528 #endif
3529 return mat;
3530 }
3531
3532 // Set a custom modelview matrix (replaces internal modelview matrix)
rlSetMatrixModelview(Matrix view)3533 void rlSetMatrixModelview(Matrix view)
3534 {
3535 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3536 RLGL.State.modelview = view;
3537 #endif
3538 }
3539
3540 // Set a custom projection matrix (replaces internal projection matrix)
rlSetMatrixProjection(Matrix projection)3541 void rlSetMatrixProjection(Matrix projection)
3542 {
3543 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3544 RLGL.State.projection = projection;
3545 #endif
3546 }
3547
3548 // Set eyes projection matrices for stereo rendering
rlSetMatrixProjectionStereo(Matrix right,Matrix left)3549 void rlSetMatrixProjectionStereo(Matrix right, Matrix left)
3550 {
3551 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3552 RLGL.State.projectionStereo[0] = right;
3553 RLGL.State.projectionStereo[1] = left;
3554 #endif
3555 }
3556
3557 // Set eyes view offsets matrices for stereo rendering
rlSetMatrixViewOffsetStereo(Matrix right,Matrix left)3558 void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left)
3559 {
3560 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3561 RLGL.State.viewOffsetStereo[0] = right;
3562 RLGL.State.viewOffsetStereo[1] = left;
3563 #endif
3564 }
3565
3566 // Load and draw a 1x1 XY quad in NDC
rlLoadDrawQuad(void)3567 void rlLoadDrawQuad(void)
3568 {
3569 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3570 unsigned int quadVAO = 0;
3571 unsigned int quadVBO = 0;
3572
3573 float vertices[] = {
3574 // Positions Texcoords
3575 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
3576 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
3577 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
3578 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
3579 };
3580
3581 // Gen VAO to contain VBO
3582 glGenVertexArrays(1, &quadVAO);
3583 glBindVertexArray(quadVAO);
3584
3585 // Gen and fill vertex buffer (VBO)
3586 glGenBuffers(1, &quadVBO);
3587 glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
3588 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
3589
3590 // Bind vertex attributes (position, texcoords)
3591 glEnableVertexAttribArray(0);
3592 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions
3593 glEnableVertexAttribArray(1);
3594 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords
3595
3596 // Draw quad
3597 glBindVertexArray(quadVAO);
3598 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3599 glBindVertexArray(0);
3600
3601 // Delete buffers (VBO and VAO)
3602 glDeleteBuffers(1, &quadVBO);
3603 glDeleteVertexArrays(1, &quadVAO);
3604 #endif
3605 }
3606
3607 // Load and draw a 1x1 3D cube in NDC
rlLoadDrawCube(void)3608 void rlLoadDrawCube(void)
3609 {
3610 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3611 unsigned int cubeVAO = 0;
3612 unsigned int cubeVBO = 0;
3613
3614 float vertices[] = {
3615 // Positions Normals Texcoords
3616 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
3617 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
3618 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
3619 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
3620 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
3621 -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
3622 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
3623 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
3624 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
3625 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
3626 -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
3627 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
3628 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
3629 -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
3630 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
3631 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
3632 -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
3633 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
3634 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
3635 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
3636 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
3637 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
3638 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
3639 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
3640 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
3641 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
3642 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
3643 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
3644 -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
3645 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
3646 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
3647 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
3648 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
3649 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
3650 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
3651 -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f
3652 };
3653
3654 // Gen VAO to contain VBO
3655 glGenVertexArrays(1, &cubeVAO);
3656 glBindVertexArray(cubeVAO);
3657
3658 // Gen and fill vertex buffer (VBO)
3659 glGenBuffers(1, &cubeVBO);
3660 glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
3661 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
3662
3663 // Bind vertex attributes (position, normals, texcoords)
3664 glBindVertexArray(cubeVAO);
3665 glEnableVertexAttribArray(0);
3666 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions
3667 glEnableVertexAttribArray(1);
3668 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals
3669 glEnableVertexAttribArray(2);
3670 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords
3671 glBindBuffer(GL_ARRAY_BUFFER, 0);
3672 glBindVertexArray(0);
3673
3674 // Draw cube
3675 glBindVertexArray(cubeVAO);
3676 glDrawArrays(GL_TRIANGLES, 0, 36);
3677 glBindVertexArray(0);
3678
3679 // Delete VBO and VAO
3680 glDeleteBuffers(1, &cubeVBO);
3681 glDeleteVertexArrays(1, &cubeVAO);
3682 #endif
3683 }
3684
3685 //----------------------------------------------------------------------------------
3686 // Module specific Functions Definition
3687 //----------------------------------------------------------------------------------
3688 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3689 // Load default shader (just vertex positioning and texture coloring)
3690 // NOTE: This shader program is used for internal buffers
3691 // NOTE: It uses global variable: RLGL.State.defaultShader
rlLoadShaderDefault(void)3692 static void rlLoadShaderDefault(void)
3693 {
3694 RLGL.State.defaultShader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));
3695
3696 // NOTE: All locations must be reseted to -1 (no location)
3697 for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) RLGL.State.defaultShader.locs[i] = -1;
3698
3699 // Vertex shader directly defined, no external file required
3700 const char *vShaderDefault =
3701 #if defined(GRAPHICS_API_OPENGL_21)
3702 "#version 120 \n"
3703 "attribute vec3 vertexPosition; \n"
3704 "attribute vec2 vertexTexCoord; \n"
3705 "attribute vec4 vertexColor; \n"
3706 "varying vec2 fragTexCoord; \n"
3707 "varying vec4 fragColor; \n"
3708 #elif defined(GRAPHICS_API_OPENGL_33)
3709 "#version 330 \n"
3710 "in vec3 vertexPosition; \n"
3711 "in vec2 vertexTexCoord; \n"
3712 "in vec4 vertexColor; \n"
3713 "out vec2 fragTexCoord; \n"
3714 "out vec4 fragColor; \n"
3715 #endif
3716 #if defined(GRAPHICS_API_OPENGL_ES2)
3717 "#version 100 \n"
3718 "attribute vec3 vertexPosition; \n"
3719 "attribute vec2 vertexTexCoord; \n"
3720 "attribute vec4 vertexColor; \n"
3721 "varying vec2 fragTexCoord; \n"
3722 "varying vec4 fragColor; \n"
3723 #endif
3724 "uniform mat4 mvp; \n"
3725 "void main() \n"
3726 "{ \n"
3727 " fragTexCoord = vertexTexCoord; \n"
3728 " fragColor = vertexColor; \n"
3729 " gl_Position = mvp*vec4(vertexPosition, 1.0); \n"
3730 "} \n";
3731
3732 // Fragment shader directly defined, no external file required
3733 const char *fShaderDefault =
3734 #if defined(GRAPHICS_API_OPENGL_21)
3735 "#version 120 \n"
3736 "varying vec2 fragTexCoord; \n"
3737 "varying vec4 fragColor; \n"
3738 "uniform sampler2D texture0; \n"
3739 "uniform vec4 colDiffuse; \n"
3740 "void main() \n"
3741 "{ \n"
3742 " vec4 texelColor = texture2D(texture0, fragTexCoord); \n"
3743 " gl_FragColor = texelColor*colDiffuse*fragColor; \n"
3744 "} \n";
3745 #elif defined(GRAPHICS_API_OPENGL_33)
3746 "#version 330 \n"
3747 "in vec2 fragTexCoord; \n"
3748 "in vec4 fragColor; \n"
3749 "out vec4 finalColor; \n"
3750 "uniform sampler2D texture0; \n"
3751 "uniform vec4 colDiffuse; \n"
3752 "void main() \n"
3753 "{ \n"
3754 " vec4 texelColor = texture(texture0, fragTexCoord); \n"
3755 " finalColor = texelColor*colDiffuse*fragColor; \n"
3756 "} \n";
3757 #endif
3758 #if defined(GRAPHICS_API_OPENGL_ES2)
3759 "#version 100 \n"
3760 "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL)
3761 "varying vec2 fragTexCoord; \n"
3762 "varying vec4 fragColor; \n"
3763 "uniform sampler2D texture0; \n"
3764 "uniform vec4 colDiffuse; \n"
3765 "void main() \n"
3766 "{ \n"
3767 " vec4 texelColor = texture2D(texture0, fragTexCoord); \n"
3768 " gl_FragColor = texelColor*colDiffuse*fragColor; \n"
3769 "} \n";
3770 #endif
3771
3772 // NOTE: Compiled vertex/fragment shaders are kept for re-use
3773 RLGL.State.defaultVShaderId = rlCompileShader(vShaderDefault, GL_VERTEX_SHADER); // Compile default vertex shader
3774 RLGL.State.defaultFShaderId = rlCompileShader(fShaderDefault, GL_FRAGMENT_SHADER); // Compile default fragment shader
3775
3776 RLGL.State.defaultShader.id = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId);
3777
3778 if (RLGL.State.defaultShader.id > 0)
3779 {
3780 TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", RLGL.State.defaultShader.id);
3781
3782 // Set default shader locations: attributes locations
3783 RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_POSITION] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexPosition");
3784 RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexTexCoord");
3785 RLGL.State.defaultShader.locs[SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShader.id, "vertexColor");
3786
3787 // Set default shader locations: uniform locations
3788 RLGL.State.defaultShader.locs[SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShader.id, "mvp");
3789 RLGL.State.defaultShader.locs[SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShader.id, "colDiffuse");
3790 RLGL.State.defaultShader.locs[SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShader.id, "texture0");
3791 }
3792 else TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", RLGL.State.defaultShader.id);
3793 }
3794
3795 // Unload default shader
3796 // NOTE: It uses global variable: RLGL.State.defaultShader
rlUnloadShaderDefault(void)3797 static void rlUnloadShaderDefault(void)
3798 {
3799 glUseProgram(0);
3800
3801 glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultVShaderId);
3802 glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultFShaderId);
3803 glDeleteShader(RLGL.State.defaultVShaderId);
3804 glDeleteShader(RLGL.State.defaultFShaderId);
3805
3806 glDeleteProgram(RLGL.State.defaultShader.id);
3807
3808 RL_FREE(RLGL.State.defaultShader.locs);
3809
3810 TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShader.id);
3811 }
3812
3813 #if defined(SUPPORT_GL_DETAILS_INFO)
3814 // Get compressed format official GL identifier name
rlGetCompressedFormatName(int format)3815 static char *rlGetCompressedFormatName(int format)
3816 {
3817 static char compName[64] = { 0 };
3818 memset(compName, 0, 64);
3819
3820 switch (format)
3821 {
3822 // GL_EXT_texture_compression_s3tc
3823 case 0x83F0: strcpy(compName, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"); break;
3824 case 0x83F1: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"); break;
3825 case 0x83F2: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"); break;
3826 case 0x83F3: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"); break;
3827 // GL_3DFX_texture_compression_FXT1
3828 case 0x86B0: strcpy(compName, "GL_COMPRESSED_RGB_FXT1_3DFX"); break;
3829 case 0x86B1: strcpy(compName, "GL_COMPRESSED_RGBA_FXT1_3DFX"); break;
3830 // GL_IMG_texture_compression_pvrtc
3831 case 0x8C00: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"); break;
3832 case 0x8C01: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"); break;
3833 case 0x8C02: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"); break;
3834 case 0x8C03: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"); break;
3835 // GL_OES_compressed_ETC1_RGB8_texture
3836 case 0x8D64: strcpy(compName, "GL_ETC1_RGB8_OES"); break;
3837 // GL_ARB_texture_compression_rgtc
3838 case 0x8DBB: strcpy(compName, "GL_COMPRESSED_RED_RGTC1"); break;
3839 case 0x8DBC: strcpy(compName, "GL_COMPRESSED_SIGNED_RED_RGTC1"); break;
3840 case 0x8DBD: strcpy(compName, "GL_COMPRESSED_RG_RGTC2"); break;
3841 case 0x8DBE: strcpy(compName, "GL_COMPRESSED_SIGNED_RG_RGTC2"); break;
3842 // GL_ARB_texture_compression_bptc
3843 case 0x8E8C: strcpy(compName, "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"); break;
3844 case 0x8E8D: strcpy(compName, "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"); break;
3845 case 0x8E8E: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"); break;
3846 case 0x8E8F: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"); break;
3847 // GL_ARB_ES3_compatibility
3848 case 0x9274: strcpy(compName, "GL_COMPRESSED_RGB8_ETC2"); break;
3849 case 0x9275: strcpy(compName, "GL_COMPRESSED_SRGB8_ETC2"); break;
3850 case 0x9276: strcpy(compName, "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break;
3851 case 0x9277: strcpy(compName, "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break;
3852 case 0x9278: strcpy(compName, "GL_COMPRESSED_RGBA8_ETC2_EAC"); break;
3853 case 0x9279: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"); break;
3854 case 0x9270: strcpy(compName, "GL_COMPRESSED_R11_EAC"); break;
3855 case 0x9271: strcpy(compName, "GL_COMPRESSED_SIGNED_R11_EAC"); break;
3856 case 0x9272: strcpy(compName, "GL_COMPRESSED_RG11_EAC"); break;
3857 case 0x9273: strcpy(compName, "GL_COMPRESSED_SIGNED_RG11_EAC"); break;
3858 // GL_KHR_texture_compression_astc_hdr
3859 case 0x93B0: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"); break;
3860 case 0x93B1: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"); break;
3861 case 0x93B2: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"); break;
3862 case 0x93B3: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"); break;
3863 case 0x93B4: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"); break;
3864 case 0x93B5: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"); break;
3865 case 0x93B6: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"); break;
3866 case 0x93B7: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"); break;
3867 case 0x93B8: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"); break;
3868 case 0x93B9: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"); break;
3869 case 0x93BA: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"); break;
3870 case 0x93BB: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"); break;
3871 case 0x93BC: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"); break;
3872 case 0x93BD: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"); break;
3873 case 0x93D0: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"); break;
3874 case 0x93D1: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"); break;
3875 case 0x93D2: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"); break;
3876 case 0x93D3: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"); break;
3877 case 0x93D4: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"); break;
3878 case 0x93D5: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"); break;
3879 case 0x93D6: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"); break;
3880 case 0x93D7: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"); break;
3881 case 0x93D8: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"); break;
3882 case 0x93D9: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"); break;
3883 case 0x93DA: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"); break;
3884 case 0x93DB: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"); break;
3885 case 0x93DC: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"); break;
3886 case 0x93DD: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"); break;
3887 default: strcpy(compName, "GL_COMPRESSED_UNKNOWN"); break;
3888 }
3889
3890 return compName;
3891 }
3892 #endif // SUPPORT_GL_DETAILS_INFO
3893
3894 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
3895
3896 #if defined(GRAPHICS_API_OPENGL_11)
3897 // Mipmaps data is generated after image data
3898 // NOTE: Only works with RGBA (4 bytes) data!
rlGenerateMipmapsData(unsigned char * data,int baseWidth,int baseHeight)3899 static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight)
3900 {
3901 int mipmapCount = 1; // Required mipmap levels count (including base level)
3902 int width = baseWidth;
3903 int height = baseHeight;
3904 int size = baseWidth*baseHeight*4; // Size in bytes (will include mipmaps...), RGBA only
3905
3906 // Count mipmap levels required
3907 while ((width != 1) && (height != 1))
3908 {
3909 width /= 2;
3910 height /= 2;
3911
3912 TRACELOGD("TEXTURE: Next mipmap size: %i x %i", width, height);
3913
3914 mipmapCount++;
3915
3916 size += (width*height*4); // Add mipmap size (in bytes)
3917 }
3918
3919 TRACELOGD("TEXTURE: Total mipmaps required: %i", mipmapCount);
3920 TRACELOGD("TEXTURE: Total size of data required: %i", size);
3921
3922 unsigned char *temp = RL_REALLOC(data, size);
3923
3924 if (temp != NULL) data = temp;
3925 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to re-allocate required mipmaps memory");
3926
3927 width = baseWidth;
3928 height = baseHeight;
3929 size = (width*height*4);
3930
3931 // Generate mipmaps
3932 // NOTE: Every mipmap data is stored after data
3933 Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color));
3934 Color *mipmap = NULL;
3935 int offset = 0;
3936 int j = 0;
3937
3938 for (int i = 0; i < size; i += 4)
3939 {
3940 image[j].r = data[i];
3941 image[j].g = data[i + 1];
3942 image[j].b = data[i + 2];
3943 image[j].a = data[i + 3];
3944 j++;
3945 }
3946
3947 TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height);
3948
3949 for (int mip = 1; mip < mipmapCount; mip++)
3950 {
3951 mipmap = rlGenNextMipmapData(image, width, height);
3952
3953 offset += (width*height*4); // Size of last mipmap
3954 j = 0;
3955
3956 width /= 2;
3957 height /= 2;
3958 size = (width*height*4); // Mipmap size to store after offset
3959
3960 // Add mipmap to data
3961 for (int i = 0; i < size; i += 4)
3962 {
3963 data[offset + i] = mipmap[j].r;
3964 data[offset + i + 1] = mipmap[j].g;
3965 data[offset + i + 2] = mipmap[j].b;
3966 data[offset + i + 3] = mipmap[j].a;
3967 j++;
3968 }
3969
3970 RL_FREE(image);
3971
3972 image = mipmap;
3973 mipmap = NULL;
3974 }
3975
3976 RL_FREE(mipmap); // free mipmap data
3977
3978 return mipmapCount;
3979 }
3980
3981 // Manual mipmap generation (basic scaling algorithm)
rlGenNextMipmapData(Color * srcData,int srcWidth,int srcHeight)3982 static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight)
3983 {
3984 int x2, y2;
3985 Color prow, pcol;
3986
3987 int width = srcWidth/2;
3988 int height = srcHeight/2;
3989
3990 Color *mipmap = (Color *)RL_MALLOC(width*height*sizeof(Color));
3991
3992 // Scaling algorithm works perfectly (box-filter)
3993 for (int y = 0; y < height; y++)
3994 {
3995 y2 = 2*y;
3996
3997 for (int x = 0; x < width; x++)
3998 {
3999 x2 = 2*x;
4000
4001 prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2;
4002 prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2;
4003 prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2;
4004 prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2;
4005
4006 pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2;
4007 pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2;
4008 pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2;
4009 pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2;
4010
4011 mipmap[y*width + x].r = (prow.r + pcol.r)/2;
4012 mipmap[y*width + x].g = (prow.g + pcol.g)/2;
4013 mipmap[y*width + x].b = (prow.b + pcol.b)/2;
4014 mipmap[y*width + x].a = (prow.a + pcol.a)/2;
4015 }
4016 }
4017
4018 TRACELOGD("TEXTURE: Mipmap generated successfully (%ix%i)", width, height);
4019
4020 return mipmap;
4021 }
4022 #endif // GRAPHICS_API_OPENGL_11
4023
4024 // Get pixel data size in bytes (image or texture)
4025 // NOTE: Size depends on pixel format
rlGetPixelDataSize(int width,int height,int format)4026 static int rlGetPixelDataSize(int width, int height, int format)
4027 {
4028 int dataSize = 0; // Size in bytes
4029 int bpp = 0; // Bits per pixel
4030
4031 switch (format)
4032 {
4033 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
4034 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
4035 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
4036 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
4037 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
4038 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
4039 case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
4040 case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
4041 case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
4042 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
4043 case PIXELFORMAT_COMPRESSED_DXT1_RGB:
4044 case PIXELFORMAT_COMPRESSED_DXT1_RGBA:
4045 case PIXELFORMAT_COMPRESSED_ETC1_RGB:
4046 case PIXELFORMAT_COMPRESSED_ETC2_RGB:
4047 case PIXELFORMAT_COMPRESSED_PVRT_RGB:
4048 case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
4049 case PIXELFORMAT_COMPRESSED_DXT3_RGBA:
4050 case PIXELFORMAT_COMPRESSED_DXT5_RGBA:
4051 case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
4052 case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
4053 case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
4054 default: break;
4055 }
4056
4057 dataSize = width*height*bpp/8; // Total data size in bytes
4058
4059 // Most compressed formats works on 4x4 blocks,
4060 // if texture is smaller, minimum dataSize is 8 or 16
4061 if ((width < 4) && (height < 4))
4062 {
4063 if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
4064 else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
4065 }
4066
4067 return dataSize;
4068 }
4069 #endif // RLGL_IMPLEMENTATION
4070