WARNING: REDESIGNED: rlLoadExtensions() #1295

Added config flag: SUPPORT_GL_DETAILS_INFO
This commit is contained in:
Ray 2021-04-18 20:24:19 +02:00
parent 2ad3eb1d57
commit d4ccca81db
3 changed files with 306 additions and 196 deletions

View File

@ -80,6 +80,9 @@
//------------------------------------------------------------------------------------
// Module: rlgl - Configuration values
//------------------------------------------------------------------------------------
// Show OpenGL extensions and capabilities detailed logs on init
//#define SUPPORT_GL_DETAILS_INFO 1
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
#define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch limits
#elif defined(GRAPHICS_API_OPENGL_ES2)

View File

@ -3770,12 +3770,6 @@ static bool InitGraphicsDevice(int width, int height)
glfwSwapInterval(0); // No V-Sync by default
#endif
#if defined(PLATFORM_DESKTOP)
// Load OpenGL 3.3 extensions
// NOTE: GLFW loader function is passed as parameter
rlLoadExtensions(glfwGetProcAddress);
#endif
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
// NOTE: V-Sync can be enabled by graphic driver configuration
if (CORE.Window.flags & FLAG_VSYNC_HINT)
@ -4357,6 +4351,11 @@ static bool InitGraphicsDevice(int width, int height)
}
#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
// Load OpenGL extensions
// NOTE: GLFW loader function is required by GLAD but only used for OpenGL 2.1 and 3.3,
// OpenGL ES 2.0 extensions (and entry points) are loaded manually using eglGetProcAddress()
rlLoadExtensions(glfwGetProcAddress);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.screen.width and CORE.Window.screen.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.screen.width, CORE.Window.screen.height);

View File

