1/**********************************************************************************************
2*
3* rlgl - 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 auxiliar resources
11* rlglDraw() - Process internal buffers and send required draw calls
12* rlglClose() - De-initialize internal buffers data and other auxiliar resources
13*
14* CONFIGURATION:
15*
16* #define GRAPHICS_API_OPENGL_11
17* #define GRAPHICS_API_OPENGL_21
18* #define GRAPHICS_API_OPENGL_33
19* #define GRAPHICS_API_OPENGL_ES2
20* Use selected OpenGL graphics backend, should be supported by platform
21* Those preprocessor defines are only used on rlgl module, if OpenGL version is
22* required by any other module, use rlGetVersion() tocheck it
23*
24* #define RLGL_IMPLEMENTATION
25* Generates the implementation of the library into the included file.
26* If not defined, the library is in header only mode and can be included in other headers
27* or source files without problems. But only ONE file should hold the implementation.
28*
29* #define RLGL_STANDALONE
30* Use rlgl as standalone library (no raylib dependency)
31*
32* #define SUPPORT_VR_SIMULATOR
33* Support VR simulation functionality (stereo rendering)
34*
35* DEPENDENCIES:
36* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
37* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only)
38*
39*
40* LICENSE: zlib/libpng
41*
42* Copyright (c) 2014-2020 Ramon Santamaria (@raysan5)
43*
44* This software is provided "as-is", without any express or implied warranty. In no event
45* will the authors be held liable for any damages arising from the use of this software.
46*
47* Permission is granted to anyone to use this software for any purpose, including commercial
48* applications, and to alter it and redistribute it freely, subject to the following restrictions:
49*
50* 1. The origin of this software must not be misrepresented; you must not claim that you
51* wrote the original software. If you use this software in a product, an acknowledgment
52* in the product documentation would be appreciated but is not required.
53*
54* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
55* as being the original software.
56*
57* 3. This notice may not be removed or altered from any source distribution.
58*
59**********************************************************************************************/
60
61#ifndef RLGL_H
62#define RLGL_H
63
64#if defined(RLGL_STANDALONE)
65 #define RAYMATH_STANDALONE
66 #define RAYMATH_HEADER_ONLY
67
68 #define RLAPI // We are building or using rlgl as a static library (or Linux shared library)
69
70 #if defined(_WIN32)
71 #if defined(BUILD_LIBTYPE_SHARED)
72 #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
73 #elif defined(USE_LIBTYPE_SHARED)
74 #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
75 #endif
76 #endif
77
78 // Support TRACELOG macros
79 #if !defined(TRACELOG)
80 #define TRACELOG(level, ...) (void)0
81 #define TRACELOGD(...) (void)0
82 #endif
83
84 // Allow custom memory allocators
85 #ifndef RL_MALLOC
86 #define RL_MALLOC(sz) malloc(sz)
87 #endif
88 #ifndef RL_CALLOC
89 #define RL_CALLOC(n,sz) calloc(n,sz)
90 #endif
91 #ifndef RL_REALLOC
92 #define RL_REALLOC(n,sz) realloc(n,sz)
93 #endif
94 #ifndef RL_FREE
95 #define RL_FREE(p) free(p)
96 #endif
97#else
98 #include "raylib.h" // Required for: Model, Shader, Texture2D, TRACELOG()
99#endif
100
101#include "raymath.h" // Required for: Vector3, Matrix
102
103// Security check in case no GRAPHICS_API_OPENGL_* defined
104#if !defined(GRAPHICS_API_OPENGL_11) && \
105 !defined(GRAPHICS_API_OPENGL_21) && \
106 !defined(GRAPHICS_API_OPENGL_33) && \
107 !defined(GRAPHICS_API_OPENGL_ES2)
108 #define GRAPHICS_API_OPENGL_33
109#endif
110
111// Security check in case multiple GRAPHICS_API_OPENGL_* defined
112#if defined(GRAPHICS_API_OPENGL_11)
113 #if defined(GRAPHICS_API_OPENGL_21)
114 #undef GRAPHICS_API_OPENGL_21
115 #endif
116 #if defined(GRAPHICS_API_OPENGL_33)
117 #undef GRAPHICS_API_OPENGL_33
118 #endif
119 #if defined(GRAPHICS_API_OPENGL_ES2)
120 #undef GRAPHICS_API_OPENGL_ES2
121 #endif
122#endif
123
124#if defined(GRAPHICS_API_OPENGL_21)
125 #define GRAPHICS_API_OPENGL_33
126#endif
127
128//----------------------------------------------------------------------------------
129// Defines and Macros
130//----------------------------------------------------------------------------------
131#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
132 // This is the maximum amount of elements (quads) per batch
133 // NOTE: Be careful with text, every letter maps to a quad
134 #define MAX_BATCH_ELEMENTS 8192
135#elif defined(GRAPHICS_API_OPENGL_ES2)
136 // We reduce memory sizes for embedded systems (RPI and HTML5)
137 // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care...
138 #define MAX_BATCH_ELEMENTS 2048
139#endif
140
141#ifndef MAX_BATCH_BUFFERING
142 #define MAX_BATCH_BUFFERING 1 // Max number of buffers for batching (multi-buffering)
143#endif
144#define MAX_MATRIX_STACK_SIZE 32 // Max size of Matrix stack
145#define MAX_DRAWCALL_REGISTERED 256 // Max draws by state changes (mode, texture)
146
147// Shader and material limits
148#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct
149#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct
150
151#ifndef RL_NEAR_CULL_DISTANCE
152 #define RL_NEAR_CULL_DISTANCE 0.01 // Default near cull distance
153#endif
154#ifndef RL_FAR_CULL_DISTANCE
155 #define RL_FAR_CULL_DISTANCE 1000.0 // Default far cull distance
156#endif
157
158// Texture parameters (equivalent to OpenGL defines)
159#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S
160#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T
161#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER
162#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER
163#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier)
164
165#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST
166#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR
167#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST
168#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR
169#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST
170#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR
171
172#define RL_WRAP_REPEAT 0x2901 // GL_REPEAT
173#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE
174#define RL_WRAP_MIRROR_REPEAT 0x8370 // GL_MIRRORED_REPEAT
175#define RL_WRAP_MIRROR_CLAMP 0x8742 // GL_MIRROR_CLAMP_EXT
176
177// Matrix modes (equivalent to OpenGL)
178#define RL_MODELVIEW 0x1700 // GL_MODELVIEW
179#define RL_PROJECTION 0x1701 // GL_PROJECTION
180#define RL_TEXTURE 0x1702 // GL_TEXTURE
181
182// Primitive assembly draw modes
183#define RL_LINES 0x0001 // GL_LINES
184#define RL_TRIANGLES 0x0004 // GL_TRIANGLES
185#define RL_QUADS 0x0007 // GL_QUADS
186
187//----------------------------------------------------------------------------------
188// Types and Structures Definition
189//----------------------------------------------------------------------------------
190typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion;
191
192typedef unsigned char byte;
193
194#if defined(RLGL_STANDALONE)
195 #ifndef __cplusplus
196 // Boolean type
197 typedef enum { false, true } bool;
198 #endif
199
200 // Color type, RGBA (32bit)
201 typedef struct Color {
202 unsigned char r;
203 unsigned char g;
204 unsigned char b;
205 unsigned char a;
206 } Color;
207
208 // Rectangle type
209 typedef struct Rectangle {
210 float x;
211 float y;
212 float width;
213 float height;
214 } Rectangle;
215
216 // Texture2D type
217 // NOTE: Data stored in GPU memory
218 typedef struct Texture2D {
219 unsigned int id; // OpenGL texture id
220 int width; // Texture base width
221 int height; // Texture base height
222 int mipmaps; // Mipmap levels, 1 by default
223 int format; // Data format (PixelFormat)
224 } Texture2D;
225
226 // Texture type, same as Texture2D
227 typedef Texture2D Texture;
228
229 // TextureCubemap type, actually, same as Texture2D
230 typedef Texture2D TextureCubemap;
231
232 // RenderTexture2D type, for texture rendering
233 typedef struct RenderTexture2D {
234 unsigned int id; // OpenGL framebuffer (fbo) id
235 Texture2D texture; // Color buffer attachment texture
236 Texture2D depth; // Depth buffer attachment texture
237 bool depthTexture; // Track if depth attachment is a texture or renderbuffer
238 } RenderTexture2D;
239
240 // RenderTexture type, same as RenderTexture2D
241 typedef RenderTexture2D RenderTexture;
242
243 // Vertex data definning a mesh
244 typedef struct Mesh {
245 int vertexCount; // number of vertices stored in arrays
246 int triangleCount; // number of triangles stored (indexed or not)
247 float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
248 float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
249 float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
250 float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
251 float *tangents; // vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
252 unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
253 unsigned short *indices;// vertex indices (in case vertex data comes indexed)
254
255 // Animation vertex data
256 float *animVertices; // Animated vertex positions (after bones transformations)
257 float *animNormals; // Animated normals (after bones transformations)
258 int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning)
259 float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
260
261 // OpenGL identifiers
262 unsigned int vaoId; // OpenGL Vertex Array Object id
263 unsigned int *vboId; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
264 } Mesh;
265
266 // Shader and material limits
267 #define MAX_SHADER_LOCATIONS 32
268 #define MAX_MATERIAL_MAPS 12
269
270 // Shader type (generic)
271 typedef struct Shader {
272 unsigned int id; // Shader program id
273 int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
274 } Shader;
275
276 // Material texture map
277 typedef struct MaterialMap {
278 Texture2D texture; // Material map texture
279 Color color; // Material map color
280 float value; // Material map value
281 } MaterialMap;
282
283 // Material type (generic)
284 typedef struct Material {
285 Shader shader; // Material shader
286 MaterialMap *maps; // Material maps (MAX_MATERIAL_MAPS)
287 float *params; // Material generic parameters (if required)
288 } Material;
289
290 // Camera type, defines a camera position/orientation in 3d space
291 typedef struct Camera {
292 Vector3 position; // Camera position
293 Vector3 target; // Camera target it looks-at
294 Vector3 up; // Camera up vector (rotation over its axis)
295 float fovy; // Camera field-of-view apperture in Y (degrees)
296 } Camera;
297
298 // Head-Mounted-Display device parameters
299 typedef struct VrDeviceInfo {
300 int hResolution; // HMD horizontal resolution in pixels
301 int vResolution; // HMD vertical resolution in pixels
302 float hScreenSize; // HMD horizontal size in meters
303 float vScreenSize; // HMD vertical size in meters
304 float vScreenCenter; // HMD screen center in meters
305 float eyeToScreenDistance; // HMD distance between eye and display in meters
306 float lensSeparationDistance; // HMD lens separation distance in meters
307 float interpupillaryDistance; // HMD IPD (distance between pupils) in meters
308 float lensDistortionValues[4]; // HMD lens distortion constant parameters
309 float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters
310 } VrDeviceInfo;
311
312 // VR Stereo rendering configuration for simulator
313 typedef struct VrStereoConfig {
314 Shader distortionShader; // VR stereo rendering distortion shader
315 Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices
316 Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices
317 int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h]
318 int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
319 } VrStereoConfig;
320
321
322 // TraceLog message types
323 typedef enum {
324 LOG_ALL,
325 LOG_TRACE,
326 LOG_DEBUG,
327 LOG_INFO,
328 LOG_WARNING,
329 LOG_ERROR,
330 LOG_FATAL,
331 LOG_NONE
332 } TraceLogType;
333
334 // Texture formats (support depends on OpenGL version)
335 typedef enum {
336 UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
337 UNCOMPRESSED_GRAY_ALPHA,
338 UNCOMPRESSED_R5G6B5, // 16 bpp
339 UNCOMPRESSED_R8G8B8, // 24 bpp
340 UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
341 UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
342 UNCOMPRESSED_R8G8B8A8, // 32 bpp
343 UNCOMPRESSED_R32, // 32 bpp (1 channel - float)
344 UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float)
345 UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float)
346 COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
347 COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
348 COMPRESSED_DXT3_RGBA, // 8 bpp
349 COMPRESSED_DXT5_RGBA, // 8 bpp
350 COMPRESSED_ETC1_RGB, // 4 bpp
351 COMPRESSED_ETC2_RGB, // 4 bpp
352 COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
353 COMPRESSED_PVRT_RGB, // 4 bpp
354 COMPRESSED_PVRT_RGBA, // 4 bpp
355 COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
356 COMPRESSED_ASTC_8x8_RGBA // 2 bpp
357 } PixelFormat;
358
359 // Texture parameters: filter mode
360 // NOTE 1: Filtering considers mipmaps if available in the texture
361 // NOTE 2: Filter is accordingly set for minification and magnification
362 typedef enum {
363 FILTER_POINT = 0, // No filter, just pixel aproximation
364 FILTER_BILINEAR, // Linear filtering
365 FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
366 FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
367 FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x
368 FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x
369 } TextureFilterMode;
370
371 // Color blending modes (pre-defined)
372 typedef enum {
373 BLEND_ALPHA = 0,
374 BLEND_ADDITIVE,
375 BLEND_MULTIPLIED
376 } BlendMode;
377
378 // Shader location point type
379 typedef enum {
380 LOC_VERTEX_POSITION = 0,
381 LOC_VERTEX_TEXCOORD01,
382 LOC_VERTEX_TEXCOORD02,
383 LOC_VERTEX_NORMAL,
384 LOC_VERTEX_TANGENT,
385 LOC_VERTEX_COLOR,
386 LOC_MATRIX_MVP,
387 LOC_MATRIX_MODEL,
388 LOC_MATRIX_VIEW,
389 LOC_MATRIX_PROJECTION,
390 LOC_VECTOR_VIEW,
391 LOC_COLOR_DIFFUSE,
392 LOC_COLOR_SPECULAR,
393 LOC_COLOR_AMBIENT,
394 LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE
395 LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
396 LOC_MAP_NORMAL,
397 LOC_MAP_ROUGHNESS,
398 LOC_MAP_OCCLUSION,
399 LOC_MAP_EMISSION,
400 LOC_MAP_HEIGHT,
401 LOC_MAP_CUBEMAP,
402 LOC_MAP_IRRADIANCE,
403 LOC_MAP_PREFILTER,
404 LOC_MAP_BRDF
405 } ShaderLocationIndex;
406
407 // Shader uniform data types
408 typedef enum {
409 UNIFORM_FLOAT = 0,
410 UNIFORM_VEC2,
411 UNIFORM_VEC3,
412 UNIFORM_VEC4,
413 UNIFORM_INT,
414 UNIFORM_IVEC2,
415 UNIFORM_IVEC3,
416 UNIFORM_IVEC4,
417 UNIFORM_SAMPLER2D
418 } ShaderUniformDataType;
419
420 #define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
421 #define LOC_MAP_SPECULAR LOC_MAP_METALNESS
422
423 // Material map type
424 typedef enum {
425 MAP_ALBEDO = 0, // MAP_DIFFUSE
426 MAP_METALNESS = 1, // MAP_SPECULAR
427 MAP_NORMAL = 2,
428 MAP_ROUGHNESS = 3,
429 MAP_OCCLUSION,
430 MAP_EMISSION,
431 MAP_HEIGHT,
432 MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP
433 MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP
434 MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP
435 MAP_BRDF
436 } MaterialMapType;
437
438 #define MAP_DIFFUSE MAP_ALBEDO
439 #define MAP_SPECULAR MAP_METALNESS
440#endif
441
442#if defined(__cplusplus)
443extern "C" { // Prevents name mangling of functions
444#endif
445
446//------------------------------------------------------------------------------------
447// Functions Declaration - Matrix operations
448//------------------------------------------------------------------------------------
449RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed
450RLAPI void rlPushMatrix(void); // Push the current matrix to stack
451RLAPI void rlPopMatrix(void); // Pop lattest inserted matrix from stack
452RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix
453RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
454RLAPI void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix
455RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
456RLAPI void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix
457RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar);
458RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar);
459RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area
460
461//------------------------------------------------------------------------------------
462// Functions Declaration - Vertex level operations
463//------------------------------------------------------------------------------------
464RLAPI void rlBegin(int mode); // Initialize drawing mode (how to organize vertex)
465RLAPI void rlEnd(void); // Finish vertex providing
466RLAPI void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int
467RLAPI void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float
468RLAPI void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float
469RLAPI void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float
470RLAPI void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float
471RLAPI void rlColor4ub(byte r, byte g, byte b, byte a); // Define one vertex (color) - 4 byte
472RLAPI void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float
473RLAPI void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float
474
475//------------------------------------------------------------------------------------
476// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
477// NOTE: This functions are used to completely abstract raylib code from OpenGL layer
478//------------------------------------------------------------------------------------
479RLAPI void rlEnableTexture(unsigned int id); // Enable texture usage
480RLAPI void rlDisableTexture(void); // Disable texture usage
481RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
482RLAPI void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo)
483RLAPI void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer
484RLAPI void rlEnableDepthTest(void); // Enable depth test
485RLAPI void rlDisableDepthTest(void); // Disable depth test
486RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling
487RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling
488RLAPI void rlEnableScissorTest(void); // Enable scissor test
489RLAPI void rlDisableScissorTest(void); // Disable scissor test
490RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
491RLAPI void rlEnableWireMode(void); // Enable wire mode
492RLAPI void rlDisableWireMode(void); // Disable wire mode
493RLAPI void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
494RLAPI void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU
495RLAPI void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU
496RLAPI void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory
497RLAPI void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
498RLAPI void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
499RLAPI void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
500RLAPI void rlUpdateBuffer(int bufferId, void *data, int dataSize); // Update GPU buffer with new data
501RLAPI unsigned int rlLoadAttribBuffer(unsigned int vaoId, int shaderLoc, void *buffer, int size, bool dynamic); // Load a new attributes buffer
502
503//------------------------------------------------------------------------------------
504// Functions Declaration - rlgl functionality
505//------------------------------------------------------------------------------------
506RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
507RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
508RLAPI void rlglDraw(void); // Update and draw default internal buffers
509
510RLAPI int rlGetVersion(void); // Returns current OpenGL version
511RLAPI bool rlCheckBufferLimit(int vCount); // Check internal buffer overflow for a given number of vertex
512RLAPI void rlSetDebugMarker(const char *text); // Set debug marker for analysis
513RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions
514RLAPI Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
515
516// Textures data management
517RLAPI unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
518RLAPI unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo)
519RLAPI unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap
520RLAPI void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
521RLAPI void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats
522RLAPI void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory
523
524RLAPI void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
525RLAPI void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data
526RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
527
528// Render texture management (fbo)
529RLAPI RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depthBits, bool useDepthTexture); // Load a render texture (with color and depth attachments)
530RLAPI void rlRenderTextureAttach(RenderTexture target, unsigned int id, int attachType); // Attach texture/renderbuffer to an fbo
531RLAPI bool rlRenderTextureComplete(RenderTexture target); // Verify render texture is complete
532
533// Vertex data management
534RLAPI void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
535RLAPI void rlUpdateMesh(Mesh mesh, int buffer, int num); // Update vertex or index data on GPU (upload new data to one buffer)
536RLAPI void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index); // Update vertex or index data on GPU, at index
537RLAPI void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
538RLAPI void rlUnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU
539
540// NOTE: There is a set of shader related functions that are available to end user,
541// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
542
543#if defined(RLGL_STANDALONE)
544//------------------------------------------------------------------------------------
545// Shaders System Functions (Module: rlgl)
546// NOTE: This functions are useless when using OpenGL 1.1
547//------------------------------------------------------------------------------------
548// Shader loading/unloading functions
549RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
550RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
551RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
552
553RLAPI Shader GetShaderDefault(void); // Get default shader
554RLAPI Texture2D GetTextureDefault(void); // Get default texture
555RLAPI Texture2D GetShapesTexture(void); // Get texture to draw shapes
556RLAPI Rectangle GetShapesTextureRec(void); // Get texture rectangle to draw shapes
557
558// Shader configuration functions
559RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
560RLAPI void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType); // Set shader uniform value
561RLAPI void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count); // Set shader uniform value vector
562RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
563RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
564RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
565RLAPI Matrix GetMatrixModelview(void); // Get internal modelview matrix
566
567// Texture maps generation (PBR)
568// NOTE: Required shaders should be provided
569RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size); // Generate cubemap texture from HDR texture
570RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
571RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
572RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture using cubemap data
573
574// Shading begin/end functions
575RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
576RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
577RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
578RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
579
580// VR control functions
581RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters
582RLAPI void CloseVrSimulator(void); // Close VR simulator for current device
583RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
584RLAPI void SetVrConfiguration(VrDeviceInfo info, Shader distortion); // Set stereo rendering configuration parameters
585RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready
586RLAPI void ToggleVrMode(void); // Enable/Disable VR experience
587RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering
588RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering
589
590RLAPI char *LoadFileText(const char *fileName); // Load chars array from text file
591RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture)
592#endif
593
594#if defined(__cplusplus)
595}
596#endif
597
598#endif // RLGL_H
599
600/***********************************************************************************
601*
602* RLGL IMPLEMENTATION
603*
604************************************************************************************/
605
606#if defined(RLGL_IMPLEMENTATION)
607
608#if defined(RLGL_STANDALONE)
609 #include <stdio.h> // Required for: fopen(), fseek(), fread(), fclose() [LoadFileText]
610#else
611 // Check if config flags have been externally provided on compilation line
612 #if !defined(EXTERNAL_CONFIG_FLAGS)
613 #include "config.h" // Defines module configuration flags
614 #endif
615 #include "raymath.h" // Required for: Vector3 and Matrix functions
616#endif
617
618#include <stdlib.h> // Required for: malloc(), free()
619#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
620#include <math.h> // Required for: atan2f(), fabs()
621
622#if defined(GRAPHICS_API_OPENGL_11)
623 #if defined(__APPLE__)
624 #include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
625 #include <OpenGL/glext.h>
626 #else
627 // APIENTRY for OpenGL function pointer declarations is required
628 #ifndef APIENTRY
629 #if defined(_WIN32)
630 #define APIENTRY __stdcall
631 #else
632 #define APIENTRY
633 #endif
634 #endif
635 // WINGDIAPI definition. Some Windows OpenGL headers need it
636 #if !defined(WINGDIAPI) && defined(_WIN32)
637 #define WINGDIAPI __declspec(dllimport)
638 #endif
639
640 #include <GL/gl.h> // OpenGL 1.1 library
641 #endif
642#endif
643
644#if defined(GRAPHICS_API_OPENGL_21)
645 #define GRAPHICS_API_OPENGL_33 // OpenGL 2.1 uses mostly OpenGL 3.3 Core functionality
646#endif
647
648#if defined(GRAPHICS_API_OPENGL_33)
649 #if defined(__APPLE__)
650 #include <OpenGL/gl3.h> // OpenGL 3 library for OSX
651 #include <OpenGL/gl3ext.h> // OpenGL 3 extensions library for OSX
652 #else
653 #define GLAD_REALLOC RL_REALLOC
654 #define GLAD_FREE RL_FREE
655
656 #define GLAD_IMPLEMENTATION
657 #if defined(RLGL_STANDALONE)
658 #include "glad.h" // GLAD extensions loading library, includes OpenGL headers
659 #else
660 #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers
661 #endif
662 #endif
663#endif
664
665#if defined(GRAPHICS_API_OPENGL_ES2)
666 #include <EGL/egl.h> // EGL library
667 #include <GLES2/gl2.h> // OpenGL ES 2.0 library
668 #include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library
669#endif
670
671//----------------------------------------------------------------------------------
672// Defines and Macros
673//----------------------------------------------------------------------------------
674#ifndef GL_SHADING_LANGUAGE_VERSION
675 #define GL_SHADING_LANGUAGE_VERSION 0x8B8C
676#endif
677
678#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
679 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
680#endif
681#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
682 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
683#endif
684#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
685 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
686#endif
687#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
688 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
689#endif
690#ifndef GL_ETC1_RGB8_OES
691 #define GL_ETC1_RGB8_OES 0x8D64
692#endif
693#ifndef GL_COMPRESSED_RGB8_ETC2
694 #define GL_COMPRESSED_RGB8_ETC2 0x9274
695#endif
696#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
697 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
698#endif
699#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
700 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
701#endif
702#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
703 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
704#endif
705#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR
706 #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0
707#endif
708#ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR
709 #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7
710#endif
711
712#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
713 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
714#endif
715
716#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
717 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
718#endif
719
720#if defined(GRAPHICS_API_OPENGL_11)
721 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
722 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
723 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
724#endif
725
726#if defined(GRAPHICS_API_OPENGL_21)
727 #define GL_LUMINANCE 0x1909
728 #define GL_LUMINANCE_ALPHA 0x190A
729#endif
730
731#if defined(GRAPHICS_API_OPENGL_ES2)
732 #define glClearDepth glClearDepthf
733 #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
734 #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
735#endif
736
737// Default vertex attribute names on shader to set location points
738#define DEFAULT_ATTRIB_POSITION_NAME "vertexPosition" // shader-location = 0
739#define DEFAULT_ATTRIB_TEXCOORD_NAME "vertexTexCoord" // shader-location = 1
740#define DEFAULT_ATTRIB_NORMAL_NAME "vertexNormal" // shader-location = 2
741#define DEFAULT_ATTRIB_COLOR_NAME "vertexColor" // shader-location = 3
742#define DEFAULT_ATTRIB_TANGENT_NAME "vertexTangent" // shader-location = 4
743#define DEFAULT_ATTRIB_TEXCOORD2_NAME "vertexTexCoord2" // shader-location = 5
744
745//----------------------------------------------------------------------------------
746// Types and Structures Definition
747//----------------------------------------------------------------------------------
748
749// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
750typedef struct DynamicBuffer {
751 int vCounter; // vertex position counter to process (and draw) from full buffer
752 int tcCounter; // vertex texcoord counter to process (and draw) from full buffer
753 int cCounter; // vertex color counter to process (and draw) from full buffer
754
755 float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
756 float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
757 unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
758#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
759 unsigned int *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
760#elif defined(GRAPHICS_API_OPENGL_ES2)
761 unsigned short *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
762#endif
763 unsigned int vaoId; // OpenGL Vertex Array Object id
764 unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data)
765} DynamicBuffer;
766
767// Draw call type
768typedef struct DrawCall {
769 int mode; // Drawing mode: LINES, TRIANGLES, QUADS
770 int vertexCount; // Number of vertex of the draw
771 int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES)
772 //unsigned int vaoId; // Vertex array id to be used on the draw
773 //unsigned int shaderId; // Shader id to be used on the draw
774 unsigned int textureId; // Texture id to be used on the draw
775
776 //Matrix projection; // Projection matrix for this draw
777 //Matrix modelview; // Modelview matrix for this draw
778} DrawCall;
779
780#if defined(SUPPORT_VR_SIMULATOR)
781// VR Stereo rendering configuration for simulator
782typedef struct VrStereoConfig {
783 Shader distortionShader; // VR stereo rendering distortion shader
784 Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices
785 Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices
786 int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h]
787 int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
788} VrStereoConfig;
789#endif
790
791#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
792typedef struct rlglData {
793 struct {
794 int currentMatrixMode; // Current matrix mode
795 Matrix *currentMatrix; // Current matrix pointer
796 Matrix modelview; // Default modelview matrix
797 Matrix projection; // Default projection matrix
798 Matrix transform; // Transform matrix to be used with rlTranslate, rlRotate, rlScale
799 bool doTransform; // Use transform matrix against vertex (if required)
800 Matrix stack[MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop
801 int stackCounter; // Matrix stack counter
802
803 DynamicBuffer vertexData[MAX_BATCH_BUFFERING];// Default dynamic buffer for elements data
804 int currentBuffer; // Current buffer tracking, multi-buffering system is supported
805 DrawCall *draws; // Draw calls array
806 int drawsCounter; // Draw calls counter
807
808 Texture2D shapesTexture; // Texture used on shapes drawing (usually a white)
809 Rectangle shapesTextureRec; // Texture source rectangle used on shapes drawing
810 unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader)
811 unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program)
812 unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program)
813 Shader defaultShader; // Basic shader, support vertex color and diffuse texture
814 Shader currentShader; // Shader to be used on rendering (by default, defaultShader)
815 float currentDepth; // Current depth value
816
817 int framebufferWidth; // Default framebuffer width
818 int framebufferHeight; // Default framebuffer height
819
820 } State;
821 struct {
822 bool vao; // VAO support (OpenGL ES2 could not support VAO extension)
823 bool texNPOT; // NPOT textures full support
824 bool texDepth; // Depth textures supported
825 bool texFloat32; // float textures support (32 bit per channel)
826 bool texCompDXT; // DDS texture compression support
827 bool texCompETC1; // ETC1 texture compression support
828 bool texCompETC2; // ETC2/EAC texture compression support
829 bool texCompPVRT; // PVR texture compression support
830 bool texCompASTC; // ASTC texture compression support
831 bool texMirrorClamp; // Clamp mirror wrap mode supported
832 bool texAnisoFilter; // Anisotropic texture filtering support
833 bool debugMarker; // Debug marker support
834
835 float maxAnisotropicLevel; // Maximum anisotropy level supported (minimum is 2.0f)
836 int maxDepthBits; // Maximum bits for depth component
837
838 } ExtSupported; // Extensions supported flags
839#if defined(SUPPORT_VR_SIMULATOR)
840 struct {
841 VrStereoConfig config; // VR stereo configuration for simulator
842 RenderTexture2D stereoFbo; // VR stereo rendering framebuffer
843 bool simulatorReady; // VR simulator ready flag
844 bool stereoRender; // VR stereo rendering enabled/disabled flag
845 } Vr;
846#endif // SUPPORT_VR_SIMULATOR
847} rlglData;
848#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
849
850//----------------------------------------------------------------------------------
851// Global Variables Definition
852//----------------------------------------------------------------------------------
853#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
854static rlglData RLGL = { 0 };
855#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
856
857#if defined(GRAPHICS_API_OPENGL_ES2)
858// NOTE: VAO functionality is exposed through extensions (OES)
859static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays; // Entry point pointer to function glGenVertexArrays()
860static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray; // Entry point pointer to function glBindVertexArray()
861static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; // Entry point pointer to function glDeleteVertexArrays()
862#endif
863
864//----------------------------------------------------------------------------------
865// Module specific Functions Declaration
866//----------------------------------------------------------------------------------
867#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
868static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id
869static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program
870
871static Shader LoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring)
872static void SetShaderDefaultLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
873static void UnloadShaderDefault(void); // Unload default shader
874
875static void LoadBuffersDefault(void); // Load default internal buffers
876static void UpdateBuffersDefault(void); // Update default internal buffers (VAOs/VBOs) with vertex data
877static void DrawBuffersDefault(void); // Draw default internal buffers vertex data
878static void UnloadBuffersDefault(void); // Unload default internal buffers vertex data from CPU and GPU
879
880static void GenDrawCube(void); // Generate and draw cube
881static void GenDrawQuad(void); // Generate and draw quad
882
883#if defined(SUPPORT_VR_SIMULATOR)
884static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye
885#endif
886
887#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
888
889#if defined(GRAPHICS_API_OPENGL_11)
890static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
891static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight);
892#endif
893
894//----------------------------------------------------------------------------------
895// Module Functions Definition - Matrix operations
896//----------------------------------------------------------------------------------
897
898#if defined(GRAPHICS_API_OPENGL_11)
899
900// Fallback to OpenGL 1.1 function calls
901//---------------------------------------
902void rlMatrixMode(int mode)
903{
904 switch (mode)
905 {
906 case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break;
907 case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break;
908 case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break;
909 default: break;
910 }
911}
912
913void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar)
914{
915 glFrustum(left, right, bottom, top, znear, zfar);
916}
917
918void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
919{
920 glOrtho(left, right, bottom, top, znear, zfar);
921}
922
923void rlPushMatrix(void) { glPushMatrix(); }
924void rlPopMatrix(void) { glPopMatrix(); }
925void rlLoadIdentity(void) { glLoadIdentity(); }
926void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); }
927void rlRotatef(float angleDeg, float x, float y, float z) { glRotatef(angleDeg, x, y, z); }
928void rlScalef(float x, float y, float z) { glScalef(x, y, z); }
929void rlMultMatrixf(float *matf) { glMultMatrixf(matf); }
930
931#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
932
933// Choose the current matrix to be transformed
934void rlMatrixMode(int mode)
935{
936 if (mode == RL_PROJECTION) RLGL.State.currentMatrix = &RLGL.State.projection;
937 else if (mode == RL_MODELVIEW) RLGL.State.currentMatrix = &RLGL.State.modelview;
938 //else if (mode == RL_TEXTURE) // Not supported
939
940 RLGL.State.currentMatrixMode = mode;
941}
942
943// Push the current matrix into RLGL.State.stack
944void rlPushMatrix(void)
945{
946 if (RLGL.State.stackCounter >= MAX_MATRIX_STACK_SIZE) TRACELOG(LOG_ERROR, "RLGL: Matrix stack overflow (MAX_MATRIX_STACK_SIZE)");
947
948 if (RLGL.State.currentMatrixMode == RL_MODELVIEW)
949 {
950 RLGL.State.doTransform = true;
951 RLGL.State.currentMatrix = &RLGL.State.transform;
952 }
953
954 RLGL.State.stack[RLGL.State.stackCounter] = *RLGL.State.currentMatrix;
955 RLGL.State.stackCounter++;
956}
957
958// Pop lattest inserted matrix from RLGL.State.stack
959void rlPopMatrix(void)
960{
961 if (RLGL.State.stackCounter > 0)
962 {
963 Matrix mat = RLGL.State.stack[RLGL.State.stackCounter - 1];
964 *RLGL.State.currentMatrix = mat;
965 RLGL.State.stackCounter--;
966 }
967
968 if ((RLGL.State.stackCounter == 0) && (RLGL.State.currentMatrixMode == RL_MODELVIEW))
969 {
970 RLGL.State.currentMatrix = &RLGL.State.modelview;
971 RLGL.State.doTransform = false;
972 }
973}
974
975// Reset current matrix to identity matrix
976void rlLoadIdentity(void)
977{
978 *RLGL.State.currentMatrix = MatrixIdentity();
979}
980
981// Multiply the current matrix by a translation matrix
982void rlTranslatef(float x, float y, float z)
983{
984 Matrix matTranslation = MatrixTranslate(x, y, z);
985
986 // NOTE: We transpose matrix with multiplication order
987 *RLGL.State.currentMatrix = MatrixMultiply(matTranslation, *RLGL.State.currentMatrix);
988}
989
990// Multiply the current matrix by a rotation matrix
991void rlRotatef(float angleDeg, float x, float y, float z)
992{
993 Matrix matRotation = MatrixIdentity();
994
995 Vector3 axis = (Vector3){ x, y, z };
996 matRotation = MatrixRotate(Vector3Normalize(axis), angleDeg*DEG2RAD);
997
998 // NOTE: We transpose matrix with multiplication order
999 *RLGL.State.currentMatrix = MatrixMultiply(matRotation, *RLGL.State.currentMatrix);
1000}
1001
1002// Multiply the current matrix by a scaling matrix
1003void rlScalef(float x, float y, float z)
1004{
1005 Matrix matScale = MatrixScale(x, y, z);
1006
1007 // NOTE: We transpose matrix with multiplication order
1008 *RLGL.State.currentMatrix = MatrixMultiply(matScale, *RLGL.State.currentMatrix);
1009}
1010
1011// Multiply the current matrix by another matrix
1012void rlMultMatrixf(float *matf)
1013{
1014 // Matrix creation from array
1015 Matrix mat = { matf[0], matf[4], matf[8], matf[12],
1016 matf[1], matf[5], matf[9], matf[13],
1017 matf[2], matf[6], matf[10], matf[14],
1018 matf[3], matf[7], matf[11], matf[15] };
1019
1020 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, mat);
1021}
1022
1023// Multiply the current matrix by a perspective matrix generated by parameters
1024void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar)
1025{
1026 Matrix matPerps = MatrixFrustum(left, right, bottom, top, znear, zfar);
1027
1028 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matPerps);
1029}
1030
1031// Multiply the current matrix by an orthographic matrix generated by parameters
1032void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
1033{
1034 Matrix matOrtho = MatrixOrtho(left, right, bottom, top, znear, zfar);
1035
1036 *RLGL.State.currentMatrix = MatrixMultiply(*RLGL.State.currentMatrix, matOrtho);
1037}
1038
1039#endif
1040
1041// Set the viewport area (transformation from normalized device coordinates to window coordinates)
1042// NOTE: Updates global variables: RLGL.State.framebufferWidth, RLGL.State.framebufferHeight
1043void rlViewport(int x, int y, int width, int height)
1044{
1045 glViewport(x, y, width, height);
1046}
1047
1048//----------------------------------------------------------------------------------
1049// Module Functions Definition - Vertex level operations
1050//----------------------------------------------------------------------------------
1051#if defined(GRAPHICS_API_OPENGL_11)
1052
1053// Fallback to OpenGL 1.1 function calls
1054//---------------------------------------
1055void rlBegin(int mode)
1056{
1057 switch (mode)
1058 {
1059 case RL_LINES: glBegin(GL_LINES); break;
1060 case RL_TRIANGLES: glBegin(GL_TRIANGLES); break;
1061 case RL_QUADS: glBegin(GL_QUADS); break;
1062 default: break;
1063 }
1064}
1065
1066void rlEnd() { glEnd(); }
1067void rlVertex2i(int x, int y) { glVertex2i(x, y); }
1068void rlVertex2f(float x, float y) { glVertex2f(x, y); }
1069void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); }
1070void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); }
1071void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); }
1072void rlColor4ub(byte r, byte g, byte b, byte a) { glColor4ub(r, g, b, a); }
1073void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); }
1074void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); }
1075
1076#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1077
1078// Initialize drawing mode (how to organize vertex)
1079void rlBegin(int mode)
1080{
1081 // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS
1082 // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer
1083 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode != mode)
1084 {
1085 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount > 0)
1086 {
1087 // Make sure current RLGL.State.draws[i].vertexCount is aligned a multiple of 4,
1088 // that way, following QUADS drawing will keep aligned with index processing
1089 // It implies adding some extra alignment vertex at the end of the draw,
1090 // those vertex are not processed but they are considered as an additional offset
1091 // for the next set of vertex to be drawn
1092 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_LINES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount : RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4);
1093 else if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_TRIANGLES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4)));
1094
1095 else RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = 0;
1096
1097 if (rlCheckBufferLimit(RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment)) rlglDraw();
1098 else
1099 {
1100 RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1101 RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1102 RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1103
1104 RLGL.State.drawsCounter++;
1105 }
1106 }
1107
1108 if (RLGL.State.drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw();
1109
1110 RLGL.State.draws[RLGL.State.drawsCounter - 1].mode = mode;
1111 RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount = 0;
1112 RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId = RLGL.State.defaultTextureId;
1113 }
1114}
1115
1116// Finish vertex providing
1117void rlEnd(void)
1118{
1119 // Make sure vertexCount is the same for vertices, texcoords, colors and normals
1120 // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls
1121
1122 // Make sure colors count match vertex count
1123 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter != RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter)
1124 {
1125 int addColors = RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter - RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter;
1126
1127 for (int i = 0; i < addColors; i++)
1128 {
1129 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 4];
1130 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 1] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 3];
1131 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 2] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 2];
1132 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 3] = RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter - 1];
1133 RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter++;
1134 }
1135 }
1136
1137 // Make sure texcoords count match vertex count
1138 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter != RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter)
1139 {
1140 int addTexCoords = RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter - RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter;
1141
1142 for (int i = 0; i < addTexCoords; i++)
1143 {
1144 RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter] = 0.0f;
1145 RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter + 1] = 0.0f;
1146 RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter++;
1147 }
1148 }
1149
1150 // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P
1151
1152 // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
1153 // as well as depth buffer bit-depth (16bit or 24bit or 32bit)
1154 // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
1155 RLGL.State.currentDepth += (1.0f/20000.0f);
1156
1157 // Verify internal buffers limits
1158 // NOTE: This check is combined with usage of rlCheckBufferLimit()
1159 if ((RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter) >= (MAX_BATCH_ELEMENTS*4 - 4))
1160 {
1161 // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(),
1162 // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call!
1163 // If we have multiple matrix pushed, it will require "RLGL.State.stackCounter" pops before launching the draw
1164 for (int i = RLGL.State.stackCounter; i >= 0; i--) rlPopMatrix();
1165 rlglDraw();
1166 }
1167}
1168
1169// Define one vertex (position)
1170// NOTE: Vertex position data is the basic information required for drawing
1171void rlVertex3f(float x, float y, float z)
1172{
1173 Vector3 vec = { x, y, z };
1174
1175 // Transform provided vector if required
1176 if (RLGL.State.doTransform) vec = Vector3Transform(vec, RLGL.State.transform);
1177
1178 // Verify that MAX_BATCH_ELEMENTS limit not reached
1179 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4))
1180 {
1181 RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter] = vec.x;
1182 RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + 1] = vec.y;
1183 RLGL.State.vertexData[RLGL.State.currentBuffer].vertices[3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + 2] = vec.z;
1184 RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter++;
1185
1186 RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount++;
1187 }
1188 else TRACELOG(LOG_ERROR, "RLGL: Batch elements overflow (MAX_BATCH_ELEMENTS)");
1189}
1190
1191// Define one vertex (position)
1192void rlVertex2f(float x, float y)
1193{
1194 rlVertex3f(x, y, RLGL.State.currentDepth);
1195}
1196
1197// Define one vertex (position)
1198void rlVertex2i(int x, int y)
1199{
1200 rlVertex3f((float)x, (float)y, RLGL.State.currentDepth);
1201}
1202
1203// Define one vertex (texture coordinate)
1204// NOTE: Texture coordinates are limited to QUADS only
1205void rlTexCoord2f(float x, float y)
1206{
1207 RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter] = x;
1208 RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords[2*RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter + 1] = y;
1209 RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter++;
1210}
1211
1212// Define one vertex (normal)
1213// NOTE: Normals limited to TRIANGLES only?
1214void rlNormal3f(float x, float y, float z)
1215{
1216 // TODO: Normals usage...
1217}
1218
1219// Define one vertex (color)
1220void rlColor4ub(byte x, byte y, byte z, byte w)
1221{
1222 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter] = x;
1223 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 1] = y;
1224 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 2] = z;
1225 RLGL.State.vertexData[RLGL.State.currentBuffer].colors[4*RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter + 3] = w;
1226 RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter++;
1227}
1228
1229// Define one vertex (color)
1230void rlColor4f(float r, float g, float b, float a)
1231{
1232 rlColor4ub((byte)(r*255), (byte)(g*255), (byte)(b*255), (byte)(a*255));
1233}
1234
1235// Define one vertex (color)
1236void rlColor3f(float x, float y, float z)
1237{
1238 rlColor4ub((byte)(x*255), (byte)(y*255), (byte)(z*255), 255);
1239}
1240
1241#endif
1242
1243//----------------------------------------------------------------------------------
1244// Module Functions Definition - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
1245//----------------------------------------------------------------------------------
1246
1247// Enable texture usage
1248void rlEnableTexture(unsigned int id)
1249{
1250#if defined(GRAPHICS_API_OPENGL_11)
1251 glEnable(GL_TEXTURE_2D);
1252 glBindTexture(GL_TEXTURE_2D, id);
1253#endif
1254
1255#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1256 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId != id)
1257 {
1258 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount > 0)
1259 {
1260 // Make sure current RLGL.State.draws[i].vertexCount is aligned a multiple of 4,
1261 // that way, following QUADS drawing will keep aligned with index processing
1262 // It implies adding some extra alignment vertex at the end of the draw,
1263 // those vertex are not processed but they are considered as an additional offset
1264 // for the next set of vertex to be drawn
1265 if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_LINES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount : RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4);
1266 else if (RLGL.State.draws[RLGL.State.drawsCounter - 1].mode == RL_TRIANGLES) RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = ((RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount%4)));
1267
1268 else RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment = 0;
1269
1270 if (rlCheckBufferLimit(RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment)) rlglDraw();
1271 else
1272 {
1273 RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1274 RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1275 RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter += RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexAlignment;
1276
1277 RLGL.State.drawsCounter++;
1278 }
1279 }
1280
1281 if (RLGL.State.drawsCounter >= MAX_DRAWCALL_REGISTERED) rlglDraw();
1282
1283 RLGL.State.draws[RLGL.State.drawsCounter - 1].textureId = id;
1284 RLGL.State.draws[RLGL.State.drawsCounter - 1].vertexCount = 0;
1285 }
1286#endif
1287}
1288
1289// Disable texture usage
1290void rlDisableTexture(void)
1291{
1292#if defined(GRAPHICS_API_OPENGL_11)
1293 glDisable(GL_TEXTURE_2D);
1294 glBindTexture(GL_TEXTURE_2D, 0);
1295#else
1296 // NOTE: If quads batch limit is reached,
1297 // we force a draw call and next batch starts
1298 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter >= (MAX_BATCH_ELEMENTS*4)) rlglDraw();
1299#endif
1300}
1301
1302// Set texture parameters (wrap mode/filter mode)
1303void rlTextureParameters(unsigned int id, int param, int value)
1304{
1305 glBindTexture(GL_TEXTURE_2D, id);
1306
1307 switch (param)
1308 {
1309 case RL_TEXTURE_WRAP_S:
1310 case RL_TEXTURE_WRAP_T:
1311 {
1312 if (value == RL_WRAP_MIRROR_CLAMP)
1313 {
1314#if !defined(GRAPHICS_API_OPENGL_11)
1315 if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_2D, param, value);
1316 else TRACELOG(LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
1317#endif
1318 }
1319 else glTexParameteri(GL_TEXTURE_2D, param, value);
1320
1321 } break;
1322 case RL_TEXTURE_MAG_FILTER:
1323 case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
1324 case RL_TEXTURE_ANISOTROPIC_FILTER:
1325 {
1326#if !defined(GRAPHICS_API_OPENGL_11)
1327 if (value <= RLGL.ExtSupported.maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
1328 else if (RLGL.ExtSupported.maxAnisotropicLevel > 0.0f)
1329 {
1330 TRACELOG(LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropicLevel);
1331 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
1332 }
1333 else TRACELOG(LOG_WARNING, "GL: Anisotropic filtering not supported");
1334#endif
1335 } break;
1336 default: break;
1337 }
1338
1339 glBindTexture(GL_TEXTURE_2D, 0);
1340}
1341
1342// Enable rendering to texture (fbo)
1343void rlEnableRenderTexture(unsigned int id)
1344{
1345#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1346 glBindFramebuffer(GL_FRAMEBUFFER, id);
1347
1348 //glDisable(GL_CULL_FACE); // Allow double side drawing for texture flipping
1349 //glCullFace(GL_FRONT);
1350#endif
1351}
1352
1353// Disable rendering to texture
1354void rlDisableRenderTexture(void)
1355{
1356#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1357 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1358
1359 //glEnable(GL_CULL_FACE);
1360 //glCullFace(GL_BACK);
1361#endif
1362}
1363
1364// Enable depth test
1365void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); }
1366
1367// Disable depth test
1368void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); }
1369
1370// Enable backface culling
1371void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); }
1372
1373// Disable backface culling
1374void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); }
1375
1376// Enable scissor test
1377RLAPI void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); }
1378
1379// Disable scissor test
1380RLAPI void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); }
1381
1382// Scissor test
1383RLAPI void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); }
1384
1385// Enable wire mode
1386void rlEnableWireMode(void)
1387{
1388#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
1389 // NOTE: glPolygonMode() not available on OpenGL ES
1390 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1391#endif
1392}
1393
1394// Disable wire mode
1395void rlDisableWireMode(void)
1396{
1397#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
1398 // NOTE: glPolygonMode() not available on OpenGL ES
1399 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1400#endif
1401}
1402
1403// Unload texture from GPU memory
1404void rlDeleteTextures(unsigned int id)
1405{
1406 if (id > 0) glDeleteTextures(1, &id);
1407}
1408
1409// Unload render texture from GPU memory
1410void rlDeleteRenderTextures(RenderTexture2D target)
1411{
1412#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1413 if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id);
1414 if (target.depth.id > 0)
1415 {
1416 if (target.depthTexture) glDeleteTextures(1, &target.depth.id);
1417 else glDeleteRenderbuffers(1, &target.depth.id);
1418 }
1419
1420 if (target.id > 0) glDeleteFramebuffers(1, &target.id);
1421
1422 TRACELOG(LOG_INFO, "FBO: [ID %i] Unloaded render texture data from VRAM (GPU)", target.id);
1423#endif
1424}
1425
1426// Unload shader from GPU memory
1427void rlDeleteShader(unsigned int id)
1428{
1429#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1430 if (id != 0) glDeleteProgram(id);
1431#endif
1432}
1433
1434// Unload vertex data (VAO) from GPU memory
1435void rlDeleteVertexArrays(unsigned int id)
1436{
1437#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1438 if (RLGL.ExtSupported.vao)
1439 {
1440 if (id != 0) glDeleteVertexArrays(1, &id);
1441 TRACELOG(LOG_INFO, "VAO: [ID %i] Unloaded vertex data from VRAM (GPU)", id);
1442 }
1443#endif
1444}
1445
1446// Unload vertex data (VBO) from GPU memory
1447void rlDeleteBuffers(unsigned int id)
1448{
1449#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1450 if (id != 0)
1451 {
1452 glDeleteBuffers(1, &id);
1453 if (!RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "VBO: [ID %i] Unloaded vertex data from VRAM (GPU)", id);
1454 }
1455#endif
1456}
1457
1458// Clear color buffer with color
1459void rlClearColor(byte r, byte g, byte b, byte a)
1460{
1461 // Color values clamp to 0.0f(0) and 1.0f(255)
1462 float cr = (float)r/255;
1463 float cg = (float)g/255;
1464 float cb = (float)b/255;
1465 float ca = (float)a/255;
1466
1467 glClearColor(cr, cg, cb, ca);
1468}
1469
1470// Clear used screen buffers (color and depth)
1471void rlClearScreenBuffers(void)
1472{
1473 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D)
1474 //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
1475}
1476
1477// Update GPU buffer with new data
1478void rlUpdateBuffer(int bufferId, void *data, int dataSize)
1479{
1480#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1481 glBindBuffer(GL_ARRAY_BUFFER, bufferId);
1482 glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, data);
1483#endif
1484}
1485
1486//----------------------------------------------------------------------------------
1487// Module Functions Definition - rlgl Functions
1488//----------------------------------------------------------------------------------
1489
1490// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
1491void rlglInit(int width, int height)
1492{
1493 // Check OpenGL information and capabilities
1494 //------------------------------------------------------------------------------
1495 // Print current OpenGL and GLSL version
1496 TRACELOG(LOG_INFO, "GL: OpenGL device information:");
1497 TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR));
1498 TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER));
1499 TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION));
1500 TRACELOG(LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
1501
1502 // NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
1503 //int maxTexSize;
1504 //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
1505 //TRACELOG(LOG_INFO, "GL: Maximum texture size: %i", maxTexSize);
1506
1507 //GL_MAX_TEXTURE_IMAGE_UNITS
1508 //GL_MAX_VIEWPORT_DIMS
1509
1510 //int numAuxBuffers;
1511 //glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
1512 //TRACELOG(LOG_INFO, "GL: Number of aixiliar buffers: %i", numAuxBuffers);
1513
1514 //GLint numComp = 0;
1515 //GLint format[32] = { 0 };
1516 //glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
1517 //glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
1518 //for (int i = 0; i < numComp; i++) TRACELOG(LOG_INFO, "GL: Supported compressed format: 0x%x", format[i]);
1519
1520 // NOTE: We don't need that much data on screen... right now...
1521
1522 // TODO: Automatize extensions loading using rlLoadExtensions() and GLAD
1523 // Actually, when rlglInit() is called in InitWindow() in core.c,
1524 // OpenGL required extensions have already been loaded (PLATFORM_DESKTOP)
1525
1526#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1527 // Get supported extensions list
1528 GLint numExt = 0;
1529
1530#if defined(GRAPHICS_API_OPENGL_33)
1531 // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
1532 RLGL.ExtSupported.vao = true;
1533
1534 // Multiple texture extensions supported by default
1535 RLGL.ExtSupported.texNPOT = true;
1536 RLGL.ExtSupported.texFloat32 = true;
1537 RLGL.ExtSupported.texDepth = true;
1538
1539 // We get a list of available extensions and we check for some of them (compressed textures)
1540 // NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that)
1541 glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
1542
1543 // Allocate numExt strings pointers
1544 const char **extList = RL_MALLOC(sizeof(const char *)*numExt);
1545
1546 // Get extensions strings
1547 for (int i = 0; i < numExt; i++) extList[i] = (const char *)glGetStringi(GL_EXTENSIONS, i);
1548
1549#elif defined(GRAPHICS_API_OPENGL_ES2)
1550 // Allocate 512 strings pointers (2 KB)
1551 const char **extList = RL_MALLOC(sizeof(const char *)*512);
1552
1553 const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
1554
1555 // NOTE: We have to duplicate string because glGetString() returns a const string
1556 int len = strlen(extensions) + 1;
1557 char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char));
1558 strcpy(extensionsDup, extensions);
1559
1560 extList[numExt] = extensionsDup;
1561
1562 for (int i = 0; i < len; i++)
1563 {
1564 if (extensionsDup[i] == ' ')
1565 {
1566 extensionsDup[i] = '\0';
1567
1568 numExt++;
1569 extList[numExt] = &extensionsDup[i + 1];
1570 }
1571 }
1572
1573 // NOTE: Duplicated string (extensionsDup) must be deallocated
1574#endif
1575
1576 TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt);
1577
1578 // Show supported extensions
1579 //for (int i = 0; i < numExt; i++) TRACELOG(LOG_INFO, "Supported extension: %s", extList[i]);
1580
1581 // Check required extensions
1582 for (int i = 0; i < numExt; i++)
1583 {
1584#if defined(GRAPHICS_API_OPENGL_ES2)
1585 // Check VAO support
1586 // NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature
1587 if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0)
1588 {
1589 // The extension is supported by our hardware and driver, try to get related functions pointers
1590 // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
1591 glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
1592 glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
1593 glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
1594 //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted
1595
1596 if ((glGenVertexArrays != NULL) && (glBindVertexArray != NULL) && (glDeleteVertexArrays != NULL)) RLGL.ExtSupported.vao = true;
1597 }
1598
1599 // Check NPOT textures support
1600 // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
1601 if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) RLGL.ExtSupported.texNPOT = true;
1602
1603 // Check texture float support
1604 if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true;
1605
1606 // Check depth texture support
1607 if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) ||
1608 (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true;
1609
1610 if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24;
1611 if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32;
1612#endif
1613 // DDS texture compression support
1614 if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
1615 (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
1616 (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) RLGL.ExtSupported.texCompDXT = true;
1617
1618 // ETC1 texture compression support
1619 if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) ||
1620 (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) RLGL.ExtSupported.texCompETC1 = true;
1621
1622 // ETC2/EAC texture compression support
1623 if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) RLGL.ExtSupported.texCompETC2 = true;
1624
1625 // PVR texture compression support
1626 if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) RLGL.ExtSupported.texCompPVRT = true;
1627
1628 // ASTC texture compression support
1629 if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) RLGL.ExtSupported.texCompASTC = true;
1630
1631 // Anisotropic texture filter support
1632 if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0)
1633 {
1634 RLGL.ExtSupported.texAnisoFilter = true;
1635 glGetFloatv(0x84FF, &RLGL.ExtSupported.maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
1636 }
1637
1638 // Clamp mirror wrap mode supported
1639 if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) RLGL.ExtSupported.texMirrorClamp = true;
1640
1641 // Debug marker support
1642 if (strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) RLGL.ExtSupported.debugMarker = true;
1643 }
1644
1645 // Free extensions pointers
1646 RL_FREE(extList);
1647
1648#if defined(GRAPHICS_API_OPENGL_ES2)
1649 RL_FREE(extensionsDup); // Duplicated string must be deallocated
1650
1651 if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions initialized successfully");
1652 else TRACELOG(LOG_WARNING, "GL: VAO extension not found, VAO usage not supported");
1653
1654 if (RLGL.ExtSupported.texNPOT) TRACELOG(LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported");
1655 else TRACELOG(LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)");
1656#endif
1657
1658 if (RLGL.ExtSupported.texCompDXT) TRACELOG(LOG_INFO, "GL: DXT compressed textures supported");
1659 if (RLGL.ExtSupported.texCompETC1) TRACELOG(LOG_INFO, "GL: ETC1 compressed textures supported");
1660 if (RLGL.ExtSupported.texCompETC2) TRACELOG(LOG_INFO, "GL: ETC2/EAC compressed textures supported");
1661 if (RLGL.ExtSupported.texCompPVRT) TRACELOG(LOG_INFO, "GL: PVRT compressed textures supported");
1662 if (RLGL.ExtSupported.texCompASTC) TRACELOG(LOG_INFO, "GL: ASTC compressed textures supported");
1663
1664 if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(LOG_INFO, "GL: Anisotropic textures filtering supported (max: %.0fX)", RLGL.ExtSupported.maxAnisotropicLevel);
1665 if (RLGL.ExtSupported.texMirrorClamp) TRACELOG(LOG_INFO, "GL: Mirror clamp wrap texture mode supported");
1666
1667 if (RLGL.ExtSupported.debugMarker) TRACELOG(LOG_INFO, "GL: Debug Marker supported");
1668
1669 // Initialize buffers, default shaders and default textures
1670 //----------------------------------------------------------
1671 // Init default white texture
1672 unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
1673 RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, UNCOMPRESSED_R8G8B8A8, 1);
1674
1675 if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId);
1676 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture");
1677
1678 // Init default Shader (customized for GL 3.3 and ES2)
1679 RLGL.State.defaultShader = LoadShaderDefault();
1680 RLGL.State.currentShader = RLGL.State.defaultShader;
1681
1682 // Init default vertex arrays buffers
1683 LoadBuffersDefault();
1684
1685 // Init transformations matrix accumulator
1686 RLGL.State.transform = MatrixIdentity();
1687
1688 // Init draw calls tracking system
1689 RLGL.State.draws = (DrawCall *)RL_MALLOC(sizeof(DrawCall)*MAX_DRAWCALL_REGISTERED);
1690
1691 for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++)
1692 {
1693 RLGL.State.draws[i].mode = RL_QUADS;
1694 RLGL.State.draws[i].vertexCount = 0;
1695 RLGL.State.draws[i].vertexAlignment = 0;
1696 //RLGL.State.draws[i].vaoId = 0;
1697 //RLGL.State.draws[i].shaderId = 0;
1698 RLGL.State.draws[i].textureId = RLGL.State.defaultTextureId;
1699 //RLGL.State.draws[i].RLGL.State.projection = MatrixIdentity();
1700 //RLGL.State.draws[i].RLGL.State.modelview = MatrixIdentity();
1701 }
1702
1703 RLGL.State.drawsCounter = 1; // Reset draws counter
1704 RLGL.State.currentDepth = -1.0f; // Reset depth value
1705
1706 // Init RLGL.State.stack matrices (emulating OpenGL 1.1)
1707 for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity();
1708
1709 // Init RLGL.State.projection and RLGL.State.modelview matrices
1710 RLGL.State.projection = MatrixIdentity();
1711 RLGL.State.modelview = MatrixIdentity();
1712 RLGL.State.currentMatrix = &RLGL.State.modelview;
1713
1714#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
1715
1716 // Initialize OpenGL default states
1717 //----------------------------------------------------------
1718 // Init state: Depth test
1719 glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
1720 glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
1721
1722 // Init state: Blending mode
1723 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
1724 glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
1725
1726 // Init state: Culling
1727 // NOTE: All shapes/models triangles are drawn CCW
1728 glCullFace(GL_BACK); // Cull the back face (default)
1729 glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
1730 glEnable(GL_CULL_FACE); // Enable backface culling
1731
1732#if defined(GRAPHICS_API_OPENGL_11)
1733 // Init state: Color hints (deprecated in OpenGL 3.0+)
1734 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
1735 glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
1736#endif
1737
1738 // Init state: Color/Depth buffers clear
1739 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
1740 glClearDepth(1.0f); // Set clear depth value (default)
1741 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
1742
1743 // Store screen size into global variables
1744 RLGL.State.framebufferWidth = width;
1745 RLGL.State.framebufferHeight = height;
1746
1747 // Init texture and rectangle used on basic shapes drawing
1748 RLGL.State.shapesTexture = GetTextureDefault();
1749 RLGL.State.shapesTextureRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
1750
1751 TRACELOG(LOG_INFO, "RLGL: Default state initialized successfully");
1752}
1753
1754// Vertex Buffer Object deinitialization (memory free)
1755void rlglClose(void)
1756{
1757#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1758 UnloadShaderDefault(); // Unload default shader
1759 UnloadBuffersDefault(); // Unload default buffers
1760 glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
1761
1762 TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded default texture data from VRAM (GPU)", RLGL.State.defaultTextureId);
1763
1764 RL_FREE(RLGL.State.draws);
1765#endif
1766}
1767
1768// Update and draw internal buffers
1769void rlglDraw(void)
1770{
1771#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1772 // Only process data if we have data to process
1773 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0)
1774 {
1775 UpdateBuffersDefault();
1776 DrawBuffersDefault(); // NOTE: Stereo rendering is checked inside
1777 }
1778#endif
1779}
1780
1781// Returns current OpenGL version
1782int rlGetVersion(void)
1783{
1784#if defined(GRAPHICS_API_OPENGL_11)
1785 return OPENGL_11;
1786#elif defined(GRAPHICS_API_OPENGL_21)
1787 #if defined(__APPLE__)
1788 return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX
1789 #else
1790 return OPENGL_21;
1791 #endif
1792#elif defined(GRAPHICS_API_OPENGL_33)
1793 return OPENGL_33;
1794#elif defined(GRAPHICS_API_OPENGL_ES2)
1795 return OPENGL_ES_20;
1796#endif
1797}
1798
1799// Check internal buffer overflow for a given number of vertex
1800bool rlCheckBufferLimit(int vCount)
1801{
1802 bool overflow = false;
1803#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1804 if ((RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter + vCount) >= (MAX_BATCH_ELEMENTS*4)) overflow = true;
1805#endif
1806 return overflow;
1807}
1808
1809// Set debug marker
1810void rlSetDebugMarker(const char *text)
1811{
1812#if defined(GRAPHICS_API_OPENGL_33)
1813 if (RLGL.ExtSupported.debugMarker) glInsertEventMarkerEXT(0, text);
1814#endif
1815}
1816
1817// Load OpenGL extensions
1818// NOTE: External loader function could be passed as a pointer
1819void rlLoadExtensions(void *loader)
1820{
1821#if defined(GRAPHICS_API_OPENGL_33)
1822 // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
1823 #if !defined(__APPLE__)
1824 if (!gladLoadGLLoader((GLADloadproc)loader)) TRACELOG(LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
1825 else TRACELOG(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
1826
1827 #if defined(GRAPHICS_API_OPENGL_21)
1828 if (GLAD_GL_VERSION_2_1) TRACELOG(LOG_INFO, "GL: OpenGL 2.1 profile supported");
1829 #elif defined(GRAPHICS_API_OPENGL_33)
1830 if (GLAD_GL_VERSION_3_3) TRACELOG(LOG_INFO, "GL: OpenGL 3.3 Core profile supported");
1831 else TRACELOG(LOG_ERROR, "GL: OpenGL 3.3 Core profile not supported");
1832 #endif
1833 #endif
1834
1835 // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans
1836 //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object
1837#endif
1838}
1839
1840// Get world coordinates from screen coordinates
1841Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view)
1842{
1843 Vector3 result = { 0.0f, 0.0f, 0.0f };
1844
1845 // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
1846 Matrix matViewProj = MatrixMultiply(view, proj);
1847 matViewProj = MatrixInvert(matViewProj);
1848
1849 // Create quaternion from source point
1850 Quaternion quat = { source.x, source.y, source.z, 1.0f };
1851
1852 // Multiply quat point by unproject matrix
1853 quat = QuaternionTransform(quat, matViewProj);
1854
1855 // Normalized world points in vectors
1856 result.x = quat.x/quat.w;
1857 result.y = quat.y/quat.w;
1858 result.z = quat.z/quat.w;
1859
1860 return result;
1861}
1862
1863// Convert image data to OpenGL texture (returns OpenGL valid Id)
1864unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount)
1865{
1866 glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
1867
1868 unsigned int id = 0;
1869
1870 // Check texture format support by OpenGL 1.1 (compressed textures not supported)
1871#if defined(GRAPHICS_API_OPENGL_11)
1872 if (format >= COMPRESSED_DXT1_RGB)
1873 {
1874 TRACELOG(LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats");
1875 return id;
1876 }
1877#else
1878 if ((!RLGL.ExtSupported.texCompDXT) && ((format == COMPRESSED_DXT1_RGB) || (format == COMPRESSED_DXT1_RGBA) ||
1879 (format == COMPRESSED_DXT3_RGBA) || (format == COMPRESSED_DXT5_RGBA)))
1880 {
1881 TRACELOG(LOG_WARNING, "GL: DXT compressed texture format not supported");
1882 return id;
1883 }
1884#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1885 if ((!RLGL.ExtSupported.texCompETC1) && (format == COMPRESSED_ETC1_RGB))
1886 {
1887 TRACELOG(LOG_WARNING, "GL: ETC1 compressed texture format not supported");
1888 return id;
1889 }
1890
1891 if ((!RLGL.ExtSupported.texCompETC2) && ((format == COMPRESSED_ETC2_RGB) || (format == COMPRESSED_ETC2_EAC_RGBA)))
1892 {
1893 TRACELOG(LOG_WARNING, "GL: ETC2 compressed texture format not supported");
1894 return id;
1895 }
1896
1897 if ((!RLGL.ExtSupported.texCompPVRT) && ((format == COMPRESSED_PVRT_RGB) || (format == COMPRESSED_PVRT_RGBA)))
1898 {
1899 TRACELOG(LOG_WARNING, "GL: PVRT compressed texture format not supported");
1900 return id;
1901 }
1902
1903 if ((!RLGL.ExtSupported.texCompASTC) && ((format == COMPRESSED_ASTC_4x4_RGBA) || (format == COMPRESSED_ASTC_8x8_RGBA)))
1904 {
1905 TRACELOG(LOG_WARNING, "GL: ASTC compressed texture format not supported");
1906 return id;
1907 }
1908#endif
1909#endif // GRAPHICS_API_OPENGL_11
1910
1911 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1912
1913 glGenTextures(1, &id); // Generate texture id
1914
1915#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
1916 //glActiveTexture(GL_TEXTURE0); // If not defined, using GL_TEXTURE0 by default (shader texture)
1917#endif
1918
1919 glBindTexture(GL_TEXTURE_2D, id);
1920
1921 int mipWidth = width;
1922 int mipHeight = height;
1923 int mipOffset = 0; // Mipmap data offset
1924
1925 TRACELOGD("TEXTURE: Load texture from data memory address: 0x%x", data);
1926
1927 // Load the different mipmap levels
1928 for (int i = 0; i < mipmapCount; i++)
1929 {
1930 unsigned int mipSize = GetPixelDataSize(mipWidth, mipHeight, format);
1931
1932 unsigned int glInternalFormat, glFormat, glType;
1933 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
1934
1935 TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
1936
1937 if (glInternalFormat != -1)
1938 {
1939 if (format < COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, (unsigned char *)data + mipOffset);
1940 #if !defined(GRAPHICS_API_OPENGL_11)
1941 else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, (unsigned char *)data + mipOffset);
1942 #endif
1943
1944 #if defined(GRAPHICS_API_OPENGL_33)
1945 if (format == UNCOMPRESSED_GRAYSCALE)
1946 {
1947 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
1948 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
1949 }
1950 else if (format == UNCOMPRESSED_GRAY_ALPHA)
1951 {
1952 #if defined(GRAPHICS_API_OPENGL_21)
1953 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA };
1954 #elif defined(GRAPHICS_API_OPENGL_33)
1955 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
1956 #endif
1957 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
1958 }
1959 #endif
1960 }
1961
1962 mipWidth /= 2;
1963 mipHeight /= 2;
1964 mipOffset += mipSize;
1965
1966 // Security check for NPOT textures
1967 if (mipWidth < 1) mipWidth = 1;
1968 if (mipHeight < 1) mipHeight = 1;
1969 }
1970
1971 // Texture parameters configuration
1972 // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
1973#if defined(GRAPHICS_API_OPENGL_ES2)
1974 // 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
1975 if (RLGL.ExtSupported.texNPOT)
1976 {
1977 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
1978 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
1979 }
1980 else
1981 {
1982 // NOTE: If using negative texture coordinates (LoadOBJ()), it does not work!
1983 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis
1984 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis
1985 }
1986#else
1987 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
1988 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
1989#endif
1990
1991 // Magnification and minification filters
1992 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
1993 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
1994
1995#if defined(GRAPHICS_API_OPENGL_33)
1996 if (mipmapCount > 1)
1997 {
1998 // Activate Trilinear filtering if mipmaps are available
1999 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2000 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2001 }
2002#endif
2003
2004 // At this point we have the texture loaded in GPU and texture parameters configured
2005
2006 // NOTE: If mipmaps were not in data, they are not generated automatically
2007
2008 // Unbind current texture
2009 glBindTexture(GL_TEXTURE_2D, 0);
2010
2011 if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Texture created successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount);
2012 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load texture");
2013
2014 return id;
2015}
2016
2017// Load depth texture/renderbuffer (to be attached to fbo)
2018// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture/WEBGL_depth_texture extensions
2019unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderBuffer)
2020{
2021 unsigned int id = 0;
2022
2023#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2024 unsigned int glInternalFormat = GL_DEPTH_COMPONENT16;
2025
2026 if ((bits != 16) && (bits != 24) && (bits != 32)) bits = 16;
2027
2028 if (bits == 24)
2029 {
2030#if defined(GRAPHICS_API_OPENGL_33)
2031 glInternalFormat = GL_DEPTH_COMPONENT24;
2032#elif defined(GRAPHICS_API_OPENGL_ES2)
2033 if (RLGL.ExtSupported.maxDepthBits >= 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES;
2034#endif
2035 }
2036
2037 if (bits == 32)
2038 {
2039#if defined(GRAPHICS_API_OPENGL_33)
2040 glInternalFormat = GL_DEPTH_COMPONENT32;
2041#elif defined(GRAPHICS_API_OPENGL_ES2)
2042 if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES;
2043#endif
2044 }
2045
2046 if (!useRenderBuffer && RLGL.ExtSupported.texDepth)
2047 {
2048 glGenTextures(1, &id);
2049 glBindTexture(GL_TEXTURE_2D, id);
2050 glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
2051
2052 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2053 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2054 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2055 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2056
2057 glBindTexture(GL_TEXTURE_2D, 0);
2058 }
2059 else
2060 {
2061 // Create the renderbuffer that will serve as the depth attachment for the framebuffer
2062 // NOTE: A renderbuffer is simpler than a texture and could offer better performance on embedded devices
2063 glGenRenderbuffers(1, &id);
2064 glBindRenderbuffer(GL_RENDERBUFFER, id);
2065 glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height);
2066
2067 glBindRenderbuffer(GL_RENDERBUFFER, 0);
2068 }
2069#endif
2070
2071 return id;
2072}
2073
2074// Load texture cubemap
2075// NOTE: Cubemap data is expected to be 6 images in a single column,
2076// expected the following convention: +X, -X, +Y, -Y, +Z, -Z
2077unsigned int rlLoadTextureCubemap(void *data, int size, int format)
2078{
2079 unsigned int cubemapId = 0;
2080
2081#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2082 unsigned int dataSize = GetPixelDataSize(size, size, format);
2083
2084 glGenTextures(1, &cubemapId);
2085 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId);
2086
2087 unsigned int glInternalFormat, glFormat, glType;
2088 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
2089
2090 if (glInternalFormat != -1)
2091 {
2092 // Load cubemap faces
2093 for (unsigned int i = 0; i < 6; i++)
2094 {
2095 if (format < COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, (unsigned char *)data + i*dataSize);
2096 else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, dataSize, (unsigned char *)data + i*dataSize);
2097
2098#if defined(GRAPHICS_API_OPENGL_33)
2099 if (format == UNCOMPRESSED_GRAYSCALE)
2100 {
2101 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
2102 glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2103 }
2104 else if (format == UNCOMPRESSED_GRAY_ALPHA)
2105 {
2106#if defined(GRAPHICS_API_OPENGL_21)
2107 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA };
2108#elif defined(GRAPHICS_API_OPENGL_33)
2109 GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
2110#endif
2111 glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
2112 }
2113#endif
2114 }
2115 }
2116
2117 // Set cubemap texture sampling parameters
2118 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2119 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2120 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2121 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2122#if defined(GRAPHICS_API_OPENGL_33)
2123 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0
2124#endif
2125
2126 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
2127#endif
2128
2129 return cubemapId;
2130}
2131
2132// Update already loaded texture in GPU with new data
2133// NOTE: We don't know safely if internal texture format is the expected one...
2134void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data)
2135{
2136 glBindTexture(GL_TEXTURE_2D, id);
2137
2138 unsigned int glInternalFormat, glFormat, glType;
2139 rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
2140
2141 if ((glInternalFormat != -1) && (format < COMPRESSED_DXT1_RGB))
2142 {
2143 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, glFormat, glType, (unsigned char *)data);
2144 }
2145 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format);
2146}
2147
2148// Get OpenGL internal formats and data type from raylib PixelFormat
2149void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType)
2150{
2151 *glInternalFormat = -1;
2152 *glFormat = -1;
2153 *glType = -1;
2154
2155 switch (format)
2156 {
2157 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
2158 // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
2159 case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break;
2160 case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break;
2161 case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
2162 case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
2163 case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
2164 case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
2165 case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
2166 #if !defined(GRAPHICS_API_OPENGL_11)
2167 case UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2168 case UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2169 case UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float
2170 #endif
2171 #elif defined(GRAPHICS_API_OPENGL_33)
2172 case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break;
2173 case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break;
2174 case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break;
2175 case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break;
2176 case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break;
2177 case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break;
2178 case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break;
2179 case UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break;
2180 case UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break;
2181 case UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break;
2182 #endif
2183 #if !defined(GRAPHICS_API_OPENGL_11)
2184 case COMPRESSED_DXT1_RGB: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
2185 case COMPRESSED_DXT1_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
2186 case COMPRESSED_DXT3_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
2187 case COMPRESSED_DXT5_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
2188 case COMPRESSED_ETC1_RGB: if (RLGL.ExtSupported.texCompETC1) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
2189 case COMPRESSED_ETC2_RGB: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
2190 case 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
2191 case COMPRESSED_PVRT_RGB: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
2192 case COMPRESSED_PVRT_RGBA: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU
2193 case 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
2194 case 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
2195 #endif
2196 default: TRACELOG(LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break;
2197 }
2198}
2199
2200// Unload texture from GPU memory
2201void rlUnloadTexture(unsigned int id)
2202{
2203 if (id > 0) glDeleteTextures(1, &id);
2204}
2205
2206// Load a texture to be used for rendering (fbo with default color and depth attachments)
2207// NOTE: If colorFormat or depthBits are no supported, no attachment is done
2208RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depthBits, bool useDepthTexture)
2209{
2210 RenderTexture2D target = { 0 };
2211
2212#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2213 if (useDepthTexture && RLGL.ExtSupported.texDepth) target.depthTexture = true;
2214
2215 // Create the framebuffer object
2216 glGenFramebuffers(1, &target.id);
2217 glBindFramebuffer(GL_FRAMEBUFFER, target.id);
2218
2219 // Create fbo color texture attachment
2220 //-----------------------------------------------------------------------------------------------------
2221 if ((format != -1) && (format < COMPRESSED_DXT1_RGB))
2222 {
2223 // WARNING: Some texture formats are not supported for fbo color attachment
2224 target.texture.id = rlLoadTexture(NULL, width, height, format, 1);
2225 target.texture.width = width;
2226 target.texture.height = height;
2227 target.texture.format = format;
2228 target.texture.mipmaps = 1;
2229 }
2230 //-----------------------------------------------------------------------------------------------------
2231
2232 // Create fbo depth renderbuffer/texture
2233 //-----------------------------------------------------------------------------------------------------
2234 if (depthBits > 0)
2235 {
2236 target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture);
2237 target.depth.width = width;
2238 target.depth.height = height;
2239 target.depth.format = 19; //DEPTH_COMPONENT_24BIT?
2240 target.depth.mipmaps = 1;
2241 }
2242 //-----------------------------------------------------------------------------------------------------
2243
2244 // Attach color texture and depth renderbuffer to FBO
2245 //-----------------------------------------------------------------------------------------------------
2246 rlRenderTextureAttach(target, target.texture.id, 0); // COLOR attachment
2247 rlRenderTextureAttach(target, target.depth.id, 1); // DEPTH attachment
2248 //-----------------------------------------------------------------------------------------------------
2249
2250 // Check if fbo is complete with attachments (valid)
2251 //-----------------------------------------------------------------------------------------------------
2252 if (rlRenderTextureComplete(target)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
2253 //-----------------------------------------------------------------------------------------------------
2254
2255 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2256#endif
2257
2258 return target;
2259}
2260
2261// Attach color buffer texture to an fbo (unloads previous attachment)
2262// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture
2263void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachType)
2264{
2265#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2266 glBindFramebuffer(GL_FRAMEBUFFER, target.id);
2267
2268 if (attachType == 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0);
2269 else if (attachType == 1)
2270 {
2271 if (target.depthTexture) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, id, 0);
2272 else glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, id);
2273 }
2274
2275 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2276#endif
2277}
2278
2279// Verify render texture is complete
2280bool rlRenderTextureComplete(RenderTexture target)
2281{
2282 bool result = false;
2283
2284#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2285 glBindFramebuffer(GL_FRAMEBUFFER, target.id);
2286
2287 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
2288
2289 if (status != GL_FRAMEBUFFER_COMPLETE)
2290 {
2291 switch (status)
2292 {
2293 case GL_FRAMEBUFFER_UNSUPPORTED: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer is unsupported", target.id); break;
2294 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete attachment", target.id); break;
2295#if defined(GRAPHICS_API_OPENGL_ES2)
2296 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete dimensions", target.id); break;
2297#endif
2298 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TRACELOG(LOG_WARNING, "FBO: [ID %i] Framebuffer has a missing attachment", target.id); break;
2299 default: break;
2300 }
2301 }
2302
2303 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2304
2305 result = (status == GL_FRAMEBUFFER_COMPLETE);
2306#endif
2307
2308 return result;
2309}
2310
2311// Generate mipmap data for selected texture
2312void rlGenerateMipmaps(Texture2D *texture)
2313{
2314 glBindTexture(GL_TEXTURE_2D, texture->id);
2315
2316 // Check if texture is power-of-two (POT)
2317 bool texIsPOT = false;
2318
2319 if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) &&
2320 ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true;
2321
2322#if defined(GRAPHICS_API_OPENGL_11)
2323 if (texIsPOT)
2324 {
2325 // WARNING: Manual mipmap generation only works for RGBA 32bit textures!
2326 if (texture->format == UNCOMPRESSED_R8G8B8A8)
2327 {
2328 // Retrieve texture data from VRAM
2329 void *data = rlReadTexturePixels(*texture);
2330
2331 // NOTE: data size is reallocated to fit mipmaps data
2332 // NOTE: CPU mipmap generation only supports RGBA 32bit data
2333 int mipmapCount = GenerateMipmaps(data, texture->width, texture->height);
2334
2335 int size = texture->width*texture->height*4;
2336 int offset = size;
2337
2338 int mipWidth = texture->width/2;
2339 int mipHeight = texture->height/2;
2340
2341 // Load the mipmaps
2342 for (int level = 1; level < mipmapCount; level++)
2343 {
2344 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data + offset);
2345
2346 size = mipWidth*mipHeight*4;
2347 offset += size;
2348
2349 mipWidth /= 2;
2350 mipHeight /= 2;
2351 }
2352
2353 texture->mipmaps = mipmapCount + 1;
2354 RL_FREE(data); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
2355
2356 TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Mipmaps generated manually on CPU side, total: %i", texture->id, texture->mipmaps);
2357 }
2358 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps for provided texture format", texture->id);
2359 }
2360#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2361 if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
2362 {
2363 //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
2364 glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
2365
2366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps
2368
2369 #define MIN(a,b) (((a)<(b))?(a):(b))
2370 #define MAX(a,b) (((a)>(b))?(a):(b))
2371
2372 texture->mipmaps = 1 + (int)floor(log(MAX(texture->width, texture->height))/log(2));
2373 TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", texture->id, texture->mipmaps);
2374 }
2375#endif
2376 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", texture->id);
2377
2378 glBindTexture(GL_TEXTURE_2D, 0);
2379}
2380
2381// Upload vertex data into a VAO (if supported) and VBO
2382void rlLoadMesh(Mesh *mesh, bool dynamic)
2383{
2384 if (mesh->vaoId > 0)
2385 {
2386 // Check if mesh has already been loaded in GPU
2387 TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
2388 return;
2389 }
2390
2391 mesh->vaoId = 0; // Vertex Array Object
2392 mesh->vboId[0] = 0; // Vertex positions VBO
2393 mesh->vboId[1] = 0; // Vertex texcoords VBO
2394 mesh->vboId[2] = 0; // Vertex normals VBO
2395 mesh->vboId[3] = 0; // Vertex colors VBO
2396 mesh->vboId[4] = 0; // Vertex tangents VBO
2397 mesh->vboId[5] = 0; // Vertex texcoords2 VBO
2398 mesh->vboId[6] = 0; // Vertex indices VBO
2399
2400#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2401 int drawHint = GL_STATIC_DRAW;
2402 if (dynamic) drawHint = GL_DYNAMIC_DRAW;
2403
2404 if (RLGL.ExtSupported.vao)
2405 {
2406 // Initialize Quads VAO (Buffer A)
2407 glGenVertexArrays(1, &mesh->vaoId);
2408 glBindVertexArray(mesh->vaoId);
2409 }
2410
2411 // NOTE: Attributes must be uploaded considering default locations points
2412
2413 // Enable vertex attributes: position (shader-location = 0)
2414 glGenBuffers(1, &mesh->vboId[0]);
2415 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[0]);
2416 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint);
2417 glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
2418 glEnableVertexAttribArray(0);
2419
2420 // Enable vertex attributes: texcoords (shader-location = 1)
2421 glGenBuffers(1, &mesh->vboId[1]);
2422 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[1]);
2423 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint);
2424 glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
2425 glEnableVertexAttribArray(1);
2426
2427 // Enable vertex attributes: normals (shader-location = 2)
2428 if (mesh->normals != NULL)
2429 {
2430 glGenBuffers(1, &mesh->vboId[2]);
2431 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[2]);
2432 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint);
2433 glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
2434 glEnableVertexAttribArray(2);
2435 }
2436 else
2437 {
2438 // Default color vertex attribute set to WHITE
2439 glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f);
2440 glDisableVertexAttribArray(2);
2441 }
2442
2443 // Default color vertex attribute (shader-location = 3)
2444 if (mesh->colors != NULL)
2445 {
2446 glGenBuffers(1, &mesh->vboId[3]);
2447 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[3]);
2448 glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint);
2449 glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
2450 glEnableVertexAttribArray(3);
2451 }
2452 else
2453 {
2454 // Default color vertex attribute set to WHITE
2455 glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f);
2456 glDisableVertexAttribArray(3);
2457 }
2458
2459 // Default tangent vertex attribute (shader-location = 4)
2460 if (mesh->tangents != NULL)
2461 {
2462 glGenBuffers(1, &mesh->vboId[4]);
2463 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[4]);
2464 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh->vertexCount, mesh->tangents, drawHint);
2465 glVertexAttribPointer(4, 4, GL_FLOAT, 0, 0, 0);
2466 glEnableVertexAttribArray(4);
2467 }
2468 else
2469 {
2470 // Default tangents vertex attribute
2471 glVertexAttrib4f(4, 0.0f, 0.0f, 0.0f, 0.0f);
2472 glDisableVertexAttribArray(4);
2473 }
2474
2475 // Default texcoord2 vertex attribute (shader-location = 5)
2476 if (mesh->texcoords2 != NULL)
2477 {
2478 glGenBuffers(1, &mesh->vboId[5]);
2479 glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[5]);
2480 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint);
2481 glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
2482 glEnableVertexAttribArray(5);
2483 }
2484 else
2485 {
2486 // Default texcoord2 vertex attribute
2487 glVertexAttrib2f(5, 0.0f, 0.0f);
2488 glDisableVertexAttribArray(5);
2489 }
2490
2491 if (mesh->indices != NULL)
2492 {
2493 glGenBuffers(1, &mesh->vboId[6]);
2494 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vboId[6]);
2495 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*mesh->triangleCount*3, mesh->indices, drawHint);
2496 }
2497
2498 if (RLGL.ExtSupported.vao)
2499 {
2500 if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
2501 else TRACELOG(LOG_WARNING, "VAO: Failed to load mesh to VRAM (GPU)");
2502 }
2503 else
2504 {
2505 TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
2506 }
2507#endif
2508}
2509
2510// Load a new attributes buffer
2511unsigned int rlLoadAttribBuffer(unsigned int vaoId, int shaderLoc, void *buffer, int size, bool dynamic)
2512{
2513 unsigned int id = 0;
2514
2515#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2516 int drawHint = GL_STATIC_DRAW;
2517 if (dynamic) drawHint = GL_DYNAMIC_DRAW;
2518
2519 if (RLGL.ExtSupported.vao) glBindVertexArray(vaoId);
2520
2521 glGenBuffers(1, &id);
2522 glBindBuffer(GL_ARRAY_BUFFER, id);
2523 glBufferData(GL_ARRAY_BUFFER, size, buffer, drawHint);
2524 glVertexAttribPointer(shaderLoc, 2, GL_FLOAT, 0, 0, 0);
2525 glEnableVertexAttribArray(shaderLoc);
2526
2527 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2528#endif
2529
2530 return id;
2531}
2532
2533// Update vertex or index data on GPU (upload new data to one buffer)
2534void rlUpdateMesh(Mesh mesh, int buffer, int num)
2535{
2536 rlUpdateMeshAt(mesh, buffer, num, 0);
2537}
2538
2539// Update vertex or index data on GPU, at index
2540// WARNING: error checking is in place that will cause the data to not be
2541// updated if offset + size exceeds what the buffer can hold
2542void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index)
2543{
2544#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2545 // Activate mesh VAO
2546 if (RLGL.ExtSupported.vao) glBindVertexArray(mesh.vaoId);
2547
2548 switch (buffer)
2549 {
2550 case 0: // Update vertices (vertex position)
2551 {
2552 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
2553 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*num, mesh.vertices, GL_DYNAMIC_DRAW);
2554 else if (index + num >= mesh.vertexCount) break;
2555 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.vertices);
2556
2557 } break;
2558 case 1: // Update texcoords (vertex texture coordinates)
2559 {
2560 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
2561 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*num, mesh.texcoords, GL_DYNAMIC_DRAW);
2562 else if (index + num >= mesh.vertexCount) break;
2563 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords);
2564
2565 } break;
2566 case 2: // Update normals (vertex normals)
2567 {
2568 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
2569 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*num, mesh.normals, GL_DYNAMIC_DRAW);
2570 else if (index + num >= mesh.vertexCount) break;
2571 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.normals);
2572
2573 } break;
2574 case 3: // Update colors (vertex colors)
2575 {
2576 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
2577 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*num, mesh.colors, GL_DYNAMIC_DRAW);
2578 else if (index + num >= mesh.vertexCount) break;
2579 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*index, sizeof(unsigned char)*4*num, mesh.colors);
2580
2581 } break;
2582 case 4: // Update tangents (vertex tangents)
2583 {
2584 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
2585 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*num, mesh.tangents, GL_DYNAMIC_DRAW);
2586 else if (index + num >= mesh.vertexCount) break;
2587 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*4*index, sizeof(float)*4*num, mesh.tangents);
2588 } break;
2589 case 5: // Update texcoords2 (vertex second texture coordinates)
2590 {
2591 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
2592 if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*num, mesh.texcoords2, GL_DYNAMIC_DRAW);
2593 else if (index + num >= mesh.vertexCount) break;
2594 else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords2);
2595 } break;
2596 case 6: // Update indices (triangle index buffer)
2597 {
2598 // the * 3 is because each triangle has 3 indices
2599 unsigned short *indices = mesh.indices;
2600 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vboId[6]);
2601 if (index == 0 && num >= mesh.triangleCount)
2602 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*indices)*num*3, indices, GL_DYNAMIC_DRAW);
2603 else if (index + num >= mesh.triangleCount)
2604 break;
2605 else
2606 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*indices)*index*3, sizeof(*indices)*num*3, indices);
2607 } break;
2608 default: break;
2609 }
2610
2611 // Unbind the current VAO
2612 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2613
2614 // Another option would be using buffer mapping...
2615 //mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
2616 // Now we can modify vertices
2617 //glUnmapBuffer(GL_ARRAY_BUFFER);
2618#endif
2619}
2620
2621// Draw a 3d mesh with material and transform
2622void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
2623{
2624#if defined(GRAPHICS_API_OPENGL_11)
2625 glEnable(GL_TEXTURE_2D);
2626 glBindTexture(GL_TEXTURE_2D, material.maps[MAP_DIFFUSE].texture.id);
2627
2628 // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
2629 glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
2630 glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
2631 if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
2632 if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY); // Enable colors array
2633
2634 glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array
2635 glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array
2636 if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array
2637 if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array
2638
2639 rlPushMatrix();
2640 rlMultMatrixf(MatrixToFloat(transform));
2641 rlColor4ub(material.maps[MAP_DIFFUSE].color.r, material.maps[MAP_DIFFUSE].color.g, material.maps[MAP_DIFFUSE].color.b, material.maps[MAP_DIFFUSE].color.a);
2642
2643 if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
2644 else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
2645 rlPopMatrix();
2646
2647 glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
2648 glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
2649 if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
2650 if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable colors array
2651
2652 glDisable(GL_TEXTURE_2D);
2653 glBindTexture(GL_TEXTURE_2D, 0);
2654#endif
2655
2656#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2657 // Bind shader program
2658 glUseProgram(material.shader.id);
2659
2660 // Matrices and other values required by shader
2661 //-----------------------------------------------------
2662 // Calculate and send to shader model matrix (used by PBR shader)
2663 if (material.shader.locs[LOC_MATRIX_MODEL] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_MODEL], transform);
2664
2665 // Upload to shader material.colDiffuse
2666 if (material.shader.locs[LOC_COLOR_DIFFUSE] != -1)
2667 glUniform4f(material.shader.locs[LOC_COLOR_DIFFUSE], (float)material.maps[MAP_DIFFUSE].color.r/255.0f,
2668 (float)material.maps[MAP_DIFFUSE].color.g/255.0f,
2669 (float)material.maps[MAP_DIFFUSE].color.b/255.0f,
2670 (float)material.maps[MAP_DIFFUSE].color.a/255.0f);
2671
2672 // Upload to shader material.colSpecular (if available)
2673 if (material.shader.locs[LOC_COLOR_SPECULAR] != -1)
2674 glUniform4f(material.shader.locs[LOC_COLOR_SPECULAR], (float)material.maps[MAP_SPECULAR].color.r/255.0f,
2675 (float)material.maps[MAP_SPECULAR].color.g/255.0f,
2676 (float)material.maps[MAP_SPECULAR].color.b/255.0f,
2677 (float)material.maps[MAP_SPECULAR].color.a/255.0f);
2678
2679 if (material.shader.locs[LOC_MATRIX_VIEW] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_VIEW], RLGL.State.modelview);
2680 if (material.shader.locs[LOC_MATRIX_PROJECTION] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_PROJECTION], RLGL.State.projection);
2681
2682 // At this point the modelview matrix just contains the view matrix (camera)
2683 // That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
2684 Matrix matView = RLGL.State.modelview; // View matrix (camera)
2685 Matrix matProjection = RLGL.State.projection; // Projection matrix (perspective)
2686
2687 // TODO: Consider possible transform matrices in the RLGL.State.stack
2688 // Is this the right order? or should we start with the first stored matrix instead of the last one?
2689 //Matrix matStackTransform = MatrixIdentity();
2690 //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = MatrixMultiply(RLGL.State.stack[i], matStackTransform);
2691
2692 // Transform to camera-space coordinates
2693 Matrix matModelView = MatrixMultiply(transform, MatrixMultiply(RLGL.State.transform, matView));
2694 //-----------------------------------------------------
2695
2696 // Bind active texture maps (if available)
2697 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
2698 {
2699 if (material.maps[i].texture.id > 0)
2700 {
2701 glActiveTexture(GL_TEXTURE0 + i);
2702 if ((i == MAP_IRRADIANCE) || (i == MAP_PREFILTER) || (i == MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, material.maps[i].texture.id);
2703 else glBindTexture(GL_TEXTURE_2D, material.maps[i].texture.id);
2704
2705 glUniform1i(material.shader.locs[LOC_MAP_DIFFUSE + i], i);
2706 }
2707 }
2708
2709 // Bind vertex array objects (or VBOs)
2710 if (RLGL.ExtSupported.vao) glBindVertexArray(mesh.vaoId);
2711 else
2712 {
2713 // Bind mesh VBO data: vertex position (shader-location = 0)
2714 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
2715 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
2716 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_POSITION]);
2717
2718 // Bind mesh VBO data: vertex texcoords (shader-location = 1)
2719 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
2720 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
2721 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TEXCOORD01]);
2722
2723 // Bind mesh VBO data: vertex normals (shader-location = 2, if available)
2724 if (material.shader.locs[LOC_VERTEX_NORMAL] != -1)
2725 {
2726 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
2727 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0);
2728 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_NORMAL]);
2729 }
2730
2731 // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
2732 if (material.shader.locs[LOC_VERTEX_COLOR] != -1)
2733 {
2734 if (mesh.vboId[3] != 0)
2735 {
2736 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
2737 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
2738 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_COLOR]);
2739 }
2740 else
2741 {
2742 // Set default value for unused attribute
2743 // NOTE: Required when using default shader and no VAO support
2744 glVertexAttrib4f(material.shader.locs[LOC_VERTEX_COLOR], 1.0f, 1.0f, 1.0f, 1.0f);
2745 glDisableVertexAttribArray(material.shader.locs[LOC_VERTEX_COLOR]);
2746 }
2747 }
2748
2749 // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
2750 if (material.shader.locs[LOC_VERTEX_TANGENT] != -1)
2751 {
2752 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
2753 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TANGENT], 4, GL_FLOAT, 0, 0, 0);
2754 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TANGENT]);
2755 }
2756
2757 // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
2758 if (material.shader.locs[LOC_VERTEX_TEXCOORD02] != -1)
2759 {
2760 glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
2761 glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TEXCOORD02], 2, GL_FLOAT, 0, 0, 0);
2762 glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TEXCOORD02]);
2763 }
2764
2765 if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vboId[6]);
2766 }
2767
2768 int eyesCount = 1;
2769#if defined(SUPPORT_VR_SIMULATOR)
2770 if (RLGL.Vr.stereoRender) eyesCount = 2;
2771#endif
2772
2773 for (int eye = 0; eye < eyesCount; eye++)
2774 {
2775 if (eyesCount == 1) RLGL.State.modelview = matModelView;
2776 #if defined(SUPPORT_VR_SIMULATOR)
2777 else SetStereoView(eye, matProjection, matModelView);
2778 #endif
2779
2780 // Calculate model-view-projection matrix (MVP)
2781 Matrix matMVP = MatrixMultiply(RLGL.State.modelview, RLGL.State.projection); // Transform to screen-space coordinates
2782
2783 // Send combined model-view-projection matrix to shader
2784 glUniformMatrix4fv(material.shader.locs[LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP));
2785
2786 // Draw call!
2787 if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
2788 else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
2789 }
2790
2791 // Unbind all binded texture maps
2792 for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
2793 {
2794 glActiveTexture(GL_TEXTURE0 + i); // Set shader active texture
2795 if ((i == MAP_IRRADIANCE) || (i == MAP_PREFILTER) || (i == MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
2796 else glBindTexture(GL_TEXTURE_2D, 0); // Unbind current active texture
2797 }
2798
2799 // Unind vertex array objects (or VBOs)
2800 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
2801 else
2802 {
2803 glBindBuffer(GL_ARRAY_BUFFER, 0);
2804 if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2805 }
2806
2807 // Unbind shader program
2808 glUseProgram(0);
2809
2810 // Restore RLGL.State.projection/RLGL.State.modelview matrices
2811 // NOTE: In stereo rendering matrices are being modified to fit every eye
2812 RLGL.State.projection = matProjection;
2813 RLGL.State.modelview = matView;
2814#endif
2815}
2816
2817// Unload mesh data from CPU and GPU
2818void rlUnloadMesh(Mesh mesh)
2819{
2820 RL_FREE(mesh.vertices);
2821 RL_FREE(mesh.texcoords);
2822 RL_FREE(mesh.normals);
2823 RL_FREE(mesh.colors);
2824 RL_FREE(mesh.tangents);
2825 RL_FREE(mesh.texcoords2);
2826 RL_FREE(mesh.indices);
2827
2828 RL_FREE(mesh.animVertices);
2829 RL_FREE(mesh.animNormals);
2830 RL_FREE(mesh.boneWeights);
2831 RL_FREE(mesh.boneIds);
2832
2833 rlDeleteBuffers(mesh.vboId[0]); // vertex
2834 rlDeleteBuffers(mesh.vboId[1]); // texcoords
2835 rlDeleteBuffers(mesh.vboId[2]); // normals
2836 rlDeleteBuffers(mesh.vboId[3]); // colors
2837 rlDeleteBuffers(mesh.vboId[4]); // tangents
2838 rlDeleteBuffers(mesh.vboId[5]); // texcoords2
2839 rlDeleteBuffers(mesh.vboId[6]); // indices
2840
2841 rlDeleteVertexArrays(mesh.vaoId);
2842}
2843
2844// Read screen pixel data (color buffer)
2845unsigned char *rlReadScreenPixels(int width, int height)
2846{
2847 unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
2848
2849 // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
2850 // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly!
2851 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
2852
2853 // Flip image vertically!
2854 unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*sizeof(unsigned char)*4);
2855
2856 for (int y = height - 1; y >= 0; y--)
2857 {
2858 for (int x = 0; x < (width*4); x++)
2859 {
2860 imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line
2861
2862 // Set alpha component value to 255 (no trasparent image retrieval)
2863 // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
2864 if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255;
2865 }
2866 }
2867
2868 RL_FREE(screenData);
2869
2870 return imgData; // NOTE: image data should be freed
2871}
2872
2873// Read texture pixel data
2874void *rlReadTexturePixels(Texture2D texture)
2875{
2876 void *pixels = NULL;
2877
2878#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2879 glBindTexture(GL_TEXTURE_2D, texture.id);
2880
2881 // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0)
2882 // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
2883 //int width, height, format;
2884 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
2885 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
2886 //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
2887
2888 // 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.
2889 // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
2890 // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
2891 // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
2892 glPixelStorei(GL_PACK_ALIGNMENT, 1);
2893
2894 unsigned int glInternalFormat, glFormat, glType;
2895 rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType);
2896 unsigned int size = GetPixelDataSize(texture.width, texture.height, texture.format);
2897
2898 if ((glInternalFormat != -1) && (texture.format < COMPRESSED_DXT1_RGB))
2899 {
2900 pixels = (unsigned char *)RL_MALLOC(size);
2901 glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels);
2902 }
2903 else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", texture.id, texture.format);
2904
2905 glBindTexture(GL_TEXTURE_2D, 0);
2906#endif
2907
2908#if defined(GRAPHICS_API_OPENGL_ES2)
2909 // glGetTexImage() is not available on OpenGL ES 2.0
2910 // Texture2D width and height are required on OpenGL ES 2.0. There is no way to get it from texture id.
2911 // Two possible Options:
2912 // 1 - Bind texture to color fbo attachment and glReadPixels()
2913 // 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
2914 // We are using Option 1, just need to care for texture format on retrieval
2915 // NOTE: This behaviour could be conditioned by graphic driver...
2916 RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height, UNCOMPRESSED_R8G8B8A8, 16, false);
2917
2918 glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
2919 glBindTexture(GL_TEXTURE_2D, 0);
2920
2921 // Attach our texture to FBO
2922 // NOTE: Previoust attached texture is automatically detached
2923 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0);
2924
2925 // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format
2926 pixels = (unsigned char *)RL_MALLOC(GetPixelDataSize(texture.width, texture.height, UNCOMPRESSED_R8G8B8A8));
2927 glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
2928
2929 // Re-attach internal FBO color texture before deleting it
2930 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.texture.id, 0);
2931
2932 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2933
2934 // Clean up temporal fbo
2935 rlDeleteRenderTextures(fbo);
2936#endif
2937
2938 return pixels;
2939}
2940
2941//----------------------------------------------------------------------------------
2942// Module Functions Definition - Shaders Functions
2943// NOTE: Those functions are exposed directly to the user in raylib.h
2944//----------------------------------------------------------------------------------
2945
2946// Get default internal texture (white texture)
2947Texture2D GetTextureDefault(void)
2948{
2949 Texture2D texture = { 0 };
2950#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2951 texture.id = RLGL.State.defaultTextureId;
2952 texture.width = 1;
2953 texture.height = 1;
2954 texture.mipmaps = 1;
2955 texture.format = UNCOMPRESSED_R8G8B8A8;
2956#endif
2957 return texture;
2958}
2959
2960// Get texture to draw shapes (RAII)
2961Texture2D GetShapesTexture(void)
2962{
2963 return RLGL.State.shapesTexture;
2964}
2965
2966// Get texture rectangle to draw shapes
2967Rectangle GetShapesTextureRec(void)
2968{
2969 return RLGL.State.shapesTextureRec;
2970}
2971
2972// Define default texture used to draw shapes
2973void SetShapesTexture(Texture2D texture, Rectangle source)
2974{
2975 RLGL.State.shapesTexture = texture;
2976 RLGL.State.shapesTextureRec = source;
2977}
2978
2979// Get default shader
2980Shader GetShaderDefault(void)
2981{
2982#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2983 return RLGL.State.defaultShader;
2984#else
2985 Shader shader = { 0 };
2986 return shader;
2987#endif
2988}
2989
2990// Load shader from files and bind default locations
2991// NOTE: If shader string is NULL, using default vertex/fragment shaders
2992Shader LoadShader(const char *vsFileName, const char *fsFileName)
2993{
2994 Shader shader = { 0 };
2995
2996 // NOTE: Shader.locs is allocated by LoadShaderCode()
2997
2998 char *vShaderStr = NULL;
2999 char *fShaderStr = NULL;
3000
3001 if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
3002 if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
3003
3004 shader = LoadShaderCode(vShaderStr, fShaderStr);
3005
3006 if (vShaderStr != NULL) RL_FREE(vShaderStr);
3007 if (fShaderStr != NULL) RL_FREE(fShaderStr);
3008
3009 return shader;
3010}
3011
3012// Load shader from code strings
3013// NOTE: If shader string is NULL, using default vertex/fragment shaders
3014Shader LoadShaderCode(const char *vsCode, const char *fsCode)
3015{
3016 Shader shader = { 0 };
3017 shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));
3018
3019 // NOTE: All locations must be reseted to -1 (no location)
3020 for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
3021
3022#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3023 unsigned int vertexShaderId = RLGL.State.defaultVShaderId;
3024 unsigned int fragmentShaderId = RLGL.State.defaultFShaderId;
3025
3026 if (vsCode != NULL) vertexShaderId = CompileShader(vsCode, GL_VERTEX_SHADER);
3027 if (fsCode != NULL) fragmentShaderId = CompileShader(fsCode, GL_FRAGMENT_SHADER);
3028
3029 if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) shader = RLGL.State.defaultShader;
3030 else
3031 {
3032 shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId);
3033
3034 if (vertexShaderId != RLGL.State.defaultVShaderId) glDeleteShader(vertexShaderId);
3035 if (fragmentShaderId != RLGL.State.defaultFShaderId) glDeleteShader(fragmentShaderId);
3036
3037 if (shader.id == 0)
3038 {
3039 TRACELOG(LOG_WARNING, "SHADER: Failed to load custom shader code");
3040 shader = RLGL.State.defaultShader;
3041 }
3042
3043 // After shader loading, we TRY to set default location names
3044 if (shader.id > 0) SetShaderDefaultLocations(&shader);
3045 }
3046
3047 // Get available shader uniforms
3048 // NOTE: This information is useful for debug...
3049 int uniformCount = -1;
3050
3051 glGetProgramiv(shader.id, GL_ACTIVE_UNIFORMS, &uniformCount);
3052
3053 for (int i = 0; i < uniformCount; i++)
3054 {
3055 int namelen = -1;
3056 int num = -1;
3057 char name[256]; // Assume no variable names longer than 256
3058 GLenum type = GL_ZERO;
3059
3060 // Get the name of the uniforms
3061 glGetActiveUniform(shader.id, i,sizeof(name) - 1, &namelen, &num, &type, name);
3062
3063 name[namelen] = 0;
3064
3065 TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", shader.id, name, glGetUniformLocation(shader.id, name));
3066 }
3067#endif
3068
3069 return shader;
3070}
3071
3072// Unload shader from GPU memory (VRAM)
3073void UnloadShader(Shader shader)
3074{
3075 if (shader.id > 0)
3076 {
3077 rlDeleteShader(shader.id);
3078 TRACELOG(LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", shader.id);
3079 }
3080
3081 RL_FREE(shader.locs);
3082}
3083
3084// Begin custom shader mode
3085void BeginShaderMode(Shader shader)
3086{
3087#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3088 if (RLGL.State.currentShader.id != shader.id)
3089 {
3090 rlglDraw();
3091 RLGL.State.currentShader = shader;
3092 }
3093#endif
3094}
3095
3096// End custom shader mode (returns to default shader)
3097void EndShaderMode(void)
3098{
3099#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3100 BeginShaderMode(RLGL.State.defaultShader);
3101#endif
3102}
3103
3104// Get shader uniform location
3105int GetShaderLocation(Shader shader, const char *uniformName)
3106{
3107 int location = -1;
3108#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3109 location = glGetUniformLocation(shader.id, uniformName);
3110
3111 if (location == -1) TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shader.id, uniformName);
3112 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shader.id, uniformName, location);
3113#endif
3114 return location;
3115}
3116
3117// Set shader uniform value
3118void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType)
3119{
3120 SetShaderValueV(shader, uniformLoc, value, uniformType, 1);
3121}
3122
3123// Set shader uniform value vector
3124void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count)
3125{
3126#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3127 glUseProgram(shader.id);
3128
3129 switch (uniformType)
3130 {
3131 case UNIFORM_FLOAT: glUniform1fv(uniformLoc, count, (float *)value); break;
3132 case UNIFORM_VEC2: glUniform2fv(uniformLoc, count, (float *)value); break;
3133 case UNIFORM_VEC3: glUniform3fv(uniformLoc, count, (float *)value); break;
3134 case UNIFORM_VEC4: glUniform4fv(uniformLoc, count, (float *)value); break;
3135 case UNIFORM_INT: glUniform1iv(uniformLoc, count, (int *)value); break;
3136 case UNIFORM_IVEC2: glUniform2iv(uniformLoc, count, (int *)value); break;
3137 case UNIFORM_IVEC3: glUniform3iv(uniformLoc, count, (int *)value); break;
3138 case UNIFORM_IVEC4: glUniform4iv(uniformLoc, count, (int *)value); break;
3139 case UNIFORM_SAMPLER2D: glUniform1iv(uniformLoc, count, (int *)value); break;
3140 default: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to set uniform, data type not recognized", shader.id);
3141 }
3142
3143 //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set
3144#endif
3145}
3146
3147
3148// Set shader uniform value (matrix 4x4)
3149void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat)
3150{
3151#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3152 glUseProgram(shader.id);
3153
3154 glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat));
3155
3156 //glUseProgram(0);
3157#endif
3158}
3159
3160// Set shader uniform value for texture
3161void SetShaderValueTexture(Shader shader, int uniformLoc, Texture2D texture)
3162{
3163#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3164 glUseProgram(shader.id);
3165
3166 glUniform1i(uniformLoc, texture.id);
3167
3168 //glUseProgram(0);
3169#endif
3170}
3171
3172// Set a custom projection matrix (replaces internal projection matrix)
3173void SetMatrixProjection(Matrix projection)
3174{
3175#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3176 RLGL.State.projection = projection;
3177#endif
3178}
3179
3180// Return internal projection matrix
3181Matrix GetMatrixProjection(void) {
3182#if defined(GRAPHICS_API_OPENGL_11)
3183 float mat[16];
3184 glGetFloatv(GL_PROJECTION_MATRIX,mat);
3185 Matrix m;
3186 m.m0 = mat[0]; m.m1 = mat[1]; m.m2 = mat[2]; m.m3 = mat[3];
3187 m.m4 = mat[4]; m.m5 = mat[5]; m.m6 = mat[6]; m.m7 = mat[7];
3188 m.m8 = mat[8]; m.m9 = mat[9]; m.m10 = mat[10]; m.m11 = mat[11];
3189 m.m12 = mat[12]; m.m13 = mat[13]; m.m14 = mat[14]; m.m15 = mat[15];
3190 return m;
3191#else
3192 return RLGL.State.projection;
3193#endif
3194#
3195}
3196
3197// Set a custom modelview matrix (replaces internal modelview matrix)
3198void SetMatrixModelview(Matrix view)
3199{
3200#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3201 RLGL.State.modelview = view;
3202#endif
3203}
3204
3205// Return internal modelview matrix
3206Matrix GetMatrixModelview(void)
3207{
3208 Matrix matrix = MatrixIdentity();
3209#if defined(GRAPHICS_API_OPENGL_11)
3210 float mat[16];
3211 glGetFloatv(GL_MODELVIEW_MATRIX, mat);
3212 matrix.m0 = mat[0]; matrix.m1 = mat[1]; matrix.m2 = mat[2]; matrix.m3 = mat[3];
3213 matrix.m4 = mat[4]; matrix.m5 = mat[5]; matrix.m6 = mat[6]; matrix.m7 = mat[7];
3214 matrix.m8 = mat[8]; matrix.m9 = mat[9]; matrix.m10 = mat[10]; matrix.m11 = mat[11];
3215 matrix.m12 = mat[12]; matrix.m13 = mat[13]; matrix.m14 = mat[14]; matrix.m15 = mat[15];
3216#else
3217 matrix = RLGL.State.modelview;
3218#endif
3219 return matrix;
3220}
3221
3222// Generate cubemap texture from HDR texture
3223// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
3224Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size)
3225{
3226 Texture2D cubemap = { 0 };
3227#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3228 // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
3229 // Other locations should be setup externally in shader before calling the function
3230
3231 // Set up depth face culling and cubemap seamless
3232 glDisable(GL_CULL_FACE);
3233#if defined(GRAPHICS_API_OPENGL_33)
3234 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Flag not supported on OpenGL ES 2.0
3235#endif
3236
3237 // Setup framebuffer
3238 unsigned int fbo, rbo;
3239 glGenFramebuffers(1, &fbo);
3240 glGenRenderbuffers(1, &rbo);
3241 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3242 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
3243#if defined(GRAPHICS_API_OPENGL_33)
3244 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
3245#elif defined(GRAPHICS_API_OPENGL_ES2)
3246 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
3247#endif
3248 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
3249
3250 // Set up cubemap to render and attach to framebuffer
3251 // NOTE: Faces are stored as 32 bit floating point values
3252 glGenTextures(1, &cubemap.id);
3253 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
3254 for (unsigned int i = 0; i < 6; i++)
3255 {
3256#if defined(GRAPHICS_API_OPENGL_33)
3257 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3258#elif defined(GRAPHICS_API_OPENGL_ES2)
3259 if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3260#endif
3261 }
3262
3263 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3264 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3265#if defined(GRAPHICS_API_OPENGL_33)
3266 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0
3267#endif
3268 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3269 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3270
3271 // Create projection and different views for each face
3272 Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_NEAR_CULL_DISTANCE, RL_FAR_CULL_DISTANCE);
3273 Matrix fboViews[6] = {
3274 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3275 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3276 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
3277 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
3278 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3279 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
3280 };
3281
3282 // Convert HDR equirectangular environment map to cubemap equivalent
3283 glUseProgram(shader.id);
3284 glActiveTexture(GL_TEXTURE0);
3285 glBindTexture(GL_TEXTURE_2D, map.id);
3286 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
3287
3288 // Note: don't forget to configure the viewport to the capture dimensions
3289 glViewport(0, 0, size, size);
3290 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3291
3292 for (int i = 0; i < 6; i++)
3293 {
3294 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
3295 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap.id, 0);
3296 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3297 GenDrawCube();
3298 }
3299
3300 // Unbind framebuffer and textures
3301 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3302
3303 // Reset viewport dimensions to default
3304 glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3305 //glEnable(GL_CULL_FACE);
3306
3307 // NOTE: Texture2D is a GL_TEXTURE_CUBE_MAP, not a GL_TEXTURE_2D!
3308 cubemap.width = size;
3309 cubemap.height = size;
3310 cubemap.mipmaps = 1;
3311 cubemap.format = UNCOMPRESSED_R32G32B32;
3312#endif
3313 return cubemap;
3314}
3315
3316// Generate irradiance texture using cubemap data
3317// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
3318Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
3319{
3320 Texture2D irradiance = { 0 };
3321
3322#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
3323 // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
3324 // Other locations should be setup externally in shader before calling the function
3325
3326 // Setup framebuffer
3327 unsigned int fbo, rbo;
3328 glGenFramebuffers(1, &fbo);
3329 glGenRenderbuffers(1, &rbo);
3330 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3331 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
3332 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
3333 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
3334
3335 // Create an irradiance cubemap, and re-scale capture FBO to irradiance scale
3336 glGenTextures(1, &irradiance.id);
3337 glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance.id);
3338 for (unsigned int i = 0; i < 6; i++)
3339 {
3340 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3341 }
3342
3343 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3344 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3345 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
3346 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3347 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3348
3349 // Create projection (transposed) and different views for each face
3350 Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_NEAR_CULL_DISTANCE, RL_FAR_CULL_DISTANCE);
3351 Matrix fboViews[6] = {
3352 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3353 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3354 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
3355 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
3356 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3357 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
3358 };
3359
3360 // Solve diffuse integral by convolution to create an irradiance cubemap
3361 glUseProgram(shader.id);
3362 glActiveTexture(GL_TEXTURE0);
3363 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
3364 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
3365
3366 // Note: don't forget to configure the viewport to the capture dimensions
3367 glViewport(0, 0, size, size);
3368 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3369
3370 for (int i = 0; i < 6; i++)
3371 {
3372 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
3373 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance.id, 0);
3374 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3375 GenDrawCube();
3376 }
3377
3378 // Unbind framebuffer and textures
3379 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3380
3381 // Reset viewport dimensions to default
3382 glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3383
3384 irradiance.width = size;
3385 irradiance.height = size;
3386 irradiance.mipmaps = 1;
3387 //irradiance.format = UNCOMPRESSED_R16G16B16;
3388#endif
3389 return irradiance;
3390}
3391
3392// Generate prefilter texture using cubemap data
3393// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
3394Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
3395{
3396 Texture2D prefilter = { 0 };
3397
3398#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
3399 // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
3400 // Other locations should be setup externally in shader before calling the function
3401 // TODO: Locations should be taken out of this function... too shader dependant...
3402 int roughnessLoc = GetShaderLocation(shader, "roughness");
3403
3404 // Setup framebuffer
3405 unsigned int fbo, rbo;
3406 glGenFramebuffers(1, &fbo);
3407 glGenRenderbuffers(1, &rbo);
3408 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3409 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
3410 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
3411 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
3412
3413 // Create a prefiltered HDR environment map
3414 glGenTextures(1, &prefilter.id);
3415 glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter.id);
3416 for (unsigned int i = 0; i < 6; i++)
3417 {
3418 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3419 }
3420
3421 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3422 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3423 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
3424 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
3425 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3426
3427 // Generate mipmaps for the prefiltered HDR texture
3428 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
3429
3430 // Create projection (transposed) and different views for each face
3431 Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_NEAR_CULL_DISTANCE, RL_FAR_CULL_DISTANCE);
3432 Matrix fboViews[6] = {
3433 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3434 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3435 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
3436 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
3437 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
3438 MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
3439 };
3440
3441 // Prefilter HDR and store data into mipmap levels
3442 glUseProgram(shader.id);
3443 glActiveTexture(GL_TEXTURE0);
3444 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
3445 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
3446
3447 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3448
3449 #define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps
3450
3451 for (int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++)
3452 {
3453 // Resize framebuffer according to mip-level size.
3454 unsigned int mipWidth = size*(int)powf(0.5f, (float)mip);
3455 unsigned int mipHeight = size*(int)powf(0.5f, (float)mip);
3456
3457 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
3458 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
3459 glViewport(0, 0, mipWidth, mipHeight);
3460
3461 float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1);
3462 glUniform1f(roughnessLoc, roughness);
3463
3464 for (int i = 0; i < 6; i++)
3465 {
3466 SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
3467 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip);
3468 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3469 GenDrawCube();
3470 }
3471 }
3472
3473 // Unbind framebuffer and textures
3474 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3475
3476 // Reset viewport dimensions to default
3477 glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3478
3479 prefilter.width = size;
3480 prefilter.height = size;
3481 //prefilter.mipmaps = 1 + (int)floor(log(size)/log(2));
3482 //prefilter.format = UNCOMPRESSED_R16G16B16;
3483#endif
3484 return prefilter;
3485}
3486
3487// Generate BRDF texture using cubemap data
3488// NOTE: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
3489// TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator
3490Texture2D GenTextureBRDF(Shader shader, int size)
3491{
3492 Texture2D brdf = { 0 };
3493#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3494 // Generate BRDF convolution texture
3495 glGenTextures(1, &brdf.id);
3496 glBindTexture(GL_TEXTURE_2D, brdf.id);
3497#if defined(GRAPHICS_API_OPENGL_33)
3498 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3499#elif defined(GRAPHICS_API_OPENGL_ES2)
3500 if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
3501#endif
3502
3503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3506 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3507
3508 // Render BRDF LUT into a quad using FBO
3509 unsigned int fbo, rbo;
3510 glGenFramebuffers(1, &fbo);
3511 glGenRenderbuffers(1, &rbo);
3512 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3513 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
3514#if defined(GRAPHICS_API_OPENGL_33)
3515 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
3516#elif defined(GRAPHICS_API_OPENGL_ES2)
3517 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
3518#endif
3519 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdf.id, 0);
3520
3521 glViewport(0, 0, size, size);
3522 glUseProgram(shader.id);
3523 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3524 GenDrawQuad();
3525
3526 // Unbind framebuffer and textures
3527 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3528
3529 // Unload framebuffer but keep color texture
3530 glDeleteRenderbuffers(1, &rbo);
3531 glDeleteFramebuffers(1, &fbo);
3532
3533 // Reset viewport dimensions to default
3534 glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3535
3536 brdf.width = size;
3537 brdf.height = size;
3538 brdf.mipmaps = 1;
3539 brdf.format = UNCOMPRESSED_R32G32B32;
3540#endif
3541 return brdf;
3542}
3543
3544// Begin blending mode (alpha, additive, multiplied)
3545// NOTE: Only 3 blending modes supported, default blend mode is alpha
3546void BeginBlendMode(int mode)
3547{
3548 static int blendMode = 0; // Track current blending mode
3549
3550 if ((blendMode != mode) && (mode < 3))
3551 {
3552 rlglDraw();
3553
3554 switch (mode)
3555 {
3556 case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
3557 case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE);
3558 case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;
3559 default: break;
3560 }
3561
3562 blendMode = mode;
3563 }
3564}
3565
3566// End blending mode (reset to default: alpha blending)
3567void EndBlendMode(void)
3568{
3569 BeginBlendMode(BLEND_ALPHA);
3570}
3571
3572#if defined(SUPPORT_VR_SIMULATOR)
3573// Init VR simulator for selected device parameters
3574// NOTE: It modifies the global variable: RLGL.Vr.stereoFbo
3575void InitVrSimulator(void)
3576{
3577#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3578 // Initialize framebuffer and textures for stereo rendering
3579 // NOTE: Screen size should match HMD aspect ratio
3580 RLGL.Vr.stereoFbo = rlLoadRenderTexture(RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, UNCOMPRESSED_R8G8B8A8, 24, false);
3581
3582 RLGL.Vr.simulatorReady = true;
3583#else
3584 TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1");
3585#endif
3586}
3587
3588// Update VR tracking (position and orientation) and camera
3589// NOTE: Camera (position, target, up) gets update with head tracking information
3590void UpdateVrTracking(Camera *camera)
3591{
3592 // TODO: Simulate 1st person camera system
3593}
3594
3595// Close VR simulator for current device
3596void CloseVrSimulator(void)
3597{
3598#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3599 if (RLGL.Vr.simulatorReady) rlDeleteRenderTextures(RLGL.Vr.stereoFbo); // Unload stereo framebuffer and texture
3600#endif
3601}
3602
3603// Set stereo rendering configuration parameters
3604void SetVrConfiguration(VrDeviceInfo hmd, Shader distortion)
3605{
3606#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3607 // Reset RLGL.Vr.config for a new values assignment
3608 memset(&RLGL.Vr.config, 0, sizeof(RLGL.Vr.config));
3609
3610 // Assign distortion shader
3611 RLGL.Vr.config.distortionShader = distortion;
3612
3613 // Compute aspect ratio
3614 float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution;
3615
3616 // Compute lens parameters
3617 float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize;
3618 float leftLensCenter[2] = { 0.25f + lensShift, 0.5f };
3619 float rightLensCenter[2] = { 0.75f - lensShift, 0.5f };
3620 float leftScreenCenter[2] = { 0.25f, 0.5f };
3621 float rightScreenCenter[2] = { 0.75f, 0.5f };
3622
3623 // Compute distortion scale parameters
3624 // NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
3625 float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
3626 float lensRadiusSq = lensRadius*lensRadius;
3627 float distortionScale = hmd.lensDistortionValues[0] +
3628 hmd.lensDistortionValues[1]*lensRadiusSq +
3629 hmd.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq +
3630 hmd.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq;
3631
3632 TRACELOGD("RLGL: VR device configuration:");
3633 TRACELOGD(" > Distortion Scale: %f", distortionScale);
3634
3635 float normScreenWidth = 0.5f;
3636 float normScreenHeight = 1.0f;
3637 float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect };
3638 float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale };
3639
3640 TRACELOGD(" > Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]);
3641 TRACELOGD(" > Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]);
3642 TRACELOGD(" > Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]);
3643 TRACELOGD(" > Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]);
3644
3645 // Fovy is normally computed with: 2*atan2f(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)
3646 // ...but with lens distortion it is increased (see Oculus SDK Documentation)
3647 //float fovy = 2.0f*atan2f(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance); // Really need distortionScale?
3648 float fovy = 2.0f*(float)atan2f(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance);
3649
3650 // Compute camera projection matrices
3651 float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1]
3652 Matrix proj = MatrixPerspective(fovy, aspect, RL_NEAR_CULL_DISTANCE, RL_FAR_CULL_DISTANCE);
3653 RLGL.Vr.config.eyesProjection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f));
3654 RLGL.Vr.config.eyesProjection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f));
3655
3656 // Compute camera transformation matrices
3657 // NOTE: Camera movement might seem more natural if we model the head.
3658 // Our axis of rotation is the base of our head, so we might want to add
3659 // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions.
3660 RLGL.Vr.config.eyesViewOffset[0] = MatrixTranslate(-hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);
3661 RLGL.Vr.config.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);
3662
3663 // Compute eyes Viewports
3664 RLGL.Vr.config.eyeViewportRight[2] = hmd.hResolution/2;
3665 RLGL.Vr.config.eyeViewportRight[3] = hmd.vResolution;
3666
3667 RLGL.Vr.config.eyeViewportLeft[0] = hmd.hResolution/2;
3668 RLGL.Vr.config.eyeViewportLeft[1] = 0;
3669 RLGL.Vr.config.eyeViewportLeft[2] = hmd.hResolution/2;
3670 RLGL.Vr.config.eyeViewportLeft[3] = hmd.vResolution;
3671
3672 if (RLGL.Vr.config.distortionShader.id > 0)
3673 {
3674 // Update distortion shader with lens and distortion-scale parameters
3675 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "leftLensCenter"), leftLensCenter, UNIFORM_VEC2);
3676 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "rightLensCenter"), rightLensCenter, UNIFORM_VEC2);
3677 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "leftScreenCenter"), leftScreenCenter, UNIFORM_VEC2);
3678 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "rightScreenCenter"), rightScreenCenter, UNIFORM_VEC2);
3679
3680 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "scale"), scale, UNIFORM_VEC2);
3681 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "scaleIn"), scaleIn, UNIFORM_VEC2);
3682 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, UNIFORM_VEC4);
3683 SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, UNIFORM_VEC4);
3684 }
3685#endif
3686}
3687
3688// Detect if VR simulator is running
3689bool IsVrSimulatorReady(void)
3690{
3691#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3692 return RLGL.Vr.simulatorReady;
3693#else
3694 return false;
3695#endif
3696}
3697
3698// Enable/Disable VR experience (device or simulator)
3699void ToggleVrMode(void)
3700{
3701#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3702 RLGL.Vr.simulatorReady = !RLGL.Vr.simulatorReady;
3703
3704 if (!RLGL.Vr.simulatorReady)
3705 {
3706 RLGL.Vr.stereoRender = false;
3707
3708 // Reset viewport and default projection-modelview matrices
3709 rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3710 RLGL.State.projection = MatrixOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0);
3711 RLGL.State.modelview = MatrixIdentity();
3712 }
3713 else RLGL.Vr.stereoRender = true;
3714#endif
3715}
3716
3717// Begin VR drawing configuration
3718void BeginVrDrawing(void)
3719{
3720#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3721 if (RLGL.Vr.simulatorReady)
3722 {
3723 rlEnableRenderTexture(RLGL.Vr.stereoFbo.id); // Setup framebuffer for stereo rendering
3724 //glEnable(GL_FRAMEBUFFER_SRGB); // Enable SRGB framebuffer (only if required)
3725
3726 //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye)
3727 rlClearScreenBuffers(); // Clear current framebuffer
3728
3729 RLGL.Vr.stereoRender = true;
3730 }
3731#endif
3732}
3733
3734// End VR drawing process (and desktop mirror)
3735void EndVrDrawing(void)
3736{
3737#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3738 if (RLGL.Vr.simulatorReady)
3739 {
3740 RLGL.Vr.stereoRender = false; // Disable stereo render
3741
3742 rlDisableRenderTexture(); // Unbind current framebuffer
3743
3744 rlClearScreenBuffers(); // Clear current framebuffer
3745
3746 // Set viewport to default framebuffer size (screen size)
3747 rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3748
3749 // Let rlgl reconfigure internal matrices
3750 rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix
3751 rlLoadIdentity(); // Reset internal projection matrix
3752 rlOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0); // Recalculate internal RLGL.State.projection matrix
3753 rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix
3754 rlLoadIdentity(); // Reset internal modelview matrix
3755
3756 // Draw RenderTexture (RLGL.Vr.stereoFbo) using distortion shader if available
3757 if (RLGL.Vr.config.distortionShader.id > 0) RLGL.State.currentShader = RLGL.Vr.config.distortionShader;
3758 else RLGL.State.currentShader = GetShaderDefault();
3759
3760 rlEnableTexture(RLGL.Vr.stereoFbo.texture.id);
3761
3762 rlPushMatrix();
3763 rlBegin(RL_QUADS);
3764 rlColor4ub(255, 255, 255, 255);
3765 rlNormal3f(0.0f, 0.0f, 1.0f);
3766
3767 // Bottom-left corner for texture and quad
3768 rlTexCoord2f(0.0f, 1.0f);
3769 rlVertex2f(0.0f, 0.0f);
3770
3771 // Bottom-right corner for texture and quad
3772 rlTexCoord2f(0.0f, 0.0f);
3773 rlVertex2f(0.0f, (float)RLGL.Vr.stereoFbo.texture.height);
3774
3775 // Top-right corner for texture and quad
3776 rlTexCoord2f(1.0f, 0.0f);
3777 rlVertex2f((float)RLGL.Vr.stereoFbo.texture.width, (float)RLGL.Vr.stereoFbo.texture.height);
3778
3779 // Top-left corner for texture and quad
3780 rlTexCoord2f(1.0f, 1.0f);
3781 rlVertex2f((float)RLGL.Vr.stereoFbo.texture.width, 0.0f);
3782 rlEnd();
3783 rlPopMatrix();
3784
3785 rlDisableTexture();
3786
3787 // Update and draw render texture fbo with distortion to backbuffer
3788 UpdateBuffersDefault();
3789 DrawBuffersDefault();
3790
3791 // Restore RLGL.State.defaultShader
3792 RLGL.State.currentShader = RLGL.State.defaultShader;
3793
3794 // Reset viewport and default projection-modelview matrices
3795 rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
3796 RLGL.State.projection = MatrixOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0);
3797 RLGL.State.modelview = MatrixIdentity();
3798
3799 rlDisableDepthTest();
3800 }
3801#endif
3802}
3803#endif // SUPPORT_VR_SIMULATOR
3804
3805//----------------------------------------------------------------------------------
3806// Module specific Functions Definition
3807//----------------------------------------------------------------------------------
3808
3809#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3810// Compile custom shader and return shader id
3811static unsigned int CompileShader(const char *shaderStr, int type)
3812{
3813 unsigned int shader = glCreateShader(type);
3814 glShaderSource(shader, 1, &shaderStr, NULL);
3815
3816 GLint success = 0;
3817 glCompileShader(shader);
3818 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
3819
3820 if (success != GL_TRUE)
3821 {
3822 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile shader code", shader);
3823 int maxLength = 0;
3824 int length;
3825 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
3826
3827#if defined(_MSC_VER)
3828 char *log = RL_MALLOC(maxLength);
3829#else
3830 char log[maxLength];
3831#endif
3832 glGetShaderInfoLog(shader, maxLength, &length, log);
3833
3834 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log);
3835
3836#if defined(_MSC_VER)
3837 RL_FREE(log);
3838#endif
3839 }
3840 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Compiled successfully", shader);
3841
3842 return shader;
3843}
3844
3845// Load custom shader strings and return program id
3846static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
3847{
3848 unsigned int program = 0;
3849
3850#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
3851
3852 GLint success = 0;
3853 program = glCreateProgram();
3854
3855 glAttachShader(program, vShaderId);
3856 glAttachShader(program, fShaderId);
3857
3858 // NOTE: Default attribute shader locations must be binded before linking
3859 glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME);
3860 glBindAttribLocation(program, 1, DEFAULT_ATTRIB_TEXCOORD_NAME);
3861 glBindAttribLocation(program, 2, DEFAULT_ATTRIB_NORMAL_NAME);
3862 glBindAttribLocation(program, 3, DEFAULT_ATTRIB_COLOR_NAME);
3863 glBindAttribLocation(program, 4, DEFAULT_ATTRIB_TANGENT_NAME);
3864 glBindAttribLocation(program, 5, DEFAULT_ATTRIB_TEXCOORD2_NAME);
3865
3866 // NOTE: If some attrib name is no found on the shader, it locations becomes -1
3867
3868 glLinkProgram(program);
3869
3870 // NOTE: All uniform variables are intitialised to 0 when a program links
3871
3872 glGetProgramiv(program, GL_LINK_STATUS, &success);
3873
3874 if (success == GL_FALSE)
3875 {
3876 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program);
3877
3878 int maxLength = 0;
3879 int length;
3880
3881 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
3882
3883#if defined(_MSC_VER)
3884 char *log = RL_MALLOC(maxLength);
3885#else
3886 char log[maxLength];
3887#endif
3888 glGetProgramInfoLog(program, maxLength, &length, log);
3889
3890 TRACELOG(LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
3891
3892#if defined(_MSC_VER)
3893 RL_FREE(log);
3894#endif
3895 glDeleteProgram(program);
3896
3897 program = 0;
3898 }
3899 else TRACELOG(LOG_INFO, "SHADER: [ID %i] Program loaded successfully", program);
3900#endif
3901 return program;
3902}
3903
3904
3905// Load default shader (just vertex positioning and texture coloring)
3906// NOTE: This shader program is used for internal buffers
3907static Shader LoadShaderDefault(void)
3908{
3909 Shader shader = { 0 };
3910 shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));
3911
3912 // NOTE: All locations must be reseted to -1 (no location)
3913 for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
3914
3915 // Vertex shader directly defined, no external file required
3916 const char *defaultVShaderStr =
3917#if defined(GRAPHICS_API_OPENGL_21)
3918 "#version 120 \n"
3919#elif defined(GRAPHICS_API_OPENGL_ES2)
3920 "#version 100 \n"
3921#endif
3922#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
3923 "attribute vec3 vertexPosition; \n"
3924 "attribute vec2 vertexTexCoord; \n"
3925 "attribute vec4 vertexColor; \n"
3926 "varying vec2 fragTexCoord; \n"
3927 "varying vec4 fragColor; \n"
3928#elif defined(GRAPHICS_API_OPENGL_33)
3929 "#version 330 \n"
3930 "in vec3 vertexPosition; \n"
3931 "in vec2 vertexTexCoord; \n"
3932 "in vec4 vertexColor; \n"
3933 "out vec2 fragTexCoord; \n"
3934 "out vec4 fragColor; \n"
3935#endif
3936 "uniform mat4 mvp; \n"
3937 "void main() \n"
3938 "{ \n"
3939 " fragTexCoord = vertexTexCoord; \n"
3940 " fragColor = vertexColor; \n"
3941 " gl_Position = mvp*vec4(vertexPosition, 1.0); \n"
3942 "} \n";
3943
3944 // Fragment shader directly defined, no external file required
3945 const char *defaultFShaderStr =
3946#if defined(GRAPHICS_API_OPENGL_21)
3947 "#version 120 \n"
3948#elif defined(GRAPHICS_API_OPENGL_ES2)
3949 "#version 100 \n"
3950 "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL)
3951#endif
3952#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
3953 "varying vec2 fragTexCoord; \n"
3954 "varying vec4 fragColor; \n"
3955#elif defined(GRAPHICS_API_OPENGL_33)
3956 "#version 330 \n"
3957 "in vec2 fragTexCoord; \n"
3958 "in vec4 fragColor; \n"
3959 "out vec4 finalColor; \n"
3960#endif
3961 "uniform sampler2D texture0; \n"
3962 "uniform vec4 colDiffuse; \n"
3963 "void main() \n"
3964 "{ \n"
3965#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
3966 " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
3967 " gl_FragColor = texelColor*colDiffuse*fragColor; \n"
3968#elif defined(GRAPHICS_API_OPENGL_33)
3969 " vec4 texelColor = texture(texture0, fragTexCoord); \n"
3970 " finalColor = texelColor*colDiffuse*fragColor; \n"
3971#endif
3972 "} \n";
3973
3974 // NOTE: Compiled vertex/fragment shaders are kept for re-use
3975 RLGL.State.defaultVShaderId = CompileShader(defaultVShaderStr, GL_VERTEX_SHADER); // Compile default vertex shader
3976 RLGL.State.defaultFShaderId = CompileShader(defaultFShaderStr, GL_FRAGMENT_SHADER); // Compile default fragment shader
3977
3978 shader.id = LoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId);
3979
3980 if (shader.id > 0)
3981 {
3982 TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", shader.id);
3983
3984 // Set default shader locations: attributes locations
3985 shader.locs[LOC_VERTEX_POSITION] = glGetAttribLocation(shader.id, "vertexPosition");
3986 shader.locs[LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(shader.id, "vertexTexCoord");
3987 shader.locs[LOC_VERTEX_COLOR] = glGetAttribLocation(shader.id, "vertexColor");
3988
3989 // Set default shader locations: uniform locations
3990 shader.locs[LOC_MATRIX_MVP] = glGetUniformLocation(shader.id, "mvp");
3991 shader.locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader.id, "colDiffuse");
3992 shader.locs[LOC_MAP_DIFFUSE] = glGetUniformLocation(shader.id, "texture0");
3993
3994 // NOTE: We could also use below function but in case DEFAULT_ATTRIB_* points are
3995 // changed for external custom shaders, we just use direct bindings above
3996 //SetShaderDefaultLocations(&shader);
3997 }
3998 else TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", shader.id);
3999
4000 return shader;
4001}
4002
4003// Get location handlers to for shader attributes and uniforms
4004// NOTE: If any location is not found, loc point becomes -1
4005static void SetShaderDefaultLocations(Shader *shader)
4006{
4007 // NOTE: Default shader attrib locations have been fixed before linking:
4008 // vertex position location = 0
4009 // vertex texcoord location = 1
4010 // vertex normal location = 2
4011 // vertex color location = 3
4012 // vertex tangent location = 4
4013 // vertex texcoord2 location = 5
4014
4015 // Get handles to GLSL input attibute locations
4016 shader->locs[LOC_VERTEX_POSITION] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
4017 shader->locs[LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
4018 shader->locs[LOC_VERTEX_TEXCOORD02] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME);
4019 shader->locs[LOC_VERTEX_NORMAL] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME);
4020 shader->locs[LOC_VERTEX_TANGENT] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME);
4021 shader->locs[LOC_VERTEX_COLOR] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME);
4022
4023 // Get handles to GLSL uniform locations (vertex shader)
4024 shader->locs[LOC_MATRIX_MVP] = glGetUniformLocation(shader->id, "mvp");
4025 shader->locs[LOC_MATRIX_PROJECTION] = glGetUniformLocation(shader->id, "projection");
4026 shader->locs[LOC_MATRIX_VIEW] = glGetUniformLocation(shader->id, "view");
4027
4028 // Get handles to GLSL uniform locations (fragment shader)
4029 shader->locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader->id, "colDiffuse");
4030 shader->locs[LOC_MAP_DIFFUSE] = glGetUniformLocation(shader->id, "texture0");
4031 shader->locs[LOC_MAP_SPECULAR] = glGetUniformLocation(shader->id, "texture1");
4032 shader->locs[LOC_MAP_NORMAL] = glGetUniformLocation(shader->id, "texture2");
4033}
4034
4035// Unload default shader
4036static void UnloadShaderDefault(void)
4037{
4038 glUseProgram(0);
4039
4040 glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultVShaderId);
4041 glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultFShaderId);
4042 glDeleteShader(RLGL.State.defaultVShaderId);
4043 glDeleteShader(RLGL.State.defaultFShaderId);
4044
4045 glDeleteProgram(RLGL.State.defaultShader.id);
4046}
4047
4048// Load default internal buffers
4049static void LoadBuffersDefault(void)
4050{
4051 // Initialize CPU (RAM) arrays (vertex position, texcoord, color data and indexes)
4052 //--------------------------------------------------------------------------------------------
4053 for (int i = 0; i < MAX_BATCH_BUFFERING; i++)
4054 {
4055 RLGL.State.vertexData[i].vertices = (float *)RL_MALLOC(sizeof(float)*3*4*MAX_BATCH_ELEMENTS); // 3 float by vertex, 4 vertex by quad
4056 RLGL.State.vertexData[i].texcoords = (float *)RL_MALLOC(sizeof(float)*2*4*MAX_BATCH_ELEMENTS); // 2 float by texcoord, 4 texcoord by quad
4057 RLGL.State.vertexData[i].colors = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS); // 4 float by color, 4 colors by quad
4058#if defined(GRAPHICS_API_OPENGL_33)
4059 RLGL.State.vertexData[i].indices = (unsigned int *)RL_MALLOC(sizeof(unsigned int)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices)
4060#elif defined(GRAPHICS_API_OPENGL_ES2)
4061 RLGL.State.vertexData[i].indices = (unsigned short *)RL_MALLOC(sizeof(unsigned short)*6*MAX_BATCH_ELEMENTS); // 6 int by quad (indices)
4062#endif
4063
4064 for (int j = 0; j < (3*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].vertices[j] = 0.0f;
4065 for (int j = 0; j < (2*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].texcoords[j] = 0.0f;
4066 for (int j = 0; j < (4*4*MAX_BATCH_ELEMENTS); j++) RLGL.State.vertexData[i].colors[j] = 0;
4067
4068 int k = 0;
4069
4070 // Indices can be initialized right now
4071 for (int j = 0; j < (6*MAX_BATCH_ELEMENTS); j += 6)
4072 {
4073 RLGL.State.vertexData[i].indices[j] = 4*k;
4074 RLGL.State.vertexData[i].indices[j + 1] = 4*k + 1;
4075 RLGL.State.vertexData[i].indices[j + 2] = 4*k + 2;
4076 RLGL.State.vertexData[i].indices[j + 3] = 4*k;
4077 RLGL.State.vertexData[i].indices[j + 4] = 4*k + 2;
4078 RLGL.State.vertexData[i].indices[j + 5] = 4*k + 3;
4079
4080 k++;
4081 }
4082
4083 RLGL.State.vertexData[i].vCounter = 0;
4084 RLGL.State.vertexData[i].tcCounter = 0;
4085 RLGL.State.vertexData[i].cCounter = 0;
4086 }
4087
4088 TRACELOG(LOG_INFO, "RLGL: Internal vertex buffers initialized successfully in RAM (CPU)");
4089 //--------------------------------------------------------------------------------------------
4090
4091 // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs
4092 //--------------------------------------------------------------------------------------------
4093 for (int i = 0; i < MAX_BATCH_BUFFERING; i++)
4094 {
4095 if (RLGL.ExtSupported.vao)
4096 {
4097 // Initialize Quads VAO
4098 glGenVertexArrays(1, &RLGL.State.vertexData[i].vaoId);
4099 glBindVertexArray(RLGL.State.vertexData[i].vaoId);
4100 }
4101
4102 // Quads - Vertex buffers binding and attributes enable
4103 // Vertex position buffer (shader-location = 0)
4104 glGenBuffers(1, &RLGL.State.vertexData[i].vboId[0]);
4105 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[0]);
4106 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].vertices, GL_DYNAMIC_DRAW);
4107 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]);
4108 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
4109
4110 // Vertex texcoord buffer (shader-location = 1)
4111 glGenBuffers(1, &RLGL.State.vertexData[i].vboId[1]);
4112 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[1]);
4113 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].texcoords, GL_DYNAMIC_DRAW);
4114 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]);
4115 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
4116
4117 // Vertex color buffer (shader-location = 3)
4118 glGenBuffers(1, &RLGL.State.vertexData[i].vboId[2]);
4119 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[2]);
4120 glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].colors, GL_DYNAMIC_DRAW);
4121 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]);
4122 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
4123
4124 // Fill index buffer
4125 glGenBuffers(1, &RLGL.State.vertexData[i].vboId[3]);
4126 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RLGL.State.vertexData[i].vboId[3]);
4127#if defined(GRAPHICS_API_OPENGL_33)
4128 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].indices, GL_STATIC_DRAW);
4129#elif defined(GRAPHICS_API_OPENGL_ES2)
4130 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[i].indices, GL_STATIC_DRAW);
4131#endif
4132 }
4133
4134 TRACELOG(LOG_INFO, "RLGL: Internal vertex buffers uploaded successfully to VRAM (GPU)");
4135
4136 // Unbind the current VAO
4137 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
4138 //--------------------------------------------------------------------------------------------
4139}
4140
4141// Update default internal buffers (VAOs/VBOs) with vertex array data
4142// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
4143// TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required)
4144static void UpdateBuffersDefault(void)
4145{
4146 // Update vertex buffers data
4147 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0)
4148 {
4149 // Activate elements VAO
4150 if (RLGL.ExtSupported.vao) glBindVertexArray(RLGL.State.vertexData[RLGL.State.currentBuffer].vaoId);
4151
4152 // Vertex positions buffer
4153 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[0]);
4154 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].vertices);
4155 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer
4156
4157 // Texture coordinates buffer
4158 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[1]);
4159 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords);
4160 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer
4161
4162 // Colors buffer
4163 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[2]);
4164 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter, RLGL.State.vertexData[RLGL.State.currentBuffer].colors);
4165 //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, RLGL.State.vertexData[RLGL.State.currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer
4166
4167 // NOTE: glMapBuffer() causes sync issue.
4168 // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job.
4169 // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer().
4170 // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new
4171 // allocated pointer immediately even if GPU is still working with the previous data.
4172
4173 // Another option: map the buffer object into client's memory
4174 // Probably this code could be moved somewhere else...
4175 // RLGL.State.vertexData[RLGL.State.currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
4176 // if (RLGL.State.vertexData[RLGL.State.currentBuffer].vertices)
4177 // {
4178 // Update vertex data
4179 // }
4180 // glUnmapBuffer(GL_ARRAY_BUFFER);
4181
4182 // Unbind the current VAO
4183 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
4184 }
4185}
4186
4187// Draw default internal buffers vertex data
4188static void DrawBuffersDefault(void)
4189{
4190 Matrix matProjection = RLGL.State.projection;
4191 Matrix matModelView = RLGL.State.modelview;
4192
4193 int eyesCount = 1;
4194#if defined(SUPPORT_VR_SIMULATOR)
4195 if (RLGL.Vr.stereoRender) eyesCount = 2;
4196#endif
4197
4198 for (int eye = 0; eye < eyesCount; eye++)
4199 {
4200#if defined(SUPPORT_VR_SIMULATOR)
4201 if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView);
4202#endif
4203
4204 // Draw buffers
4205 if (RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter > 0)
4206 {
4207 // Set current shader and upload current MVP matrix
4208 glUseProgram(RLGL.State.currentShader.id);
4209
4210 // Create modelview-projection matrix
4211 Matrix matMVP = MatrixMultiply(RLGL.State.modelview, RLGL.State.projection);
4212
4213 glUniformMatrix4fv(RLGL.State.currentShader.locs[LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP));
4214 glUniform4f(RLGL.State.currentShader.locs[LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f);
4215 glUniform1i(RLGL.State.currentShader.locs[LOC_MAP_DIFFUSE], 0); // Provided value refers to the texture unit (active)
4216
4217 // TODO: Support additional texture units on custom shader
4218 //if (RLGL.State.currentShader->locs[LOC_MAP_SPECULAR] > 0) glUniform1i(RLGL.State.currentShader.locs[LOC_MAP_SPECULAR], 1);
4219 //if (RLGL.State.currentShader->locs[LOC_MAP_NORMAL] > 0) glUniform1i(RLGL.State.currentShader.locs[LOC_MAP_NORMAL], 2);
4220
4221 // NOTE: Right now additional map textures not considered for default buffers drawing
4222
4223 int vertexOffset = 0;
4224
4225 if (RLGL.ExtSupported.vao) glBindVertexArray(RLGL.State.vertexData[RLGL.State.currentBuffer].vaoId);
4226 else
4227 {
4228 // Bind vertex attrib: position (shader-location = 0)
4229 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[0]);
4230 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
4231 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]);
4232
4233 // Bind vertex attrib: texcoord (shader-location = 1)
4234 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[1]);
4235 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
4236 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]);
4237
4238 // Bind vertex attrib: color (shader-location = 3)
4239 glBindBuffer(GL_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[2]);
4240 glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
4241 glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]);
4242
4243 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RLGL.State.vertexData[RLGL.State.currentBuffer].vboId[3]);
4244 }
4245
4246 glActiveTexture(GL_TEXTURE0);
4247
4248 for (int i = 0; i < RLGL.State.drawsCounter; i++)
4249 {
4250 glBindTexture(GL_TEXTURE_2D, RLGL.State.draws[i].textureId);
4251
4252 // TODO: Find some way to bind additional textures --> Use global texture IDs? Register them on draw[i]?
4253 //if (RLGL.State.currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureUnit1_id); }
4254 //if (RLGL.State.currentShader->locs[LOC_MAP_SPECULAR] > 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureUnit2_id); }
4255
4256 if ((RLGL.State.draws[i].mode == RL_LINES) || (RLGL.State.draws[i].mode == RL_TRIANGLES)) glDrawArrays(RLGL.State.draws[i].mode, vertexOffset, RLGL.State.draws[i].vertexCount);
4257 else
4258 {
4259#if defined(GRAPHICS_API_OPENGL_33)
4260 // We need to define the number of indices to be processed: quadsCount*6
4261 // NOTE: The final parameter tells the GPU the offset in bytes from the
4262 // start of the index buffer to the location of the first index to process
4263 glDrawElements(GL_TRIANGLES, RLGL.State.draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6));
4264#elif defined(GRAPHICS_API_OPENGL_ES2)
4265 glDrawElements(GL_TRIANGLES, RLGL.State.draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*vertexOffset/4*6));
4266#endif
4267 }
4268
4269 vertexOffset += (RLGL.State.draws[i].vertexCount + RLGL.State.draws[i].vertexAlignment);
4270 }
4271
4272 if (!RLGL.ExtSupported.vao)
4273 {
4274 glBindBuffer(GL_ARRAY_BUFFER, 0);
4275 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4276 }
4277
4278 glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
4279 }
4280
4281 if (RLGL.ExtSupported.vao) glBindVertexArray(0); // Unbind VAO
4282
4283 glUseProgram(0); // Unbind shader program
4284 }
4285
4286 // Reset vertex counters for next frame
4287 RLGL.State.vertexData[RLGL.State.currentBuffer].vCounter = 0;
4288 RLGL.State.vertexData[RLGL.State.currentBuffer].tcCounter = 0;
4289 RLGL.State.vertexData[RLGL.State.currentBuffer].cCounter = 0;
4290
4291 // Reset depth for next draw
4292 RLGL.State.currentDepth = -1.0f;
4293
4294 // Restore projection/modelview matrices
4295 RLGL.State.projection = matProjection;
4296 RLGL.State.modelview = matModelView;
4297
4298 // Reset RLGL.State.draws array
4299 for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++)
4300 {
4301 RLGL.State.draws[i].mode = RL_QUADS;
4302 RLGL.State.draws[i].vertexCount = 0;
4303 RLGL.State.draws[i].textureId = RLGL.State.defaultTextureId;
4304 }
4305
4306 RLGL.State.drawsCounter = 1;
4307
4308 // Change to next buffer in the list
4309 RLGL.State.currentBuffer++;
4310 if (RLGL.State.currentBuffer >= MAX_BATCH_BUFFERING) RLGL.State.currentBuffer = 0;
4311}
4312
4313// Unload default internal buffers vertex data from CPU and GPU
4314static void UnloadBuffersDefault(void)
4315{
4316 // Unbind everything
4317 if (RLGL.ExtSupported.vao) glBindVertexArray(0);
4318 glDisableVertexAttribArray(0);
4319 glDisableVertexAttribArray(1);
4320 glDisableVertexAttribArray(2);
4321 glDisableVertexAttribArray(3);
4322 glBindBuffer(GL_ARRAY_BUFFER, 0);
4323 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4324
4325 for (int i = 0; i < MAX_BATCH_BUFFERING; i++)
4326 {
4327 // Delete VBOs from GPU (VRAM)
4328 glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[0]);
4329 glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[1]);
4330 glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[2]);
4331 glDeleteBuffers(1, &RLGL.State.vertexData[i].vboId[3]);
4332
4333 // Delete VAOs from GPU (VRAM)
4334 if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &RLGL.State.vertexData[i].vaoId);
4335
4336 // Free vertex arrays memory from CPU (RAM)
4337 RL_FREE(RLGL.State.vertexData[i].vertices);
4338 RL_FREE(RLGL.State.vertexData[i].texcoords);
4339 RL_FREE(RLGL.State.vertexData[i].colors);
4340 RL_FREE(RLGL.State.vertexData[i].indices);
4341 }
4342}
4343
4344// Renders a 1x1 XY quad in NDC
4345static void GenDrawQuad(void)
4346{
4347 unsigned int quadVAO = 0;
4348 unsigned int quadVBO = 0;
4349
4350 float vertices[] = {
4351 // Positions // Texture Coords
4352 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
4353 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
4354 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
4355 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
4356 };
4357
4358 // Set up plane VAO
4359 glGenVertexArrays(1, &quadVAO);
4360 glGenBuffers(1, &quadVBO);
4361 glBindVertexArray(quadVAO);
4362
4363 // Fill buffer
4364 glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
4365 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
4366
4367 // Link vertex attributes
4368 glEnableVertexAttribArray(0);
4369 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0);
4370 glEnableVertexAttribArray(1);
4371 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float)));
4372
4373 // Draw quad
4374 glBindVertexArray(quadVAO);
4375 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4376 glBindVertexArray(0);
4377
4378 glDeleteBuffers(1, &quadVBO);
4379 glDeleteVertexArrays(1, &quadVAO);
4380}
4381
4382// Renders a 1x1 3D cube in NDC
4383static void GenDrawCube(void)
4384{
4385 unsigned int cubeVAO = 0;
4386 unsigned int cubeVBO = 0;
4387
4388 float vertices[] = {
4389 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
4390 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
4391 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
4392 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
4393 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
4394 -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
4395 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
4396 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
4397 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
4398 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
4399 -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
4400 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
4401 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
4402 -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
4403 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
4404 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
4405 -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
4406 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
4407 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
4408 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
4409 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
4410 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
4411 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
4412 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
4413 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
4414 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
4415 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
4416 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
4417 -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
4418 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
4419 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
4420 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
4421 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
4422 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
4423 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
4424 -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f
4425 };
4426
4427 // Set up cube VAO
4428 glGenVertexArrays(1, &cubeVAO);
4429 glGenBuffers(1, &cubeVBO);
4430
4431 // Fill buffer
4432 glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
4433 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
4434
4435 // Link vertex attributes
4436 glBindVertexArray(cubeVAO);
4437 glEnableVertexAttribArray(0);
4438 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0);
4439 glEnableVertexAttribArray(1);
4440 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float)));
4441 glEnableVertexAttribArray(2);
4442 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float)));
4443 glBindBuffer(GL_ARRAY_BUFFER, 0);
4444 glBindVertexArray(0);
4445
4446 // Draw cube
4447 glBindVertexArray(cubeVAO);
4448 glDrawArrays(GL_TRIANGLES, 0, 36);
4449 glBindVertexArray(0);
4450
4451 glDeleteBuffers(1, &cubeVBO);
4452 glDeleteVertexArrays(1, &cubeVAO);
4453}
4454
4455#if defined(SUPPORT_VR_SIMULATOR)
4456// Set internal projection and modelview matrix depending on eyes tracking data
4457static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView)
4458{
4459 Matrix eyeProjection = matProjection;
4460 Matrix eyeModelView = matModelView;
4461
4462 // Setup viewport and projection/modelview matrices using tracking data
4463 rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight);
4464
4465 // Apply view offset to modelview matrix
4466 eyeModelView = MatrixMultiply(matModelView, RLGL.Vr.config.eyesViewOffset[eye]);
4467
4468 // Set current eye projection matrix
4469 eyeProjection = RLGL.Vr.config.eyesProjection[eye];
4470
4471 SetMatrixModelview(eyeModelView);
4472 SetMatrixProjection(eyeProjection);
4473}
4474#endif // SUPPORT_VR_SIMULATOR
4475
4476#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
4477
4478#if defined(GRAPHICS_API_OPENGL_11)
4479// Mipmaps data is generated after image data
4480// NOTE: Only works with RGBA (4 bytes) data!
4481static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight)
4482{
4483 int mipmapCount = 1; // Required mipmap levels count (including base level)
4484 int width = baseWidth;
4485 int height = baseHeight;
4486 int size = baseWidth*baseHeight*4; // Size in bytes (will include mipmaps...), RGBA only
4487
4488 // Count mipmap levels required
4489 while ((width != 1) && (height != 1))
4490 {
4491 if (width != 1) width /= 2;
4492 if (height != 1) height /= 2;
4493
4494 TRACELOGD("TEXTURE: Next mipmap size: %i x %i", width, height);
4495
4496 mipmapCount++;
4497
4498 size += (width*height*4); // Add mipmap size (in bytes)
4499 }
4500
4501 TRACELOGD("TEXTURE: Total mipmaps required: %i", mipmapCount);
4502 TRACELOGD("TEXTURE: Total size of data required: %i", size);
4503
4504 unsigned char *temp = RL_REALLOC(data, size);
4505
4506 if (temp != NULL) data = temp;
4507 else TRACELOG(LOG_WARNING, "TEXTURE: Failed to allocate required mipmaps memory");
4508
4509 width = baseWidth;
4510 height = baseHeight;
4511 size = (width*height*4);
4512
4513 // Generate mipmaps
4514 // NOTE: Every mipmap data is stored after data
4515 Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color));
4516 Color *mipmap = NULL;
4517 int offset = 0;
4518 int j = 0;
4519
4520 for (int i = 0; i < size; i += 4)
4521 {
4522 image[j].r = data[i];
4523 image[j].g = data[i + 1];
4524 image[j].b = data[i + 2];
4525 image[j].a = data[i + 3];
4526 j++;
4527 }
4528
4529 TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height);
4530
4531 for (int mip = 1; mip < mipmapCount; mip++)
4532 {
4533 mipmap = GenNextMipmap(image, width, height);
4534
4535 offset += (width*height*4); // Size of last mipmap
4536 j = 0;
4537
4538 width /= 2;
4539 height /= 2;
4540 size = (width*height*4); // Mipmap size to store after offset
4541
4542 // Add mipmap to data
4543 for (int i = 0; i < size; i += 4)
4544 {
4545 data[offset + i] = mipmap[j].r;
4546 data[offset + i + 1] = mipmap[j].g;
4547 data[offset + i + 2] = mipmap[j].b;
4548 data[offset + i + 3] = mipmap[j].a;
4549 j++;
4550 }
4551
4552 RL_FREE(image);
4553
4554 image = mipmap;
4555 mipmap = NULL;
4556 }
4557
4558 RL_FREE(mipmap); // free mipmap data
4559
4560 return mipmapCount;
4561}
4562
4563// Manual mipmap generation (basic scaling algorithm)
4564static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight)
4565{
4566 int x2, y2;
4567 Color prow, pcol;
4568
4569 int width = srcWidth/2;
4570 int height = srcHeight/2;
4571
4572 Color *mipmap = (Color *)RL_MALLOC(width*height*sizeof(Color));
4573
4574 // Scaling algorithm works perfectly (box-filter)
4575 for (int y = 0; y < height; y++)
4576 {
4577 y2 = 2*y;
4578
4579 for (int x = 0; x < width; x++)
4580 {
4581 x2 = 2*x;
4582
4583 prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2;
4584 prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2;
4585 prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2;
4586 prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2;
4587
4588 pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2;
4589 pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2;
4590 pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2;
4591 pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2;
4592
4593 mipmap[y*width + x].r = (prow.r + pcol.r)/2;
4594 mipmap[y*width + x].g = (prow.g + pcol.g)/2;
4595 mipmap[y*width + x].b = (prow.b + pcol.b)/2;
4596 mipmap[y*width + x].a = (prow.a + pcol.a)/2;
4597 }
4598 }
4599
4600 TRACELOGD("TEXTURE: Mipmap generated successfully (%ix%i)", width, height);
4601
4602 return mipmap;
4603}
4604#endif
4605
4606#if defined(RLGL_STANDALONE)
4607// Load text data from file, returns a '\0' terminated string
4608// NOTE: text chars array should be freed manually
4609char *LoadFileText(const char *fileName)
4610{
4611 char *text = NULL;
4612
4613 if (fileName != NULL)
4614 {
4615 FILE *textFile = fopen(fileName, "rt");
4616
4617 if (textFile != NULL)
4618 {
4619 // WARNING: When reading a file as 'text' file,
4620 // text mode causes carriage return-linefeed translation...
4621 // ...but using fseek() should return correct byte-offset
4622 fseek(textFile, 0, SEEK_END);
4623 int size = ftell(textFile);
4624 fseek(textFile, 0, SEEK_SET);
4625
4626 if (size > 0)
4627 {
4628 text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
4629 int count = fread(text, sizeof(char), size, textFile);
4630
4631 // WARNING: \r\n is converted to \n on reading, so,
4632 // read bytes count gets reduced by the number of lines
4633 if (count < size) text = RL_REALLOC(text, count + 1);
4634
4635 // Zero-terminate the string
4636 text[count] = '\0';
4637
4638 TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName);
4639 }
4640 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName);
4641
4642 fclose(textFile);
4643 }
4644 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
4645 }
4646 else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
4647
4648 return text;
4649}
4650
4651// Get pixel data size in bytes (image or texture)
4652// NOTE: Size depends on pixel format
4653int GetPixelDataSize(int width, int height, int format)
4654{
4655 int dataSize = 0; // Size in bytes
4656 int bpp = 0; // Bits per pixel
4657
4658 switch (format)
4659 {
4660 case UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
4661 case UNCOMPRESSED_GRAY_ALPHA:
4662 case UNCOMPRESSED_R5G6B5:
4663 case UNCOMPRESSED_R5G5B5A1:
4664 case UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
4665 case UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
4666 case UNCOMPRESSED_R8G8B8: bpp = 24; break;
4667 case UNCOMPRESSED_R32: bpp = 32; break;
4668 case UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
4669 case UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
4670 case COMPRESSED_DXT1_RGB:
4671 case COMPRESSED_DXT1_RGBA:
4672 case COMPRESSED_ETC1_RGB:
4673 case COMPRESSED_ETC2_RGB:
4674 case COMPRESSED_PVRT_RGB:
4675 case COMPRESSED_PVRT_RGBA: bpp = 4; break;
4676 case COMPRESSED_DXT3_RGBA:
4677 case COMPRESSED_DXT5_RGBA:
4678 case COMPRESSED_ETC2_EAC_RGBA:
4679 case COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
4680 case COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
4681 default: break;
4682 }
4683
4684 dataSize = width*height*bpp/8; // Total data size in bytes
4685
4686 // Most compressed formats works on 4x4 blocks,
4687 // if texture is smaller, minimum dataSize is 8 or 16
4688 if ((width < 4) && (height < 4))
4689 {
4690 if ((format >= COMPRESSED_DXT1_RGB) && (format < COMPRESSED_DXT3_RGBA)) dataSize = 8;
4691 else if ((format >= COMPRESSED_DXT3_RGBA) && (format < COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
4692 }
4693
4694 return dataSize;
4695}
4696#endif // RLGL_STANDALONE
4697
4698#endif // RLGL_IMPLEMENTATION
4699