2014-09-16 22:51:31 +02:00
/**********************************************************************************************
2014-09-03 16:51:28 +02:00
*
2014-03-25 12:40:35 +01:00
* rlgl - raylib OpenGL abstraction layer
2014-09-03 16:51:28 +02:00
*
2018-06-30 21:56:26 +02:00
* rlgl is a wrapper for multiple OpenGL versions ( 1.1 , 2.1 , 3.3 Core , ES 2.0 ) to
* pseudo - OpenGL 1.1 style functions ( rlVertex , rlTranslate , rlRotate . . . ) .
2016-11-16 18:46:13 +01:00
*
2017-01-28 23:02:30 +01:00
* When chosing an OpenGL version greater than OpenGL 1.1 , rlgl stores vertex data on internal
2016-11-16 18:46:13 +01:00
* VBO buffers ( and VAOs if available ) . It requires calling 3 functions :
* rlglInit ( ) - Initialize internal buffers and auxiliar resources
* rlglDraw ( ) - Process internal buffers and send required draw calls
* rlglClose ( ) - De - initialize internal buffers data and other auxiliar resources
*
2017-02-16 00:50:02 +01:00
* CONFIGURATION :
*
* # define GRAPHICS_API_OPENGL_11
* # define GRAPHICS_API_OPENGL_21
* # define GRAPHICS_API_OPENGL_33
* # define GRAPHICS_API_OPENGL_ES2
2017-03-20 20:34:44 +01:00
* Use selected OpenGL backend
2017-02-16 00:50:02 +01:00
*
* # define RLGL_STANDALONE
* Use rlgl as standalone library ( no raylib dependency )
*
2017-04-18 11:49:02 +02:00
* # define SUPPORT_VR_SIMULATOR
2017-03-20 20:34:44 +01:00
* Support VR simulation functionality ( stereo rendering )
2017-02-16 00:50:02 +01:00
*
2017-03-25 12:01:01 +01:00
* # define SUPPORT_DISTORTION_SHADER
2017-03-20 20:34:44 +01:00
* Include stereo rendering distortion shader ( shader_distortion . h )
2017-02-16 00:50:02 +01:00
*
* DEPENDENCIES :
2016-11-16 18:46:13 +01:00
* raymath - 3 D math functionality ( Vector3 , Matrix , Quaternion )
* GLAD - OpenGL extensions loading ( OpenGL 3.3 Core only )
*
*
2017-02-16 00:50:02 +01:00
* LICENSE : zlib / libpng
2014-09-03 16:51:28 +02:00
*
2017-12-20 12:35:12 +01:00
* Copyright ( c ) 2014 - 2018 Ramon Santamaria ( @ raysan5 )
2014-09-03 16:51:28 +02:00
*
* This software is provided " as-is " , without any express or implied warranty . In no event
2014-03-25 12:40:35 +01:00
* will the authors be held liable for any damages arising from the use of this software .
*
2014-09-03 16:51:28 +02:00
* Permission is granted to anyone to use this software for any purpose , including commercial
2014-03-25 12:40:35 +01:00
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
*
2014-09-03 16:51:28 +02:00
* 1. The origin of this software must not be misrepresented ; you must not claim that you
* wrote the original software . If you use this software in a product , an acknowledgment
2014-03-25 12:40:35 +01:00
* in the product documentation would be appreciated but is not required .
*
* 2. Altered source versions must be plainly marked as such , and must not be misrepresented
* as being the original software .
*
* 3. This notice may not be removed or altered from any source distribution .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-04-07 22:29:53 +02:00
# include "config.h"
2017-03-25 12:01:01 +01:00
2014-03-25 12:40:35 +01:00
# include "rlgl.h"
2017-01-15 01:09:15 +01:00
# include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on LoadText()]
2016-06-02 01:26:44 +02:00
# include <stdlib.h> // Required for: malloc(), free(), rand()
2017-04-30 13:03:31 +02:00
# include <string.h> // Required for: strcmp(), strlen(), strtok() [Used only in extensions loading]
2016-07-10 20:09:18 +02:00
# include <math.h> // Required for: atan2()
2014-03-25 12:40:35 +01:00
2017-05-08 02:47:44 +02:00
# if !defined(RLGL_STANDALONE)
2016-10-31 20:39:03 +01:00
# include "raymath.h" // Required for: Vector3 and Matrix functions
2016-03-20 13:39:27 +01:00
# endif
2016-01-20 18:20:05 +01:00
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2017-05-08 02:47:44 +02:00
# if defined(__APPLE__)
2016-06-02 01:26:44 +02:00
# include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
2018-01-25 22:43:45 +01:00
# include <OpenGL/glext.h>
2015-02-02 00:57:08 +01:00
# else
2018-02-21 23:47:48 +01:00
// APIENTRY for OpenGL function pointer declarations is required
# ifndef APIENTRY
# ifdef _WIN32
# define APIENTRY __stdcall
# else
# define APIENTRY
# endif
# endif
// WINGDIAPI definition. Some Windows OpenGL headers need it
# if !defined(WINGDIAPI) && defined(_WIN32)
# define WINGDIAPI __declspec(dllimport)
# endif
2018-01-17 14:21:23 +01:00
2018-05-20 01:55:46 +02:00
# include <GL/gl.h> // OpenGL 1.1 library
2015-02-02 00:57:08 +01:00
# endif
2014-03-25 12:40:35 +01:00
# endif
2016-06-16 20:25:50 +02:00
# if defined(GRAPHICS_API_OPENGL_21)
2018-05-20 01:55:46 +02:00
# define GRAPHICS_API_OPENGL_33 // OpenGL 2.1 uses mostly OpenGL 3.3 Core functionality
2016-06-16 20:25:50 +02:00
# endif
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2017-05-08 02:47:44 +02:00
# if defined(__APPLE__)
2018-05-20 01:55:46 +02:00
# include <OpenGL/gl3.h> // OpenGL 3 library for OSX
# include <OpenGL/gl3ext.h> // OpenGL 3 extensions library for OSX
2015-02-02 00:57:08 +01:00
# else
2017-08-04 19:18:55 +02:00
# define GLAD_IMPLEMENTATION
# if defined(RLGL_STANDALONE)
# include "glad.h" // GLAD extensions loading library, includes OpenGL headers
# else
# include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers
# endif
2014-11-22 00:13:09 +01:00
# endif
2014-03-25 12:40:35 +01:00
# endif
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2018-05-20 01:55:46 +02:00
# include <EGL/egl.h> // EGL library
# include <GLES2/gl2.h> // OpenGL ES 2.0 library
# include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library
2014-09-16 22:51:31 +02:00
# endif
2014-03-25 12:40:35 +01:00
2015-08-05 19:18:40 +02:00
# if defined(RLGL_STANDALONE)
2018-05-20 01:55:46 +02:00
# include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()]
2016-06-02 20:23:09 +02:00
# endif
2015-08-05 19:18:40 +02:00
2017-03-25 12:01:01 +01:00
# if !defined(GRAPHICS_API_OPENGL_11) && defined(SUPPORT_DISTORTION_SHADER)
2018-05-20 01:55:46 +02:00
# include "shader_distortion.h" // Distortion shader to be embedded
2016-06-07 00:32:45 +02:00
# endif
2018-01-25 22:43:45 +01:00
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2014-04-04 20:11:57 +02:00
# define MATRIX_STACK_SIZE 16 // Matrix stack max size
2014-03-25 12:40:35 +01:00
# define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
2014-04-09 20:25:26 +02:00
# define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
2014-09-16 22:51:31 +02:00
// NOTE: Every vertex are 3 floats (12 bytes)
2014-03-25 12:40:35 +01:00
2015-05-11 00:15:46 +02:00
# ifndef GL_SHADING_LANGUAGE_VERSION
# define GL_SHADING_LANGUAGE_VERSION 0x8B8C
# endif
2015-04-06 14:02:29 +02:00
# ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_ETC1_RGB8_OES
2015-05-11 00:15:46 +02:00
# define GL_ETC1_RGB8_OES 0x8D64
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_COMPRESSED_RGB8_ETC2
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGB8_ETC2 0x9274
2015-04-06 14:02:29 +02:00
# endif
# ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
2015-05-11 00:15:46 +02:00
# define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
# endif
# ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
# define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
# endif
# ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
# define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
# endif
# ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR
# define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0
# endif
# ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR
# define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7
2015-04-06 14:02:29 +02:00
# endif
2016-10-29 22:17:19 +02:00
# ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
# endif
# ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
# endif
2015-05-11 00:15:46 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2017-03-14 01:05:22 +01:00
# define GL_UNSIGNED_SHORT_5_6_5 0x8363
# define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
# define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
2015-05-11 00:15:46 +02:00
# endif
2016-05-09 12:41:53 +02:00
2017-11-05 09:58:25 +01:00
# if defined(GRAPHICS_API_OPENGL_21)
# define GL_LUMINANCE 0x1909
# define GL_LUMINANCE_ALPHA 0x190A
# endif
2016-06-26 18:43:10 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
# define glClearDepth glClearDepthf
# define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
# define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
2016-06-26 18:43:10 +02:00
# endif
2016-05-09 12:41:53 +02:00
// Default vertex attribute names on shader to set location points
# define DEFAULT_ATTRIB_POSITION_NAME "vertexPosition" // shader-location = 0
# define DEFAULT_ATTRIB_TEXCOORD_NAME "vertexTexCoord" // shader-location = 1
# define DEFAULT_ATTRIB_NORMAL_NAME "vertexNormal" // shader-location = 2
# define DEFAULT_ATTRIB_COLOR_NAME "vertexColor" // shader-location = 3
# define DEFAULT_ATTRIB_TANGENT_NAME "vertexTangent" // shader-location = 4
# define DEFAULT_ATTRIB_TEXCOORD2_NAME "vertexTexCoord2" // shader-location = 5
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2016-05-12 12:20:23 +02:00
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
2016-12-27 17:37:35 +01:00
typedef struct DynamicBuffer {
2016-05-12 12:20:23 +02:00
int vCounter ; // vertex position counter to process (and draw) from full buffer
int tcCounter ; // vertex texcoord counter to process (and draw) from full buffer
int cCounter ; // vertex color counter to process (and draw) from full buffer
float * vertices ; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float * texcoords ; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
unsigned char * colors ; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2016-05-12 12:20:23 +02:00
unsigned int * indices ; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-05-12 12:20:23 +02:00
unsigned short * indices ; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
2014-09-16 22:51:31 +02:00
// NOTE: 6*2 byte = 12 byte, not alignment problem!
# endif
2016-05-12 12:20:23 +02:00
unsigned int vaoId ; // OpenGL Vertex Array Object id
unsigned int vboId [ 4 ] ; // OpenGL Vertex Buffer Objects id (4 types of vertex data)
} DynamicBuffer ;
2014-03-25 12:40:35 +01:00
2014-04-19 16:36:49 +02:00
// Draw call type
// NOTE: Used to track required draw-calls, organized by texture
2016-12-27 17:37:35 +01:00
typedef struct DrawCall {
2014-04-19 16:36:49 +02:00
int vertexCount ;
2016-06-12 19:40:08 +02:00
GLuint vaoId ;
GLuint textureId ;
GLuint shaderId ;
Matrix projection ;
Matrix modelview ;
// TODO: Store additional draw state data
//int blendMode;
//Guint fboId;
2014-03-25 12:40:35 +01:00
} DrawCall ;
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2016-07-10 20:09:18 +02:00
// VR Stereo rendering configuration for simulator
2016-12-27 17:37:35 +01:00
typedef struct VrStereoConfig {
2016-07-10 20:09:18 +02:00
RenderTexture2D stereoFbo ; // VR stereo rendering framebuffer
Shader distortionShader ; // VR stereo rendering distortion shader
2017-11-12 11:00:28 +01:00
Rectangle eyesViewport [ 2 ] ; // VR stereo rendering eyes viewports
2016-07-10 20:09:18 +02:00
Matrix eyesProjection [ 2 ] ; // VR stereo rendering eyes projection matrices
Matrix eyesViewOffset [ 2 ] ; // VR stereo rendering eyes view offset matrices
} VrStereoConfig ;
2017-04-18 11:49:02 +02:00
# endif
2016-07-10 20:09:18 +02:00
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 12:40:35 +01:00
static Matrix stack [ MATRIX_STACK_SIZE ] ;
static int stackCounter = 0 ;
static Matrix modelview ;
static Matrix projection ;
static Matrix * currentMatrix ;
static int currentMatrixMode ;
2017-03-21 13:21:07 +01:00
static int currentDrawMode ;
2014-03-25 12:40:35 +01:00
2015-09-21 12:48:43 +02:00
static float currentDepth = - 1.0f ;
2016-07-13 20:05:00 +02:00
static DynamicBuffer lines ; // Default dynamic buffer for lines data
static DynamicBuffer triangles ; // Default dynamic buffer for triangles data
static DynamicBuffer quads ; // Default dynamic buffer for quads data (used to draw textures)
2014-03-25 12:40:35 +01:00
2016-05-03 19:20:25 +02:00
// Default buffers draw calls
2014-03-25 12:40:35 +01:00
static DrawCall * draws ;
static int drawsCounter ;
// Temp vertex buffer to be used with rlTranslate, rlRotate, rlScale
static Vector3 * tempBuffer ;
static int tempBufferCount = 0 ;
static bool useTempBuffer = false ;
2017-11-09 20:47:22 +01:00
// Shaders
2017-11-12 10:33:44 +01:00
static unsigned int defaultVShaderId ; // Default vertex shader id (used by default shader program)
static unsigned int defaultFShaderId ; // Default fragment shader Id (used by default shader program)
2018-01-19 11:41:51 +01:00
2016-07-13 20:05:00 +02:00
static Shader defaultShader ; // Basic shader, support vertex color and diffuse texture
static Shader currentShader ; // Shader to be used on rendering (by default, defaultShader)
2016-05-03 19:20:25 +02:00
2016-10-29 22:17:19 +02:00
// Extension supported flag: VAO
2016-06-07 00:32:45 +02:00
static bool vaoSupported = false ; // VAO support (OpenGL ES2 could not support VAO extension)
2015-05-21 00:18:22 +02:00
2016-10-29 22:17:19 +02:00
// Extension supported flag: Compressed textures
2016-06-07 00:32:45 +02:00
static bool texCompETC1Supported = false ; // ETC1 texture compression support
static bool texCompETC2Supported = false ; // ETC2/EAC texture compression support
static bool texCompPVRTSupported = false ; // PVR texture compression support
static bool texCompASTCSupported = false ; // ASTC texture compression support
2017-03-20 20:34:44 +01:00
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2017-03-20 20:34:44 +01:00
// VR global variables
static VrStereoConfig vrConfig ; // VR stereo configuration for simulator
static bool vrSimulatorReady = false ; // VR simulator ready flag
static bool vrStereoRender = false ; // VR stereo rendering enabled/disabled flag
// NOTE: This flag is useful to render data over stereo image (i.e. FPS)
2017-04-18 11:49:02 +02:00
# endif // defined(SUPPORT_VR_SIMULATOR)
# endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-10-29 22:17:19 +02:00
// Extension supported flag: Anisotropic filtering
static bool texAnisotropicFilterSupported = false ; // Anisotropic texture filtering support
2018-05-20 01:55:46 +02:00
static float maxAnisotropicLevel = 0.0f ; // Maximum anisotropy level supported (minimum is 2.0f)
2016-10-29 22:17:19 +02:00
// Extension supported flag: Clamp mirror wrap mode
2018-05-20 01:55:46 +02:00
static bool texClampMirrorSupported = false ; // Clamp mirror wrap mode supported
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: VAO functionality is exposed through extensions (OES)
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays ;
static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray ;
static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays ;
2018-05-20 01:55:46 +02:00
//static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted
2014-03-25 12:40:35 +01:00
# endif
2017-12-14 11:44:48 +01:00
static bool debugMarkerSupported = false ;
2016-07-10 20:09:18 +02:00
// Compressed textures support flags
static bool texCompDXTSupported = false ; // DDS texture compression support
2017-07-20 12:26:25 +02:00
static bool texNPOTSupported = false ; // NPOT textures full support
2017-05-08 12:31:47 +02:00
static bool texFloatSupported = false ; // float textures support (32 bit per channel)
2016-07-10 20:09:18 +02:00
2016-06-24 19:37:52 +02:00
static int blendMode = 0 ; // Track current blending mode
2015-08-07 17:24:28 +02:00
2014-12-31 19:25:39 +01:00
// White texture useful for plain color polys (required by shader)
2016-06-11 12:41:03 +02:00
static unsigned int whiteTexture ;
2014-12-31 19:25:39 +01:00
2017-03-14 01:05:22 +01:00
// Default framebuffer size
2016-06-24 19:37:52 +02:00
static int screenWidth ; // Default framebuffer width
static int screenHeight ; // Default framebuffer height
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-11-12 10:33:44 +01:00
static unsigned int CompileShader ( const char * shaderStr , int type ) ; // Compile custom shader and return shader id
static unsigned int LoadShaderProgram ( unsigned int vShaderId , unsigned int fShaderId ) ; // Load custom shader program
2016-05-03 19:20:25 +02:00
2017-07-17 00:33:40 +02:00
static Shader LoadShaderDefault ( void ) ; // Load default shader (just vertex positioning and texture coloring)
static void SetShaderDefaultLocations ( Shader * shader ) ; // Bind default shader locations (attributes and uniforms)
2017-07-17 12:02:46 +02:00
static void UnloadShaderDefault ( void ) ; // Unload default shader
2015-05-21 00:18:22 +02:00
2017-07-19 10:09:34 +02:00
static void LoadBuffersDefault ( void ) ; // Load default internal buffers (lines, triangles, quads)
static void UpdateBuffersDefault ( void ) ; // Update default internal buffers (VAOs/VBOs) with vertex data
static void DrawBuffersDefault ( void ) ; // Draw default internal buffers vertex data
static void UnloadBuffersDefault ( void ) ; // Unload default internal buffers vertex data from CPU and GPU
2016-05-03 19:20:25 +02:00
2017-07-19 10:09:34 +02:00
static void GenDrawCube ( void ) ; // Generate and draw cube
static void GenDrawQuad ( void ) ; // Generate and draw quad
2017-07-17 00:33:40 +02:00
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
static void SetStereoConfig ( VrDeviceInfo info ) ; // Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetStereoView ( int eye , Matrix matProjection , Matrix matModelView ) ; // Set internal projection and modelview matrix depending on eye
2014-03-25 12:40:35 +01:00
# endif
2017-04-18 11:49:02 +02:00
# endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2018-02-21 23:47:48 +01:00
// Get OpenGL internal formats and data type from raylib PixelFormat
static void GetGlFormats ( int format , int * glInternalFormat , int * glFormat , int * glType ) ;
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 16:36:49 +02:00
static int GenerateMipmaps ( unsigned char * data , int baseWidth , int baseHeight ) ;
2016-04-01 10:39:33 +02:00
static Color * GenNextMipmap ( Color * srcData , int srcWidth , int srcHeight ) ;
2014-04-19 16:36:49 +02:00
# endif
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix operations
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 12:40:35 +01:00
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
2014-09-03 16:51:28 +02:00
void rlMatrixMode ( int mode )
{
switch ( mode )
2014-03-25 12:40:35 +01:00
{
case RL_PROJECTION : glMatrixMode ( GL_PROJECTION ) ; break ;
2014-09-03 16:51:28 +02:00
case RL_MODELVIEW : glMatrixMode ( GL_MODELVIEW ) ; break ;
2014-03-25 12:40:35 +01:00
case RL_TEXTURE : glMatrixMode ( GL_TEXTURE ) ; break ;
default : break ;
}
}
2016-07-29 13:17:50 +02:00
void rlFrustum ( double left , double right , double bottom , double top , double zNear , double zFar )
2014-09-03 16:51:28 +02:00
{
2016-07-29 13:17:50 +02:00
glFrustum ( left , right , bottom , top , zNear , zFar ) ;
2014-03-25 12:40:35 +01:00
}
2016-07-29 13:17:50 +02:00
void rlOrtho ( double left , double right , double bottom , double top , double zNear , double zFar )
2014-09-03 16:51:28 +02:00
{
2016-07-29 13:17:50 +02:00
glOrtho ( left , right , bottom , top , zNear , zFar ) ;
2014-03-25 12:40:35 +01:00
}
2014-09-03 17:06:10 +02:00
void rlPushMatrix ( void ) { glPushMatrix ( ) ; }
void rlPopMatrix ( void ) { glPopMatrix ( ) ; }
void rlLoadIdentity ( void ) { glLoadIdentity ( ) ; }
2014-03-25 12:40:35 +01:00
void rlTranslatef ( float x , float y , float z ) { glTranslatef ( x , y , z ) ; }
void rlRotatef ( float angleDeg , float x , float y , float z ) { glRotatef ( angleDeg , x , y , z ) ; }
void rlScalef ( float x , float y , float z ) { glScalef ( x , y , z ) ; }
2017-07-21 17:19:28 +02:00
void rlMultMatrixf ( float * matf ) { glMultMatrixf ( matf ) ; }
2014-03-25 12:40:35 +01:00
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 12:40:35 +01:00
// Choose the current matrix to be transformed
void rlMatrixMode ( int mode )
{
if ( mode = = RL_PROJECTION ) currentMatrix = & projection ;
else if ( mode = = RL_MODELVIEW ) currentMatrix = & modelview ;
2014-04-19 16:36:49 +02:00
//else if (mode == RL_TEXTURE) // Not supported
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
currentMatrixMode = mode ;
}
// Push the current matrix to stack
2014-09-03 17:06:10 +02:00
void rlPushMatrix ( void )
2014-03-25 12:40:35 +01:00
{
if ( stackCounter = = MATRIX_STACK_SIZE - 1 )
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_ERROR , " Stack Buffer Overflow (MAX %i Matrix) " , MATRIX_STACK_SIZE ) ;
2014-03-25 12:40:35 +01:00
}
stack [ stackCounter ] = * currentMatrix ;
2018-01-08 01:03:04 +01:00
rlLoadIdentity ( ) ; // TODO: Review matrix stack logic!
2014-03-25 12:40:35 +01:00
stackCounter + + ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
if ( currentMatrixMode = = RL_MODELVIEW ) useTempBuffer = true ;
}
// Pop lattest inserted matrix from stack
2014-09-03 17:06:10 +02:00
void rlPopMatrix ( void )
2014-03-25 12:40:35 +01:00
{
if ( stackCounter > 0 )
2014-09-03 16:51:28 +02:00
{
Matrix mat = stack [ stackCounter - 1 ] ;
2014-03-25 12:40:35 +01:00
* currentMatrix = mat ;
stackCounter - - ;
}
}
// Reset current matrix to identity matrix
2014-09-03 17:06:10 +02:00
void rlLoadIdentity ( void )
2014-03-25 12:40:35 +01:00
{
* currentMatrix = MatrixIdentity ( ) ;
}
// Multiply the current matrix by a translation matrix
void rlTranslatef ( float x , float y , float z )
{
2016-01-04 20:02:57 +01:00
Matrix matTranslation = MatrixTranslate ( x , y , z ) ;
2014-09-03 16:51:28 +02:00
2017-08-04 18:34:51 +02:00
// NOTE: We transpose matrix with multiplication order
* currentMatrix = MatrixMultiply ( matTranslation , * currentMatrix ) ;
2014-03-25 12:40:35 +01:00
}
// Multiply the current matrix by a rotation matrix
void rlRotatef ( float angleDeg , float x , float y , float z )
{
2016-01-04 20:02:57 +01:00
Matrix matRotation = MatrixIdentity ( ) ;
2014-09-03 16:51:28 +02:00
2015-05-11 00:15:46 +02:00
Vector3 axis = ( Vector3 ) { x , y , z } ;
2018-04-02 15:16:45 +02:00
matRotation = MatrixRotate ( Vector3Normalize ( axis ) , angleDeg * DEG2RAD ) ;
2014-09-03 16:51:28 +02:00
2017-08-04 18:34:51 +02:00
// NOTE: We transpose matrix with multiplication order
* currentMatrix = MatrixMultiply ( matRotation , * currentMatrix ) ;
2014-03-25 12:40:35 +01:00
}
// Multiply the current matrix by a scaling matrix
void rlScalef ( float x , float y , float z )
{
2016-01-04 20:02:57 +01:00
Matrix matScale = MatrixScale ( x , y , z ) ;
2014-09-03 16:51:28 +02:00
2017-08-04 18:34:51 +02:00
// NOTE: We transpose matrix with multiplication order
* currentMatrix = MatrixMultiply ( matScale , * currentMatrix ) ;
2014-03-25 12:40:35 +01:00
}
// Multiply the current matrix by another matrix
2017-07-21 17:19:28 +02:00
void rlMultMatrixf ( float * matf )
2014-03-25 12:40:35 +01:00
{
2015-02-09 18:29:32 +01:00
// Matrix creation from array
2017-07-21 17:19:28 +02:00
Matrix mat = { matf [ 0 ] , matf [ 4 ] , matf [ 8 ] , matf [ 12 ] ,
matf [ 1 ] , matf [ 5 ] , matf [ 9 ] , matf [ 13 ] ,
matf [ 2 ] , matf [ 6 ] , matf [ 10 ] , matf [ 14 ] ,
matf [ 3 ] , matf [ 7 ] , matf [ 11 ] , matf [ 15 ] } ;
2014-03-25 12:40:35 +01:00
2017-07-21 17:19:28 +02:00
* currentMatrix = MatrixMultiply ( * currentMatrix , mat ) ;
2014-03-25 12:40:35 +01:00
}
// Multiply the current matrix by a perspective matrix generated by parameters
void rlFrustum ( double left , double right , double bottom , double top , double near , double far )
{
Matrix matPerps = MatrixFrustum ( left , right , bottom , top , near , far ) ;
* currentMatrix = MatrixMultiply ( * currentMatrix , matPerps ) ;
}
// Multiply the current matrix by an orthographic matrix generated by parameters
2014-09-03 16:51:28 +02:00
void rlOrtho ( double left , double right , double bottom , double top , double near , double far )
2014-03-25 12:40:35 +01:00
{
Matrix matOrtho = MatrixOrtho ( left , right , bottom , top , near , far ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
* currentMatrix = MatrixMultiply ( * currentMatrix , matOrtho ) ;
}
# endif
2016-06-25 23:28:50 +02:00
// Set the viewport area (transformation from normalized device coordinates to window coordinates)
// NOTE: Updates global variables: screenWidth, screenHeight
2016-05-29 11:49:13 +02:00
void rlViewport ( int x , int y , int width , int height )
{
glViewport ( x , y , width , height ) ;
}
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Vertex level operations
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 12:40:35 +01:00
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
2014-09-03 16:51:28 +02:00
void rlBegin ( int mode )
2014-03-25 12:40:35 +01:00
{
switch ( mode )
{
case RL_LINES : glBegin ( GL_LINES ) ; break ;
case RL_TRIANGLES : glBegin ( GL_TRIANGLES ) ; break ;
case RL_QUADS : glBegin ( GL_QUADS ) ; break ;
default : break ;
}
}
2014-09-16 22:51:31 +02:00
void rlEnd ( ) { glEnd ( ) ; }
2014-03-25 12:40:35 +01:00
void rlVertex2i ( int x , int y ) { glVertex2i ( x , y ) ; }
void rlVertex2f ( float x , float y ) { glVertex2f ( x , y ) ; }
void rlVertex3f ( float x , float y , float z ) { glVertex3f ( x , y , z ) ; }
void rlTexCoord2f ( float x , float y ) { glTexCoord2f ( x , y ) ; }
void rlNormal3f ( float x , float y , float z ) { glNormal3f ( x , y , z ) ; }
void rlColor4ub ( byte r , byte g , byte b , byte a ) { glColor4ub ( r , g , b , a ) ; }
void rlColor3f ( float x , float y , float z ) { glColor3f ( x , y , z ) ; }
void rlColor4f ( float x , float y , float z , float w ) { glColor4f ( x , y , z , w ) ; }
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 12:40:35 +01:00
// Initialize drawing mode (how to organize vertex)
void rlBegin ( int mode )
{
// Draw mode can only be RL_LINES, RL_TRIANGLES and RL_QUADS
currentDrawMode = mode ;
}
// Finish vertex providing
2014-09-03 17:06:10 +02:00
void rlEnd ( void )
2014-03-25 12:40:35 +01:00
{
if ( useTempBuffer )
{
2014-04-19 16:36:49 +02:00
// NOTE: In this case, *currentMatrix is already transposed because transposing has been applied
// independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1)
// This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1
2014-03-25 12:40:35 +01:00
// Apply transformation matrix to all temp vertices
2018-03-16 13:47:01 +01:00
for ( int i = 0 ; i < tempBufferCount ; i + + ) tempBuffer [ i ] = Vector3Transform ( tempBuffer [ i ] , * currentMatrix ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Deactivate tempBuffer usage to allow rlVertex3f do its job
useTempBuffer = false ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Copy all transformed vertices to right VAO
for ( int i = 0 ; i < tempBufferCount ; i + + ) rlVertex3f ( tempBuffer [ i ] . x , tempBuffer [ i ] . y , tempBuffer [ i ] . z ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Reset temp buffer
tempBufferCount = 0 ;
}
2014-04-19 16:36:49 +02:00
// Make sure vertexCount is the same for vertices-texcoords-normals-colors
2014-03-25 12:40:35 +01:00
// NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls.
switch ( currentDrawMode )
{
case RL_LINES :
{
if ( lines . vCounter ! = lines . cCounter )
{
int addColors = lines . vCounter - lines . cCounter ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
for ( int i = 0 ; i < addColors ; i + + )
{
lines . colors [ 4 * lines . cCounter ] = lines . colors [ 4 * lines . cCounter - 4 ] ;
lines . colors [ 4 * lines . cCounter + 1 ] = lines . colors [ 4 * lines . cCounter - 3 ] ;
lines . colors [ 4 * lines . cCounter + 2 ] = lines . colors [ 4 * lines . cCounter - 2 ] ;
lines . colors [ 4 * lines . cCounter + 3 ] = lines . colors [ 4 * lines . cCounter - 1 ] ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
lines . cCounter + + ;
}
}
} break ;
case RL_TRIANGLES :
{
if ( triangles . vCounter ! = triangles . cCounter )
{
int addColors = triangles . vCounter - triangles . cCounter ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
for ( int i = 0 ; i < addColors ; i + + )
{
triangles . colors [ 4 * triangles . cCounter ] = triangles . colors [ 4 * triangles . cCounter - 4 ] ;
triangles . colors [ 4 * triangles . cCounter + 1 ] = triangles . colors [ 4 * triangles . cCounter - 3 ] ;
triangles . colors [ 4 * triangles . cCounter + 2 ] = triangles . colors [ 4 * triangles . cCounter - 2 ] ;
triangles . colors [ 4 * triangles . cCounter + 3 ] = triangles . colors [ 4 * triangles . cCounter - 1 ] ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
triangles . cCounter + + ;
}
2014-09-03 16:51:28 +02:00
}
2014-03-25 12:40:35 +01:00
} break ;
case RL_QUADS :
{
// Make sure colors count match vertex count
if ( quads . vCounter ! = quads . cCounter )
{
int addColors = quads . vCounter - quads . cCounter ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
for ( int i = 0 ; i < addColors ; i + + )
{
quads . colors [ 4 * quads . cCounter ] = quads . colors [ 4 * quads . cCounter - 4 ] ;
quads . colors [ 4 * quads . cCounter + 1 ] = quads . colors [ 4 * quads . cCounter - 3 ] ;
quads . colors [ 4 * quads . cCounter + 2 ] = quads . colors [ 4 * quads . cCounter - 2 ] ;
quads . colors [ 4 * quads . cCounter + 3 ] = quads . colors [ 4 * quads . cCounter - 1 ] ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
quads . cCounter + + ;
}
}
// Make sure texcoords count match vertex count
if ( quads . vCounter ! = quads . tcCounter )
{
int addTexCoords = quads . vCounter - quads . tcCounter ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
for ( int i = 0 ; i < addTexCoords ; i + + )
{
quads . texcoords [ 2 * quads . tcCounter ] = 0.0f ;
quads . texcoords [ 2 * quads . tcCounter + 1 ] = 0.0f ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
quads . tcCounter + + ;
}
}
2014-09-03 16:51:28 +02:00
2015-02-09 18:29:32 +01:00
// TODO: Make sure normals count match vertex count... if normals support is added in a future... :P
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
default : break ;
}
2017-01-28 23:02:30 +01:00
2015-09-21 12:48:43 +02:00
// NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
// as well as depth buffer bit-depth (16bit or 24bit or 32bit)
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
currentDepth + = ( 1.0f / 20000.0f ) ;
2018-06-30 21:56:26 +02:00
2018-05-20 01:55:46 +02:00
// Verify internal buffers limits
// NOTE: This check is combined with usage of rlCheckBufferLimit()
2018-01-07 23:54:11 +01:00
if ( ( lines . vCounter / 2 > = MAX_LINES_BATCH - 2 ) | |
2018-05-20 01:55:46 +02:00
( triangles . vCounter / 3 > = MAX_TRIANGLES_BATCH - 3 ) | |
( quads . vCounter / 4 > = MAX_QUADS_BATCH - 4 ) ) rlglDraw ( ) ;
2014-03-25 12:40:35 +01:00
}
// Define one vertex (position)
void rlVertex3f ( float x , float y , float z )
{
if ( useTempBuffer )
{
tempBuffer [ tempBufferCount ] . x = x ;
tempBuffer [ tempBufferCount ] . y = y ;
tempBuffer [ tempBufferCount ] . z = z ;
tempBufferCount + + ;
}
else
{
switch ( currentDrawMode )
{
case RL_LINES :
{
2014-09-16 22:51:31 +02:00
// Verify that MAX_LINES_BATCH limit not reached
2016-09-12 19:36:41 +02:00
if ( lines . vCounter / 2 < MAX_LINES_BATCH )
2014-09-16 22:51:31 +02:00
{
lines . vertices [ 3 * lines . vCounter ] = x ;
lines . vertices [ 3 * lines . vCounter + 1 ] = y ;
lines . vertices [ 3 * lines . vCounter + 2 ] = z ;
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
lines . vCounter + + ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_ERROR , " MAX_LINES_BATCH overflow " ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
case RL_TRIANGLES :
{
2014-09-16 22:51:31 +02:00
// Verify that MAX_TRIANGLES_BATCH limit not reached
2016-09-12 19:36:41 +02:00
if ( triangles . vCounter / 3 < MAX_TRIANGLES_BATCH )
2014-09-16 22:51:31 +02:00
{
triangles . vertices [ 3 * triangles . vCounter ] = x ;
triangles . vertices [ 3 * triangles . vCounter + 1 ] = y ;
triangles . vertices [ 3 * triangles . vCounter + 2 ] = z ;
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
triangles . vCounter + + ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_ERROR , " MAX_TRIANGLES_BATCH overflow " ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
case RL_QUADS :
{
2014-09-16 22:51:31 +02:00
// Verify that MAX_QUADS_BATCH limit not reached
2016-09-12 19:36:41 +02:00
if ( quads . vCounter / 4 < MAX_QUADS_BATCH )
2014-09-16 22:51:31 +02:00
{
quads . vertices [ 3 * quads . vCounter ] = x ;
quads . vertices [ 3 * quads . vCounter + 1 ] = y ;
quads . vertices [ 3 * quads . vCounter + 2 ] = z ;
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
quads . vCounter + + ;
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
draws [ drawsCounter - 1 ] . vertexCount + + ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_ERROR , " MAX_QUADS_BATCH overflow " ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
default : break ;
}
}
}
// Define one vertex (position)
void rlVertex2f ( float x , float y )
{
2015-09-21 12:48:43 +02:00
rlVertex3f ( x , y , currentDepth ) ;
2014-03-25 12:40:35 +01:00
}
// Define one vertex (position)
void rlVertex2i ( int x , int y )
{
2015-09-21 12:48:43 +02:00
rlVertex3f ( ( float ) x , ( float ) y , currentDepth ) ;
2014-03-25 12:40:35 +01:00
}
// Define one vertex (texture coordinate)
2014-09-16 22:51:31 +02:00
// NOTE: Texture coordinates are limited to QUADS only
2014-03-25 12:40:35 +01:00
void rlTexCoord2f ( float x , float y )
{
if ( currentDrawMode = = RL_QUADS )
{
quads . texcoords [ 2 * quads . tcCounter ] = x ;
quads . texcoords [ 2 * quads . tcCounter + 1 ] = y ;
quads . tcCounter + + ;
}
}
// Define one vertex (normal)
// NOTE: Normals limited to TRIANGLES only ?
void rlNormal3f ( float x , float y , float z )
{
// TODO: Normals usage...
}
// Define one vertex (color)
2014-07-23 00:06:24 +02:00
void rlColor4ub ( byte x , byte y , byte z , byte w )
2014-03-25 12:40:35 +01:00
{
switch ( currentDrawMode )
{
case RL_LINES :
{
lines . colors [ 4 * lines . cCounter ] = x ;
lines . colors [ 4 * lines . cCounter + 1 ] = y ;
lines . colors [ 4 * lines . cCounter + 2 ] = z ;
lines . colors [ 4 * lines . cCounter + 3 ] = w ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
lines . cCounter + + ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
case RL_TRIANGLES :
{
triangles . colors [ 4 * triangles . cCounter ] = x ;
triangles . colors [ 4 * triangles . cCounter + 1 ] = y ;
triangles . colors [ 4 * triangles . cCounter + 2 ] = z ;
triangles . colors [ 4 * triangles . cCounter + 3 ] = w ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
triangles . cCounter + + ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
case RL_QUADS :
{
quads . colors [ 4 * quads . cCounter ] = x ;
quads . colors [ 4 * quads . cCounter + 1 ] = y ;
quads . colors [ 4 * quads . cCounter + 2 ] = z ;
quads . colors [ 4 * quads . cCounter + 3 ] = w ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
quads . cCounter + + ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
} break ;
default : break ;
}
}
// Define one vertex (color)
2014-07-23 00:06:24 +02:00
void rlColor4f ( float r , float g , float b , float a )
2014-03-25 12:40:35 +01:00
{
2014-09-03 16:51:28 +02:00
rlColor4ub ( ( byte ) ( r * 255 ) , ( byte ) ( g * 255 ) , ( byte ) ( b * 255 ) , ( byte ) ( a * 255 ) ) ;
2014-03-25 12:40:35 +01:00
}
// Define one vertex (color)
void rlColor3f ( float x , float y , float z )
{
2014-07-23 00:06:24 +02:00
rlColor4ub ( ( byte ) ( x * 255 ) , ( byte ) ( y * 255 ) , ( byte ) ( z * 255 ) , 255 ) ;
2014-03-25 12:40:35 +01:00
}
# endif
//----------------------------------------------------------------------------------
// Module Functions Definition - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
//----------------------------------------------------------------------------------
// Enable texture usage
void rlEnableTexture ( unsigned int id )
{
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 12:40:35 +01:00
glEnable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , id ) ;
# endif
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-04-19 16:36:49 +02:00
if ( draws [ drawsCounter - 1 ] . textureId ! = id )
2014-03-25 12:40:35 +01:00
{
2014-04-19 16:36:49 +02:00
if ( draws [ drawsCounter - 1 ] . vertexCount > 0 ) drawsCounter + + ;
2018-06-30 21:56:26 +02:00
2017-09-13 22:23:24 +02:00
if ( drawsCounter > = MAX_DRAWS_BY_TEXTURE )
{
rlglDraw ( ) ;
drawsCounter = 1 ;
}
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
draws [ drawsCounter - 1 ] . textureId = id ;
draws [ drawsCounter - 1 ] . vertexCount = 0 ;
2014-03-25 12:40:35 +01:00
}
# endif
}
// Disable texture usage
2014-09-03 17:06:10 +02:00
void rlDisableTexture ( void )
2014-03-25 12:40:35 +01:00
{
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 12:40:35 +01:00
glDisable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-12-05 01:14:18 +01:00
# else
2017-01-28 23:02:30 +01:00
// NOTE: If quads batch limit is reached,
2016-12-05 01:14:18 +01:00
// we force a draw call and next batch starts
if ( quads . vCounter / 4 > = MAX_QUADS_BATCH ) rlglDraw ( ) ;
2014-03-25 12:40:35 +01:00
# endif
}
2016-10-29 22:17:19 +02:00
// Set texture parameters (wrap mode/filter mode)
2016-10-27 13:40:48 +02:00
void rlTextureParameters ( unsigned int id , int param , int value )
{
glBindTexture ( GL_TEXTURE_2D , id ) ;
2016-10-29 22:17:19 +02:00
switch ( param )
2016-10-27 13:40:48 +02:00
{
2016-10-29 22:17:19 +02:00
case RL_TEXTURE_WRAP_S :
case RL_TEXTURE_WRAP_T :
{
2017-07-02 12:35:13 +02:00
if ( ( value = = RL_WRAP_CLAMP_MIRROR ) & & ! texClampMirrorSupported ) TraceLog ( LOG_WARNING , " Clamp mirror wrap mode not supported " ) ;
2016-10-29 22:17:19 +02:00
else glTexParameteri ( GL_TEXTURE_2D , param , value ) ;
} break ;
case RL_TEXTURE_MAG_FILTER :
case RL_TEXTURE_MIN_FILTER : glTexParameteri ( GL_TEXTURE_2D , param , value ) ; break ;
case RL_TEXTURE_ANISOTROPIC_FILTER :
{
2016-12-05 01:14:18 +01:00
if ( value < = maxAnisotropicLevel ) glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , ( float ) value ) ;
2016-10-29 22:17:19 +02:00
else if ( maxAnisotropicLevel > 0.0f )
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " [TEX ID %i] Maximum anisotropic filter level supported is %iX " , id , maxAnisotropicLevel ) ;
2016-12-05 01:14:18 +01:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , ( float ) value ) ;
2016-10-29 22:17:19 +02:00
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " Anisotropic filtering not supported " ) ;
2016-10-29 22:17:19 +02:00
} break ;
2016-10-27 13:40:48 +02:00
default : break ;
}
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2016-05-29 11:49:13 +02:00
// Enable rendering to texture (fbo)
2016-03-30 20:09:16 +02:00
void rlEnableRenderTexture ( unsigned int id )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer ( GL_FRAMEBUFFER , id ) ;
2016-05-29 11:49:13 +02:00
//glDisable(GL_CULL_FACE); // Allow double side drawing for texture flipping
//glCullFace(GL_FRONT);
2016-03-30 20:09:16 +02:00
# endif
}
2016-05-29 11:49:13 +02:00
// Disable rendering to texture
2016-03-30 20:09:16 +02:00
void rlDisableRenderTexture ( void )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2016-05-29 11:49:13 +02:00
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
2016-03-30 20:09:16 +02:00
# endif
}
2016-03-17 13:51:48 +01:00
// Enable depth test
void rlEnableDepthTest ( void )
{
glEnable ( GL_DEPTH_TEST ) ;
}
// Disable depth test
void rlDisableDepthTest ( void )
{
glDisable ( GL_DEPTH_TEST ) ;
}
2016-05-18 13:22:14 +02:00
// Enable wire mode
void rlEnableWireMode ( void )
{
# if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
# endif
}
// Disable wire mode
void rlDisableWireMode ( void )
{
# if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
# endif
}
2014-03-25 12:40:35 +01:00
// Unload texture from GPU memory
void rlDeleteTextures ( unsigned int id )
{
2017-07-17 00:33:40 +02:00
if ( id > 0 ) glDeleteTextures ( 1 , & id ) ;
2014-03-25 12:40:35 +01:00
}
2016-03-30 20:09:16 +02:00
// Unload render texture from GPU memory
void rlDeleteRenderTextures ( RenderTexture2D target )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-17 00:33:40 +02:00
if ( target . id > 0 ) glDeleteFramebuffers ( 1 , & target . id ) ;
if ( target . texture . id > 0 ) glDeleteTextures ( 1 , & target . texture . id ) ;
if ( target . depth . id > 0 ) glDeleteTextures ( 1 , & target . depth . id ) ;
2017-01-28 23:02:30 +01:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [FBO ID %i] Unloaded render texture data from VRAM (GPU) " , target . id ) ;
2016-03-30 20:09:16 +02:00
# endif
}
2015-02-02 00:57:08 +01:00
// Unload shader from GPU memory
void rlDeleteShader ( unsigned int id )
{
2015-04-06 14:02:29 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-10 18:24:28 +02:00
if ( id ! = 0 ) glDeleteProgram ( id ) ;
2015-03-01 16:00:52 +01:00
# endif
2015-04-06 14:02:29 +02:00
}
2015-02-02 00:57:08 +01:00
2014-09-16 22:51:31 +02:00
// Unload vertex data (VAO) from GPU memory
2014-04-04 20:11:57 +02:00
void rlDeleteVertexArrays ( unsigned int id )
{
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-01-28 23:02:30 +01:00
if ( vaoSupported )
2016-03-27 18:33:30 +02:00
{
2016-05-10 18:24:28 +02:00
if ( id ! = 0 ) glDeleteVertexArrays ( 1 , & id ) ;
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [VAO ID %i] Unloaded model data from VRAM (GPU) " , id ) ;
2016-03-27 18:33:30 +02:00
}
2014-09-16 22:51:31 +02:00
# endif
}
// Unload vertex data (VBO) from GPU memory
void rlDeleteBuffers ( unsigned int id )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-08 15:24:02 +02:00
if ( id ! = 0 )
{
glDeleteBuffers ( 1 , & id ) ;
2017-07-02 12:35:13 +02:00
if ( ! vaoSupported ) TraceLog ( LOG_INFO , " [VBO ID %i] Unloaded model vertex data from VRAM (GPU) " , id ) ;
2016-05-08 15:24:02 +02:00
}
2014-04-04 20:11:57 +02:00
# endif
}
2014-03-25 12:40:35 +01:00
// Clear color buffer with color
void rlClearColor ( byte r , byte g , byte b , byte a )
{
// Color values clamp to 0.0f(0) and 1.0f(255)
2016-01-13 19:30:35 +01:00
float cr = ( float ) r / 255 ;
float cg = ( float ) g / 255 ;
float cb = ( float ) b / 255 ;
float ca = ( float ) a / 255 ;
2014-03-25 12:40:35 +01:00
glClearColor ( cr , cg , cb , ca ) ;
}
// Clear used screen buffers (color and depth)
2014-09-03 17:06:10 +02:00
void rlClearScreenBuffers ( void )
2014-03-25 12:40:35 +01:00
{
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; // Clear used buffers: Color and Depth (Depth is used for 3D)
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
}
//----------------------------------------------------------------------------------
// Module Functions Definition - rlgl Functions
//----------------------------------------------------------------------------------
2016-06-25 23:28:50 +02:00
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
2016-06-26 14:13:11 +02:00
void rlglInit ( int width , int height )
2014-09-03 16:51:28 +02:00
{
2015-05-21 00:18:22 +02:00
// Check OpenGL information and capabilities
//------------------------------------------------------------------------------
2017-01-28 23:02:30 +01:00
2014-09-16 22:51:31 +02:00
// Print current OpenGL and GLSL version
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " GPU: Vendor: %s " , glGetString ( GL_VENDOR ) ) ;
TraceLog ( LOG_INFO , " GPU: Renderer: %s " , glGetString ( GL_RENDERER ) ) ;
TraceLog ( LOG_INFO , " GPU: Version: %s " , glGetString ( GL_VERSION ) ) ;
TraceLog ( LOG_INFO , " GPU: GLSL: %s " , glGetString ( GL_SHADING_LANGUAGE_VERSION ) ) ;
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
// NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
//int maxTexSize;
//glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
2017-07-02 12:35:13 +02:00
//TraceLog(LOG_INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize);
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
//GL_MAX_TEXTURE_IMAGE_UNITS
//GL_MAX_VIEWPORT_DIMS
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
//int numAuxBuffers;
//glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
2017-07-02 12:35:13 +02:00
//TraceLog(LOG_INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers);
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
//GLint numComp = 0;
//GLint format[32] = { 0 };
//glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
//glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
2017-07-02 12:35:13 +02:00
//for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]);
2014-09-16 22:51:31 +02:00
// NOTE: We don't need that much data on screen... right now...
2017-01-28 23:02:30 +01:00
2015-08-27 16:12:03 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2017-07-02 12:35:13 +02:00
//TraceLog(LOG_INFO, "OpenGL 1.1 (or driver default) profile initialized");
2015-08-27 16:12:03 +02:00
# endif
2015-04-13 20:15:28 +02:00
2015-05-21 00:18:22 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Get supported extensions list
2015-09-02 01:08:41 +02:00
GLint numExt = 0 ;
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2015-08-27 16:12:03 +02:00
2016-01-21 12:24:35 +01:00
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
vaoSupported = true ;
2017-05-08 12:31:47 +02:00
texNPOTSupported = true ;
2017-05-10 19:37:48 +02:00
texFloatSupported = true ;
2015-08-27 16:12:03 +02:00
2015-05-21 00:18:22 +02:00
// We get a list of available extensions and we check for some of them (compressed textures)
2016-06-02 18:20:59 +02:00
// NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that)
2014-09-16 22:51:31 +02:00
glGetIntegerv ( GL_NUM_EXTENSIONS , & numExt ) ;
2017-01-28 23:02:30 +01:00
2016-07-29 13:17:50 +02:00
# ifdef _MSC_VER
const char * * extList = malloc ( sizeof ( const char * ) * numExt ) ;
# else
const char * extList [ numExt ] ;
# endif
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
for ( int i = 0 ; i < numExt ; i + + ) extList [ i ] = ( char * ) glGetStringi ( GL_EXTENSIONS , i ) ;
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2015-09-02 01:08:41 +02:00
char * extensions = ( char * ) glGetString ( GL_EXTENSIONS ) ; // One big const string
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
// NOTE: We have to duplicate string because glGetString() returns a const value
// If not duplicated, it fails in some systems (Raspberry Pi)
2016-05-03 19:20:25 +02:00
// Equivalent to function: char *strdup(const char *str)
char * extensionsDup ;
size_t len = strlen ( extensions ) + 1 ;
void * newstr = malloc ( len ) ;
if ( newstr = = NULL ) extensionsDup = NULL ;
extensionsDup = ( char * ) memcpy ( newstr , extensions , len ) ;
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
// NOTE: String could be splitted using strtok() function (string.h)
2015-09-02 01:08:41 +02:00
// NOTE: strtok() modifies the received string, it can not be const
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
char * extList [ 512 ] ; // Allocate 512 strings pointers (2 KB)
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
extList [ numExt ] = strtok ( extensionsDup , " " ) ;
while ( extList [ numExt ] ! = NULL )
{
numExt + + ;
extList [ numExt ] = strtok ( NULL , " " ) ;
}
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
free ( extensionsDup ) ; // Duplicated string must be deallocated
2017-01-28 23:02:30 +01:00
2015-09-02 01:08:41 +02:00
numExt - = 1 ;
2015-05-21 00:18:22 +02:00
# endif
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " Number of supported extensions: %i " , numExt ) ;
2014-09-16 22:51:31 +02:00
2015-05-21 00:18:22 +02:00
// Show supported extensions
2017-07-02 12:35:13 +02:00
//for (int i = 0; i < numExt; i++) TraceLog(LOG_INFO, "Supported extension: %s", extList[i]);
2015-05-21 00:18:22 +02:00
// Check required extensions
2014-09-16 22:51:31 +02:00
for ( int i = 0 ; i < numExt ; i + + )
2014-03-25 12:40:35 +01:00
{
2015-05-21 00:18:22 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
// Check VAO support
// NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature
2015-09-02 01:08:41 +02:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_vertex_array_object " ) = = 0 )
2015-04-13 20:15:28 +02:00
{
2015-05-21 00:18:22 +02:00
vaoSupported = true ;
2017-01-28 23:02:30 +01:00
// The extension is supported by our hardware and driver, try to get related functions pointers
2015-05-21 00:18:22 +02:00
// NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
glGenVertexArrays = ( PFNGLGENVERTEXARRAYSOESPROC ) eglGetProcAddress ( " glGenVertexArraysOES " ) ;
glBindVertexArray = ( PFNGLBINDVERTEXARRAYOESPROC ) eglGetProcAddress ( " glBindVertexArrayOES " ) ;
glDeleteVertexArrays = ( PFNGLDELETEVERTEXARRAYSOESPROC ) eglGetProcAddress ( " glDeleteVertexArraysOES " ) ;
//glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted
2015-04-13 20:15:28 +02:00
}
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
// Check NPOT textures support
// NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
2017-05-08 12:31:47 +02:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_texture_npot " ) = = 0 ) texNPOTSupported = true ;
2018-06-30 21:56:26 +02:00
2017-05-08 12:31:47 +02:00
// Check texture float support
2017-12-28 19:27:02 +01:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_texture_float " ) = = 0 ) texFloatSupported = true ;
2016-10-29 22:17:19 +02:00
# endif
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
// DDS texture compression support
2015-10-26 11:50:13 +01:00
if ( ( strcmp ( extList [ i ] , ( const char * ) " GL_EXT_texture_compression_s3tc " ) = = 0 ) | |
2016-05-01 01:09:48 +02:00
( strcmp ( extList [ i ] , ( const char * ) " GL_WEBGL_compressed_texture_s3tc " ) = = 0 ) | |
2017-01-28 23:02:30 +01:00
( strcmp ( extList [ i ] , ( const char * ) " GL_WEBKIT_WEBGL_compressed_texture_s3tc " ) = = 0 ) ) texCompDXTSupported = true ;
2015-05-21 00:18:22 +02:00
// ETC1 texture compression support
2016-05-01 01:09:48 +02:00
if ( ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_compressed_ETC1_RGB8_texture " ) = = 0 ) | |
( strcmp ( extList [ i ] , ( const char * ) " GL_WEBGL_compressed_texture_etc1 " ) = = 0 ) ) texCompETC1Supported = true ;
2014-09-16 22:51:31 +02:00
2015-05-21 00:18:22 +02:00
// ETC2/EAC texture compression support
2015-09-02 01:08:41 +02:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_ARB_ES3_compatibility " ) = = 0 ) texCompETC2Supported = true ;
2015-05-21 00:18:22 +02:00
// PVR texture compression support
2015-09-02 01:08:41 +02:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_IMG_texture_compression_pvrtc " ) = = 0 ) texCompPVRTSupported = true ;
2015-05-21 00:18:22 +02:00
// ASTC texture compression support
2015-09-02 01:08:41 +02:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_KHR_texture_compression_astc_hdr " ) = = 0 ) texCompASTCSupported = true ;
2017-01-28 23:02:30 +01:00
2016-10-29 22:17:19 +02:00
// Anisotropic texture filter support
if ( strcmp ( extList [ i ] , ( const char * ) " GL_EXT_texture_filter_anisotropic " ) = = 0 )
{
texAnisotropicFilterSupported = true ;
2017-01-28 23:02:30 +01:00
glGetFloatv ( 0x84FF , & maxAnisotropicLevel ) ; // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
2016-10-29 22:17:19 +02:00
}
2017-01-28 23:02:30 +01:00
2016-10-29 22:17:19 +02:00
// Clamp mirror wrap mode supported
if ( strcmp ( extList [ i ] , ( const char * ) " GL_EXT_texture_mirror_clamp " ) = = 0 ) texClampMirrorSupported = true ;
2018-06-30 21:56:26 +02:00
2017-12-28 19:27:02 +01:00
// Debug marker support
if ( strcmp ( extList [ i ] , ( const char * ) " GL_EXT_debug_marker " ) = = 0 ) debugMarkerSupported = true ;
2015-05-21 00:18:22 +02:00
}
2017-01-28 23:02:30 +01:00
2018-01-19 12:02:15 +01:00
# if defined(_MSC_VER)
2017-11-10 12:37:53 +01:00
//free(extList);
2016-07-29 13:17:50 +02:00
# endif
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2017-07-02 12:35:13 +02:00
if ( vaoSupported ) TraceLog ( LOG_INFO , " [EXTENSION] VAO extension detected, VAO functions initialized successfully " ) ;
else TraceLog ( LOG_WARNING , " [EXTENSION] VAO extension not found, VAO usage not supported " ) ;
2017-01-28 23:02:30 +01:00
2017-07-02 12:35:13 +02:00
if ( texNPOTSupported ) TraceLog ( LOG_INFO , " [EXTENSION] NPOT textures extension detected, full NPOT textures supported " ) ;
else TraceLog ( LOG_WARNING , " [EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat) " ) ;
2015-05-21 00:18:22 +02:00
# endif
2014-09-16 22:51:31 +02:00
2017-07-02 12:35:13 +02:00
if ( texCompDXTSupported ) TraceLog ( LOG_INFO , " [EXTENSION] DXT compressed textures supported " ) ;
if ( texCompETC1Supported ) TraceLog ( LOG_INFO , " [EXTENSION] ETC1 compressed textures supported " ) ;
if ( texCompETC2Supported ) TraceLog ( LOG_INFO , " [EXTENSION] ETC2/EAC compressed textures supported " ) ;
if ( texCompPVRTSupported ) TraceLog ( LOG_INFO , " [EXTENSION] PVRT compressed textures supported " ) ;
if ( texCompASTCSupported ) TraceLog ( LOG_INFO , " [EXTENSION] ASTC compressed textures supported " ) ;
2017-01-28 23:02:30 +01:00
2017-07-02 12:35:13 +02:00
if ( texAnisotropicFilterSupported ) TraceLog ( LOG_INFO , " [EXTENSION] Anisotropic textures filtering supported (max: %.0fX) " , maxAnisotropicLevel ) ;
if ( texClampMirrorSupported ) TraceLog ( LOG_INFO , " [EXTENSION] Clamp mirror wrap texture mode supported " ) ;
2015-05-21 00:18:22 +02:00
2017-12-14 11:44:48 +01:00
if ( debugMarkerSupported ) TraceLog ( LOG_INFO , " [EXTENSION] Debug Marker supported " ) ;
2015-05-21 00:18:22 +02:00
// Initialize buffers, default shaders and default textures
//----------------------------------------------------------
2017-01-28 23:02:30 +01:00
2016-06-24 19:37:52 +02:00
// Init default white texture
2015-09-02 01:08:41 +02:00
unsigned char pixels [ 4 ] = { 255 , 255 , 255 , 255 } ; // 1 pixel RGBA (4 bytes)
2014-03-25 12:40:35 +01:00
2017-07-17 00:33:40 +02:00
whiteTexture = rlLoadTexture ( pixels , 1 , 1 , UNCOMPRESSED_R8G8B8A8 , 1 ) ;
2015-09-02 01:08:41 +02:00
2017-07-02 12:35:13 +02:00
if ( whiteTexture ! = 0 ) TraceLog ( LOG_INFO , " [TEX ID %i] Base white texture loaded successfully " , whiteTexture ) ;
else TraceLog ( LOG_WARNING , " Base white texture could not be loaded " ) ;
2015-09-02 01:08:41 +02:00
2016-04-03 20:14:07 +02:00
// Init default Shader (customized for GL 3.3 and ES2)
2017-07-17 00:33:40 +02:00
defaultShader = LoadShaderDefault ( ) ;
2015-05-04 23:46:31 +02:00
currentShader = defaultShader ;
2014-09-03 16:51:28 +02:00
2016-06-24 19:37:52 +02:00
// Init default vertex arrays buffers (lines, triangles, quads)
2017-07-19 10:09:34 +02:00
LoadBuffersDefault ( ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Init temp vertex buffer, used when transformation required (translate, rotate, scale)
tempBuffer = ( Vector3 * ) malloc ( sizeof ( Vector3 ) * TEMP_VERTEX_BUFFER_SIZE ) ;
2014-09-03 16:51:28 +02:00
2017-07-22 22:15:50 +02:00
for ( int i = 0 ; i < TEMP_VERTEX_BUFFER_SIZE ; i + + ) tempBuffer [ i ] = Vector3Zero ( ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Init draw calls tracking system
draws = ( DrawCall * ) malloc ( sizeof ( DrawCall ) * MAX_DRAWS_BY_TEXTURE ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
for ( int i = 0 ; i < MAX_DRAWS_BY_TEXTURE ; i + + )
{
2014-04-19 16:36:49 +02:00
draws [ i ] . textureId = 0 ;
draws [ i ] . vertexCount = 0 ;
2014-03-25 12:40:35 +01:00
}
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
drawsCounter = 1 ;
2015-04-06 14:02:29 +02:00
draws [ drawsCounter - 1 ] . textureId = whiteTexture ;
2016-06-24 19:37:52 +02:00
currentDrawMode = RL_TRIANGLES ; // Set default draw mode
2017-01-28 23:02:30 +01:00
2016-06-24 19:37:52 +02:00
// Init internal matrix stack (emulating OpenGL 1.1)
for ( int i = 0 ; i < MATRIX_STACK_SIZE ; i + + ) stack [ i ] = MatrixIdentity ( ) ;
// Init internal projection and modelview matrices
projection = MatrixIdentity ( ) ;
modelview = MatrixIdentity ( ) ;
currentMatrix = & modelview ;
2016-06-25 23:28:50 +02:00
# endif // defined(GRAPHICS_API_OPENGL_33) || defined(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
# if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
2017-01-28 23:02:30 +01:00
glHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ; // Improve quality of color and texture coordinate interpolation
2016-06-25 23:28:50 +02:00
glShadeModel ( GL_SMOOTH ) ; // Smooth shading between vertex (vertex colors interpolation)
2014-09-16 22:51:31 +02:00
# endif
2016-06-25 23:28:50 +02:00
// 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)
2017-01-28 23:02:30 +01:00
2016-06-26 14:13:11 +02:00
// Store screen size into global variables
screenWidth = width ;
screenHeight = height ;
2016-06-25 23:28:50 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " OpenGL default states initialized successfully " ) ;
2014-03-25 12:40:35 +01:00
}
// Vertex Buffer Object deinitialization (memory free)
2014-09-03 17:06:10 +02:00
void rlglClose ( void )
2014-03-25 12:40:35 +01:00
{
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-19 19:53:53 +02:00
UnloadShaderDefault ( ) ; // Unload default shader
2018-06-30 21:56:26 +02:00
UnloadBuffersDefault ( ) ; // Unload default buffers (lines, triangles, quads)
2017-07-19 19:53:53 +02:00
glDeleteTextures ( 1 , & whiteTexture ) ; // Unload default texture
2018-06-30 21:56:26 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [TEX ID %i] Unloaded texture data (base white texture) from VRAM " , whiteTexture ) ;
2015-04-06 14:02:29 +02:00
2014-04-19 16:36:49 +02:00
free ( draws ) ;
2014-09-16 22:51:31 +02:00
# endif
2014-03-25 12:40:35 +01:00
}
2015-05-04 23:46:31 +02:00
// Drawing batches: triangles, quads, lines
2014-09-03 17:06:10 +02:00
void rlglDraw ( void )
2014-03-25 12:40:35 +01:00
{
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-07-04 01:29:23 +02:00
// NOTE: In a future version, models could be stored in a stack...
2017-07-17 00:33:40 +02:00
//for (int i = 0; i < modelsCount; i++) rlDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform);
2016-07-04 01:29:23 +02:00
// NOTE: Default buffers upload and draw
2017-07-19 10:09:34 +02:00
UpdateBuffersDefault ( ) ;
DrawBuffersDefault ( ) ; // NOTE: Stereo rendering is checked inside
2014-09-16 22:51:31 +02:00
# endif
2014-04-04 20:11:57 +02:00
}
2017-07-19 19:53:53 +02:00
// Returns current OpenGL version
int rlGetVersion ( void )
{
# if defined(GRAPHICS_API_OPENGL_11)
return OPENGL_11 ;
# elif defined(GRAPHICS_API_OPENGL_21)
2017-08-04 19:18:55 +02:00
# if defined(__APPLE__)
return OPENGL_33 ; // NOTE: Force OpenGL 3.3 on OSX
# else
return OPENGL_21 ;
# endif
2017-07-19 19:53:53 +02:00
# elif defined(GRAPHICS_API_OPENGL_33)
return OPENGL_33 ;
# elif defined(GRAPHICS_API_OPENGL_ES2)
return OPENGL_ES_20 ;
# endif
}
2018-05-20 01:55:46 +02:00
// Check internal buffer overflow for a given number of vertex
bool rlCheckBufferLimit ( int type , int vCount )
{
bool overflow = false ;
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
switch ( type )
{
case RL_LINES : overflow = ( ( lines . vCounter + vCount ) / 2 > = MAX_LINES_BATCH ) ; break ;
case RL_TRIANGLES : overflow = ( ( triangles . vCounter + vCount ) / 3 > = MAX_TRIANGLES_BATCH ) ; break ;
case RL_QUADS : overflow = ( ( quads . vCounter + vCount ) / 4 > = MAX_QUADS_BATCH ) ; break ;
default : break ;
}
# endif
return overflow ;
}
2017-12-15 13:44:31 +01:00
// Set debug marker
void rlSetDebugMarker ( const char * text )
{
2017-12-20 12:35:12 +01:00
# if defined(GRAPHICS_API_OPENGL_33)
if ( debugMarkerSupported ) glInsertEventMarkerEXT ( 0 , text ) ;
# endif
2017-12-15 13:44:31 +01:00
}
2016-06-14 17:16:20 +02:00
// Load OpenGL extensions
// NOTE: External loader function could be passed as a pointer
2017-07-19 10:09:34 +02:00
void rlLoadExtensions ( void * loader )
2016-06-14 17:16:20 +02:00
{
2018-05-20 01:55:46 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2016-06-17 00:29:46 +02:00
// NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
2017-05-08 02:47:44 +02:00
# if !defined(__APPLE__)
2017-07-02 12:35:13 +02:00
if ( ! gladLoadGLLoader ( ( GLADloadproc ) loader ) ) TraceLog ( LOG_WARNING , " GLAD: Cannot load OpenGL extensions " ) ;
else TraceLog ( LOG_INFO , " GLAD: OpenGL extensions loaded successfully " ) ;
2017-01-28 23:02:30 +01:00
2017-05-08 02:47:44 +02:00
# if defined(GRAPHICS_API_OPENGL_21)
2017-07-02 12:35:13 +02:00
if ( GLAD_GL_VERSION_2_1 ) TraceLog ( LOG_INFO , " OpenGL 2.1 profile supported " ) ;
2017-05-08 02:47:44 +02:00
# elif defined(GRAPHICS_API_OPENGL_33)
2017-07-02 12:35:13 +02:00
if ( GLAD_GL_VERSION_3_3 ) TraceLog ( LOG_INFO , " OpenGL 3.3 Core profile supported " ) ;
else TraceLog ( LOG_ERROR , " OpenGL 3.3 Core profile not supported " ) ;
2017-05-08 02:47:44 +02:00
# endif
2016-07-22 11:55:04 -04:00
# endif
2016-06-14 17:16:20 +02:00
// 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
}
2017-07-19 19:53:53 +02:00
// Get world coordinates from screen coordinates
Vector3 rlUnproject ( Vector3 source , Matrix proj , Matrix view )
{
Vector3 result = { 0.0f , 0.0f , 0.0f } ;
2017-07-22 11:02:40 +02:00
// Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
Matrix matViewProj = MatrixMultiply ( view , proj ) ;
2018-04-02 15:16:45 +02:00
matViewProj = MatrixInvert ( matViewProj ) ;
2017-07-19 19:53:53 +02:00
// Create quaternion from source point
Quaternion quat = { source . x , source . y , source . z , 1.0f } ;
// Multiply quat point by unproject matrix
2018-03-16 13:47:01 +01:00
quat = QuaternionTransform ( quat , matViewProj ) ;
2017-07-19 19:53:53 +02:00
// Normalized world points in vectors
result . x = quat . x / quat . w ;
result . y = quat . y / quat . w ;
result . z = quat . z / quat . w ;
return result ;
}
2014-03-25 12:40:35 +01:00
// Convert image data to OpenGL texture (returns OpenGL valid Id)
2017-07-17 00:33:40 +02:00
unsigned int rlLoadTexture ( void * data , int width , int height , int format , int mipmapCount )
2014-03-25 12:40:35 +01:00
{
2015-04-06 14:02:29 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Free any old binding
2014-03-25 12:40:35 +01:00
2015-05-21 00:18:22 +02:00
GLuint id = 0 ;
2017-01-28 23:02:30 +01:00
2015-05-21 00:18:22 +02:00
// Check texture format support by OpenGL 1.1 (compressed textures not supported)
2017-01-28 23:02:30 +01:00
# if defined(GRAPHICS_API_OPENGL_11)
2017-04-22 22:35:04 +02:00
if ( format > = COMPRESSED_DXT1_RGB )
2015-04-06 14:02:29 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " OpenGL 1.1 does not support GPU compressed texture formats " ) ;
2015-05-21 00:18:22 +02:00
return id ;
2015-04-06 14:02:29 +02:00
}
2016-06-14 15:42:04 +02:00
# endif
2017-01-28 23:02:30 +01:00
2017-04-22 22:35:04 +02:00
if ( ( ! texCompDXTSupported ) & & ( ( format = = COMPRESSED_DXT1_RGB ) | | ( format = = COMPRESSED_DXT1_RGBA ) | |
( format = = COMPRESSED_DXT3_RGBA ) | | ( format = = COMPRESSED_DXT5_RGBA ) ) )
2015-05-21 14:13:51 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " DXT compressed texture format not supported " ) ;
2015-05-21 14:13:51 +02:00
return id ;
}
2017-01-28 23:02:30 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-04-22 22:35:04 +02:00
if ( ( ! texCompETC1Supported ) & & ( format = = COMPRESSED_ETC1_RGB ) )
2015-05-21 14:13:51 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " ETC1 compressed texture format not supported " ) ;
2015-05-21 14:13:51 +02:00
return id ;
}
2017-01-28 23:02:30 +01:00
2017-04-22 22:35:04 +02:00
if ( ( ! texCompETC2Supported ) & & ( ( format = = COMPRESSED_ETC2_RGB ) | | ( format = = COMPRESSED_ETC2_EAC_RGBA ) ) )
2015-05-21 14:13:51 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " ETC2 compressed texture format not supported " ) ;
2015-05-21 14:13:51 +02:00
return id ;
}
2017-01-28 23:02:30 +01:00
2017-04-22 22:35:04 +02:00
if ( ( ! texCompPVRTSupported ) & & ( ( format = = COMPRESSED_PVRT_RGB ) | | ( format = = COMPRESSED_PVRT_RGBA ) ) )
2015-05-21 14:13:51 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " PVRT compressed texture format not supported " ) ;
2015-05-21 14:13:51 +02:00
return id ;
}
2017-01-28 23:02:30 +01:00
2017-04-22 22:35:04 +02:00
if ( ( ! texCompASTCSupported ) & & ( ( format = = COMPRESSED_ASTC_4x4_RGBA ) | | ( format = = COMPRESSED_ASTC_8x8_RGBA ) ) )
2015-05-21 14:13:51 +02:00
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " ASTC compressed texture format not supported " ) ;
2015-05-21 14:13:51 +02:00
return id ;
}
2015-07-05 18:21:01 +02:00
# endif
2018-01-16 00:00:05 +01:00
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
2015-04-06 14:02:29 +02:00
glGenTextures ( 1 , & id ) ; // Generate Pointer to the texture
2014-09-03 16:51:28 +02:00
2015-05-18 13:12:24 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-05-21 14:13:51 +02:00
//glActiveTexture(GL_TEXTURE0); // If not defined, using GL_TEXTURE0 by default (shader texture)
2015-05-18 13:12:24 +02:00
# endif
2014-03-25 12:40:35 +01:00
glBindTexture ( GL_TEXTURE_2D , id ) ;
2018-06-30 21:56:26 +02:00
2018-01-16 00:00:05 +01:00
int mipWidth = width ;
int mipHeight = height ;
int mipOffset = 0 ; // Mipmap data offset
2018-06-30 21:56:26 +02:00
2018-01-23 13:23:34 +01:00
TraceLog ( LOG_DEBUG , " Load texture from data memory address: 0x%x " , data ) ;
2018-06-30 21:56:26 +02:00
2018-01-16 00:00:05 +01:00
// Load the different mipmap levels
for ( int i = 0 ; i < mipmapCount ; i + + )
2015-03-01 16:00:52 +01:00
{
2018-01-16 00:00:05 +01:00
unsigned int mipSize = GetPixelDataSize ( mipWidth , mipHeight , format ) ;
2018-06-30 21:56:26 +02:00
2018-01-22 00:20:42 +01:00
int glInternalFormat , glFormat , glType ;
GetGlFormats ( format , & glInternalFormat , & glFormat , & glType ) ;
2018-06-30 21:56:26 +02:00
2018-01-23 13:23:34 +01:00
TraceLog ( LOG_DEBUG , " Load mipmap level %i (%i x %i), size: %i, offset: %i " , i , mipWidth , mipHeight , mipSize , mipOffset ) ;
2018-06-30 21:56:26 +02:00
2018-01-22 00:20:42 +01:00
if ( glInternalFormat ! = - 1 )
2015-04-06 14:02:29 +02:00
{
2018-01-22 00:20:42 +01:00
if ( format < COMPRESSED_DXT1_RGB ) glTexImage2D ( GL_TEXTURE_2D , i , glInternalFormat , mipWidth , mipHeight , 0 , glFormat , glType , ( unsigned char * ) data + mipOffset ) ;
2018-06-30 21:56:26 +02:00
# if !defined(GRAPHICS_API_OPENGL_11)
2018-01-22 00:20:42 +01:00
else glCompressedTexImage2D ( GL_TEXTURE_2D , i , glInternalFormat , mipWidth , mipHeight , 0 , mipSize , ( unsigned char * ) data + mipOffset ) ;
2018-02-21 23:47:48 +01:00
# endif
2018-06-30 21:56:26 +02:00
2018-05-20 01:55:46 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2018-01-22 00:20:42 +01:00
if ( format = = UNCOMPRESSED_GRAYSCALE )
2018-01-16 00:00:05 +01:00
{
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , GL_ONE } ;
glTexParameteriv ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_RGBA , swizzleMask ) ;
2018-01-22 00:20:42 +01:00
}
else if ( format = = UNCOMPRESSED_GRAY_ALPHA )
2018-01-16 00:00:05 +01:00
{
2018-05-20 00:41:12 +02:00
# if defined(GRAPHICS_API_OPENGL_21)
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , GL_ALPHA } ;
# elif defined(GRAPHICS_API_OPENGL_33)
2018-01-16 00:00:05 +01:00
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , GL_GREEN } ;
2018-05-20 00:41:12 +02:00
# endif
2018-01-16 00:00:05 +01:00
glTexParameteriv ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_RGBA , swizzleMask ) ;
2018-01-22 00:20:42 +01:00
}
2018-01-16 00:00:05 +01:00
# endif
}
2018-06-30 21:56:26 +02:00
2018-01-16 00:00:05 +01:00
mipWidth / = 2 ;
mipHeight / = 2 ;
mipOffset + = mipSize ;
2018-06-30 21:56:26 +02:00
2018-01-16 00:00:05 +01:00
// Security check for NPOT textures
if ( mipWidth < 1 ) mipWidth = 1 ;
if ( mipHeight < 1 ) mipHeight = 1 ;
2015-03-01 16:00:52 +01:00
}
2015-05-11 00:15:46 +02:00
2015-07-05 18:21:01 +02:00
// Texture parameters configuration
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
# if defined(GRAPHICS_API_OPENGL_ES2)
// 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
2017-05-08 12:31:47 +02:00
if ( texNPOTSupported )
2015-09-02 20:36:05 +02:00
{
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ; // Set texture to repeat on x-axis
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ; // Set texture to repeat on y-axis
}
else
{
// NOTE: If using negative texture coordinates (LoadOBJ()), it does not work!
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ; // Set texture to clamp on x-axis
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ; // Set texture to clamp on y-axis
}
2015-07-05 18:21:01 +02:00
# else
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ; // Set texture to repeat on x-axis
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ; // Set texture to repeat on y-axis
# endif
// Magnification and minification filters
2015-08-03 17:27:53 +02:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ; // Alternative: GL_LINEAR
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ; // Alternative: GL_LINEAR
2017-01-28 23:02:30 +01:00
2015-07-05 18:21:01 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
if ( mipmapCount > 1 )
{
2018-01-16 00:00:05 +01:00
// Activate Trilinear filtering if mipmaps are available
2015-07-05 18:21:01 +02:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2018-01-16 00:00:05 +01:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ;
2015-07-05 18:21:01 +02:00
}
# endif
// At this point we have the texture loaded in GPU and texture parameters configured
2017-01-28 23:02:30 +01:00
2015-07-05 18:21:01 +02:00
// NOTE: If mipmaps were not in data, they are not generated automatically
// Unbind current texture
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2018-01-23 13:23:34 +01:00
if ( id > 0 ) TraceLog ( LOG_INFO , " [TEX ID %i] Texture created successfully (%ix%i - %i mipmaps) " , id , width , height , mipmapCount ) ;
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " Texture could not be created " ) ;
2015-07-05 18:21:01 +02:00
return id ;
}
2017-07-17 00:33:40 +02:00
// Update already loaded texture in GPU with new data
void rlUpdateTexture ( unsigned int id , int width , int height , int format , const void * data )
{
glBindTexture ( GL_TEXTURE_2D , id ) ;
2018-06-30 21:56:26 +02:00
2018-01-22 00:20:42 +01:00
int glInternalFormat , glFormat , glType ;
GetGlFormats ( format , & glInternalFormat , & glFormat , & glType ) ;
2017-07-17 00:33:40 +02:00
2018-01-22 00:20:42 +01:00
if ( ( glInternalFormat ! = - 1 ) & & ( format < COMPRESSED_DXT1_RGB ) )
2017-07-17 00:33:40 +02:00
{
2018-01-22 00:20:42 +01:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , glFormat , glType , ( unsigned char * ) data ) ;
2017-07-17 00:33:40 +02:00
}
2018-01-22 00:20:42 +01:00
else TraceLog ( LOG_WARNING , " Texture format updating not supported " ) ;
2017-07-17 00:33:40 +02:00
}
// Unload texture from GPU memory
void rlUnloadTexture ( unsigned int id )
{
if ( id > 0 ) glDeleteTextures ( 1 , & id ) ;
}
2016-03-30 20:09:16 +02:00
// Load a texture to be used for rendering (fbo with color and depth attachments)
2017-07-17 00:33:40 +02:00
RenderTexture2D rlLoadRenderTexture ( int width , int height )
2016-03-30 20:09:16 +02:00
{
RenderTexture2D target ;
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
target . id = 0 ;
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
target . texture . id = 0 ;
target . texture . width = width ;
target . texture . height = height ;
2016-10-10 19:42:59 +02:00
target . texture . format = UNCOMPRESSED_R8G8B8A8 ;
2016-03-30 20:09:16 +02:00
target . texture . mipmaps = 1 ;
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
target . depth . id = 0 ;
target . depth . width = width ;
target . depth . height = height ;
2016-04-10 19:38:57 +02:00
target . depth . format = 19 ; //DEPTH_COMPONENT_24BIT
2016-03-30 20:09:16 +02:00
target . depth . mipmaps = 1 ;
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the texture that will serve as the color attachment for the framebuffer
glGenTextures ( 1 , & target . texture . id ) ;
glBindTexture ( GL_TEXTURE_2D , target . texture . id ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2016-10-10 19:42:59 +02:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2016-03-30 20:09:16 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2017-01-28 23:02:30 +01:00
2017-11-06 13:58:11 +01:00
# if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
2016-04-10 19:38:57 +02:00
# define USE_DEPTH_RENDERBUFFER
2017-11-06 13:58:11 +01:00
# else
# define USE_DEPTH_TEXTURE
2016-04-10 19:38:57 +02:00
# endif
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
# if defined(USE_DEPTH_RENDERBUFFER)
// Create the renderbuffer that will serve as the depth attachment for the framebuffer.
glGenRenderbuffers ( 1 , & target . depth . id ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , target . depth . id ) ;
2016-04-17 11:25:04 +02:00
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT16 , width , height ) ; // GL_DEPTH_COMPONENT24 not supported on Android
2016-03-30 20:09:16 +02:00
# elif defined(USE_DEPTH_TEXTURE)
// NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extension required)
// A renderbuffer is simpler than a texture and could offer better performance on embedded devices
glGenTextures ( 1 , & target . depth . id ) ;
glBindTexture ( GL_TEXTURE_2D , target . depth . id ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2016-04-10 19:38:57 +02:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT24 , width , height , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , NULL ) ;
2016-03-30 20:09:16 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
# endif
// Create the framebuffer object
glGenFramebuffers ( 1 , & target . id ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , target . id ) ;
// Attach color texture and depth renderbuffer to FBO
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , target . texture . id , 0 ) ;
# if defined(USE_DEPTH_RENDERBUFFER)
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , target . depth . id ) ;
# elif defined(USE_DEPTH_TEXTURE)
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , target . depth . id , 0 ) ;
# endif
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE )
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " Framebuffer object could not be created... " ) ;
2017-01-28 23:02:30 +01:00
2016-05-21 18:22:15 +02:00
switch ( status )
2016-03-30 20:09:16 +02:00
{
2017-07-02 12:35:13 +02:00
case GL_FRAMEBUFFER_UNSUPPORTED : TraceLog ( LOG_WARNING , " Framebuffer is unsupported " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : TraceLog ( LOG_WARNING , " Framebuffer incomplete attachment " ) ; break ;
2016-03-30 20:09:16 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2017-07-02 12:35:13 +02:00
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS : TraceLog ( LOG_WARNING , " Framebuffer incomplete dimensions " ) ; break ;
2016-03-30 20:09:16 +02:00
# endif
2017-07-02 12:35:13 +02:00
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : TraceLog ( LOG_WARNING , " Framebuffer incomplete missing attachment " ) ; break ;
2016-03-30 20:09:16 +02:00
default : break ;
}
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
glDeleteTextures ( 1 , & target . texture . id ) ;
glDeleteTextures ( 1 , & target . depth . id ) ;
glDeleteFramebuffers ( 1 , & target . id ) ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_INFO , " [FBO ID %i] Framebuffer object created successfully " , target . id ) ;
2017-01-28 23:02:30 +01:00
2016-03-30 20:09:16 +02:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
# endif
2017-01-28 23:02:30 +01:00
return target ;
2016-03-30 20:09:16 +02:00
}
2015-07-05 18:21:01 +02:00
// Generate mipmap data for selected texture
2017-07-17 00:33:40 +02:00
void rlGenerateMipmaps ( Texture2D * texture )
2015-07-05 18:21:01 +02:00
{
2016-11-22 12:14:55 +01:00
glBindTexture ( GL_TEXTURE_2D , texture - > id ) ;
2017-01-28 23:02:30 +01:00
2015-07-18 19:25:15 +02:00
// Check if texture is power-of-two (POT)
bool texIsPOT = false ;
2017-01-28 23:02:30 +01:00
if ( ( ( texture - > width > 0 ) & & ( ( texture - > width & ( texture - > width - 1 ) ) = = 0 ) ) & &
2016-11-22 12:14:55 +01:00
( ( texture - > height > 0 ) & & ( ( texture - > height & ( texture - > height - 1 ) ) = = 0 ) ) ) texIsPOT = true ;
2015-05-11 00:15:46 +02:00
2017-05-08 12:31:47 +02:00
if ( ( texIsPOT ) | | ( texNPOTSupported ) )
2015-05-11 00:15:46 +02:00
{
# if defined(GRAPHICS_API_OPENGL_11)
2018-05-20 00:39:56 +02:00
// WARNING: Manual mipmap generation only works for RGBA 32bit textures!
if ( texture - > format = = UNCOMPRESSED_R8G8B8A8 )
{
// Retrieve texture data from VRAM
void * data = rlReadTexturePixels ( * texture ) ;
2018-06-30 21:56:26 +02:00
2018-05-20 00:39:56 +02:00
// NOTE: data size is reallocated to fit mipmaps data
// NOTE: CPU mipmap generation only supports RGBA 32bit data
int mipmapCount = GenerateMipmaps ( data , texture - > width , texture - > height ) ;
2017-01-28 23:02:30 +01:00
2018-05-20 00:39:56 +02:00
int size = texture - > width * texture - > height * 4 ;
int offset = size ;
2015-05-11 00:15:46 +02:00
2018-05-20 00:39:56 +02:00
int mipWidth = texture - > width / 2 ;
int mipHeight = texture - > height / 2 ;
2015-05-11 00:15:46 +02:00
2018-05-20 00:39:56 +02:00
// Load the mipmaps
for ( int level = 1 ; level < mipmapCount ; level + + )
{
glTexImage2D ( GL_TEXTURE_2D , level , GL_RGBA8 , mipWidth , mipHeight , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( unsigned char * ) data + offset ) ;
2015-05-11 00:15:46 +02:00
2018-05-20 00:39:56 +02:00
size = mipWidth * mipHeight * 4 ;
offset + = size ;
2015-04-06 14:02:29 +02:00
2018-05-20 00:39:56 +02:00
mipWidth / = 2 ;
mipHeight / = 2 ;
}
2015-05-11 00:15:46 +02:00
2018-05-20 00:39:56 +02:00
texture - > mipmaps = mipmapCount + 1 ;
free ( data ) ; // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
2018-06-30 21:56:26 +02:00
2018-05-20 00:39:56 +02:00
TraceLog ( LOG_WARNING , " [TEX ID %i] Mipmaps [%i] generated manually on CPU side " , texture - > id , texture - > mipmaps ) ;
2015-05-11 00:15:46 +02:00
}
2018-05-20 00:39:56 +02:00
else TraceLog ( LOG_WARNING , " [TEX ID %i] Mipmaps could not be generated for texture format " , texture - > id ) ;
2016-05-03 19:20:25 +02:00
# endif
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-10-29 22:17:19 +02:00
//glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
2015-07-05 18:21:01 +02:00
glGenerateMipmap ( GL_TEXTURE_2D ) ; // Generate mipmaps automatically
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [TEX ID %i] Mipmaps generated automatically " , texture - > id ) ;
2015-05-11 00:15:46 +02:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2016-11-22 12:14:55 +01:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ; // Activate Trilinear filtering for mipmaps
2017-01-28 23:02:30 +01:00
2016-11-22 12:14:55 +01:00
# define MIN(a,b) (((a)<(b))?(a):(b))
# define MAX(a,b) (((a)>(b))?(a):(b))
2017-01-28 23:02:30 +01:00
2016-12-09 10:15:44 +01:00
texture - > mipmaps = 1 + ( int ) floor ( log ( MAX ( texture - > width , texture - > height ) ) / log ( 2 ) ) ;
2015-05-11 00:15:46 +02:00
# endif
2015-07-05 18:21:01 +02:00
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " [TEX ID %i] Mipmaps can not be generated " , texture - > id ) ;
2016-03-01 15:36:45 +01:00
2014-03-25 12:40:35 +01:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2016-05-07 18:07:15 +02:00
// Upload vertex data into a VAO (if supported) and VBO
2017-07-17 00:33:40 +02:00
// TODO: Check if mesh has already been loaded in GPU
void rlLoadMesh ( Mesh * mesh , bool dynamic )
2014-09-16 22:51:31 +02:00
{
2016-05-07 18:07:15 +02:00
mesh - > vaoId = 0 ; // Vertex Array Object
mesh - > vboId [ 0 ] = 0 ; // Vertex positions VBO
mesh - > vboId [ 1 ] = 0 ; // Vertex texcoords VBO
mesh - > vboId [ 2 ] = 0 ; // Vertex normals VBO
2016-05-08 23:50:35 +02:00
mesh - > vboId [ 3 ] = 0 ; // Vertex colors VBO
mesh - > vboId [ 4 ] = 0 ; // Vertex tangents VBO
mesh - > vboId [ 5 ] = 0 ; // Vertex texcoords2 VBO
2016-05-10 18:24:28 +02:00
mesh - > vboId [ 6 ] = 0 ; // Vertex indices VBO
2017-01-28 23:02:30 +01:00
2016-06-01 12:37:51 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-20 09:36:02 +02:00
int drawHint = GL_STATIC_DRAW ;
if ( dynamic ) drawHint = GL_DYNAMIC_DRAW ;
2016-05-08 15:24:02 +02:00
2014-09-16 22:51:31 +02:00
if ( vaoSupported )
{
// Initialize Quads VAO (Buffer A)
2017-07-20 12:26:25 +02:00
glGenVertexArrays ( 1 , & mesh - > vaoId ) ;
glBindVertexArray ( mesh - > vaoId ) ;
2014-09-16 22:51:31 +02:00
}
2017-01-28 23:02:30 +01:00
// NOTE: Attributes must be uploaded considering default locations points
2016-05-07 18:07:15 +02:00
// Enable vertex attributes: position (shader-location = 0)
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 0 ] ) ;
2016-05-20 09:36:02 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh - > vertexCount , mesh - > vertices , drawHint ) ;
2016-05-07 18:07:15 +02:00
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 0 ) ;
2014-09-16 22:51:31 +02:00
2016-05-07 18:07:15 +02:00
// Enable vertex attributes: texcoords (shader-location = 1)
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 1 ] ) ;
2016-05-20 09:36:02 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * mesh - > vertexCount , mesh - > texcoords , drawHint ) ;
2016-05-07 18:07:15 +02:00
glVertexAttribPointer ( 1 , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 1 ) ;
2014-09-16 22:51:31 +02:00
2016-05-07 18:07:15 +02:00
// Enable vertex attributes: normals (shader-location = 2)
2016-05-08 15:24:02 +02:00
if ( mesh - > normals ! = NULL )
{
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 2 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 2 ] ) ;
2016-05-20 09:36:02 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh - > vertexCount , mesh - > normals , drawHint ) ;
2016-05-08 15:24:02 +02:00
glVertexAttribPointer ( 2 , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 2 ) ;
}
else
{
// Default color vertex attribute set to WHITE
glVertexAttrib3f ( 2 , 1.0f , 1.0f , 1.0f ) ;
glDisableVertexAttribArray ( 2 ) ;
}
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// Default color vertex attribute (shader-location = 3)
2016-05-08 15:24:02 +02:00
if ( mesh - > colors ! = NULL )
{
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 3 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 3 ] ) ;
2016-05-20 09:36:02 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * mesh - > vertexCount , mesh - > colors , drawHint ) ;
2016-05-08 15:24:02 +02:00
glVertexAttribPointer ( 3 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( 3 ) ;
}
else
{
// Default color vertex attribute set to WHITE
glVertexAttrib4f ( 3 , 1.0f , 1.0f , 1.0f , 1.0f ) ;
glDisableVertexAttribArray ( 3 ) ;
}
2017-01-28 23:02:30 +01:00
2016-05-08 15:24:02 +02:00
// Default tangent vertex attribute (shader-location = 4)
if ( mesh - > tangents ! = NULL )
{
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 4 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 4 ] ) ;
2018-02-24 12:31:32 +01:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 4 * mesh - > vertexCount , mesh - > tangents , drawHint ) ;
glVertexAttribPointer ( 4 , 4 , GL_FLOAT , 0 , 0 , 0 ) ;
2016-05-08 15:24:02 +02:00
glEnableVertexAttribArray ( 4 ) ;
}
else
{
// Default tangents vertex attribute
2018-02-24 12:31:32 +01:00
glVertexAttrib4f ( 4 , 0.0f , 0.0f , 0.0f , 0.0f ) ;
2016-05-08 15:24:02 +02:00
glDisableVertexAttribArray ( 4 ) ;
}
2017-01-28 23:02:30 +01:00
2016-05-08 15:24:02 +02:00
// Default texcoord2 vertex attribute (shader-location = 5)
if ( mesh - > texcoords2 ! = NULL )
{
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 5 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , mesh - > vboId [ 5 ] ) ;
2016-05-20 09:36:02 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * mesh - > vertexCount , mesh - > texcoords2 , drawHint ) ;
2016-05-08 15:24:02 +02:00
glVertexAttribPointer ( 5 , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 5 ) ;
}
else
{
2018-02-24 12:31:32 +01:00
// Default texcoord2 vertex attribute
2016-05-08 15:24:02 +02:00
glVertexAttrib2f ( 5 , 0.0f , 0.0f ) ;
glDisableVertexAttribArray ( 5 ) ;
}
2017-01-28 23:02:30 +01:00
2016-05-10 18:24:28 +02:00
if ( mesh - > indices ! = NULL )
{
2017-07-20 12:26:25 +02:00
glGenBuffers ( 1 , & mesh - > vboId [ 6 ] ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , mesh - > vboId [ 6 ] ) ;
2016-05-10 19:25:06 +02:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( unsigned short ) * mesh - > triangleCount * 3 , mesh - > indices , GL_STATIC_DRAW ) ;
2016-05-10 18:24:28 +02:00
}
2014-09-16 22:51:31 +02:00
if ( vaoSupported )
{
2017-07-20 12:26:25 +02:00
if ( mesh - > vaoId > 0 ) TraceLog ( LOG_INFO , " [VAO ID %i] Mesh uploaded successfully to VRAM (GPU) " , mesh - > vaoId ) ;
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " Mesh could not be uploaded to VRAM (GPU) " ) ;
2014-09-16 22:51:31 +02:00
}
else
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [VBOs] Mesh uploaded successfully to VRAM (GPU) " ) ;
2014-09-16 22:51:31 +02:00
}
# endif
}
2014-04-09 20:25:26 +02:00
2016-05-18 13:22:14 +02:00
// Update vertex data on GPU (upload new data to one buffer)
2017-07-17 00:33:40 +02:00
void rlUpdateMesh ( Mesh mesh , int buffer , int numVertex )
2016-05-18 13:22:14 +02:00
{
2016-06-01 12:37:51 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-18 13:22:14 +02:00
// Activate mesh VAO
if ( vaoSupported ) glBindVertexArray ( mesh . vaoId ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
switch ( buffer )
{
case 0 : // Update vertices (vertex position)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 0 ] ) ;
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * numVertex , mesh . vertices , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * numVertex , mesh . vertices ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
} break ;
case 1 : // Update texcoords (vertex texture coordinates)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 1 ] ) ;
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * numVertex , mesh . texcoords , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 2 * numVertex , mesh . texcoords ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
} break ;
case 2 : // Update normals (vertex normals)
{
2016-12-31 14:05:30 -08:00
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 2 ] ) ;
2016-05-18 13:22:14 +02:00
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * numVertex , mesh . normals , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * numVertex , mesh . normals ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
} break ;
case 3 : // Update colors (vertex colors)
{
2016-12-31 14:05:30 -08:00
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 3 ] ) ;
2016-05-18 13:22:14 +02:00
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 4 * numVertex , mesh . colors , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( unsigned char ) * 4 * numVertex , mesh . colors ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
} break ;
case 4 : // Update tangents (vertex tangents)
{
2016-12-31 14:05:30 -08:00
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 4 ] ) ;
2018-02-24 12:31:32 +01:00
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 4 * numVertex , mesh . tangents , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 4 * numVertex , mesh . tangents ) ;
2016-05-18 13:22:14 +02:00
} break ;
case 5 : // Update texcoords2 (vertex second texture coordinates)
{
2016-12-31 14:05:30 -08:00
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 5 ] ) ;
2016-05-18 13:22:14 +02:00
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * numVertex , mesh . texcoords2 , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 2 * numVertex , mesh . texcoords2 ) ;
} break ;
default : break ;
}
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
// Unbind the current VAO
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
// Another option would be using buffer mapping...
//mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
// Now we can modify vertices
//glUnmapBuffer(GL_ARRAY_BUFFER);
2016-06-01 12:37:51 +02:00
# endif
2016-05-18 13:22:14 +02:00
}
// Draw a 3d mesh with material and transform
2017-07-17 00:33:40 +02:00
void rlDrawMesh ( Mesh mesh , Material material , Matrix transform )
2016-05-18 13:22:14 +02:00
{
# if defined(GRAPHICS_API_OPENGL_11)
glEnable ( GL_TEXTURE_2D ) ;
2017-07-20 12:26:25 +02:00
glBindTexture ( GL_TEXTURE_2D , material . maps [ MAP_DIFFUSE ] . texture . id ) ;
2016-05-18 13:22:14 +02:00
// NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
glEnableClientState ( GL_VERTEX_ARRAY ) ; // Enable vertex array
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ; // Enable texture coords array
if ( mesh . normals ! = NULL ) glEnableClientState ( GL_NORMAL_ARRAY ) ; // Enable normals array
if ( mesh . colors ! = NULL ) glEnableClientState ( GL_COLOR_ARRAY ) ; // Enable colors array
glVertexPointer ( 3 , GL_FLOAT , 0 , mesh . vertices ) ; // Pointer to vertex coords array
glTexCoordPointer ( 2 , GL_FLOAT , 0 , mesh . texcoords ) ; // Pointer to texture coords array
if ( mesh . normals ! = NULL ) glNormalPointer ( GL_FLOAT , 0 , mesh . normals ) ; // Pointer to normals array
if ( mesh . colors ! = NULL ) glColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , mesh . colors ) ; // Pointer to colors array
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
rlPushMatrix ( ) ;
rlMultMatrixf ( MatrixToFloat ( transform ) ) ;
2017-07-20 12:26:25 +02:00
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 ) ;
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
if ( mesh . indices ! = NULL ) glDrawElements ( GL_TRIANGLES , mesh . triangleCount * 3 , GL_UNSIGNED_SHORT , mesh . indices ) ;
else glDrawArrays ( GL_TRIANGLES , 0 , mesh . vertexCount ) ;
rlPopMatrix ( ) ;
glDisableClientState ( GL_VERTEX_ARRAY ) ; // Disable vertex array
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ; // Disable texture coords array
if ( mesh . normals ! = NULL ) glDisableClientState ( GL_NORMAL_ARRAY ) ; // Disable normals array
if ( mesh . colors ! = NULL ) glDisableClientState ( GL_NORMAL_ARRAY ) ; // Disable colors array
glDisable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
# endif
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-17 00:33:40 +02:00
// Bind shader program
2018-06-30 21:56:26 +02:00
glUseProgram ( material . shader . id ) ;
2017-01-28 23:02:30 +01:00
2017-07-17 00:33:40 +02:00
// Matrices and other values required by shader
//-----------------------------------------------------
// Calculate and send to shader model matrix (used by PBR shader)
2017-10-04 12:11:40 +02:00
if ( material . shader . locs [ LOC_MATRIX_MODEL ] ! = - 1 ) SetShaderValueMatrix ( material . shader , material . shader . locs [ LOC_MATRIX_MODEL ] , transform ) ;
2018-06-30 21:56:26 +02:00
2016-07-04 01:29:23 +02:00
// Upload to shader material.colDiffuse
2017-07-19 18:55:26 +02:00
if ( material . shader . locs [ LOC_COLOR_DIFFUSE ] ! = - 1 )
2018-06-30 21:56:26 +02:00
glUniform4f ( material . shader . locs [ LOC_COLOR_DIFFUSE ] , ( float ) material . maps [ MAP_DIFFUSE ] . color . r / 255.0f ,
( float ) material . maps [ MAP_DIFFUSE ] . color . g / 255.0f ,
( float ) material . maps [ MAP_DIFFUSE ] . color . b / 255.0f ,
2017-11-06 13:41:13 +01:00
( float ) material . maps [ MAP_DIFFUSE ] . color . a / 255.0f ) ;
2017-01-28 23:02:30 +01:00
2016-09-05 20:15:21 +02:00
// Upload to shader material.colSpecular (if available)
2018-06-30 21:56:26 +02:00
if ( material . shader . locs [ LOC_COLOR_SPECULAR ] ! = - 1 )
glUniform4f ( material . shader . locs [ LOC_COLOR_SPECULAR ] , ( float ) material . maps [ MAP_SPECULAR ] . color . r / 255.0f ,
( float ) material . maps [ MAP_SPECULAR ] . color . g / 255.0f ,
( float ) material . maps [ MAP_SPECULAR ] . color . b / 255.0f ,
2017-11-06 13:41:13 +01:00
( float ) material . maps [ MAP_SPECULAR ] . color . a / 255.0f ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 18:55:26 +02:00
if ( material . shader . locs [ LOC_MATRIX_VIEW ] ! = - 1 ) SetShaderValueMatrix ( material . shader , material . shader . locs [ LOC_MATRIX_VIEW ] , modelview ) ;
if ( material . shader . locs [ LOC_MATRIX_PROJECTION ] ! = - 1 ) SetShaderValueMatrix ( material . shader , material . shader . locs [ LOC_MATRIX_PROJECTION ] , projection ) ;
2016-09-05 20:15:21 +02:00
2016-05-18 13:22:14 +02:00
// At this point the modelview matrix just contains the view matrix (camera)
2018-05-04 16:54:05 +02:00
// That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
2016-05-18 13:22:14 +02:00
Matrix matView = modelview ; // View matrix (camera)
Matrix matProjection = projection ; // Projection matrix (perspective)
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply ( transform , matView ) ; // Transform to camera-space coordinates
2017-07-17 00:33:40 +02:00
//-----------------------------------------------------
2016-05-18 13:22:14 +02:00
2017-07-17 00:33:40 +02:00
// Bind active texture maps (if available)
2017-07-19 10:09:34 +02:00
for ( int i = 0 ; i < MAX_MATERIAL_MAPS ; i + + )
2016-05-20 17:18:07 +02:00
{
2017-07-19 10:09:34 +02:00
if ( material . maps [ i ] . texture . id > 0 )
2016-09-05 20:15:21 +02:00
{
2017-07-17 00:33:40 +02:00
glActiveTexture ( GL_TEXTURE0 + i ) ;
2017-07-19 10:09:34 +02:00
if ( ( i = = MAP_IRRADIANCE ) | | ( i = = MAP_PREFILTER ) | | ( i = = MAP_CUBEMAP ) ) glBindTexture ( GL_TEXTURE_CUBE_MAP , material . maps [ i ] . texture . id ) ;
else glBindTexture ( GL_TEXTURE_2D , material . maps [ i ] . texture . id ) ;
2017-01-28 23:02:30 +01:00
2017-07-19 10:09:34 +02:00
glUniform1i ( material . shader . locs [ LOC_MAP_DIFFUSE + i ] , i ) ;
2016-09-05 20:15:21 +02:00
}
2016-05-18 13:22:14 +02:00
}
2017-01-28 23:02:30 +01:00
2017-07-17 00:33:40 +02:00
// Bind vertex array objects (or VBOs)
if ( vaoSupported ) glBindVertexArray ( mesh . vaoId ) ;
2016-05-18 13:22:14 +02:00
else
{
2017-07-17 00:33:40 +02:00
// TODO: Simplify VBO binding into a for loop
2016-05-18 13:22:14 +02:00
// Bind mesh VBO data: vertex position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 0 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_POSITION ] ) ;
2016-05-18 13:22:14 +02:00
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 1 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_TEXCOORD01 ] , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_TEXCOORD01 ] ) ;
2016-05-18 13:22:14 +02:00
// Bind mesh VBO data: vertex normals (shader-location = 2, if available)
2017-07-17 00:33:40 +02:00
if ( material . shader . locs [ LOC_VERTEX_NORMAL ] ! = - 1 )
2016-05-18 13:22:14 +02:00
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 2 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_NORMAL ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_NORMAL ] ) ;
2016-05-18 13:22:14 +02:00
}
2017-01-28 23:02:30 +01:00
2016-07-04 18:34:28 +02:00
// Bind mesh VBO data: vertex colors (shader-location = 3, if available)
2017-07-17 00:33:40 +02:00
if ( material . shader . locs [ LOC_VERTEX_COLOR ] ! = - 1 )
2016-05-18 13:22:14 +02:00
{
2016-07-04 18:34:28 +02:00
if ( mesh . vboId [ 3 ] ! = 0 )
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 3 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_COLOR ] ) ;
2016-07-04 18:34:28 +02:00
}
else
{
// Set default value for unused attribute
// NOTE: Required when using default shader and no VAO support
2017-07-17 00:33:40 +02:00
glVertexAttrib4f ( material . shader . locs [ LOC_VERTEX_COLOR ] , 1.0f , 1.0f , 1.0f , 1.0f ) ;
glDisableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_COLOR ] ) ;
2016-07-04 18:34:28 +02:00
}
2016-05-18 13:22:14 +02:00
}
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
2017-07-17 00:33:40 +02:00
if ( material . shader . locs [ LOC_VERTEX_TANGENT ] ! = - 1 )
2016-05-18 13:22:14 +02:00
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 4 ] ) ;
2018-02-24 12:31:32 +01:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_TANGENT ] , 4 , GL_FLOAT , 0 , 0 , 0 ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_TANGENT ] ) ;
2016-05-18 13:22:14 +02:00
}
2017-01-28 23:02:30 +01:00
2016-05-18 13:22:14 +02:00
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
2017-07-17 00:33:40 +02:00
if ( material . shader . locs [ LOC_VERTEX_TEXCOORD02 ] ! = - 1 )
2016-05-18 13:22:14 +02:00
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 5 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( material . shader . locs [ LOC_VERTEX_TEXCOORD02 ] , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . locs [ LOC_VERTEX_TEXCOORD02 ] ) ;
2016-05-18 13:22:14 +02:00
}
2017-01-28 23:02:30 +01:00
2017-07-17 00:33:40 +02:00
if ( mesh . indices ! = NULL ) glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , mesh . vboId [ 6 ] ) ;
2016-05-18 13:22:14 +02:00
}
2017-03-14 01:05:22 +01:00
int eyesCount = 1 ;
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2017-03-14 01:05:22 +01:00
if ( vrStereoRender ) eyesCount = 2 ;
2017-04-18 11:49:02 +02:00
# endif
2018-06-30 21:56:26 +02:00
2016-07-04 01:29:23 +02:00
for ( int eye = 0 ; eye < eyesCount ; eye + + )
{
2017-04-18 11:49:02 +02:00
if ( eyesCount = = 1 ) modelview = matModelView ;
# if defined(SUPPORT_VR_SIMULATOR)
else SetStereoView ( eye , matProjection , matModelView ) ;
# endif
2016-07-04 01:29:23 +02:00
// Calculate model-view-projection matrix (MVP)
Matrix matMVP = MatrixMultiply ( modelview , projection ) ; // Transform to screen-space coordinates
// Send combined model-view-projection matrix to shader
2017-07-17 00:33:40 +02:00
glUniformMatrix4fv ( material . shader . locs [ LOC_MATRIX_MVP ] , 1 , false , MatrixToFloat ( matMVP ) ) ;
2016-07-04 01:29:23 +02:00
// Draw call!
if ( mesh . indices ! = NULL ) glDrawElements ( GL_TRIANGLES , mesh . triangleCount * 3 , GL_UNSIGNED_SHORT , 0 ) ; // Indexed vertices draw
else glDrawArrays ( GL_TRIANGLES , 0 , mesh . vertexCount ) ;
}
2018-06-30 21:56:26 +02:00
2017-07-17 00:33:40 +02:00
// Unbind all binded texture maps
2017-07-19 10:09:34 +02:00
for ( int i = 0 ; i < MAX_MATERIAL_MAPS ; i + + )
2016-05-18 13:22:14 +02:00
{
2017-07-17 00:33:40 +02:00
glActiveTexture ( GL_TEXTURE0 + i ) ; // Set shader active texture
2017-07-19 10:09:34 +02:00
if ( ( i = = MAP_IRRADIANCE ) | | ( i = = MAP_PREFILTER ) | | ( i = = MAP_CUBEMAP ) ) glBindTexture ( GL_TEXTURE_CUBE_MAP , 0 ) ;
2017-07-17 00:33:40 +02:00
else glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind current active texture
2016-05-18 13:22:14 +02:00
}
2017-07-17 00:33:40 +02:00
// Unind vertex array objects (or VBOs)
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2016-05-18 13:22:14 +02:00
else
{
2017-07-17 00:33:40 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2016-05-18 13:22:14 +02:00
if ( mesh . indices ! = NULL ) glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
2017-07-17 00:33:40 +02:00
// Unbind shader program
glUseProgram ( 0 ) ;
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
// Restore projection/modelview matrices
2017-07-17 00:33:40 +02:00
// NOTE: In stereo rendering matrices are being modified to fit every eye
2016-07-04 01:29:23 +02:00
projection = matProjection ;
modelview = matView ;
2016-05-18 13:22:14 +02:00
# endif
}
// Unload mesh data from CPU and GPU
2017-07-17 00:33:40 +02:00
void rlUnloadMesh ( Mesh * mesh )
2016-05-18 13:22:14 +02:00
{
if ( mesh - > vertices ! = NULL ) free ( mesh - > vertices ) ;
if ( mesh - > texcoords ! = NULL ) free ( mesh - > texcoords ) ;
if ( mesh - > normals ! = NULL ) free ( mesh - > normals ) ;
if ( mesh - > colors ! = NULL ) free ( mesh - > colors ) ;
if ( mesh - > tangents ! = NULL ) free ( mesh - > tangents ) ;
if ( mesh - > texcoords2 ! = NULL ) free ( mesh - > texcoords2 ) ;
if ( mesh - > indices ! = NULL ) free ( mesh - > indices ) ;
rlDeleteBuffers ( mesh - > vboId [ 0 ] ) ; // vertex
rlDeleteBuffers ( mesh - > vboId [ 1 ] ) ; // texcoords
rlDeleteBuffers ( mesh - > vboId [ 2 ] ) ; // normals
rlDeleteBuffers ( mesh - > vboId [ 3 ] ) ; // colors
rlDeleteBuffers ( mesh - > vboId [ 4 ] ) ; // tangents
rlDeleteBuffers ( mesh - > vboId [ 5 ] ) ; // texcoords2
rlDeleteBuffers ( mesh - > vboId [ 6 ] ) ; // indices
rlDeleteVertexArrays ( mesh - > vaoId ) ;
}
2015-07-13 18:20:16 +02:00
// Read screen pixel data (color buffer)
2017-07-17 00:33:40 +02:00
unsigned char * rlReadScreenPixels ( int width , int height )
2015-07-13 18:20:16 +02:00
{
2017-02-01 00:28:28 +01:00
unsigned char * screenData = ( unsigned char * ) calloc ( width * height * 4 , sizeof ( unsigned char ) ) ;
2015-07-13 18:20:16 +02:00
// NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
glReadPixels ( 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , screenData ) ;
// Flip image vertically!
2015-08-29 17:01:36 +02:00
unsigned char * imgData = ( unsigned char * ) malloc ( width * height * sizeof ( unsigned char ) * 4 ) ;
2015-07-13 18:20:16 +02:00
2015-11-05 09:46:18 +01:00
for ( int y = height - 1 ; y > = 0 ; y - - )
2015-07-13 18:20:16 +02:00
{
for ( int x = 0 ; x < ( width * 4 ) ; x + + )
{
2015-11-05 09:46:18 +01:00
// Flip line
imgData [ ( ( height - 1 ) - y ) * width * 4 + x ] = screenData [ ( y * width * 4 ) + x ] ;
2017-01-28 23:02:30 +01:00
2015-11-05 09:46:18 +01:00
// Set alpha component value to 255 (no trasparent image retrieval)
// NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
if ( ( ( x + 1 ) % 4 ) = = 0 ) imgData [ ( ( height - 1 ) - y ) * width * 4 + x ] = 255 ;
2015-07-13 18:20:16 +02:00
}
}
free ( screenData ) ;
return imgData ; // NOTE: image data should be freed
}
// Read texture pixel data
2015-11-05 12:32:47 +01:00
// NOTE: glGetTexImage() is not available on OpenGL ES 2.0
// Texture2D width and height are required on OpenGL ES 2.0. There is no way to get it from texture id.
2017-07-17 00:33:40 +02:00
void * rlReadTexturePixels ( Texture2D texture )
2015-07-13 18:20:16 +02:00
{
2015-07-18 19:25:15 +02:00
void * pixels = NULL ;
2017-01-28 23:02:30 +01:00
2015-07-18 19:25:15 +02:00
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2015-11-05 12:32:47 +01:00
glBindTexture ( GL_TEXTURE_2D , texture . id ) ;
2017-01-28 23:02:30 +01:00
2015-11-05 12:32:47 +01:00
// NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0)
/*
int width , height , format ;
2015-07-13 18:20:16 +02:00
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & width ) ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_HEIGHT , & height ) ;
2015-11-05 12:32:47 +01:00
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_INTERNAL_FORMAT , & format ) ;
// Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
*/
2018-06-30 21:56:26 +02:00
2015-07-13 18:20:16 +02:00
// 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.
2017-01-28 23:02:30 +01:00
// Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
// GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
2015-07-13 18:20:16 +02:00
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2015-08-07 17:24:28 +02:00
2018-01-22 00:20:42 +01:00
int glInternalFormat , glFormat , glType ;
GetGlFormats ( texture . format , & glInternalFormat , & glFormat , & glType ) ;
unsigned int size = GetPixelDataSize ( texture . width , texture . height , texture . format ) ;
2018-06-30 21:56:26 +02:00
2018-01-22 00:20:42 +01:00
if ( ( glInternalFormat ! = - 1 ) & & ( texture . format < COMPRESSED_DXT1_RGB ) )
{
pixels = ( unsigned char * ) malloc ( size ) ;
glGetTexImage ( GL_TEXTURE_2D , 0 , glFormat , glType , pixels ) ;
}
else TraceLog ( LOG_WARNING , " Texture data retrieval not suported for pixel format " ) ;
2017-01-28 23:02:30 +01:00
2015-07-13 18:20:16 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-07-18 19:25:15 +02:00
# endif
2015-10-06 17:25:27 +02:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2017-07-17 00:33:40 +02:00
RenderTexture2D fbo = rlLoadRenderTexture ( texture . width , texture . height ) ;
2016-04-17 11:25:04 +02:00
2015-11-04 18:33:46 +01:00
// NOTE: Two possible Options:
// 1 - Bind texture to color fbo attachment and glReadPixels()
// 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
2017-01-28 23:02:30 +01:00
2015-11-05 12:32:47 +01:00
# define GET_TEXTURE_FBO_OPTION_1 // It works
2015-11-04 18:33:46 +01:00
# if defined(GET_TEXTURE_FBO_OPTION_1)
glBindFramebuffer ( GL_FRAMEBUFFER , fbo . id ) ;
2015-11-05 12:32:47 +01:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-11-04 18:33:46 +01:00
2017-10-25 12:33:44 +02:00
// Attach our texture to FBO -> Texture must be RGBA
2015-11-05 12:32:47 +01:00
// NOTE: Previoust attached texture is automatically detached
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texture . id , 0 ) ;
2017-01-28 23:02:30 +01:00
2015-11-05 12:32:47 +01:00
pixels = ( unsigned char * ) malloc ( texture . width * texture . height * 4 * sizeof ( unsigned char ) ) ;
2017-01-28 23:02:30 +01:00
2017-04-05 00:02:40 +02:00
// NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture...
2015-11-05 12:32:47 +01:00
glReadPixels ( 0 , 0 , texture . width , texture . height , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
2017-01-28 23:02:30 +01:00
2015-11-05 12:32:47 +01:00
// Re-attach internal FBO color texture before deleting it
2016-04-17 11:25:04 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , fbo . texture . id , 0 ) ;
2017-01-28 23:02:30 +01:00
2015-11-04 18:33:46 +01:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2017-01-28 23:02:30 +01:00
2015-11-04 18:33:46 +01:00
# elif defined(GET_TEXTURE_FBO_OPTION_2)
2015-10-06 17:25:27 +02:00
// Render texture to fbo
glBindFramebuffer ( GL_FRAMEBUFFER , fbo . id ) ;
2017-01-28 23:02:30 +01:00
2016-01-13 19:30:35 +01:00
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
2015-10-06 17:25:27 +02:00
glClearDepthf ( 1.0f ) ;
//glDisable(GL_TEXTURE_2D);
glEnable ( GL_DEPTH_TEST ) ;
2017-10-25 12:46:26 +02:00
//glDisable(GL_BLEND);
2018-06-30 21:56:26 +02:00
2017-10-30 13:51:46 +01:00
glViewport ( 0 , 0 , texture . width , texture . height ) ;
rlOrtho ( 0.0 , texture . width , texture . height , 0.0 , 0.0 , 1.0 ) ;
2017-01-28 23:02:30 +01:00
2017-10-25 12:46:26 +02:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glUseProgram ( GetShaderDefault ( ) . id ) ;
glBindTexture ( GL_TEXTURE_2D , texture . id ) ;
GenDrawQuad ( ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glUseProgram ( 0 ) ;
2018-06-30 21:56:26 +02:00
2017-10-25 12:46:26 +02:00
pixels = ( unsigned char * ) malloc ( texture . width * texture . height * 4 * sizeof ( unsigned char ) ) ;
2017-01-28 23:02:30 +01:00
2017-10-25 12:46:26 +02:00
glReadPixels ( 0 , 0 , texture . width , texture . height , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
2015-10-06 17:25:27 +02:00
// Bind framebuffer 0, which means render to back buffer
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-10-25 12:46:26 +02:00
// Reset viewport dimensions to default
glViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2018-06-30 21:56:26 +02:00
2015-11-04 18:33:46 +01:00
# endif // GET_TEXTURE_FBO_OPTION
2015-10-06 17:25:27 +02:00
// Clean up temporal fbo
2016-04-17 11:25:04 +02:00
rlDeleteRenderTextures ( fbo ) ;
2015-10-06 17:25:27 +02:00
# endif
2015-07-13 18:20:16 +02:00
return pixels ;
}
2016-06-12 19:40:08 +02:00
/*
// TODO: Record draw calls to be processed in batch
// NOTE: Global state must be kept
2017-07-17 00:33:40 +02:00
void rlRecordDraw ( void )
2016-06-12 19:40:08 +02:00
{
// TODO: Before adding a new draw, check if anything changed from last stored draw
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
draws [ drawsCounter ] . vaoId = currentState . vaoId ; // lines.id, trangles.id, quads.id?
draws [ drawsCounter ] . textureId = currentState . textureId ; // whiteTexture?
draws [ drawsCounter ] . shaderId = currentState . shaderId ; // defaultShader.id
draws [ drawsCounter ] . projection = projection ;
draws [ drawsCounter ] . modelview = modelview ;
draws [ drawsCounter ] . vertexCount = currentState . vertexCount ;
2017-01-28 23:02:30 +01:00
2016-06-12 19:40:08 +02:00
drawsCounter + + ;
# endif
}
*/
2015-07-13 18:20:16 +02:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Shaders Functions
// NOTE: Those functions are exposed directly to the user in raylib.h
//----------------------------------------------------------------------------------
2016-05-07 18:28:40 +02:00
// Get default internal texture (white texture)
2017-07-17 00:33:40 +02:00
Texture2D GetTextureDefault ( void )
2016-05-07 18:28:40 +02:00
{
Texture2D texture ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:28:40 +02:00
texture . id = whiteTexture ;
texture . width = 1 ;
texture . height = 1 ;
texture . mipmaps = 1 ;
texture . format = UNCOMPRESSED_R8G8B8A8 ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:28:40 +02:00
return texture ;
}
2017-07-19 10:09:34 +02:00
// Get default shader
Shader GetShaderDefault ( void )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
return defaultShader ;
# else
Shader shader = { 0 } ;
return shader ;
# endif
}
2017-01-15 01:09:15 +01:00
// Load text data from file
// NOTE: text chars array should be freed manually
char * LoadText ( const char * fileName )
{
FILE * textFile ;
char * text = NULL ;
int count = 0 ;
if ( fileName ! = NULL )
{
textFile = fopen ( fileName , " rt " ) ;
if ( textFile ! = NULL )
{
fseek ( textFile , 0 , SEEK_END ) ;
count = ftell ( textFile ) ;
rewind ( textFile ) ;
if ( count > 0 )
{
text = ( char * ) malloc ( sizeof ( char ) * ( count + 1 ) ) ;
count = fread ( text , sizeof ( char ) , count , textFile ) ;
text [ count ] = ' \0 ' ;
}
fclose ( textFile ) ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " [%s] Text file could not be opened " , fileName ) ;
2017-01-15 01:09:15 +01:00
}
return text ;
}
2016-12-25 02:01:13 +01:00
// Load shader from files and bind default locations
2017-11-12 10:33:44 +01:00
// NOTE: If shader string is NULL, using default vertex/fragment shaders
2018-02-05 01:03:13 +01:00
Shader LoadShader ( const char * vsFileName , const char * fsFileName )
2015-07-13 18:20:16 +02:00
{
2016-04-03 18:31:42 +02:00
Shader shader = { 0 } ;
2018-02-05 01:03:13 +01:00
char * vShaderStr = NULL ;
char * fShaderStr = NULL ;
if ( vsFileName ! = NULL ) vShaderStr = LoadText ( vsFileName ) ;
if ( fsFileName ! = NULL ) fShaderStr = LoadText ( fsFileName ) ;
2018-06-30 21:56:26 +02:00
2018-02-05 01:03:13 +01:00
shader = LoadShaderCode ( vShaderStr , fShaderStr ) ;
2018-06-30 21:56:26 +02:00
2018-02-05 01:03:13 +01:00
if ( vShaderStr ! = NULL ) free ( vShaderStr ) ;
if ( fShaderStr ! = NULL ) free ( fShaderStr ) ;
return shader ;
}
// Load shader from code strings
// NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShaderCode ( char * vsCode , char * fsCode )
{
Shader shader = { 0 } ;
2017-11-06 13:41:13 +01:00
// NOTE: All locations must be reseted to -1 (no location)
for ( int i = 0 ; i < MAX_SHADER_LOCATIONS ; i + + ) shader . locs [ i ] = - 1 ;
2018-06-30 21:56:26 +02:00
2015-03-01 16:00:52 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-12-13 20:10:13 +01:00
unsigned int vertexShaderId = defaultVShaderId ;
unsigned int fragmentShaderId = defaultFShaderId ;
2018-06-30 21:56:26 +02:00
2018-02-05 01:03:13 +01:00
if ( vsCode ! = NULL ) vertexShaderId = CompileShader ( vsCode , GL_VERTEX_SHADER ) ;
if ( fsCode ! = NULL ) fragmentShaderId = CompileShader ( fsCode , GL_FRAGMENT_SHADER ) ;
2018-06-30 21:56:26 +02:00
2017-12-13 20:10:13 +01:00
if ( ( vertexShaderId = = defaultVShaderId ) & & ( fragmentShaderId = = defaultFShaderId ) ) shader = defaultShader ;
2018-06-30 21:56:26 +02:00
else
2015-08-03 17:27:53 +02:00
{
2017-12-13 20:10:13 +01:00
shader . id = LoadShaderProgram ( vertexShaderId , fragmentShaderId ) ;
2017-11-09 20:47:22 +01:00
2017-12-13 20:10:13 +01:00
if ( vertexShaderId ! = defaultVShaderId ) glDeleteShader ( vertexShaderId ) ;
if ( fragmentShaderId ! = defaultFShaderId ) glDeleteShader ( fragmentShaderId ) ;
2017-11-09 20:47:22 +01:00
2017-12-13 20:10:13 +01:00
if ( shader . id = = 0 )
{
TraceLog ( LOG_WARNING , " Custom shader could not be loaded " ) ;
shader = defaultShader ;
}
2018-06-30 21:56:26 +02:00
2017-12-13 20:10:13 +01:00
// After shader loading, we TRY to set default location names
if ( shader . id > 0 ) SetShaderDefaultLocations ( & shader ) ;
2017-01-28 23:02:30 +01:00
}
2018-06-30 21:56:26 +02:00
2017-07-17 00:33:40 +02:00
// Get available shader uniforms
// NOTE: This information is useful for debug...
int uniformCount = - 1 ;
2018-06-30 21:56:26 +02:00
2017-07-17 00:33:40 +02:00
glGetProgramiv ( shader . id , GL_ACTIVE_UNIFORMS , & uniformCount ) ;
2018-06-30 21:56:26 +02:00
2017-07-17 00:33:40 +02:00
for ( int i = 0 ; i < uniformCount ; i + + )
{
int namelen = - 1 ;
int num = - 1 ;
char name [ 256 ] ; // Assume no variable names longer than 256
GLenum type = GL_ZERO ;
// Get the name of the uniforms
glGetActiveUniform ( shader . id , i , sizeof ( name ) - 1 , & namelen , & num , & type , name ) ;
2018-06-30 21:56:26 +02:00
2017-07-17 00:33:40 +02:00
name [ namelen ] = 0 ;
// Get the location of the named uniform
GLuint location = glGetUniformLocation ( shader . id , name ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 18:55:26 +02:00
TraceLog ( LOG_DEBUG , " [SHDR ID %i] Active uniform [%s] set at location: %i " , shader . id , name , location ) ;
2017-07-17 00:33:40 +02:00
}
2015-07-13 18:20:16 +02:00
# endif
2018-06-30 21:56:26 +02:00
2015-07-13 18:20:16 +02:00
return shader ;
}
2016-12-25 02:01:13 +01:00
// Unload shader from GPU memory (VRAM)
2015-07-13 18:20:16 +02:00
void UnloadShader ( Shader shader )
2014-03-25 12:40:35 +01:00
{
2017-07-17 00:33:40 +02:00
if ( shader . id > 0 )
2015-09-01 23:15:26 +02:00
{
rlDeleteShader ( shader . id ) ;
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [SHDR ID %i] Unloaded shader program data " , shader . id ) ;
2015-09-01 23:15:26 +02:00
}
2015-07-13 18:20:16 +02:00
}
2014-03-25 12:40:35 +01:00
2016-06-02 20:23:09 +02:00
// Begin custom shader mode
2016-05-31 17:11:02 +02:00
void BeginShaderMode ( Shader shader )
2015-07-13 18:20:16 +02:00
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ( currentShader . id ! = shader . id )
{
rlglDraw ( ) ;
currentShader = shader ;
}
# endif
2014-03-25 12:40:35 +01:00
}
2016-06-02 20:23:09 +02:00
// End custom shader mode (returns to default shader)
2016-05-31 17:11:02 +02:00
void EndShaderMode ( void )
2015-02-02 00:57:08 +01:00
{
2015-04-06 14:02:29 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-31 17:11:02 +02:00
BeginShaderMode ( defaultShader ) ;
2015-04-06 14:02:29 +02:00
# endif
2015-02-02 00:57:08 +01:00
}
2015-07-13 18:20:16 +02:00
// Get shader uniform location
2015-05-21 14:13:51 +02:00
int GetShaderLocation ( Shader shader , const char * uniformName )
{
2015-07-05 18:21:01 +02:00
int location = - 1 ;
2017-01-28 23:02:30 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-07-05 18:21:01 +02:00
location = glGetUniformLocation ( shader . id , uniformName ) ;
2017-01-28 23:02:30 +01:00
2017-07-17 00:33:40 +02:00
if ( location = = - 1 ) TraceLog ( LOG_WARNING , " [SHDR ID %i] Shader uniform [%s] COULD NOT BE FOUND " , shader . id , uniformName ) ;
else TraceLog ( LOG_INFO , " [SHDR ID %i] Shader uniform [%s] set at location: %i " , shader . id , uniformName , location ) ;
2015-07-05 18:21:01 +02:00
# endif
2015-05-21 14:13:51 +02:00
return location ;
}
2015-07-13 18:20:16 +02:00
// Set shader uniform value (float)
2017-11-05 21:57:29 +01:00
void SetShaderValue ( Shader shader , int uniformLoc , const float * value , int size )
2015-05-21 14:13:51 +02:00
{
2015-07-05 18:21:01 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-05-21 14:13:51 +02:00
glUseProgram ( shader . id ) ;
if ( size = = 1 ) glUniform1fv ( uniformLoc , 1 , value ) ; // Shader uniform type: float
else if ( size = = 2 ) glUniform2fv ( uniformLoc , 1 , value ) ; // Shader uniform type: vec2
else if ( size = = 3 ) glUniform3fv ( uniformLoc , 1 , value ) ; // Shader uniform type: vec3
else if ( size = = 4 ) glUniform4fv ( uniformLoc , 1 , value ) ; // Shader uniform type: vec4
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " Shader value float array size not supported " ) ;
2017-01-28 23:02:30 +01:00
2017-01-27 23:03:08 +01:00
//glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set
2015-07-05 18:21:01 +02:00
# endif
2015-05-21 14:13:51 +02:00
}
2017-07-19 10:09:34 +02:00
// Set shader uniform value (int)
2017-11-05 21:57:29 +01:00
void SetShaderValuei ( Shader shader , int uniformLoc , const int * value , int size )
2017-07-19 10:09:34 +02:00
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram ( shader . id ) ;
if ( size = = 1 ) glUniform1iv ( uniformLoc , 1 , value ) ; // Shader uniform type: int
else if ( size = = 2 ) glUniform2iv ( uniformLoc , 1 , value ) ; // Shader uniform type: ivec2
else if ( size = = 3 ) glUniform3iv ( uniformLoc , 1 , value ) ; // Shader uniform type: ivec3
else if ( size = = 4 ) glUniform4iv ( uniformLoc , 1 , value ) ; // Shader uniform type: ivec4
else TraceLog ( LOG_WARNING , " Shader value int array size not supported " ) ;
//glUseProgram(0);
# endif
}
// Set shader uniform value (matrix 4x4)
void SetShaderValueMatrix ( Shader shader , int uniformLoc , Matrix mat )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram ( shader . id ) ;
glUniformMatrix4fv ( uniformLoc , 1 , false , MatrixToFloat ( mat ) ) ;
//glUseProgram(0);
# endif
}
// Set a custom projection matrix (replaces internal projection matrix)
void SetMatrixProjection ( Matrix proj )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
projection = proj ;
# endif
}
// Set a custom modelview matrix (replaces internal modelview matrix)
void SetMatrixModelview ( Matrix view )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
modelview = view ;
# endif
}
2018-01-16 00:00:05 +01:00
// Return internal modelview matrix
2018-06-30 21:56:26 +02:00
Matrix GetMatrixModelview ( )
2018-01-16 00:00:05 +01:00
{
Matrix matrix = MatrixIdentity ( ) ;
# if defined(GRAPHICS_API_OPENGL_11)
float mat [ 16 ] ;
glGetFloatv ( GL_MODELVIEW_MATRIX , mat ) ;
# else
matrix = modelview ;
2017-12-14 11:43:06 +01:00
# endif
2018-01-16 00:00:05 +01:00
return matrix ;
2017-12-14 11:43:06 +01:00
}
2017-07-19 10:09:34 +02:00
// Generate cubemap texture from HDR texture
2017-07-28 19:59:04 +02:00
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
2017-07-19 18:55:26 +02:00
Texture2D GenTextureCubemap ( Shader shader , Texture2D skyHDR , int size )
2017-07-19 10:09:34 +02:00
{
Texture2D cubemap = { 0 } ;
2018-06-30 21:56:26 +02:00
# if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-20 14:27:59 +02:00
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
2017-07-21 09:34:09 +02:00
// Other locations should be setup externally in shader before calling the function
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Set up depth face culling and cubemap seamless
glDisable ( GL_CULL_FACE ) ;
2017-07-28 19:59:04 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
glEnable ( GL_TEXTURE_CUBE_MAP_SEAMLESS ) ; // Flag not supported on OpenGL ES 2.0
# endif
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Setup framebuffer
unsigned int fbo , rbo ;
glGenFramebuffers ( 1 , & fbo ) ;
glGenRenderbuffers ( 1 , & rbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , rbo ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , size , size ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rbo ) ;
// Set up cubemap to render and attach to framebuffer
// NOTE: faces are stored with 16 bit floating point values
glGenTextures ( 1 , & cubemap . id ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , cubemap . id ) ;
2018-06-30 21:56:26 +02:00
for ( unsigned int i = 0 ; i < 6 ; i + + )
2017-07-19 10:09:34 +02:00
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , 0 , GL_RGB16F , size , size , 0 , GL_RGB , GL_FLOAT , NULL ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
2017-07-28 19:59:04 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE ) ; // Flag not supported on OpenGL ES 2.0
# endif
2017-07-19 10:09:34 +02:00
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
// Create projection (transposed) and different views for each face
2017-07-21 10:42:57 +02:00
Matrix fboProjection = MatrixPerspective ( 90.0 * DEG2RAD , 1.0 , 0.01 , 1000.0 ) ;
2017-07-21 17:19:28 +02:00
//MatrixTranspose(&fboProjection);
2017-07-19 10:09:34 +02:00
Matrix fboViews [ 6 ] = {
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { - 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } )
} ;
// Convert HDR equirectangular environment map to cubemap equivalent
glUseProgram ( shader . id ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , skyHDR . id ) ;
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_PROJECTION ] , fboProjection ) ;
2017-07-19 10:09:34 +02:00
// Note: don't forget to configure the viewport to the capture dimensions
glViewport ( 0 , 0 , size , size ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
for ( unsigned int i = 0 ; i < 6 ; i + + )
{
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_VIEW ] , fboViews [ i ] ) ;
2017-07-19 10:09:34 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , cubemap . id , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
GenDrawCube ( ) ;
}
// Unbind framebuffer and textures
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Reset viewport dimensions to default
2017-07-21 10:42:57 +02:00
glViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-07-19 10:09:34 +02:00
//glEnable(GL_CULL_FACE);
cubemap . width = size ;
cubemap . height = size ;
2017-07-20 12:26:25 +02:00
# endif
2017-07-19 10:09:34 +02:00
return cubemap ;
}
// Generate irradiance texture using cubemap data
2017-07-28 19:59:04 +02:00
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
2017-07-19 18:55:26 +02:00
Texture2D GenTextureIrradiance ( Shader shader , Texture2D cubemap , int size )
2017-07-19 10:09:34 +02:00
{
Texture2D irradiance = { 0 } ;
2018-06-30 21:56:26 +02:00
2017-07-28 19:59:04 +02:00
# if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-20 14:27:59 +02:00
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
2017-07-21 09:34:09 +02:00
// Other locations should be setup externally in shader before calling the function
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Setup framebuffer
unsigned int fbo , rbo ;
glGenFramebuffers ( 1 , & fbo ) ;
glGenRenderbuffers ( 1 , & rbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , rbo ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , size , size ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rbo ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Create an irradiance cubemap, and re-scale capture FBO to irradiance scale
glGenTextures ( 1 , & irradiance . id ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , irradiance . id ) ;
2018-06-30 21:56:26 +02:00
for ( unsigned int i = 0 ; i < 6 ; i + + )
2017-07-19 10:09:34 +02:00
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , 0 , GL_RGB16F , size , size , 0 , GL_RGB , GL_FLOAT , NULL ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Create projection (transposed) and different views for each face
2017-07-21 10:42:57 +02:00
Matrix fboProjection = MatrixPerspective ( 90.0 * DEG2RAD , 1.0 , 0.01 , 1000.0 ) ;
2017-07-21 17:19:28 +02:00
//MatrixTranspose(&fboProjection);
2017-07-19 10:09:34 +02:00
Matrix fboViews [ 6 ] = {
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { - 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } )
} ;
// Solve diffuse integral by convolution to create an irradiance cubemap
glUseProgram ( shader . id ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , cubemap . id ) ;
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_PROJECTION ] , fboProjection ) ;
2017-07-19 10:09:34 +02:00
// Note: don't forget to configure the viewport to the capture dimensions
glViewport ( 0 , 0 , size , size ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
for ( unsigned int i = 0 ; i < 6 ; i + + )
{
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_VIEW ] , fboViews [ i ] ) ;
2017-07-19 10:09:34 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , irradiance . id , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
GenDrawCube ( ) ;
}
// Unbind framebuffer and textures
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Reset viewport dimensions to default
2017-07-21 10:42:57 +02:00
glViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-07-19 18:55:26 +02:00
2017-07-19 10:09:34 +02:00
irradiance . width = size ;
irradiance . height = size ;
2017-07-20 12:26:25 +02:00
# endif
2017-07-19 10:09:34 +02:00
return irradiance ;
}
// Generate prefilter texture using cubemap data
2017-07-28 19:59:04 +02:00
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
2017-07-19 18:55:26 +02:00
Texture2D GenTexturePrefilter ( Shader shader , Texture2D cubemap , int size )
2015-07-13 18:20:16 +02:00
{
2017-07-19 10:09:34 +02:00
Texture2D prefilter = { 0 } ;
2018-06-30 21:56:26 +02:00
2017-07-28 19:59:04 +02:00
# if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-20 14:27:59 +02:00
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
2017-07-21 09:34:09 +02:00
// Other locations should be setup externally in shader before calling the function
2017-07-20 14:27:59 +02:00
// TODO: Locations should be taken out of this function... too shader dependant...
2017-07-21 09:34:09 +02:00
int roughnessLoc = GetShaderLocation ( shader , " roughness " ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Setup framebuffer
unsigned int fbo , rbo ;
glGenFramebuffers ( 1 , & fbo ) ;
glGenRenderbuffers ( 1 , & rbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , rbo ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , size , size ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rbo ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Create a prefiltered HDR environment map
glGenTextures ( 1 , & prefilter . id ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , prefilter . id ) ;
2018-06-30 21:56:26 +02:00
for ( unsigned int i = 0 ; i < 6 ; i + + )
2017-07-19 10:09:34 +02:00
glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , 0 , GL_RGB16F , size , size , 0 , GL_RGB , GL_FLOAT , NULL ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
// Generate mipmaps for the prefiltered HDR texture
glGenerateMipmap ( GL_TEXTURE_CUBE_MAP ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Create projection (transposed) and different views for each face
2017-07-21 10:42:57 +02:00
Matrix fboProjection = MatrixPerspective ( 90.0 * DEG2RAD , 1.0 , 0.01 , 1000.0 ) ;
2017-07-21 17:19:28 +02:00
//MatrixTranspose(&fboProjection);
2017-07-19 10:09:34 +02:00
Matrix fboViews [ 6 ] = {
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { - 1.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } ) ,
MatrixLookAt ( ( Vector3 ) { 0.0f , 0.0f , 0.0f } , ( Vector3 ) { 0.0f , 0.0f , - 1.0f } , ( Vector3 ) { 0.0f , - 1.0f , 0.0f } )
} ;
// Prefilter HDR and store data into mipmap levels
2015-07-13 18:20:16 +02:00
glUseProgram ( shader . id ) ;
2017-07-19 10:09:34 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_CUBE_MAP , cubemap . id ) ;
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_PROJECTION ] , fboProjection ) ;
2015-07-13 18:20:16 +02:00
2017-07-19 10:09:34 +02:00
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
# define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps
2017-01-28 23:02:30 +01:00
2017-07-19 10:09:34 +02:00
for ( unsigned int mip = 0 ; mip < MAX_MIPMAP_LEVELS ; mip + + )
{
// Resize framebuffer according to mip-level size.
unsigned int mipWidth = size * powf ( 0.5f , mip ) ;
unsigned int mipHeight = size * powf ( 0.5f , mip ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
glBindRenderbuffer ( GL_RENDERBUFFER , rbo ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , mipWidth , mipHeight ) ;
glViewport ( 0 , 0 , mipWidth , mipHeight ) ;
2015-07-13 18:20:16 +02:00
2017-07-19 10:09:34 +02:00
float roughness = ( float ) mip / ( float ) ( MAX_MIPMAP_LEVELS - 1 ) ;
glUniform1f ( roughnessLoc , roughness ) ;
2016-01-25 13:54:09 +01:00
2017-07-19 10:09:34 +02:00
for ( unsigned int i = 0 ; i < 6 ; + + i )
{
2017-07-19 18:55:26 +02:00
SetShaderValueMatrix ( shader , shader . locs [ LOC_MATRIX_VIEW ] , fboViews [ i ] ) ;
2017-07-19 10:09:34 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , prefilter . id , mip ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
GenDrawCube ( ) ;
}
}
2017-01-28 23:02:30 +01:00
2017-07-19 10:09:34 +02:00
// Unbind framebuffer and textures
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Reset viewport dimensions to default
2017-07-21 10:42:57 +02:00
glViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-07-19 18:55:26 +02:00
2017-07-19 10:09:34 +02:00
prefilter . width = size ;
prefilter . height = size ;
2017-07-20 12:26:25 +02:00
# endif
2017-07-19 10:09:34 +02:00
return prefilter ;
2016-01-25 13:54:09 +01:00
}
2017-07-19 10:09:34 +02:00
// Generate BRDF texture using cubemap data
2017-07-28 19:59:04 +02:00
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
2017-07-19 18:55:26 +02:00
Texture2D GenTextureBRDF ( Shader shader , Texture2D cubemap , int size )
2016-06-02 20:23:09 +02:00
{
2017-07-19 10:09:34 +02:00
Texture2D brdf = { 0 } ;
2017-07-28 19:59:04 +02:00
# if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
2017-07-19 10:09:34 +02:00
// Generate BRDF convolution texture
glGenTextures ( 1 , & brdf . id ) ;
glBindTexture ( GL_TEXTURE_2D , brdf . id ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RG16F , size , size , 0 , GL_RG , GL_FLOAT , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2016-06-02 20:23:09 +02:00
2017-07-19 10:09:34 +02:00
// Render BRDF LUT into a quad using FBO
unsigned int fbo , rbo ;
glGenFramebuffers ( 1 , & fbo ) ;
glGenRenderbuffers ( 1 , & rbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , rbo ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , size , size ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , brdf . id , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
glViewport ( 0 , 0 , size , size ) ;
glUseProgram ( shader . id ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
GenDrawQuad ( ) ;
// Unbind framebuffer and textures
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
// Reset viewport dimensions to default
2017-07-21 10:42:57 +02:00
glViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
brdf . width = size ;
brdf . height = size ;
2017-07-20 12:26:25 +02:00
# endif
2017-07-19 10:09:34 +02:00
return brdf ;
2016-06-02 20:23:09 +02:00
}
2016-05-31 17:11:02 +02:00
// Begin blending mode (alpha, additive, multiplied)
// NOTE: Only 3 blending modes supported, default blend mode is alpha
void BeginBlendMode ( int mode )
2015-08-07 17:24:28 +02:00
{
if ( ( blendMode ! = mode ) & & ( mode < 3 ) )
{
rlglDraw ( ) ;
2017-01-28 23:02:30 +01:00
2015-08-07 17:24:28 +02:00
switch ( mode )
{
case BLEND_ALPHA : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ; break ;
case BLEND_ADDITIVE : glBlendFunc ( GL_SRC_ALPHA , GL_ONE ) ; break ; // Alternative: glBlendFunc(GL_ONE, GL_ONE);
case BLEND_MULTIPLIED : glBlendFunc ( GL_DST_COLOR , GL_ONE_MINUS_SRC_ALPHA ) ; break ;
default : break ;
}
2017-01-28 23:02:30 +01:00
2015-08-07 17:24:28 +02:00
blendMode = mode ;
}
}
2016-05-31 17:11:02 +02:00
// End blending mode (reset to default: alpha blending)
void EndBlendMode ( void )
{
BeginBlendMode ( BLEND_ALPHA ) ;
}
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2017-10-17 13:32:15 +02:00
// Get VR device information for some standard devices
VrDeviceInfo GetVrDeviceInfo ( int vrDeviceType )
2016-06-14 17:16:20 +02:00
{
2017-10-17 13:32:15 +02:00
VrDeviceInfo hmd = { 0 } ; // Current VR device info
2018-06-30 21:56:26 +02:00
2017-10-17 13:32:15 +02:00
switch ( vrDeviceType )
2017-03-14 01:05:22 +01:00
{
2017-10-17 13:32:15 +02:00
case HMD_DEFAULT_DEVICE :
case HMD_OCULUS_RIFT_CV1 :
{
// Oculus Rift CV1 parameters
// NOTE: CV1 represents a complete HMD redesign compared to previous versions,
// new Fresnel-hybrid-asymmetric lenses have been added and, consequently,
// previous parameters (DK2) and distortion shader (DK2) doesn't work any more.
// I just defined a set of parameters for simulator that approximate to CV1 stereo rendering
// but result is not the same obtained with Oculus PC SDK.
hmd . hResolution = 2160 ; // HMD horizontal resolution in pixels
hmd . vResolution = 1200 ; // HMD vertical resolution in pixels
hmd . hScreenSize = 0.133793f ; // HMD horizontal size in meters
hmd . vScreenSize = 0.0669f ; // HMD vertical size in meters
hmd . vScreenCenter = 0.04678f ; // HMD screen center in meters
hmd . eyeToScreenDistance = 0.041f ; // HMD distance between eye and display in meters
hmd . lensSeparationDistance = 0.07f ; // HMD lens separation distance in meters
hmd . interpupillaryDistance = 0.07f ; // HMD IPD (distance between pupils) in meters
hmd . lensDistortionValues [ 0 ] = 1.0f ; // HMD lens distortion constant parameter 0
hmd . lensDistortionValues [ 1 ] = 0.22f ; // HMD lens distortion constant parameter 1
hmd . lensDistortionValues [ 2 ] = 0.24f ; // HMD lens distortion constant parameter 2
hmd . lensDistortionValues [ 3 ] = 0.0f ; // HMD lens distortion constant parameter 3
hmd . chromaAbCorrection [ 0 ] = 0.996f ; // HMD chromatic aberration correction parameter 0
hmd . chromaAbCorrection [ 1 ] = - 0.004f ; // HMD chromatic aberration correction parameter 1
hmd . chromaAbCorrection [ 2 ] = 1.014f ; // HMD chromatic aberration correction parameter 2
hmd . chromaAbCorrection [ 3 ] = 0.0f ; // HMD chromatic aberration correction parameter 3
2018-06-30 21:56:26 +02:00
2017-10-17 13:32:15 +02:00
TraceLog ( LOG_INFO , " Initializing VR Simulator (Oculus Rift CV1) " ) ;
} break ;
case HMD_OCULUS_RIFT_DK2 :
{
// Oculus Rift DK2 parameters
hmd . hResolution = 1280 ; // HMD horizontal resolution in pixels
hmd . vResolution = 800 ; // HMD vertical resolution in pixels
hmd . hScreenSize = 0.14976f ; // HMD horizontal size in meters
hmd . vScreenSize = 0.09356f ; // HMD vertical size in meters
hmd . vScreenCenter = 0.04678f ; // HMD screen center in meters
hmd . eyeToScreenDistance = 0.041f ; // HMD distance between eye and display in meters
hmd . lensSeparationDistance = 0.0635f ; // HMD lens separation distance in meters
hmd . interpupillaryDistance = 0.064f ; // HMD IPD (distance between pupils) in meters
hmd . lensDistortionValues [ 0 ] = 1.0f ; // HMD lens distortion constant parameter 0
hmd . lensDistortionValues [ 1 ] = 0.22f ; // HMD lens distortion constant parameter 1
hmd . lensDistortionValues [ 2 ] = 0.24f ; // HMD lens distortion constant parameter 2
hmd . lensDistortionValues [ 3 ] = 0.0f ; // HMD lens distortion constant parameter 3
hmd . chromaAbCorrection [ 0 ] = 0.996f ; // HMD chromatic aberration correction parameter 0
hmd . chromaAbCorrection [ 1 ] = - 0.004f ; // HMD chromatic aberration correction parameter 1
hmd . chromaAbCorrection [ 2 ] = 1.014f ; // HMD chromatic aberration correction parameter 2
hmd . chromaAbCorrection [ 3 ] = 0.0f ; // HMD chromatic aberration correction parameter 3
2018-06-30 21:56:26 +02:00
2017-10-17 13:32:15 +02:00
TraceLog ( LOG_INFO , " Initializing VR Simulator (Oculus Rift DK2) " ) ;
2018-06-30 21:56:26 +02:00
} break ;
2017-10-17 13:32:15 +02:00
case HMD_OCULUS_GO :
{
// TODO: Provide device display and lens parameters
}
case HMD_VALVE_HTC_VIVE :
{
// TODO: Provide device display and lens parameters
}
case HMD_SONY_PSVR :
{
// TODO: Provide device display and lens parameters
}
default : break ;
2017-03-14 01:05:22 +01:00
}
2018-06-30 21:56:26 +02:00
2017-10-17 13:32:15 +02:00
return hmd ;
}
2017-03-14 01:05:22 +01:00
2017-10-17 13:32:15 +02:00
// Init VR simulator for selected device parameters
// NOTE: It modifies the global variable: VrStereoConfig vrConfig
void InitVrSimulator ( VrDeviceInfo info )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
// Initialize framebuffer and textures for stereo rendering
2017-10-17 13:32:15 +02:00
// NOTE: Screen size should match HMD aspect ratio
2017-07-17 00:33:40 +02:00
vrConfig . stereoFbo = rlLoadRenderTexture ( screenWidth , screenHeight ) ;
2018-06-30 21:56:26 +02:00
2017-03-25 12:01:01 +01:00
# if defined(SUPPORT_DISTORTION_SHADER)
2017-11-12 11:00:28 +01:00
// Load distortion shader
2017-11-12 10:33:44 +01:00
unsigned int vertexShaderId = CompileShader ( distortionVShaderStr , GL_VERTEX_SHADER ) ;
unsigned int fragmentShaderId = CompileShader ( distortionFShaderStr , GL_FRAGMENT_SHADER ) ;
2018-06-30 21:56:26 +02:00
2017-11-12 10:33:44 +01:00
vrConfig . distortionShader . id = LoadShaderProgram ( vertexShaderId , fragmentShaderId ) ;
2017-07-17 00:33:40 +02:00
if ( vrConfig . distortionShader . id > 0 ) SetShaderDefaultLocations ( & vrConfig . distortionShader ) ;
2017-03-25 12:01:01 +01:00
# endif
2017-03-14 01:05:22 +01:00
2017-11-12 11:00:28 +01:00
// Set VR configutarion parameters, including distortion shader
2017-10-17 13:32:15 +02:00
SetStereoConfig ( info ) ;
2017-03-14 01:05:22 +01:00
vrSimulatorReady = true ;
2016-07-11 17:34:12 +02:00
# endif
2016-07-16 14:58:53 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " VR Simulator not supported on OpenGL 1.1 " ) ;
2016-07-16 14:58:53 +02:00
# endif
2016-06-14 17:16:20 +02:00
}
2017-03-14 01:05:22 +01:00
// Close VR simulator for current device
void CloseVrSimulator ( void )
2016-06-14 17:16:20 +02:00
{
2016-07-11 17:34:12 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
if ( vrSimulatorReady )
2016-06-19 19:12:47 +02:00
{
2016-07-10 20:09:18 +02:00
rlDeleteRenderTextures ( vrConfig . stereoFbo ) ; // Unload stereo framebuffer and texture
2017-03-25 12:01:01 +01:00
# if defined(SUPPORT_DISTORTION_SHADER)
2016-07-10 20:09:18 +02:00
UnloadShader ( vrConfig . distortionShader ) ; // Unload distortion shader
2017-03-25 12:01:01 +01:00
# endif
2016-06-19 19:12:47 +02:00
}
2016-07-11 17:34:12 +02:00
# endif
2016-06-26 15:36:12 +02:00
}
2016-10-09 20:56:58 +02:00
// Detect if VR simulator is running
2017-03-14 01:05:22 +01:00
bool IsVrSimulatorReady ( void )
2016-10-09 20:56:58 +02:00
{
2017-03-20 20:34:44 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
return vrSimulatorReady ;
2017-03-20 20:34:44 +01:00
# else
return false ;
# endif
2016-10-09 20:56:58 +02:00
}
2017-11-12 11:00:28 +01:00
// Set VR distortion shader for stereoscopic rendering
// TODO: Review VR system to be more flexible, move distortion shader to user side
void SetVrDistortionShader ( Shader shader )
{
2018-01-16 00:00:05 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-11-12 11:00:28 +01:00
vrConfig . distortionShader = shader ;
//SetStereoConfig(info); // TODO: Must be reviewed to set new distortion shader uniform values...
2018-01-16 00:00:05 +01:00
# endif
2017-11-12 11:00:28 +01:00
}
2016-07-06 00:54:38 +02:00
// Enable/Disable VR experience (device or simulator)
void ToggleVrMode ( void )
2016-06-26 15:36:12 +02:00
{
2016-07-16 14:58:53 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
vrSimulatorReady = ! vrSimulatorReady ;
2017-01-28 23:02:30 +01:00
2017-03-14 01:05:22 +01:00
if ( ! vrSimulatorReady )
2017-01-28 23:02:30 +01:00
{
2017-03-14 01:05:22 +01:00
vrStereoRender = false ;
2018-06-30 21:56:26 +02:00
2016-07-12 18:44:45 +02:00
// Reset viewport and default projection-modelview matrices
2016-07-16 19:25:15 +02:00
rlViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-09-13 22:23:24 +02:00
projection = MatrixOrtho ( 0.0 , screenWidth , screenHeight , 0.0 , 0.0 , 1.0 ) ;
2016-07-12 18:44:45 +02:00
modelview = MatrixIdentity ( ) ;
}
2017-03-14 01:05:22 +01:00
else vrStereoRender = true ;
2016-07-16 14:58:53 +02:00
# endif
2016-06-14 17:16:20 +02:00
}
2016-10-10 19:42:59 +02:00
// Update VR tracking (position and orientation) and camera
2016-10-17 17:02:33 +02:00
// NOTE: Camera (position, target, up) gets update with head tracking information
2016-10-10 19:42:59 +02:00
void UpdateVrTracking ( Camera * camera )
2016-06-14 17:16:20 +02:00
{
2017-03-14 01:05:22 +01:00
// TODO: Simulate 1st person camera system
2016-06-14 17:16:20 +02:00
}
2016-06-19 19:12:47 +02:00
// Begin Oculus drawing configuration
2016-07-06 00:54:38 +02:00
void BeginVrDrawing ( void )
2016-06-14 17:16:20 +02:00
{
2016-07-11 17:34:12 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
if ( vrSimulatorReady )
2016-06-19 19:12:47 +02:00
{
2016-06-21 13:49:13 +02:00
// Setup framebuffer for stereo rendering
2016-07-10 20:09:18 +02:00
rlEnableRenderTexture ( vrConfig . stereoFbo . id ) ;
2016-06-14 17:16:20 +02:00
2017-03-14 01:05:22 +01:00
// NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA)
// and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then:
// - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB
// - Do NOT enable GL_FRAMEBUFFER_SRGB
//glEnable(GL_FRAMEBUFFER_SRGB);
2017-01-28 23:02:30 +01:00
2017-03-14 01:05:22 +01:00
//glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye)
rlClearScreenBuffers ( ) ; // Clear current framebuffer(s)
2018-06-30 21:56:26 +02:00
2017-03-14 01:05:22 +01:00
vrStereoRender = true ;
}
2016-07-11 17:34:12 +02:00
# endif
2016-06-14 17:16:20 +02:00
}
2016-06-19 19:12:47 +02:00
// End Oculus drawing process (and desktop mirror)
2016-07-06 00:54:38 +02:00
void EndVrDrawing ( void )
2016-06-14 17:16:20 +02:00
{
2016-07-11 17:34:12 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-03-14 01:05:22 +01:00
if ( vrSimulatorReady )
2016-06-19 19:12:47 +02:00
{
2017-03-14 01:05:22 +01:00
vrStereoRender = false ; // Disable stereo render
2018-06-30 21:56:26 +02:00
2017-03-14 01:05:22 +01:00
rlDisableRenderTexture ( ) ; // Unbind current framebuffer
2017-01-28 23:02:30 +01:00
2017-03-14 01:05:22 +01:00
rlClearScreenBuffers ( ) ; // Clear current framebuffer
2016-06-19 19:12:47 +02:00
2016-06-21 13:49:13 +02:00
// Set viewport to default framebuffer size (screen size)
rlViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-01-28 23:02:30 +01:00
2016-06-21 13:49:13 +02:00
// Let rlgl reconfigure internal matrices
rlMatrixMode ( RL_PROJECTION ) ; // Enable internal projection matrix
rlLoadIdentity ( ) ; // Reset internal projection matrix
rlOrtho ( 0.0 , screenWidth , screenHeight , 0.0 , 0.0 , 1.0 ) ; // Recalculate internal projection matrix
rlMatrixMode ( RL_MODELVIEW ) ; // Enable internal modelview matrix
rlLoadIdentity ( ) ; // Reset internal modelview matrix
2017-03-25 12:01:01 +01:00
# if defined(SUPPORT_DISTORTION_SHADER)
2017-01-28 23:02:30 +01:00
// Draw RenderTexture (stereoFbo) using distortion shader
2016-07-10 20:09:18 +02:00
currentShader = vrConfig . distortionShader ;
2017-03-25 12:01:01 +01:00
# else
2017-07-17 00:33:40 +02:00
currentShader = GetShaderDefault ( ) ;
2017-03-25 12:01:01 +01:00
# endif
2016-06-21 13:49:13 +02:00
2016-07-10 20:09:18 +02:00
rlEnableTexture ( vrConfig . stereoFbo . texture . id ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
rlPushMatrix ( ) ;
rlBegin ( RL_QUADS ) ;
rlColor4ub ( 255 , 255 , 255 , 255 ) ;
rlNormal3f ( 0.0f , 0.0f , 1.0f ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
// Bottom-left corner for texture and quad
rlTexCoord2f ( 0.0f , 1.0f ) ;
rlVertex2f ( 0.0f , 0.0f ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
// Bottom-right corner for texture and quad
rlTexCoord2f ( 0.0f , 0.0f ) ;
2016-07-10 20:09:18 +02:00
rlVertex2f ( 0.0f , vrConfig . stereoFbo . texture . height ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
// Top-right corner for texture and quad
rlTexCoord2f ( 1.0f , 0.0f ) ;
2016-07-10 20:09:18 +02:00
rlVertex2f ( vrConfig . stereoFbo . texture . width , vrConfig . stereoFbo . texture . height ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
// Top-left corner for texture and quad
rlTexCoord2f ( 1.0f , 1.0f ) ;
2016-07-10 20:09:18 +02:00
rlVertex2f ( vrConfig . stereoFbo . texture . width , 0.0f ) ;
2016-07-04 01:29:23 +02:00
rlEnd ( ) ;
rlPopMatrix ( ) ;
2016-06-21 13:49:13 +02:00
2016-07-04 01:29:23 +02:00
rlDisableTexture ( ) ;
2017-03-14 01:05:22 +01:00
// Update and draw render texture fbo with distortion to backbuffer
2017-07-19 10:09:34 +02:00
UpdateBuffersDefault ( ) ;
DrawBuffersDefault ( ) ;
2018-06-30 21:56:26 +02:00
2017-03-14 01:05:22 +01:00
// Restore defaultShader
2016-07-04 01:29:23 +02:00
currentShader = defaultShader ;
2016-06-19 19:12:47 +02:00
2017-03-14 01:05:22 +01:00
// Reset viewport and default projection-modelview matrices
rlViewport ( 0 , 0 , screenWidth , screenHeight ) ;
2017-09-13 22:23:24 +02:00
projection = MatrixOrtho ( 0.0 , screenWidth , screenHeight , 0.0 , 0.0 , 1.0 ) ;
2017-03-14 01:05:22 +01:00
modelview = MatrixIdentity ( ) ;
2018-06-30 21:56:26 +02:00
2017-03-14 01:05:22 +01:00
rlDisableDepthTest ( ) ;
}
2016-07-11 17:34:12 +02:00
# endif
2016-06-14 17:16:20 +02:00
}
2017-04-18 11:49:02 +02:00
# endif // SUPPORT_VR_SIMULATOR
2016-06-14 17:16:20 +02:00
2014-03-25 12:40:35 +01:00
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2017-11-12 10:33:44 +01:00
// Compile custom shader and return shader id
static unsigned int CompileShader ( const char * shaderStr , int type )
2016-05-07 18:07:15 +02:00
{
2018-01-19 12:02:15 +01:00
unsigned int shader = glCreateShader ( type ) ;
glShaderSource ( shader , 1 , & shaderStr , NULL ) ;
2016-05-07 18:07:15 +02:00
GLint success = 0 ;
2018-01-19 12:02:15 +01:00
glCompileShader ( shader ) ;
glGetShaderiv ( shader , GL_COMPILE_STATUS , & success ) ;
2016-05-07 18:07:15 +02:00
if ( success ! = GL_TRUE )
{
2018-01-19 12:02:15 +01:00
TraceLog ( LOG_WARNING , " [SHDR ID %i] Failed to compile shader... " , shader ) ;
2016-05-07 18:07:15 +02:00
int maxLength = 0 ;
int length ;
2018-01-19 12:02:15 +01:00
glGetShaderiv ( shader , GL_INFO_LOG_LENGTH , & maxLength ) ;
2017-11-10 12:37:53 +01:00
2018-01-19 12:02:15 +01:00
# if defined(_MSC_VER)
2016-07-29 13:17:50 +02:00
char * log = malloc ( maxLength ) ;
# else
2016-05-07 18:07:15 +02:00
char log [ maxLength ] ;
2016-07-29 13:17:50 +02:00
# endif
2018-01-19 12:02:15 +01:00
glGetShaderInfoLog ( shader , maxLength , & length , log ) ;
2016-05-07 18:07:15 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " %s " , log ) ;
2017-01-28 23:02:30 +01:00
2018-01-19 12:02:15 +01:00
# if defined(_MSC_VER)
2016-07-29 13:17:50 +02:00
free ( log ) ;
# endif
2016-05-07 18:07:15 +02:00
}
2018-01-19 12:02:15 +01:00
else TraceLog ( LOG_INFO , " [SHDR ID %i] Shader compiled successfully " , shader ) ;
2016-05-07 18:07:15 +02:00
2018-01-19 12:02:15 +01:00
return shader ;
}
2016-05-07 18:07:15 +02:00
2017-11-09 20:47:22 +01:00
// Load custom shader strings and return program id
2017-11-12 10:33:44 +01:00
static unsigned int LoadShaderProgram ( unsigned int vShaderId , unsigned int fShaderId )
2017-11-09 20:47:22 +01:00
{
unsigned int program = 0 ;
2016-07-29 13:17:50 +02:00
2018-01-19 12:02:15 +01:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-07 18:07:15 +02:00
2018-01-19 12:02:15 +01:00
GLint success = 0 ;
2016-05-07 18:07:15 +02:00
program = glCreateProgram ( ) ;
2017-11-12 10:33:44 +01:00
glAttachShader ( program , vShaderId ) ;
glAttachShader ( program , fShaderId ) ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// NOTE: Default attribute shader locations must be binded before linking
2016-05-09 12:41:53 +02:00
glBindAttribLocation ( program , 0 , DEFAULT_ATTRIB_POSITION_NAME ) ;
glBindAttribLocation ( program , 1 , DEFAULT_ATTRIB_TEXCOORD_NAME ) ;
glBindAttribLocation ( program , 2 , DEFAULT_ATTRIB_NORMAL_NAME ) ;
glBindAttribLocation ( program , 3 , DEFAULT_ATTRIB_COLOR_NAME ) ;
glBindAttribLocation ( program , 4 , DEFAULT_ATTRIB_TANGENT_NAME ) ;
glBindAttribLocation ( program , 5 , DEFAULT_ATTRIB_TEXCOORD2_NAME ) ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// NOTE: If some attrib name is no found on the shader, it locations becomes -1
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
glLinkProgram ( program ) ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// NOTE: All uniform variables are intitialised to 0 when a program links
glGetProgramiv ( program , GL_LINK_STATUS , & success ) ;
if ( success = = GL_FALSE )
{
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_WARNING , " [SHDR ID %i] Failed to link shader program... " , program ) ;
2016-05-07 18:07:15 +02:00
int maxLength = 0 ;
int length ;
glGetProgramiv ( program , GL_INFO_LOG_LENGTH , & maxLength ) ;
2016-07-29 13:17:50 +02:00
# ifdef _MSC_VER
char * log = malloc ( maxLength ) ;
# else
2016-05-07 18:07:15 +02:00
char log [ maxLength ] ;
2016-07-29 13:17:50 +02:00
# endif
2016-05-07 18:07:15 +02:00
glGetProgramInfoLog ( program , maxLength , & length , log ) ;
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " %s " , log ) ;
2017-01-28 23:02:30 +01:00
2016-07-29 13:17:50 +02:00
# ifdef _MSC_VER
free ( log ) ;
# endif
2016-05-07 18:07:15 +02:00
glDeleteProgram ( program ) ;
program = 0 ;
}
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_INFO , " [SHDR ID %i] Shader program loaded successfully " , program ) ;
2016-05-07 18:07:15 +02:00
# endif
return program ;
}
// Load default shader (just vertex positioning and texture coloring)
2016-03-06 02:05:16 +01:00
// NOTE: This shader program is used for batch buffers (lines, triangles, quads)
2017-07-17 00:33:40 +02:00
static Shader LoadShaderDefault ( void )
2014-03-25 12:40:35 +01:00
{
2017-11-06 13:41:13 +01:00
Shader shader = { 0 } ;
2018-06-30 21:56:26 +02:00
2017-11-06 13:41:13 +01:00
// NOTE: All locations must be reseted to -1 (no location)
for ( int i = 0 ; i < MAX_SHADER_LOCATIONS ; i + + ) shader . locs [ i ] = - 1 ;
2015-04-06 14:02:29 +02:00
2014-03-25 12:40:35 +01:00
// Vertex shader directly defined, no external file required
2017-11-12 10:33:44 +01:00
char defaultVShaderStr [ ] =
2016-06-16 20:25:50 +02:00
# if defined(GRAPHICS_API_OPENGL_21)
" #version 120 \n "
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-06-16 20:25:50 +02:00
" #version 100 \n "
# endif
# if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" attribute vec3 vertexPosition; \n "
" attribute vec2 vertexTexCoord; \n "
" attribute vec4 vertexColor; \n "
" varying vec2 fragTexCoord; \n "
" varying vec4 fragColor; \n "
# elif defined(GRAPHICS_API_OPENGL_33)
" #version 330 \n "
" in vec3 vertexPosition; \n "
" in vec2 vertexTexCoord; \n "
" in vec4 vertexColor; \n "
" out vec2 fragTexCoord; \n "
" out vec4 fragColor; \n "
# endif
2017-08-25 01:43:55 +02:00
" uniform mat4 mvp; \n "
2016-06-16 20:25:50 +02:00
" void main() \n "
" { \n "
" fragTexCoord = vertexTexCoord; \n "
" fragColor = vertexColor; \n "
2017-08-25 01:43:55 +02:00
" gl_Position = mvp*vec4(vertexPosition, 1.0); \n "
2016-06-16 20:25:50 +02:00
" } \n " ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Fragment shader directly defined, no external file required
2017-11-12 10:33:44 +01:00
char defaultFShaderStr [ ] =
2016-06-16 20:25:50 +02:00
# if defined(GRAPHICS_API_OPENGL_21)
" #version 120 \n "
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-06-16 20:25:50 +02:00
" #version 100 \n "
" precision mediump float; \n " // precision required for OpenGL ES2 (WebGL)
# endif
# if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" varying vec2 fragTexCoord; \n "
" varying vec4 fragColor; \n "
# elif defined(GRAPHICS_API_OPENGL_33)
" #version 330 \n "
" in vec2 fragTexCoord; \n "
" in vec4 fragColor; \n "
" out vec4 finalColor; \n "
# endif
" uniform sampler2D texture0; \n "
" uniform vec4 colDiffuse; \n "
" void main() \n "
" { \n "
# if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" vec4 texelColor = texture2D(texture0, fragTexCoord); \n " // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
" gl_FragColor = texelColor*colDiffuse*fragColor; \n "
# elif defined(GRAPHICS_API_OPENGL_33)
" vec4 texelColor = texture(texture0, fragTexCoord); \n "
" finalColor = texelColor*colDiffuse*fragColor; \n "
2016-03-20 13:39:27 +01:00
# endif
2016-06-16 20:25:50 +02:00
" } \n " ;
2014-03-25 12:40:35 +01:00
2017-11-12 10:33:44 +01:00
// NOTE: Compiled vertex/fragment shaders are kept for re-use
defaultVShaderId = CompileShader ( defaultVShaderStr , GL_VERTEX_SHADER ) ; // Compile default vertex shader
defaultFShaderId = CompileShader ( defaultFShaderStr , GL_FRAGMENT_SHADER ) ; // Compile default fragment shader
2018-06-30 21:56:26 +02:00
2017-11-12 10:33:44 +01:00
shader . id = LoadShaderProgram ( defaultVShaderId , defaultFShaderId ) ;
2015-03-01 16:00:52 +01:00
2018-06-30 21:56:26 +02:00
if ( shader . id > 0 )
2017-07-17 00:33:40 +02:00
{
TraceLog ( LOG_INFO , " [SHDR ID %i] Default shader loaded successfully " , shader . id ) ;
2017-11-06 13:41:13 +01:00
// Set default shader locations: attributes locations
2017-07-17 00:33:40 +02:00
shader . locs [ LOC_VERTEX_POSITION ] = glGetAttribLocation ( shader . id , " vertexPosition " ) ;
shader . locs [ LOC_VERTEX_TEXCOORD01 ] = glGetAttribLocation ( shader . id , " vertexTexCoord " ) ;
shader . locs [ LOC_VERTEX_COLOR ] = glGetAttribLocation ( shader . id , " vertexColor " ) ;
2015-04-06 14:02:29 +02:00
2017-11-06 13:41:13 +01:00
// Set default shader locations: uniform locations
2017-08-25 01:43:55 +02:00
shader . locs [ LOC_MATRIX_MVP ] = glGetUniformLocation ( shader . id , " mvp " ) ;
2017-07-17 00:33:40 +02:00
shader . locs [ LOC_COLOR_DIFFUSE ] = glGetUniformLocation ( shader . id , " colDiffuse " ) ;
2017-07-19 10:09:34 +02:00
shader . locs [ LOC_MAP_DIFFUSE ] = glGetUniformLocation ( shader . id , " texture0 " ) ;
2018-06-30 21:56:26 +02:00
2017-11-06 13:41:13 +01:00
// NOTE: We could also use below function but in case DEFAULT_ATTRIB_* points are
// changed for external custom shaders, we just use direct bindings above
//SetShaderDefaultLocations(&shader);
2017-07-17 00:33:40 +02:00
}
2017-07-17 12:02:46 +02:00
else TraceLog ( LOG_WARNING , " [SHDR ID %i] Default shader could not be loaded " , shader . id ) ;
2016-04-03 18:31:42 +02:00
return shader ;
}
// Get location handlers to for shader attributes and uniforms
2016-04-07 13:31:53 +02:00
// NOTE: If any location is not found, loc point becomes -1
2017-07-17 00:33:40 +02:00
static void SetShaderDefaultLocations ( Shader * shader )
2016-04-03 18:31:42 +02:00
{
2016-05-07 18:07:15 +02:00
// NOTE: Default shader attrib locations have been fixed before linking:
2016-09-05 20:15:21 +02:00
// vertex position location = 0
// vertex texcoord location = 1
// vertex normal location = 2
// vertex color location = 3
// vertex tangent location = 4
// vertex texcoord2 location = 5
2017-01-28 23:02:30 +01:00
2015-03-01 16:00:52 +01:00
// Get handles to GLSL input attibute locations
2017-07-17 00:33:40 +02:00
shader - > locs [ LOC_VERTEX_POSITION ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_POSITION_NAME ) ;
shader - > locs [ LOC_VERTEX_TEXCOORD01 ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TEXCOORD_NAME ) ;
shader - > locs [ LOC_VERTEX_TEXCOORD02 ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TEXCOORD2_NAME ) ;
shader - > locs [ LOC_VERTEX_NORMAL ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_NORMAL_NAME ) ;
shader - > locs [ LOC_VERTEX_TANGENT ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TANGENT_NAME ) ;
shader - > locs [ LOC_VERTEX_COLOR ] = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_COLOR_NAME ) ;
2015-04-06 14:02:29 +02:00
2015-03-01 16:00:52 +01:00
// Get handles to GLSL uniform locations (vertex shader)
2017-08-25 01:43:55 +02:00
shader - > locs [ LOC_MATRIX_MVP ] = glGetUniformLocation ( shader - > id , " mvp " ) ;
2017-07-19 18:55:26 +02:00
shader - > locs [ LOC_MATRIX_PROJECTION ] = glGetUniformLocation ( shader - > id , " projection " ) ;
shader - > locs [ LOC_MATRIX_VIEW ] = glGetUniformLocation ( shader - > id , " view " ) ;
2014-09-03 16:51:28 +02:00
2015-03-01 16:00:52 +01:00
// Get handles to GLSL uniform locations (fragment shader)
2017-07-17 00:33:40 +02:00
shader - > locs [ LOC_COLOR_DIFFUSE ] = glGetUniformLocation ( shader - > id , " colDiffuse " ) ;
2017-07-19 10:09:34 +02:00
shader - > locs [ LOC_MAP_DIFFUSE ] = glGetUniformLocation ( shader - > id , " texture0 " ) ;
2017-11-22 14:56:45 +01:00
shader - > locs [ LOC_MAP_SPECULAR ] = glGetUniformLocation ( shader - > id , " texture1 " ) ;
shader - > locs [ LOC_MAP_NORMAL ] = glGetUniformLocation ( shader - > id , " texture2 " ) ;
2014-03-25 12:40:35 +01:00
}
2017-01-28 23:02:30 +01:00
// Unload default shader
2017-07-17 00:33:40 +02:00
static void UnloadShaderDefault ( void )
2014-03-25 12:40:35 +01:00
{
2016-05-03 19:20:25 +02:00
glUseProgram ( 0 ) ;
2015-02-02 00:57:08 +01:00
2017-11-12 10:33:44 +01:00
glDetachShader ( defaultShader . id , defaultVShaderId ) ;
glDetachShader ( defaultShader . id , defaultFShaderId ) ;
glDeleteShader ( defaultVShaderId ) ;
glDeleteShader ( defaultFShaderId ) ;
2018-06-30 21:56:26 +02:00
2016-05-03 19:20:25 +02:00
glDeleteProgram ( defaultShader . id ) ;
2014-03-25 12:40:35 +01:00
}
2016-05-03 19:20:25 +02:00
// Load default internal buffers (lines, triangles, quads)
2017-07-19 10:09:34 +02:00
static void LoadBuffersDefault ( void )
2014-03-25 12:40:35 +01:00
{
2016-05-03 19:20:25 +02:00
// [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
//--------------------------------------------------------------------------------------------
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// Lines - Initialize arrays (vertex position and color data)
2014-07-23 00:06:24 +02:00
lines . vertices = ( float * ) malloc ( sizeof ( float ) * 3 * 2 * MAX_LINES_BATCH ) ; // 3 float by vertex, 2 vertex by line
lines . colors = ( unsigned char * ) malloc ( sizeof ( unsigned char ) * 4 * 2 * MAX_LINES_BATCH ) ; // 4 float by color, 2 colors by line
2016-05-12 12:20:23 +02:00
lines . texcoords = NULL ;
lines . indices = NULL ;
2014-03-25 12:40:35 +01:00
2014-09-16 22:51:31 +02:00
for ( int i = 0 ; i < ( 3 * 2 * MAX_LINES_BATCH ) ; i + + ) lines . vertices [ i ] = 0.0f ;
2014-07-23 00:06:24 +02:00
for ( int i = 0 ; i < ( 4 * 2 * MAX_LINES_BATCH ) ; i + + ) lines . colors [ i ] = 0 ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
lines . vCounter = 0 ;
lines . cCounter = 0 ;
2016-05-12 12:20:23 +02:00
lines . tcCounter = 0 ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Triangles - Initialize arrays (vertex position and color data)
2014-07-23 00:06:24 +02:00
triangles . vertices = ( float * ) malloc ( sizeof ( float ) * 3 * 3 * MAX_TRIANGLES_BATCH ) ; // 3 float by vertex, 3 vertex by triangle
triangles . colors = ( unsigned char * ) malloc ( sizeof ( unsigned char ) * 4 * 3 * MAX_TRIANGLES_BATCH ) ; // 4 float by color, 3 colors by triangle
2016-05-12 12:20:23 +02:00
triangles . texcoords = NULL ;
triangles . indices = NULL ;
2014-03-25 12:40:35 +01:00
2014-09-16 22:51:31 +02:00
for ( int i = 0 ; i < ( 3 * 3 * MAX_TRIANGLES_BATCH ) ; i + + ) triangles . vertices [ i ] = 0.0f ;
2014-07-23 00:06:24 +02:00
for ( int i = 0 ; i < ( 4 * 3 * MAX_TRIANGLES_BATCH ) ; i + + ) triangles . colors [ i ] = 0 ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
triangles . vCounter = 0 ;
triangles . cCounter = 0 ;
2016-05-12 12:20:23 +02:00
triangles . tcCounter = 0 ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Quads - Initialize arrays (vertex position, texcoord, color data and indexes)
2014-07-23 00:06:24 +02:00
quads . vertices = ( float * ) malloc ( sizeof ( float ) * 3 * 4 * MAX_QUADS_BATCH ) ; // 3 float by vertex, 4 vertex by quad
quads . texcoords = ( float * ) malloc ( sizeof ( float ) * 2 * 4 * MAX_QUADS_BATCH ) ; // 2 float by texcoord, 4 texcoord by quad
quads . colors = ( unsigned char * ) malloc ( sizeof ( unsigned char ) * 4 * 4 * MAX_QUADS_BATCH ) ; // 4 float by color, 4 colors by quad
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2018-03-11 19:26:01 +01:00
quads . indices = ( unsigned int * ) malloc ( sizeof ( unsigned int ) * 6 * MAX_QUADS_BATCH ) ; // 6 int by quad (indices)
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2018-03-11 19:26:01 +01:00
quads . indices = ( unsigned short * ) malloc ( sizeof ( unsigned short ) * 6 * MAX_QUADS_BATCH ) ; // 6 int by quad (indices)
2014-09-16 22:51:31 +02:00
# endif
for ( int i = 0 ; i < ( 3 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . vertices [ i ] = 0.0f ;
for ( int i = 0 ; i < ( 2 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . texcoords [ i ] = 0.0f ;
2014-07-23 00:06:24 +02:00
for ( int i = 0 ; i < ( 4 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . colors [ i ] = 0 ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
int k = 0 ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Indices can be initialized right now
for ( int i = 0 ; i < ( 6 * MAX_QUADS_BATCH ) ; i + = 6 )
{
quads . indices [ i ] = 4 * k ;
quads . indices [ i + 1 ] = 4 * k + 1 ;
quads . indices [ i + 2 ] = 4 * k + 2 ;
quads . indices [ i + 3 ] = 4 * k ;
quads . indices [ i + 4 ] = 4 * k + 2 ;
quads . indices [ i + 5 ] = 4 * k + 3 ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
k + + ;
}
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
quads . vCounter = 0 ;
quads . tcCounter = 0 ;
quads . cCounter = 0 ;
2014-09-16 22:51:31 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_INFO , " [CPU] Default buffers initialized successfully (lines, triangles, quads) " ) ;
2016-05-03 19:20:25 +02:00
//--------------------------------------------------------------------------------------------
2017-01-28 23:02:30 +01:00
2016-05-03 19:20:25 +02:00
// [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads)
// NOTE: Default buffers are linked to use currentShader (defaultShader)
//--------------------------------------------------------------------------------------------
2017-01-28 23:02:30 +01:00
2016-05-03 19:20:25 +02:00
// Upload and link lines vertex buffers
2014-09-16 22:51:31 +02:00
if ( vaoSupported )
{
// Initialize Lines VAO
2016-05-12 12:20:23 +02:00
glGenVertexArrays ( 1 , & lines . vaoId ) ;
glBindVertexArray ( lines . vaoId ) ;
2014-09-16 22:51:31 +02:00
}
2014-09-03 16:51:28 +02:00
2017-01-28 23:02:30 +01:00
// Lines - Vertex buffers binding and attributes enable
2016-05-07 18:07:15 +02:00
// Vertex position buffer (shader-location = 0)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 2 , & lines . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
2014-03-25 12:40:35 +01:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 2 * MAX_LINES_BATCH , lines . vertices , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Vertex color buffer (shader-location = 3)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 2 , & lines . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
2014-07-23 00:06:24 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 2 * MAX_LINES_BATCH , lines . colors , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
if ( vaoSupported ) TraceLog ( LOG_INFO , " [VAO ID %i] Default buffers VAO initialized successfully (lines) " , lines . vaoId ) ;
else TraceLog ( LOG_INFO , " [VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines) " , lines.vboId[0], lines.vboId[1]) ;
2014-09-03 16:51:28 +02:00
2016-05-03 19:20:25 +02:00
// Upload and link triangles vertex buffers
2014-09-16 22:51:31 +02:00
if ( vaoSupported )
{
// Initialize Triangles VAO
2016-05-12 12:20:23 +02:00
glGenVertexArrays ( 1 , & triangles . vaoId ) ;
glBindVertexArray ( triangles . vaoId ) ;
2014-09-16 22:51:31 +02:00
}
2015-02-02 00:57:08 +01:00
2017-01-28 23:02:30 +01:00
// Triangles - Vertex buffers binding and attributes enable
2016-05-07 18:07:15 +02:00
// Vertex position buffer (shader-location = 0)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & triangles . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
2014-03-25 12:40:35 +01:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 3 * MAX_TRIANGLES_BATCH , triangles . vertices , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Vertex color buffer (shader-location = 3)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & triangles . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
2014-07-23 00:06:24 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 3 * MAX_TRIANGLES_BATCH , triangles . colors , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
if ( vaoSupported ) TraceLog ( LOG_INFO , " [VAO ID %i] Default buffers VAO initialized successfully (triangles) " , triangles . vaoId ) ;
else TraceLog ( LOG_INFO , " [VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (triangles) " , triangles.vboId[0], triangles.vboId[1]) ;
2014-09-03 16:51:28 +02:00
2016-05-03 19:20:25 +02:00
// Upload and link quads vertex buffers
2014-09-16 22:51:31 +02:00
if ( vaoSupported )
{
// Initialize Quads VAO
2016-05-12 12:20:23 +02:00
glGenVertexArrays ( 1 , & quads . vaoId ) ;
glBindVertexArray ( quads . vaoId ) ;
2014-09-16 22:51:31 +02:00
}
2015-02-02 00:57:08 +01:00
2017-01-28 23:02:30 +01:00
// Quads - Vertex buffers binding and attributes enable
2016-05-07 18:07:15 +02:00
// Vertex position buffer (shader-location = 0)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & quads . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
2014-03-25 12:40:35 +01:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 4 * MAX_QUADS_BATCH , quads . vertices , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Vertex texcoord buffer (shader-location = 1)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & quads . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
2014-09-03 16:51:28 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * 4 * MAX_QUADS_BATCH , quads . texcoords , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_TEXCOORD01 ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_TEXCOORD01 ] , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2016-05-07 18:07:15 +02:00
// Vertex color buffer (shader-location = 3)
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & quads . vboId [ 2 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
2014-09-03 16:51:28 +02:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 4 * MAX_QUADS_BATCH , quads . colors , GL_DYNAMIC_DRAW ) ;
2017-07-17 00:33:40 +02:00
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Fill index buffer
2016-05-12 12:20:23 +02:00
glGenBuffers ( 1 , & quads . vboId [ 3 ] ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quads . vboId [ 3 ] ) ;
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-03-25 12:40:35 +01:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( int ) * 6 * MAX_QUADS_BATCH , quads . indices , GL_STATIC_DRAW ) ;
2014-09-16 22:51:31 +02:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( short ) * 6 * MAX_QUADS_BATCH , quads . indices , GL_STATIC_DRAW ) ;
# endif
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
if ( vaoSupported ) TraceLog ( LOG_INFO , " [VAO ID %i] Default buffers VAO initialized successfully (quads) " , quads . vaoId ) ;
else TraceLog ( LOG_INFO , " [VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads) " , quads.vboId[0], quads.vboId[1], quads.vboId[2], quads.vboId[3]) ;
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Unbind the current VAO
2014-09-16 22:51:31 +02:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2016-05-03 19:20:25 +02:00
//--------------------------------------------------------------------------------------------
2014-03-25 12:40:35 +01:00
}
2016-05-07 18:07:15 +02:00
// Update default internal buffers (VAOs/VBOs) with vertex array data
2015-02-09 18:29:32 +01:00
// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
2016-05-03 19:20:25 +02:00
// TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required)
2017-07-19 10:09:34 +02:00
static void UpdateBuffersDefault ( void )
2014-03-25 12:40:35 +01:00
{
2016-05-03 19:20:25 +02:00
// Update lines vertex buffers
2015-01-02 20:59:54 +01:00
if ( lines . vCounter > 0 )
{
// Activate Lines VAO
2016-05-12 12:20:23 +02:00
if ( vaoSupported ) glBindVertexArray ( lines . vaoId ) ;
2015-02-02 00:57:08 +01:00
2015-01-02 20:59:54 +01:00
// Lines - vertex positions buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * lines . vCounter , lines . vertices ) ; // target - offset (in bytes) - size (in bytes) - data pointer
// Lines - colors buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( unsigned char ) * 4 * lines . cCounter , lines . colors ) ;
}
2014-09-03 16:51:28 +02:00
2016-05-03 19:20:25 +02:00
// Update triangles vertex buffers
2015-01-02 20:59:54 +01:00
if ( triangles . vCounter > 0 )
{
// Activate Triangles VAO
2016-05-12 12:20:23 +02:00
if ( vaoSupported ) glBindVertexArray ( triangles . vaoId ) ;
2015-02-02 00:57:08 +01:00
2015-01-02 20:59:54 +01:00
// Triangles - vertex positions buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * triangles . vCounter , triangles . vertices ) ;
// Triangles - colors buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( unsigned char ) * 4 * triangles . cCounter , triangles . colors ) ;
}
2014-03-25 12:40:35 +01:00
2016-05-03 19:20:25 +02:00
// Update quads vertex buffers
2015-01-02 20:59:54 +01:00
if ( quads . vCounter > 0 )
{
// Activate Quads VAO
2016-05-12 12:20:23 +02:00
if ( vaoSupported ) glBindVertexArray ( quads . vaoId ) ;
2015-01-02 20:59:54 +01:00
// Quads - vertex positions buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * quads . vCounter , quads . vertices ) ;
// Quads - texture coordinates buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 2 * quads . vCounter , quads . texcoords ) ;
// Quads - colors buffer
2016-05-12 12:20:23 +02:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
2015-01-02 20:59:54 +01:00
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( unsigned char ) * 4 * quads . vCounter , quads . colors ) ;
// Another option would be using buffer mapping...
2016-05-03 19:20:25 +02:00
//quads.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
2015-01-02 20:59:54 +01:00
// Now we can modify vertices
//glUnmapBuffer(GL_ARRAY_BUFFER);
}
2014-03-25 12:40:35 +01:00
//--------------------------------------------------------------
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Unbind the current VAO
2014-09-16 22:51:31 +02:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2014-03-25 12:40:35 +01:00
}
2016-05-03 19:20:25 +02:00
2016-05-07 18:07:15 +02:00
// Draw default internal buffers vertex data
// NOTE: We draw in this order: lines, triangles, quads
2017-07-22 10:35:41 +02:00
static void DrawBuffersDefault ( void )
2016-05-07 18:07:15 +02:00
{
2016-07-04 01:29:23 +02:00
Matrix matProjection = projection ;
Matrix matModelView = modelview ;
2018-06-30 21:56:26 +02:00
2017-03-14 01:05:22 +01:00
int eyesCount = 1 ;
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2017-03-14 01:05:22 +01:00
if ( vrStereoRender ) eyesCount = 2 ;
2017-04-18 11:49:02 +02:00
# endif
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
for ( int eye = 0 ; eye < eyesCount ; eye + + )
2016-05-07 18:07:15 +02:00
{
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2016-07-06 00:54:38 +02:00
if ( eyesCount = = 2 ) SetStereoView ( eye , matProjection , matModelView ) ;
2017-04-18 11:49:02 +02:00
# endif
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
// Set current shader and upload current MVP matrix
if ( ( lines . vCounter > 0 ) | | ( triangles . vCounter > 0 ) | | ( quads . vCounter > 0 ) )
2016-05-07 18:07:15 +02:00
{
2016-07-04 01:29:23 +02:00
glUseProgram ( currentShader . id ) ;
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
// Create modelview-projection matrix
Matrix matMVP = MatrixMultiply ( modelview , projection ) ;
2017-07-17 00:33:40 +02:00
glUniformMatrix4fv ( currentShader . locs [ LOC_MATRIX_MVP ] , 1 , false , MatrixToFloat ( matMVP ) ) ;
glUniform4f ( currentShader . locs [ LOC_COLOR_DIFFUSE ] , 1.0f , 1.0f , 1.0f , 1.0f ) ;
2017-07-19 10:09:34 +02:00
glUniform1i ( currentShader . locs [ LOC_MAP_DIFFUSE ] , 0 ) ;
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
// NOTE: Additional map textures not considered for default buffers drawing
2016-05-07 18:07:15 +02:00
}
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
// Draw lines buffers
if ( lines . vCounter > 0 )
2016-05-07 18:07:15 +02:00
{
2017-07-17 00:33:40 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
2016-07-04 01:29:23 +02:00
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( vaoSupported )
{
glBindVertexArray ( lines . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
2016-07-04 01:29:23 +02:00
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
2016-07-04 01:29:23 +02:00
}
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
glDrawArrays ( GL_LINES , 0 , lines . vCounter ) ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-05-07 18:07:15 +02:00
}
2016-07-04 01:29:23 +02:00
// Draw triangles buffers
if ( triangles . vCounter > 0 )
{
2017-07-17 00:33:40 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
2016-07-04 01:29:23 +02:00
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( vaoSupported )
{
glBindVertexArray ( triangles . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
2016-07-04 01:29:23 +02:00
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
2016-07-04 01:29:23 +02:00
}
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
glDrawArrays ( GL_TRIANGLES , 0 , triangles . vCounter ) ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-05-07 18:07:15 +02:00
}
2016-07-04 01:29:23 +02:00
// Draw quads buffers
if ( quads . vCounter > 0 )
2016-05-07 18:07:15 +02:00
{
2016-07-04 01:29:23 +02:00
int quadsCount = 0 ;
int numIndicesToProcess = 0 ;
int indicesOffset = 0 ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( vaoSupported )
{
glBindVertexArray ( quads . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_POSITION ] , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_POSITION ] ) ;
2016-07-04 01:29:23 +02:00
// Bind vertex attrib: texcoord (shader-location = 1)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_TEXCOORD01 ] , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_TEXCOORD01 ] ) ;
2016-07-04 01:29:23 +02:00
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
2017-07-17 00:33:40 +02:00
glVertexAttribPointer ( currentShader . locs [ LOC_VERTEX_COLOR ] , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . locs [ LOC_VERTEX_COLOR ] ) ;
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quads . vboId [ 3 ] ) ;
}
2016-05-07 18:07:15 +02:00
2017-07-02 12:35:13 +02:00
//TraceLog(LOG_DEBUG, "Draws required per frame: %i", drawsCounter);
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
for ( int i = 0 ; i < drawsCounter ; i + + )
{
quadsCount = draws [ i ] . vertexCount / 4 ;
2016-09-12 19:36:41 +02:00
numIndicesToProcess = quadsCount * 6 ; // Get number of Quads*6 index by Quad
2016-05-07 18:07:15 +02:00
2017-07-02 12:35:13 +02:00
//TraceLog(LOG_DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount);
2016-05-07 18:07:15 +02:00
2017-07-17 00:33:40 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
2016-07-04 01:29:23 +02:00
glBindTexture ( GL_TEXTURE_2D , draws [ i ] . textureId ) ;
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
// NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process
# if defined(GRAPHICS_API_OPENGL_33)
glDrawElements ( GL_TRIANGLES , numIndicesToProcess , GL_UNSIGNED_INT , ( GLvoid * ) ( sizeof ( GLuint ) * indicesOffset ) ) ;
# elif defined(GRAPHICS_API_OPENGL_ES2)
glDrawElements ( GL_TRIANGLES , numIndicesToProcess , GL_UNSIGNED_SHORT , ( GLvoid * ) ( sizeof ( GLushort ) * indicesOffset ) ) ;
# endif
//GLenum err;
2017-07-02 12:35:13 +02:00
//if ((err = glGetError()) != GL_NO_ERROR) TraceLog(LOG_INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM!
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
indicesOffset + = draws [ i ] . vertexCount / 4 * 6 ;
}
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
if ( ! vaoSupported )
{
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
2016-05-07 18:07:15 +02:00
2017-07-19 10:09:34 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind textures
2016-07-04 01:29:23 +02:00
}
2016-05-07 18:07:15 +02:00
2017-07-19 10:09:34 +02:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
2016-05-07 18:07:15 +02:00
2016-07-04 01:29:23 +02:00
glUseProgram ( 0 ) ; // Unbind shader program
}
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// Reset draws counter
drawsCounter = 1 ;
draws [ 0 ] . textureId = whiteTexture ;
draws [ 0 ] . vertexCount = 0 ;
// Reset vertex counters for next frame
lines . vCounter = 0 ;
lines . cCounter = 0 ;
triangles . vCounter = 0 ;
triangles . cCounter = 0 ;
quads . vCounter = 0 ;
quads . tcCounter = 0 ;
quads . cCounter = 0 ;
2017-01-28 23:02:30 +01:00
2016-05-07 18:07:15 +02:00
// Reset depth for next draw
currentDepth = - 1.0f ;
2017-01-28 23:02:30 +01:00
2016-07-04 01:29:23 +02:00
// Restore projection/modelview matrices
projection = matProjection ;
modelview = matModelView ;
2016-05-07 18:07:15 +02:00
}
// Unload default internal buffers vertex data from CPU and GPU
2017-07-19 10:09:34 +02:00
static void UnloadBuffersDefault ( void )
2016-05-03 19:20:25 +02:00
{
// Unbind everything
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
glDisableVertexAttribArray ( 0 ) ;
glDisableVertexAttribArray ( 1 ) ;
glDisableVertexAttribArray ( 2 ) ;
glDisableVertexAttribArray ( 3 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
// Delete VBOs from GPU (VRAM)
2016-05-12 12:20:23 +02:00
glDeleteBuffers ( 1 , & lines . vboId [ 0 ] ) ;
glDeleteBuffers ( 1 , & lines . vboId [ 1 ] ) ;
glDeleteBuffers ( 1 , & triangles . vboId [ 0 ] ) ;
glDeleteBuffers ( 1 , & triangles . vboId [ 1 ] ) ;
glDeleteBuffers ( 1 , & quads . vboId [ 0 ] ) ;
glDeleteBuffers ( 1 , & quads . vboId [ 1 ] ) ;
glDeleteBuffers ( 1 , & quads . vboId [ 2 ] ) ;
glDeleteBuffers ( 1 , & quads . vboId [ 3 ] ) ;
2016-05-03 19:20:25 +02:00
if ( vaoSupported )
{
// Delete VAOs from GPU (VRAM)
2016-05-12 12:20:23 +02:00
glDeleteVertexArrays ( 1 , & lines . vaoId ) ;
glDeleteVertexArrays ( 1 , & triangles . vaoId ) ;
glDeleteVertexArrays ( 1 , & quads . vaoId ) ;
2016-05-03 19:20:25 +02:00
}
// Free vertex arrays memory from CPU (RAM)
free ( lines . vertices ) ;
free ( lines . colors ) ;
free ( triangles . vertices ) ;
free ( triangles . colors ) ;
free ( quads . vertices ) ;
free ( quads . texcoords ) ;
free ( quads . colors ) ;
free ( quads . indices ) ;
}
2017-07-19 10:09:34 +02:00
// Renders a 1x1 XY quad in NDC
static void GenDrawQuad ( void )
{
unsigned int quadVAO = 0 ;
unsigned int quadVBO = 0 ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
float vertices [ ] = {
// Positions // Texture Coords
- 1.0f , 1.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f ,
1.0f , 1.0f , 0.0f , 1.0f , 1.0f ,
1.0f , - 1.0f , 0.0f , 1.0f , 0.0f ,
} ;
// Set up plane VAO
glGenVertexArrays ( 1 , & quadVAO ) ;
glGenBuffers ( 1 , & quadVBO ) ;
glBindVertexArray ( quadVAO ) ;
// Fill buffer
glBindBuffer ( GL_ARRAY_BUFFER , quadVBO ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ) , & vertices , GL_STATIC_DRAW ) ;
// Link vertex attributes
glEnableVertexAttribArray ( 0 ) ;
2017-07-19 18:55:26 +02:00
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 5 * sizeof ( float ) , ( void * ) 0 ) ;
2017-07-19 10:09:34 +02:00
glEnableVertexAttribArray ( 1 ) ;
2017-07-19 18:55:26 +02:00
glVertexAttribPointer ( 1 , 2 , GL_FLOAT , GL_FALSE , 5 * sizeof ( float ) , ( void * ) ( 3 * sizeof ( float ) ) ) ;
2017-07-19 10:09:34 +02:00
// Draw quad
glBindVertexArray ( quadVAO ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
glBindVertexArray ( 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 10:09:34 +02:00
glDeleteBuffers ( 1 , & quadVBO ) ;
glDeleteVertexArrays ( 1 , & quadVAO ) ;
}
// Renders a 1x1 3D cube in NDC
static void GenDrawCube ( void )
{
2017-07-19 18:55:26 +02:00
unsigned int cubeVAO = 0 ;
unsigned int cubeVBO = 0 ;
float vertices [ ] = {
- 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 0.0f , 0.0f ,
1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 1.0f , 1.0f ,
1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 1.0f , 0.0f ,
1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 1.0f , 1.0f ,
- 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 0.0f , 0.0f ,
- 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f ,
1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.0f ,
1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , 1.0f ,
1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , 1.0f ,
- 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f ,
- 1.0f , 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f , 0.0f ,
- 1.0f , 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f , 1.0f ,
- 1.0f , - 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 0.0f ,
- 1.0f , 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f , 0.0f ,
1.0f , 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f ,
1.0f , - 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 0.0f , 1.0f ,
1.0f , 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f ,
1.0f , - 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 0.0f , 1.0f ,
1.0f , 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f ,
1.0f , - 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f ,
- 1.0f , - 1.0f , - 1.0f , 0.0f , - 1.0f , 0.0f , 0.0f , 1.0f ,
1.0f , - 1.0f , - 1.0f , 0.0f , - 1.0f , 0.0f , 1.0f , 1.0f ,
1.0f , - 1.0f , 1.0f , 0.0f , - 1.0f , 0.0f , 1.0f , 0.0f ,
1.0f , - 1.0f , 1.0f , 0.0f , - 1.0f , 0.0f , 1.0f , 0.0f ,
- 1.0f , - 1.0f , 1.0f , 0.0f , - 1.0f , 0.0f , 0.0f , 0.0f ,
- 1.0f , - 1.0f , - 1.0f , 0.0f , - 1.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f , 0.0f , 1.0f ,
1.0f , 1.0f , 1.0f , 0.0f , 1.0f , 0.0f , 1.0f , 0.0f ,
1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f , 1.0f , 1.0f ,
1.0f , 1.0f , 1.0f , 0.0f , 1.0f , 0.0f , 1.0f , 0.0f ,
- 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , 1.0f , 1.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f
} ;
// Set up cube VAO
glGenVertexArrays ( 1 , & cubeVAO ) ;
glGenBuffers ( 1 , & cubeVBO ) ;
// Fill buffer
glBindBuffer ( GL_ARRAY_BUFFER , cubeVBO ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ) , vertices , GL_STATIC_DRAW ) ;
// Link vertex attributes
glBindVertexArray ( cubeVAO ) ;
glEnableVertexAttribArray ( 0 ) ;
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) 0 ) ;
glEnableVertexAttribArray ( 1 ) ;
glVertexAttribPointer ( 1 , 3 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) ( 3 * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( 2 ) ;
glVertexAttribPointer ( 2 , 2 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) ( 6 * sizeof ( float ) ) ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindVertexArray ( 0 ) ;
2017-07-19 10:09:34 +02:00
// Draw cube
glBindVertexArray ( cubeVAO ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 36 ) ;
glBindVertexArray ( 0 ) ;
2018-06-30 21:56:26 +02:00
2017-07-19 18:55:26 +02:00
glDeleteBuffers ( 1 , & cubeVBO ) ;
glDeleteVertexArrays ( 1 , & cubeVAO ) ;
2017-07-19 10:09:34 +02:00
}
2017-04-18 11:49:02 +02:00
# if defined(SUPPORT_VR_SIMULATOR)
2016-07-11 17:34:12 +02:00
// Configure stereo rendering (including distortion shader) with HMD device parameters
2017-10-04 12:11:40 +02:00
// NOTE: It modifies the global variable: VrStereoConfig vrConfig
2016-07-11 17:34:12 +02:00
static void SetStereoConfig ( VrDeviceInfo hmd )
{
// Compute aspect ratio
float aspect = ( ( float ) hmd . hResolution * 0.5f ) / ( float ) hmd . vResolution ;
// Compute lens parameters
float lensShift = ( hmd . hScreenSize * 0.25f - hmd . lensSeparationDistance * 0.5f ) / hmd . hScreenSize ;
2016-10-17 00:03:38 +02:00
float leftLensCenter [ 2 ] = { 0.25f + lensShift , 0.5f } ;
float rightLensCenter [ 2 ] = { 0.75f - lensShift , 0.5f } ;
2016-07-11 17:34:12 +02:00
float leftScreenCenter [ 2 ] = { 0.25f , 0.5f } ;
float rightScreenCenter [ 2 ] = { 0.75f , 0.5f } ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
// Compute distortion scale parameters
// NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
2018-05-28 00:48:45 +02:00
float lensRadius = fabs ( - 1.0f - 4.0f * lensShift ) ;
2016-07-11 17:34:12 +02:00
float lensRadiusSq = lensRadius * lensRadius ;
2017-10-17 13:32:15 +02:00
float distortionScale = hmd . lensDistortionValues [ 0 ] +
hmd . lensDistortionValues [ 1 ] * lensRadiusSq +
hmd . lensDistortionValues [ 2 ] * lensRadiusSq * lensRadiusSq +
hmd . lensDistortionValues [ 3 ] * lensRadiusSq * lensRadiusSq * lensRadiusSq ;
2017-01-28 23:02:30 +01:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " VR: Distortion Scale: %f " , distortionScale ) ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
float normScreenWidth = 0.5f ;
float normScreenHeight = 1.0f ;
2016-10-17 00:03:38 +02:00
float scaleIn [ 2 ] = { 2.0f / normScreenWidth , 2.0f / normScreenHeight / aspect } ;
float scale [ 2 ] = { normScreenWidth * 0.5f / distortionScale , normScreenHeight * 0.5f * aspect / distortionScale } ;
2017-01-28 23:02:30 +01:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " VR: Distortion Shader: LeftLensCenter = { %f, %f } " , leftLensCenter [ 0 ] , leftLensCenter [ 1 ] ) ;
TraceLog ( LOG_DEBUG , " VR: Distortion Shader: RightLensCenter = { %f, %f } " , rightLensCenter [ 0 ] , rightLensCenter [ 1 ] ) ;
TraceLog ( LOG_DEBUG , " VR: Distortion Shader: Scale = { %f, %f } " , scale [ 0 ] , scale [ 1 ] ) ;
TraceLog ( LOG_DEBUG , " VR: Distortion Shader: ScaleIn = { %f, %f } " , scaleIn [ 0 ] , scaleIn [ 1 ] ) ;
2017-01-28 23:02:30 +01:00
2017-03-25 12:01:01 +01:00
# if defined(SUPPORT_DISTORTION_SHADER)
2016-07-11 17:34:12 +02:00
// Update distortion shader with lens and distortion-scale parameters
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " leftLensCenter " ) , leftLensCenter , 2 ) ;
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " rightLensCenter " ) , rightLensCenter , 2 ) ;
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " leftScreenCenter " ) , leftScreenCenter , 2 ) ;
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " rightScreenCenter " ) , rightScreenCenter , 2 ) ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " scale " ) , scale , 2 ) ;
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " scaleIn " ) , scaleIn , 2 ) ;
2017-10-17 13:32:15 +02:00
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " hmdWarpParam " ) , hmd . lensDistortionValues , 4 ) ;
2016-07-11 17:34:12 +02:00
SetShaderValue ( vrConfig . distortionShader , GetShaderLocation ( vrConfig . distortionShader , " chromaAbParam " ) , hmd . chromaAbCorrection , 4 ) ;
2017-03-25 12:01:01 +01:00
# endif
2016-07-11 17:34:12 +02:00
2017-07-22 10:35:41 +02:00
// Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)
2016-07-11 17:34:12 +02:00
// ...but with lens distortion it is increased (see Oculus SDK Documentation)
2017-07-22 10:35:41 +02:00
//float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance); // Really need distortionScale?
2017-07-21 17:19:28 +02:00
float fovy = 2.0f * ( float ) atan2 ( hmd . vScreenSize * 0.5f , hmd . eyeToScreenDistance ) ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
// Compute camera projection matrices
float projOffset = 4.0f * lensShift ; // Scaled to projection space coordinates [-1..1]
2017-07-21 17:19:28 +02:00
Matrix proj = MatrixPerspective ( fovy , aspect , 0.01 , 1000.0 ) ;
2016-07-11 17:34:12 +02:00
vrConfig . eyesProjection [ 0 ] = MatrixMultiply ( proj , MatrixTranslate ( projOffset , 0.0f , 0.0f ) ) ;
vrConfig . eyesProjection [ 1 ] = MatrixMultiply ( proj , MatrixTranslate ( - projOffset , 0.0f , 0.0f ) ) ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
// Compute camera transformation matrices
2017-01-28 23:02:30 +01:00
// NOTE: Camera movement might seem more natural if we model the head.
// Our axis of rotation is the base of our head, so we might want to add
2016-07-11 17:34:12 +02:00
// some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions.
vrConfig . eyesViewOffset [ 0 ] = MatrixTranslate ( - hmd . interpupillaryDistance * 0.5f , 0.075f , 0.045f ) ;
vrConfig . eyesViewOffset [ 1 ] = MatrixTranslate ( hmd . interpupillaryDistance * 0.5f , 0.075f , 0.045f ) ;
2017-01-28 23:02:30 +01:00
2016-07-11 17:34:12 +02:00
// Compute eyes Viewports
2017-11-12 11:00:28 +01:00
vrConfig . eyesViewport [ 0 ] = ( Rectangle ) { 0 , 0 , hmd . hResolution / 2 , hmd . vResolution } ;
vrConfig . eyesViewport [ 1 ] = ( Rectangle ) { hmd . hResolution / 2 , 0 , hmd . hResolution / 2 , hmd . vResolution } ;
2016-07-11 17:34:12 +02:00
}
// Set internal projection and modelview matrix depending on eyes tracking data
static void SetStereoView ( int eye , Matrix matProjection , Matrix matModelView )
2016-07-12 18:44:45 +02:00
{
2017-03-14 01:05:22 +01:00
Matrix eyeProjection = matProjection ;
Matrix eyeModelView = matModelView ;
2016-07-12 18:44:45 +02:00
2017-03-14 01:05:22 +01:00
// Setup viewport and projection/modelview matrices using tracking data
rlViewport ( eye * screenWidth / 2 , 0 , screenWidth / 2 , screenHeight ) ;
2016-07-11 17:34:12 +02:00
2017-03-14 01:05:22 +01:00
// Apply view offset to modelview matrix
eyeModelView = MatrixMultiply ( matModelView , vrConfig . eyesViewOffset [ eye ] ) ;
2017-01-28 23:02:30 +01:00
2017-10-17 13:32:15 +02:00
// Set current eye projection matrix
2017-03-14 01:05:22 +01:00
eyeProjection = vrConfig . eyesProjection [ eye ] ;
2016-07-11 17:34:12 +02:00
2017-03-14 01:05:22 +01:00
SetMatrixModelview ( eyeModelView ) ;
SetMatrixProjection ( eyeProjection ) ;
2016-07-11 17:34:12 +02:00
}
2017-04-18 11:49:02 +02:00
# endif // defined(SUPPORT_VR_SIMULATOR)
2014-09-16 22:51:31 +02:00
# endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-04-19 16:36:49 +02:00
2018-02-21 23:47:48 +01:00
// Get OpenGL internal formats and data type from raylib PixelFormat
static void GetGlFormats ( int format , int * glInternalFormat , int * glFormat , int * glType )
{
* glInternalFormat = - 1 ;
* glFormat = - 1 ;
* glType = - 1 ;
2018-06-30 21:56:26 +02:00
2018-02-21 23:47:48 +01:00
switch ( format )
{
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
case UNCOMPRESSED_GRAYSCALE : * glInternalFormat = GL_LUMINANCE ; * glFormat = GL_LUMINANCE ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_GRAY_ALPHA : * glInternalFormat = GL_LUMINANCE_ALPHA ; * glFormat = GL_LUMINANCE_ALPHA ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_R5G6B5 : * glInternalFormat = GL_RGB ; * glFormat = GL_RGB ; * glType = GL_UNSIGNED_SHORT_5_6_5 ; break ;
case UNCOMPRESSED_R8G8B8 : * glInternalFormat = GL_RGB ; * glFormat = GL_RGB ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_R5G5B5A1 : * glInternalFormat = GL_RGBA ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_SHORT_5_5_5_1 ; break ;
case UNCOMPRESSED_R4G4B4A4 : * glInternalFormat = GL_RGBA ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_SHORT_4_4_4_4 ; break ;
case UNCOMPRESSED_R8G8B8A8 : * glInternalFormat = GL_RGBA ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_BYTE ; break ;
# if !defined(GRAPHICS_API_OPENGL_11)
case UNCOMPRESSED_R32 : if ( texFloatSupported ) * glInternalFormat = GL_LUMINANCE ; * glFormat = GL_LUMINANCE ; * glType = GL_FLOAT ; break ; // NOTE: Requires extension OES_texture_float
case UNCOMPRESSED_R32G32B32 : if ( texFloatSupported ) * glInternalFormat = GL_RGB ; * glFormat = GL_RGB ; * glType = GL_FLOAT ; break ; // NOTE: Requires extension OES_texture_float
case UNCOMPRESSED_R32G32B32A32 : if ( texFloatSupported ) * glInternalFormat = GL_RGBA ; * glFormat = GL_RGBA ; * glType = GL_FLOAT ; break ; // NOTE: Requires extension OES_texture_float
# endif
# elif defined(GRAPHICS_API_OPENGL_33)
case UNCOMPRESSED_GRAYSCALE : * glInternalFormat = GL_R8 ; * glFormat = GL_RED ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_GRAY_ALPHA : * glInternalFormat = GL_RG8 ; * glFormat = GL_RG ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_R5G6B5 : * glInternalFormat = GL_RGB565 ; * glFormat = GL_RGB ; * glType = GL_UNSIGNED_SHORT_5_6_5 ; break ;
case UNCOMPRESSED_R8G8B8 : * glInternalFormat = GL_RGB8 ; * glFormat = GL_RGB ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_R5G5B5A1 : * glInternalFormat = GL_RGB5_A1 ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_SHORT_5_5_5_1 ; break ;
case UNCOMPRESSED_R4G4B4A4 : * glInternalFormat = GL_RGBA4 ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_SHORT_4_4_4_4 ; break ;
case UNCOMPRESSED_R8G8B8A8 : * glInternalFormat = GL_RGBA8 ; * glFormat = GL_RGBA ; * glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_R32 : if ( texFloatSupported ) * glInternalFormat = GL_R32F ; * glFormat = GL_RED ; * glType = GL_FLOAT ; break ;
case UNCOMPRESSED_R32G32B32 : if ( texFloatSupported ) * glInternalFormat = GL_RGB32F ; * glFormat = GL_RGB ; * glType = GL_FLOAT ; break ;
case UNCOMPRESSED_R32G32B32A32 : if ( texFloatSupported ) * glInternalFormat = GL_RGBA32F ; * glFormat = GL_RGBA ; * glType = GL_FLOAT ; break ;
# endif
# if !defined(GRAPHICS_API_OPENGL_11)
case COMPRESSED_DXT1_RGB : if ( texCompDXTSupported ) * glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT ; break ;
case COMPRESSED_DXT1_RGBA : if ( texCompDXTSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ; break ;
case COMPRESSED_DXT3_RGBA : if ( texCompDXTSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ; break ;
case COMPRESSED_DXT5_RGBA : if ( texCompDXTSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ; break ;
case COMPRESSED_ETC1_RGB : if ( texCompETC1Supported ) * glInternalFormat = GL_ETC1_RGB8_OES ; break ; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB : if ( texCompETC2Supported ) * glInternalFormat = GL_COMPRESSED_RGB8_ETC2 ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA : if ( texCompETC2Supported ) * glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB : if ( texCompPVRTSupported ) * glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA : if ( texCompPVRTSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA : if ( texCompASTCSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA : if ( texCompASTCSupported ) * glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
# endif
default : TraceLog ( LOG_WARNING , " Texture format not supported " ) ; break ;
}
}
2014-09-16 22:51:31 +02:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 16:36:49 +02:00
// Mipmaps data is generated after image data
2018-05-20 00:39:56 +02:00
// NOTE: Only works with RGBA (4 bytes) data!
2014-04-19 16:36:49 +02:00
static int GenerateMipmaps ( unsigned char * data , int baseWidth , int baseHeight )
{
int mipmapCount = 1 ; // Required mipmap levels count (including base level)
int width = baseWidth ;
int height = baseHeight ;
2016-03-01 15:36:45 +01:00
int size = baseWidth * baseHeight * 4 ; // Size in bytes (will include mipmaps...), RGBA only
2014-04-19 16:36:49 +02:00
// Count mipmap levels required
while ( ( width ! = 1 ) & & ( height ! = 1 ) )
{
if ( width ! = 1 ) width / = 2 ;
if ( height ! = 1 ) height / = 2 ;
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " Next mipmap size: %i x %i " , width , height ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
mipmapCount + + ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
size + = ( width * height * 4 ) ; // Add mipmap size (in bytes)
}
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " Total mipmaps required: %i " , mipmapCount ) ;
TraceLog ( LOG_DEBUG , " Total size of data required: %i " , size ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
unsigned char * temp = realloc ( data , size ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
if ( temp ! = NULL ) data = temp ;
2017-07-02 12:35:13 +02:00
else TraceLog ( LOG_WARNING , " Mipmaps required memory could not be allocated " ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
width = baseWidth ;
height = baseHeight ;
size = ( width * height * 4 ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
// Generate mipmaps
// NOTE: Every mipmap data is stored after data
2016-04-01 10:39:33 +02:00
Color * image = ( Color * ) malloc ( width * height * sizeof ( Color ) ) ;
Color * mipmap = NULL ;
2014-04-19 16:36:49 +02:00
int offset = 0 ;
int j = 0 ;
for ( int i = 0 ; i < size ; i + = 4 )
{
image [ j ] . r = data [ i ] ;
image [ j ] . g = data [ i + 1 ] ;
image [ j ] . b = data [ i + 2 ] ;
image [ j ] . a = data [ i + 3 ] ;
j + + ;
}
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " Mipmap base (%ix%i) " , width , height ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
for ( int mip = 1 ; mip < mipmapCount ; mip + + )
{
mipmap = GenNextMipmap ( image , width , height ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
offset + = ( width * height * 4 ) ; // Size of last mipmap
j = 0 ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
width / = 2 ;
height / = 2 ;
size = ( width * height * 4 ) ; // Mipmap size to store after offset
// Add mipmap to data
for ( int i = 0 ; i < size ; i + = 4 )
{
data [ offset + i ] = mipmap [ j ] . r ;
data [ offset + i + 1 ] = mipmap [ j ] . g ;
data [ offset + i + 2 ] = mipmap [ j ] . b ;
2014-09-03 16:51:28 +02:00
data [ offset + i + 3 ] = mipmap [ j ] . a ;
2014-04-19 16:36:49 +02:00
j + + ;
}
free ( image ) ;
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
image = mipmap ;
mipmap = NULL ;
}
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
free ( mipmap ) ; // free mipmap data
2014-09-03 16:51:28 +02:00
2014-04-19 16:36:49 +02:00
return mipmapCount ;
}
// Manual mipmap generation (basic scaling algorithm)
2016-04-01 10:39:33 +02:00
static Color * GenNextMipmap ( Color * srcData , int srcWidth , int srcHeight )
2014-04-19 16:36:49 +02:00
{
int x2 , y2 ;
2016-04-01 10:39:33 +02:00
Color prow , pcol ;
2014-04-19 16:36:49 +02:00
2016-01-13 19:30:35 +01:00
int width = srcWidth / 2 ;
int height = srcHeight / 2 ;
2014-04-19 16:36:49 +02:00
2016-04-01 10:39:33 +02:00
Color * mipmap = ( Color * ) malloc ( width * height * sizeof ( Color ) ) ;
2014-04-19 16:36:49 +02:00
// Scaling algorithm works perfectly (box-filter)
2014-09-03 16:51:28 +02:00
for ( int y = 0 ; y < height ; y + + )
2014-04-19 16:36:49 +02:00
{
2016-01-13 19:30:35 +01:00
y2 = 2 * y ;
2014-04-19 16:36:49 +02:00
2014-09-03 16:51:28 +02:00
for ( int x = 0 ; x < width ; x + + )
2014-04-19 16:36:49 +02:00
{
2016-01-13 19:30:35 +01:00
x2 = 2 * x ;
2014-04-19 16:36:49 +02:00
prow . r = ( srcData [ y2 * srcWidth + x2 ] . r + srcData [ y2 * srcWidth + x2 + 1 ] . r ) / 2 ;
prow . g = ( srcData [ y2 * srcWidth + x2 ] . g + srcData [ y2 * srcWidth + x2 + 1 ] . g ) / 2 ;
prow . b = ( srcData [ y2 * srcWidth + x2 ] . b + srcData [ y2 * srcWidth + x2 + 1 ] . b ) / 2 ;
prow . a = ( srcData [ y2 * srcWidth + x2 ] . a + srcData [ y2 * srcWidth + x2 + 1 ] . a ) / 2 ;
pcol . r = ( srcData [ ( y2 + 1 ) * srcWidth + x2 ] . r + srcData [ ( y2 + 1 ) * srcWidth + x2 + 1 ] . r ) / 2 ;
pcol . g = ( srcData [ ( y2 + 1 ) * srcWidth + x2 ] . g + srcData [ ( y2 + 1 ) * srcWidth + x2 + 1 ] . g ) / 2 ;
pcol . b = ( srcData [ ( y2 + 1 ) * srcWidth + x2 ] . b + srcData [ ( y2 + 1 ) * srcWidth + x2 + 1 ] . b ) / 2 ;
pcol . a = ( srcData [ ( y2 + 1 ) * srcWidth + x2 ] . a + srcData [ ( y2 + 1 ) * srcWidth + x2 + 1 ] . a ) / 2 ;
mipmap [ y * width + x ] . r = ( prow . r + pcol . r ) / 2 ;
mipmap [ y * width + x ] . g = ( prow . g + pcol . g ) / 2 ;
mipmap [ y * width + x ] . b = ( prow . b + pcol . b ) / 2 ;
mipmap [ y * width + x ] . a = ( prow . a + pcol . a ) / 2 ;
}
}
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
TraceLog ( LOG_DEBUG , " Mipmap generated successfully (%ix%i) " , width , height ) ;
2014-04-19 16:36:49 +02:00
return mipmap ;
}
2014-04-09 20:25:26 +02:00
# endif
2014-09-16 22:51:31 +02:00
# if defined(RLGL_STANDALONE)
2017-07-02 12:35:13 +02:00
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
2016-06-07 23:44:53 +02:00
void TraceLog ( int msgType , const char * text , . . . )
2014-04-09 20:25:26 +02:00
{
va_list args ;
va_start ( args , text ) ;
2014-09-03 16:51:28 +02:00
2016-05-21 18:22:15 +02:00
switch ( msgType )
2014-04-09 20:25:26 +02:00
{
2017-07-02 12:35:13 +02:00
case LOG_INFO : fprintf ( stdout , " INFO: " ) ; break ;
case LOG_ERROR : fprintf ( stdout , " ERROR: " ) ; break ;
case LOG_WARNING : fprintf ( stdout , " WARNING: " ) ; break ;
case LOG_DEBUG : fprintf ( stdout , " DEBUG: " ) ; break ;
2014-04-09 20:25:26 +02:00
default : break ;
}
2014-09-03 16:51:28 +02:00
2014-04-09 20:25:26 +02:00
vfprintf ( stdout , text , args ) ;
fprintf ( stdout , " \n " ) ;
2014-09-03 16:51:28 +02:00
2014-04-09 20:25:26 +02:00
va_end ( args ) ;
2014-09-03 16:51:28 +02:00
2017-07-02 12:35:13 +02:00
if ( msgType = = LOG_ERROR ) exit ( 1 ) ;
2014-04-09 20:25:26 +02:00
}
2015-05-21 00:18:22 +02:00
# endif