@ -28,6 +28,8 @@
* #define RLGL_STANDALONE
* Use rlgl as standalone library (no raylib dependency)
*
* #define SUPPORT_GL_DETAILS_INFO
* Show OpenGL extensions and capabilities detailed logs on init
*
* DEPENDENCIES:
* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
@ -837,7 +839,7 @@ typedef struct rlglData {
bool texMirrorClamp; // Clamp mirror wrap mode supported (GL_EXT_texture_mirror_clamp)
bool texAnisoFilter; // Anisotropic texture filtering support (GL_EXT_texture_filter_anisotropic)
float maxAnisotropicLevel; // Maximum anisotropy level supported (minimum is 2.0f)
float maxAnisotropyLevel; // Maximum anisotropy level supported (minimum is 2.0f)
int maxDepthBits; // Maximum bits for depth component
} ExtSupported; // Extensions supported flags
@ -869,6 +871,9 @@ static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static void rlLoadShaderDefault(void); // Load default shader (RLGL.State.defaultShader)
static void rlUnloadShaderDefault(void); // Unload default shader (RLGL.State.defaultShader)
#if defined(SUPPORT_GL_DETAILS_INFO)
static char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name
#endif // SUPPORT_GL_DETAILS_INFO
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
#if defined(GRAPHICS_API_OPENGL_11)
static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side
@ -1346,10 +1351,10 @@ void rlTextureParameters(unsigned int id, int param, int value)
case RL_TEXTURE_FILTER_ANISOTROPIC:
{
#if !defined(GRAPHICS_API_OPENGL_11)
if (value <= RLGL.ExtSupported.maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
else if (RLGL.ExtSupported.maxAnisotropicLevel > 0.0f)
if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
{
TRACELOG(LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropicLevel);
TRACELOG(LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropyLevel);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
}
else TRACELOG(LOG_WARNING, "GL: Anisotropic filtering not supported");
@ -1577,72 +1582,141 @@ void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation)
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
void rlglInit(int width, int height)
{
// Check OpenGL information and capabilities
//------------------------------------------------------------------------------
// Print current OpenGL and GLSL version
TRACELOG(LOG_INFO, "GL: OpenGL device information:");
TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR));
TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER));
TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION));
TRACELOG(LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Init default white texture
unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
// NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
//int maxTexSize;
//glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
//TRACELOG(LOG_INFO, "GL: Maximum texture size: %i", maxTexSize);
if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId);
else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture");
//GL_MAX_TEXTURE_IMAGE_UNITS
//GL_MAX_VIEWPORT_DIMS
// Init default Shader (customized for GL 3.3 and ES2)
rlLoadShaderDefault(); // RLGL.State.defaultShader
RLGL.State.currentShader = RLGL.State.defaultShader;
//int numAuxBuffers;
//glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
//TRACELOG(LOG_INFO, "GL: Number of aixiliar buffers: %i", numAuxBuffers);
// Init default vertex arrays buffers
RLGL.defaultBatch = rlLoadRenderBatch(DEFAULT_BATCH_BUFFERS, DEFAULT_BATCH_BUFFER_ELEMENTS);
RLGL.currentBatch = &RLGL.defaultBatch;
//GLint numComp = 0;
//GLint format[32] = { 0 };
//glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
//glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
//for (int i = 0; i < numComp; i++) TRACELOG(LOG_INFO, "GL: Supported compressed format: 0x%x", format[i]);
// Init stack matrices (emulating OpenGL 1.1)
for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity();
// NOTE: We don't need that much data on screen... right now...
// Init internal matrices
RLGL.State.transform = MatrixIdentity();
RLGL.State.projection = MatrixIdentity();
RLGL.State.modelview = MatrixIdentity();
RLGL.State.currentMatrix = &RLGL.State.modelview;
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
// TODO: Automatize extensions loading using rlLoadExtensions() and GLAD
// Actually, when rlglInit() is called in InitWindow() in core.c,
// OpenGL context has already been created and required extensions loaded
// Initialize OpenGL default states
//----------------------------------------------------------
// Init state: Depth test
glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
// Init state: Blending mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
// Init state: Culling
// NOTE: All shapes/models triangles are drawn CCW
glCullFace(GL_BACK); // Cull the back face (default)
glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
glEnable(GL_CULL_FACE); // Enable backface culling
// Init state: Cubemap seamless
#if defined(GRAPHICS_API_OPENGL_33)
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
#endif
#if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Get supported extensions list
GLint numExt = 0;
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
RLGL.State.framebufferHeight = height;
#if defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_21)
TRACELOG(LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
//----------------------------------------------------------
#endif
// Init state: Color/Depth buffers clear
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
}
// Vertex Buffer Object deinitialization (memory free)
void rlglClose(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
rlUnloadRenderBatch(RLGL.defaultBatch);
rlUnloadShaderDefault(); // Unload default shader
glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
#endif
}
// Load OpenGL extensions
// NOTE: External loader function could be passed as a pointer
void rlLoadExtensions(void *loader)
{
#if defined(GRAPHICS_API_OPENGL_33) // Also defined for GRAPHICS_API_OPENGL_21
// NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
#if !defined(__APPLE__)
if (!gladLoadGLLoader((GLADloadproc)loader)) TRACELOG(LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
else TRACELOG(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
#endif
// Get number of supported extensions
GLint numExt = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt);
#if defined(SUPPORT_GL_DETAILS_INFO)
// Get supported extensions list
// WARNING: glGetStringi() not available on OpenGL 2.1
char **extList = RL_MALLOC(sizeof(char *)*numExt);
TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
for (int i = 0; i < numExt; i++)
{
extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
TRACELOG(LOG_INFO, " %s", extList[i]);
}
RL_FREE(extList); // Free extensions pointers
#endif
// Register supported extensions flags
// OpenGL 3.3 extensions supported by default (core)
RLGL.ExtSupported.vao = true;
RLGL.ExtSupported.instancing = true;
RLGL.ExtSupported.texNPOT = true;
RLGL.ExtSupported.texFloat32 = true;
RLGL.ExtSupported.texDepth = true;
RLGL.ExtSupported.maxDepthBits = 32;
RLGL.ExtSupported.texAnisoFilter = true;
RLGL.ExtSupported.texMirrorClamp = true;
// NOTE: With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans
if (GLAD_GL_EXT_texture_compression_s3tc) RLGL.ExtSupported.texCompDXT = true; // Texture compression: DXT
if (GLAD_GL_ARB_ES3_compatibility) RLGL.ExtSupported.texCompETC2 = true; // Texture compression: ETC2/EAC
#endif // GRAPHICS_API_OPENGL_33
// We get a list of available extensions and we check for some of them (compressed textures)
// NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that)
glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
// Allocate numExt strings pointers
char **extList = RL_MALLOC(sizeof(char *)*numExt);
// Get extensions strings
for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
#endif
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
// Allocate 512 strings pointers (2 KB)
const char **extList = RL_MALLOC(512*sizeof(const char *));
#if defined(GRAPHICS_API_OPENGL_ES2)
// Get supported extensions list
GLint numExt = 0;
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
// NOTE: We have to duplicate string because glGetString() returns a const string
int len = strlen(extensions) + 1;
char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char));
strcpy(extensionsDup, extensions);
extList[numExt] = extensionsDup;
for (int i = 0; i < len; i++)
@ -1650,24 +1724,21 @@ void rlglInit(int width, int height)
if (extensionsDup[i] == ' ')
{
extensionsDup[i] = '\0';
numExt++;
extList[numExt] = &extensionsDup[i + 1];
}
}
// NOTE: Duplicated string (extensionsDup) must be deallocated
#endif
TRACELOG(LOG_INFO, "GL: Supported extensions count: %i", numExt);
// Show supported extensions
//for (int i = 0; i < numExt; i++) TRACELOG(LOG_INFO, "Supported extension: %s", extList[i]);
#if defined(SUPPORT_GL_DETAILS_INFO)
TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
for (int i = 0; i < numExt; i++) TRACELOG(LOG_INFO, " %s", extList[i]);
#endif
// Check required extensions
for (int i = 0; i < numExt; i++)
{
#if defined(GRAPHICS_API_OPENGL_ES2)
// Check VAO support
// NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature
if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0)
@ -1717,162 +1788,98 @@ void rlglInit(int width, int height)
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24;
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32;
#endif
// DDS texture compression support
// Check texture compression support: DXT
if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) RLGL.ExtSupported.texCompDXT = true;
// ETC1 texture compression support
// Check texture compression support: ETC1
if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) RLGL.ExtSupported.texCompETC1 = true;
// ETC2/EAC texture compression support
// Check texture compression support: ETC2/EAC
if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) RLGL.ExtSupported.texCompETC2 = true;
// PVR texture compression support
// Check texture compression support: PVR
if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) RLGL.ExtSupported.texCompPVRT = true;
// ASTC texture compression support
// Check texture compression support: ASTC
if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) RLGL.ExtSupported.texCompASTC = true;
// Anisotropic texture filter support
if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0)
{
RLGL.ExtSupported.texAnisoFilter = true;
glGetFloatv(0x84FF, &RLGL.ExtSupported.maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
}
// Check anisotropic texture filter support
if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) RLGL.ExtSupported.texAnisoFilter = true;
// Clamp mirror wrap mode supported
// Check clamp mirror wrap mode support
if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) RLGL.ExtSupported.texMirrorClamp = true;
}
// Free extensions pointers
RL_FREE(extList);
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
RL_FREE(extensionsDup); // Duplicated string must be deallocated
#endif
#endif // GRAPHICS_API_OPENGL_ES2
#if defined(GRAPHICS_API_OPENGL_ES2)
if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions initialized successfully");
// Check OpenGL information and capabilities
//------------------------------------------------------------------------------
// Show current OpenGL and GLSL version
TRACELOG(LOG_INFO, "GL: OpenGL device information:");
TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR));
TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER));
TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION));
TRACELOG(LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
// NOTE: Anisotropy levels capability is an extension
#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
#endif
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel);
#if defined(SUPPORT_GL_DETAILS_INFO)
// Show some OpenGL GPU capabilities
TRACELOG(LOG_INFO, "GL: OpenGL capabilities:");
GLint capability = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &capability);
TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_SIZE: %i", capability);
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &capability);
TRACELOG(LOG_INFO, " GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i", capability);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &capability);
TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_IMAGE_UNITS: %i", capability);
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &capability);
TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIBS: %i", capability);
#if !defined(GRAPHICS_API_OPENGL_ES2)
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &capability);
TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_BLOCK_SIZE: %i", capability);
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &capability);
TRACELOG(LOG_INFO, " GL_MAX_DRAW_BUFFERS: %i", capability);
if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(LOG_INFO, " GL_MAX_TEXTURE_MAX_ANISOTROPY: %.0f", RLGL.ExtSupported.maxAnisotropyLevel);
#endif
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &capability);
TRACELOG(LOG_INFO, " GL_NUM_COMPRESSED_TEXTURE_FORMATS: %i", capability);
GLint format[32] = { 0 };
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
for (int i = 0; i < capability; i++) TRACELOG(LOG_INFO, " %s", rlGetCompressedFormatName(format[i]));
/*
// Following capabilities are only supported by OpenGL 4.3 or greater
glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability);
TRACELOG(LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability);
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability);
TRACELOG(LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability);
*/
#else // SUPPORT_GL_DETAILS_INFO
// Show some basic info about GL supported features
#if defined(GRAPHICS_API_OPENGL_ES2)
if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully");
else TRACELOG(LOG_WARNING, "GL: VAO extension not found, VAO not supported");
if (RLGL.ExtSupported.texNPOT) TRACELOG(LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported");
else TRACELOG(LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)");
#endif
#endif
if (RLGL.ExtSupported.texCompDXT) TRACELOG(LOG_INFO, "GL: DXT compressed textures supported");
if (RLGL.ExtSupported.texCompETC1) TRACELOG(LOG_INFO, "GL: ETC1 compressed textures supported");
if (RLGL.ExtSupported.texCompETC2) TRACELOG(LOG_INFO, "GL: ETC2/EAC compressed textures supported");
if (RLGL.ExtSupported.texCompPVRT) TRACELOG(LOG_INFO, "GL: PVRT compressed textures supported");
if (RLGL.ExtSupported.texCompASTC) TRACELOG(LOG_INFO, "GL: ASTC compressed textures supported");
if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(LOG_INFO, "GL: Anisotropic textures filtering supported (max: %.0fX)", RLGL.ExtSupported.maxAnisotropicLevel);
if (RLGL.ExtSupported.texMirrorClamp) TRACELOG(LOG_INFO, "GL: Mirror clamp wrap texture mode supported");
// Initialize buffers, default shaders and default textures
//----------------------------------------------------------
// Init default white texture
unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId);
else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture");
// Init default Shader (customized for GL 3.3 and ES2)
rlLoadShaderDefault(); // RLGL.State.defaultShader
RLGL.State.currentShader = RLGL.State.defaultShader;
// Init default vertex arrays buffers
RLGL.defaultBatch = rlLoadRenderBatch(DEFAULT_BATCH_BUFFERS, DEFAULT_BATCH_BUFFER_ELEMENTS);
RLGL.currentBatch = &RLGL.defaultBatch;
// Init stack matrices (emulating OpenGL 1.1)
for (int i = 0; i < MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = MatrixIdentity();
// Init internal matrices
RLGL.State.transform = MatrixIdentity();
RLGL.State.projection = MatrixIdentity();
RLGL.State.modelview = MatrixIdentity();
RLGL.State.currentMatrix = &RLGL.State.modelview;
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
// Initialize OpenGL default states
//----------------------------------------------------------
// Init state: Depth test
glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
// Init state: Blending mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
// Init state: Culling
// NOTE: All shapes/models triangles are drawn CCW
glCullFace(GL_BACK); // Cull the back face (default)
glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
glEnable(GL_CULL_FACE); // Enable backface culling
// Init state: Cubemap seamless
#if defined(GRAPHICS_API_OPENGL_33)
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
#endif
#if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
RLGL.State.framebufferHeight = height;
TRACELOG(LOG_INFO, "RLGL: Default state initialized successfully");
#endif
// Init state: Color/Depth buffers clear
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
}
// Vertex Buffer Object deinitialization (memory free)
void rlglClose(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
rlUnloadRenderBatch(RLGL.defaultBatch);
rlUnloadShaderDefault(); // Unload default shader
glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded default texture data from VRAM (GPU)", RLGL.State.defaultTextureId);
#endif
}
// Load OpenGL extensions
// NOTE: External loader function could be passed as a pointer
void rlLoadExtensions(void *loader)
{
#if defined(GRAPHICS_API_OPENGL_33)
// NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
#if !defined(__APPLE__)
if (!gladLoadGLLoader((GLADloadproc)loader)) TRACELOG(LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
else TRACELOG(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
#if defined(GRAPHICS_API_OPENGL_21)
if (GLAD_GL_VERSION_2_1) TRACELOG(LOG_INFO, "GL: OpenGL 2.1 profile supported");
#else
if (GLAD_GL_VERSION_3_3) TRACELOG(LOG_INFO, "GL: OpenGL 3.3 Core profile supported");
else TRACELOG(LOG_ERROR, "GL: OpenGL 3.3 Core profile not supported");
#endif
#endif
// With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans
//if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object
#endif
}
@ -1991,7 +1998,7 @@ RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
batch.vertexBuffer[i].cCounter = 0;
}
TRACELOG(LOG_INFO, "RLGL: Internal vertex buffers initialized successfully in RAM (CPU)");
TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)");
//--------------------------------------------------------------------------------------------
// Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs
@ -2038,7 +2045,7 @@ RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
#endif
}
TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully");
TRACELOG(LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)");
// Unbind the current VAO
if (RLGL.ExtSupported.vao) glBindVertexArray(0);
@ -2480,7 +2487,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
// Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0);
if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Texture created successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount);
if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Texture loaded successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount);
else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load texture");
return id;
@ -2611,7 +2618,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
#endif
if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Cubemap texture created successfully (%ix%i)", id, size, size);
if (id > 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Cubemap texture loaded successfully (%ix%i)", id, size, size);
else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load cubemap texture");
return id;
@ -3245,7 +3252,14 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
if (success == GL_FALSE)
{
TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile shader code", shader);
switch (type)
{
case GL_VERTEX_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break;
case GL_FRAGMENT_SHADER: TRACELOG(LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break;
//case GL_GEOMETRY_SHADER:
//case GL_COMPUTE_SHADER:
default: break;
}
int maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
@ -3259,7 +3273,17 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
RL_FREE(log);
}
}
else TRACELOG(LOG_INFO, "SHADER: [ID %i] Compiled successfully", shader);
else
{
switch (type)
{
case GL_VERTEX_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break;
case GL_FRAGMENT_SHADER: TRACELOG(LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break;
//case GL_GEOMETRY_SHADER:
//case GL_COMPUTE_SHADER:
default: break;
}
}
#endif
return shader;
@ -3313,7 +3337,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
program = 0;
}
else TRACELOG(LOG_INFO, "SHADER: [ID %i] Program loaded successfully", program);
else TRACELOG(LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program);
#endif
return program;
}
@ -3777,7 +3801,91 @@ static void rlUnloadShaderDefault(void)
glDeleteProgram(RLGL.State.defaultShader.id);
RL_FREE(RLGL.State.defaultShader.locs);
TRACELOG(LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShader.id);
}
#if defined(SUPPORT_GL_DETAILS_INFO)
// Get compressed format official GL identifier name
static char *rlGetCompressedFormatName(int format)
{
static char compName[64] = { 0 };
memset(compName, 0, 64);
switch (format)
{
// GL_EXT_texture_compression_s3tc
case 0x83F0: strcpy(compName, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"); break;
case 0x83F1: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"); break;
case 0x83F2: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"); break;
case 0x83F3: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"); break;
// GL_3DFX_texture_compression_FXT1
case 0x86B0: strcpy(compName, "GL_COMPRESSED_RGB_FXT1_3DFX"); break;
case 0x86B1: strcpy(compName, "GL_COMPRESSED_RGBA_FXT1_3DFX"); break;
// GL_IMG_texture_compression_pvrtc
case 0x8C00: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"); break;
case 0x8C01: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"); break;
case 0x8C02: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"); break;
case 0x8C03: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"); break;
// GL_OES_compressed_ETC1_RGB8_texture
case 0x8D64: strcpy(compName, "GL_ETC1_RGB8_OES"); break;
// GL_ARB_texture_compression_rgtc
case 0x8DBB: strcpy(compName, "GL_COMPRESSED_RED_RGTC1"); break;
case 0x8DBC: strcpy(compName, "GL_COMPRESSED_SIGNED_RED_RGTC1"); break;
case 0x8DBD: strcpy(compName, "GL_COMPRESSED_RG_RGTC2"); break;
case 0x8DBE: strcpy(compName, "GL_COMPRESSED_SIGNED_RG_RGTC2"); break;
// GL_ARB_texture_compression_bptc
case 0x8E8C: strcpy(compName, "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"); break;
case 0x8E8D: strcpy(compName, "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"); break;
case 0x8E8E: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"); break;
case 0x8E8F: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"); break;
// GL_ARB_ES3_compatibility
case 0x9274: strcpy(compName, "GL_COMPRESSED_RGB8_ETC2"); break;
case 0x9275: strcpy(compName, "GL_COMPRESSED_SRGB8_ETC2"); break;
case 0x9276: strcpy(compName, "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break;
case 0x9277: strcpy(compName, "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break;
case 0x9278: strcpy(compName, "GL_COMPRESSED_RGBA8_ETC2_EAC"); break;
case 0x9279: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"); break;
case 0x9270: strcpy(compName, "GL_COMPRESSED_R11_EAC"); break;
case 0x9271: strcpy(compName, "GL_COMPRESSED_SIGNED_R11_EAC"); break;
case 0x9272: strcpy(compName, "GL_COMPRESSED_RG11_EAC"); break;
case 0x9273: strcpy(compName, "GL_COMPRESSED_SIGNED_RG11_EAC"); break;
// GL_KHR_texture_compression_astc_hdr
case 0x93B0: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"); break;
case 0x93B1: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"); break;
case 0x93B2: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"); break;
case 0x93B3: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"); break;
case 0x93B4: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"); break;
case 0x93B5: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"); break;
case 0x93B6: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"); break;
case 0x93B7: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"); break;
case 0x93B8: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"); break;
case 0x93B9: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"); break;
case 0x93BA: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"); break;
case 0x93BB: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"); break;
case 0x93BC: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"); break;
case 0x93BD: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"); break;
case 0x93D0: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"); break;
case 0x93D1: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"); break;
case 0x93D2: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"); break;
case 0x93D3: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"); break;
case 0x93D4: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"); break;
case 0x93D5: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"); break;
case 0x93D6: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"); break;
case 0x93D7: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"); break;
case 0x93D8: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"); break;
case 0x93D9: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"); break;
case 0x93DA: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"); break;
case 0x93DB: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"); break;
case 0x93DC: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"); break;
case 0x93DD: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"); break;
default: strcpy(compName, "GL_COMPRESSED_UNKNOWN"); break;
}
return compName;
}
#endif // SUPPORT_GL_DETAILS_INFO
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
#if defined(GRAPHICS_API_OPENGL_11)