2014-09-17 00:51:31 +04:00
/**********************************************************************************************
2014-09-03 18:51:28 +04:00
*
2014-03-25 15:40:35 +04:00
* rlgl - raylib OpenGL abstraction layer
2014-09-03 18:51:28 +04:00
*
2014-03-25 15:40:35 +04:00
* raylib now uses OpenGL 1.1 style functions ( rlVertex ) that are mapped to selected OpenGL version :
* OpenGL 1.1 - Direct map rl * - > gl *
2015-08-29 21:20:28 +03:00
* OpenGL 3.3 - Vertex data is stored in VAOs , call rlglDraw ( ) to render
* OpenGL ES 2 - Vertex data is stored in VBOs or VAOs ( when available ) , call rlglDraw ( ) to render
2014-09-03 18:51:28 +04:00
*
2015-07-29 22:43:30 +03:00
* Copyright ( c ) 2014 Ramon Santamaria ( @ raysan5 )
2014-09-03 18:51:28 +04:00
*
* This software is provided " as-is " , without any express or implied warranty . In no event
2014-03-25 15:40:35 +04:00
* will the authors be held liable for any damages arising from the use of this software .
*
2014-09-03 18:51:28 +04:00
* Permission is granted to anyone to use this software for any purpose , including commercial
2014-03-25 15:40:35 +04:00
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
*
2014-09-03 18:51:28 +04: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 15:40:35 +04: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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "rlgl.h"
2016-06-02 21:23:09 +03:00
# include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on ReadTextFile()]
2016-06-02 02:26:44 +03:00
# include <stdlib.h> // Required for: malloc(), free(), rand()
# include <string.h> // Required for: strcmp(), strlen(), strtok()
2016-07-04 19:34:28 +03:00
# include <math.h> // Required for: atan()
2014-03-25 15:40:35 +04:00
2016-03-20 15:39:27 +03:00
# ifndef RLGL_STANDALONE
2016-06-02 02:26:44 +03:00
# include "raymath.h" // Required for Vector3 and Matrix functions
2016-03-20 15:39:27 +03:00
# endif
2016-01-20 20:20:05 +03:00
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2016-06-02 02:26:44 +03:00
# ifdef __APPLE__
# include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
2015-02-02 02:57:08 +03:00
# else
2016-06-02 02:26:44 +03:00
# include <GL/gl.h> // OpenGL 1.1 library
2015-02-02 02:57:08 +03:00
# endif
2014-03-25 15:40:35 +04:00
# endif
2016-06-16 21:25:50 +03:00
# if defined(GRAPHICS_API_OPENGL_21)
# define GRAPHICS_API_OPENGL_33
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2016-06-02 02:26:44 +03:00
# ifdef __APPLE__
# include <OpenGL/gl3.h> // OpenGL 3 library for OSX
2015-02-02 02:57:08 +03:00
# else
2016-06-08 00:44:53 +03: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 02:13:09 +03:00
# endif
2014-03-25 15:40:35 +04:00
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2016-06-02 02:26:44 +03: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-17 00:51:31 +04:00
# endif
2014-03-25 15:40:35 +04:00
2015-08-05 20:18:40 +03:00
# if defined(RLGL_STANDALONE)
2016-06-02 21:23:09 +03:00
# include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()]
# endif
2015-08-05 20:18:40 +03:00
2016-06-24 20:37:52 +03:00
# if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_STANDARD_SHADER)
2016-06-07 01:32:45 +03:00
# include "standard_shader.h" // Standard shader to embed
# endif
2016-06-21 09:59:29 +03:00
//#define RLGL_OCULUS_SUPPORT // Enable Oculus Rift code
2016-06-14 18:16:20 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
# include "external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL
# endif
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2014-04-04 22:11:57 +04:00
# define MATRIX_STACK_SIZE 16 // Matrix stack max size
2014-03-25 15:40:35 +04:00
# define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
2014-04-09 22:25:26 +04:00
# define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
2014-09-17 00:51:31 +04:00
// NOTE: Every vertex are 3 floats (12 bytes)
2016-05-20 13:28:07 +03:00
# define MAX_LIGHTS 8 // Max lights supported by standard shader
2014-03-25 15:40:35 +04:00
2015-05-11 01:15:46 +03:00
# ifndef GL_SHADING_LANGUAGE_VERSION
# define GL_SHADING_LANGUAGE_VERSION 0x8B8C
# endif
2015-04-06 15:02:29 +03:00
# ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
2015-05-11 01:15:46 +03:00
# define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
2015-05-11 01:15:46 +03:00
# define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
2015-05-11 01:15:46 +03:00
# define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
2015-05-11 01:15:46 +03:00
# define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_ETC1_RGB8_OES
2015-05-11 01:15:46 +03:00
# define GL_ETC1_RGB8_OES 0x8D64
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_COMPRESSED_RGB8_ETC2
2015-05-11 01:15:46 +03:00
# define GL_COMPRESSED_RGB8_ETC2 0x9274
2015-04-06 15:02:29 +03:00
# endif
# ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
2015-05-11 01:15:46 +03: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 15:02:29 +03:00
# endif
2015-05-11 01:15:46 +03:00
# if defined(GRAPHICS_API_OPENGL_11)
# 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
# endif
2016-05-09 13:41:53 +03:00
2016-06-26 19:43:10 +03:00
# if defined(GRAPHICS_API_OPENGL_ES2)
# define glClearDepth glClearDepthf
# define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
# define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
# endif
2016-05-09 13:41:53 +03: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 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2016-05-12 13:20:23 +03:00
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
2014-03-25 15:40:35 +04:00
typedef struct {
2016-05-12 13:20:23 +03: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-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2016-05-12 13:20:23 +03:00
unsigned int * indices ; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-05-12 13:20:23 +03:00
unsigned short * indices ; // vertex indices (in case vertex data comes indexed) (6 indices per quad)
2014-09-17 00:51:31 +04:00
// NOTE: 6*2 byte = 12 byte, not alignment problem!
# endif
2016-05-12 13:20:23 +03: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 15:40:35 +04:00
2014-04-19 18:36:49 +04:00
// Draw call type
// NOTE: Used to track required draw-calls, organized by texture
2014-03-25 15:40:35 +04:00
typedef struct {
2014-04-19 18:36:49 +04:00
int vertexCount ;
2016-06-12 20:40:08 +03:00
GLuint vaoId ;
GLuint textureId ;
GLuint shaderId ;
Matrix projection ;
Matrix modelview ;
// TODO: Store additional draw state data
//int blendMode;
//Guint fboId;
2014-03-25 15:40:35 +04:00
} DrawCall ;
2016-07-08 01:57:27 +03:00
// Head-Mounted-Display device parameters
typedef struct {
int hResolution ; // HMD horizontal resolution in pixels
int vResolution ; // HMD vertical resolution in pixels
float hScreenSize ; // HMD horizontal size in meters
float vScreenSize ; // HMD vertical size in meters
float vScreenCenter ; // HMD screen center in meters
float eyeToScreenDistance ; // HMD distance between eye and display in meters
float lensSeparationDistance ; // HMD lens separation distance in meters
float interpupillaryDistance ; // HMD IPD (distance between pupils) in meters
float distortionK [ 4 ] ; // HMD lens distortion constant parameters
float chromaAbCorrection [ 4 ] ; // HMD chromatic aberration correction parameters
} VrDeviceInfo ;
2016-06-14 18:16:20 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
typedef struct OculusBuffer {
ovrTextureSwapChain textureChain ;
GLuint depthId ;
GLuint fboId ;
int width ;
int height ;
} OculusBuffer ;
typedef struct OculusMirror {
ovrMirrorTexture texture ;
GLuint fboId ;
int width ;
int height ;
} OculusMirror ;
typedef struct OculusLayer {
ovrViewScaleDesc viewScaleDesc ;
ovrLayerEyeFov eyeLayer ; // layer 0
//ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI
Matrix eyeProjections [ 2 ] ;
int width ;
int height ;
} OculusLayer ;
# endif
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 15:40:35 +04:00
static Matrix stack [ MATRIX_STACK_SIZE ] ;
static int stackCounter = 0 ;
static Matrix modelview ;
static Matrix projection ;
static Matrix * currentMatrix ;
static int currentMatrixMode ;
static DrawMode currentDrawMode ;
2015-09-21 13:48:43 +03:00
static float currentDepth = - 1.0f ;
2016-05-12 13:20:23 +03:00
static DynamicBuffer lines ;
static DynamicBuffer triangles ;
static DynamicBuffer quads ;
2014-03-25 15:40:35 +04:00
2016-05-03 20:20:25 +03:00
// Default buffers draw calls
2014-03-25 15:40:35 +04: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 ;
2016-05-03 20:20:25 +03:00
// Shader Programs
static Shader defaultShader ;
2016-06-07 01:32:45 +03:00
static Shader standardShader ; // Lazy initialization when GetStandardShader()
static Shader currentShader ; // By default, defaultShader
2016-06-24 20:37:52 +03:00
static bool standardShaderLoaded = false ; // Flag to track if standard shader has been loaded
2016-05-03 20:20:25 +03:00
2015-05-21 01:18:22 +03:00
// Flags for supported extensions
2016-06-07 01:32:45 +03:00
static bool vaoSupported = false ; // VAO support (OpenGL ES2 could not support VAO extension)
2015-05-21 01:18:22 +03:00
// Compressed textures support flags
2016-06-07 01:32:45 +03: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
2016-05-20 13:28:07 +03:00
// Lighting data
2016-06-07 01:32:45 +03:00
static Light lights [ MAX_LIGHTS ] ; // Lights pool
2016-07-06 21:33:46 +03:00
static int lightsCount = 0 ; // Enabled lights counter
2014-09-17 00:51:31 +04:00
# endif
2016-06-14 18:16:20 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
// OVR device variables
static ovrSession session ; // Oculus session (pointer to ovrHmdStruct)
static ovrHmdDesc hmdDesc ; // Oculus device descriptor parameters
static ovrGraphicsLuid luid ; // Oculus locally unique identifier for the program (64 bit)
static OculusLayer layer ; // Oculus drawing layer (similar to photoshop)
static OculusBuffer buffer ; // Oculus internal buffers (texture chain and fbo)
static OculusMirror mirror ; // Oculus mirror texture and fbo
static unsigned int frameIndex = 0 ; // Oculus frames counter, used to discard frames from chain
# endif
2016-06-26 16:36:12 +03:00
static bool oculusReady = false ; // Oculus device ready flag
2016-06-21 14:49:13 +03:00
static bool oculusSimulator = false ; // Oculus device simulator
2016-06-26 16:36:12 +03:00
static bool vrEnabled = false ; // VR experience enabled (Oculus device or simulator)
2016-07-04 02:29:23 +03:00
static bool vrControl = true ; // VR controlled by user code, instead of internally
2016-06-21 14:49:13 +03:00
static RenderTexture2D stereoFbo ;
2016-07-04 02:29:23 +03:00
static Shader distortionShader ;
2016-06-19 20:12:47 +03:00
2015-07-05 19:21:01 +03:00
// Compressed textures support flags
2016-06-07 01:32:45 +03:00
static bool texCompDXTSupported = false ; // DDS texture compression support
static bool npotSupported = false ; // NPOT textures full support
2015-07-05 19:21:01 +03:00
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: VAO functionality is exposed through extensions (OES)
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays ;
static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray ;
static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays ;
2015-05-21 01:18:22 +03:00
//static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted
2014-03-25 15:40:35 +04:00
# endif
2016-06-24 20:37:52 +03:00
static int blendMode = 0 ; // Track current blending mode
2015-08-07 18:24:28 +03:00
2014-12-31 21:25:39 +03:00
// White texture useful for plain color polys (required by shader)
2016-06-11 13:41:03 +03:00
static unsigned int whiteTexture ;
2014-12-31 21:25:39 +03:00
2016-06-26 00:28:50 +03:00
// Default framebuffer size (required by Oculus device)
2016-06-24 20:37:52 +03:00
static int screenWidth ; // Default framebuffer width
static int screenHeight ; // Default framebuffer height
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-03 20:20:25 +03:00
static void LoadCompressedTexture ( unsigned char * data , int width , int height , int mipmapCount , int compressedFormat ) ;
2016-06-08 23:52:54 +03:00
static unsigned int LoadShaderProgram ( const char * vShaderStr , const char * fShaderStr ) ; // Load custom shader strings and return program id
2016-05-03 20:20:25 +03:00
2016-05-07 19:07:15 +03:00
static Shader LoadDefaultShader ( void ) ; // Load default shader (just vertex positioning and texture coloring)
2016-05-20 13:28:07 +03:00
static Shader LoadStandardShader ( void ) ; // Load standard shader (support materials and lighting)
2016-05-07 19:07:15 +03:00
static void LoadDefaultShaderLocations ( Shader * shader ) ; // Bind default shader locations (attributes and uniforms)
static void UnloadDefaultShader ( void ) ; // Unload default shader
2016-06-01 13:37:51 +03:00
static void UnloadStandardShader ( void ) ; // Unload standard shader
2015-05-21 01:18:22 +03:00
2016-05-07 19:07:15 +03:00
static void LoadDefaultBuffers ( void ) ; // Load default internal buffers (lines, triangles, quads)
2016-07-04 02:29:23 +03:00
static void UpdateDefaultBuffers ( void ) ; // Update default internal buffers (VAOs/VBOs) with vertex data
static void DrawDefaultBuffers ( int eyesCount ) ; // Draw default internal buffers vertex data
2016-05-07 19:07:15 +03:00
static void UnloadDefaultBuffers ( void ) ; // Unload default internal buffers vertex data from CPU and GPU
2016-05-03 20:20:25 +03:00
2016-07-04 02:29:23 +03:00
// Set internal projection and modelview matrix depending on eyes tracking data
2016-07-06 01:54:38 +03:00
static void SetStereoView ( int eye , Matrix matProjection , Matrix matModelView ) ;
2016-07-04 02:29:23 +03:00
2016-07-08 01:57:27 +03:00
// Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetupVrDevice ( VrDeviceInfo hmd ) ;
2016-05-20 13:28:07 +03:00
static void SetShaderLights ( Shader shader ) ; // Sets shader uniform values for lights array
2016-05-03 20:20:25 +03:00
static char * ReadTextFile ( const char * fileName ) ;
2014-03-25 15:40:35 +04:00
# endif
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-14 18:16:20 +03:00
static OculusBuffer LoadOculusBuffer ( ovrSession session , int width , int height ) ; // Load Oculus required buffers
static void UnloadOculusBuffer ( ovrSession session , OculusBuffer buffer ) ; // Unload texture required buffers
static OculusMirror LoadOculusMirror ( ovrSession session , int width , int height ) ; // Load Oculus mirror buffers
static void UnloadOculusMirror ( ovrSession session , OculusMirror mirror ) ; // Unload Oculus mirror buffers
static void BlitOculusMirror ( ovrSession session , OculusMirror mirror ) ; // Copy Oculus screen buffer to mirror texture
static OculusLayer InitOculusLayer ( ovrSession session ) ; // Init Oculus layer (similar to photoshop)
static Matrix FromOvrMatrix ( ovrMatrix4f ovrM ) ; // Convert from Oculus ovrMatrix4f struct to raymath Matrix struct
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 18:36:49 +04:00
static int GenerateMipmaps ( unsigned char * data , int baseWidth , int baseHeight ) ;
2016-04-01 11:39:33 +03:00
static Color * GenNextMipmap ( Color * srcData , int srcWidth , int srcHeight ) ;
2014-04-19 18:36:49 +04:00
# endif
2015-08-05 20:18:40 +03:00
# if defined(RLGL_STANDALONE)
2016-06-01 13:37:51 +03:00
float * MatrixToFloat ( Matrix mat ) ; // Converts Matrix to float array
2015-08-05 20:18:40 +03:00
# endif
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix operations
//----------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
2014-09-03 18:51:28 +04:00
void rlMatrixMode ( int mode )
{
switch ( mode )
2014-03-25 15:40:35 +04:00
{
case RL_PROJECTION : glMatrixMode ( GL_PROJECTION ) ; break ;
2014-09-03 18:51:28 +04:00
case RL_MODELVIEW : glMatrixMode ( GL_MODELVIEW ) ; break ;
2014-03-25 15:40:35 +04:00
case RL_TEXTURE : glMatrixMode ( GL_TEXTURE ) ; break ;
default : break ;
}
}
2014-09-03 18:51:28 +04:00
void rlFrustum ( double left , double right , double bottom , double top , double near , double far )
{
glFrustum ( left , right , bottom , top , near , far ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
void rlOrtho ( double left , double right , double bottom , double top , double near , double far )
{
glOrtho ( left , right , bottom , top , near , far ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 19:06:10 +04:00
void rlPushMatrix ( void ) { glPushMatrix ( ) ; }
void rlPopMatrix ( void ) { glPopMatrix ( ) ; }
void rlLoadIdentity ( void ) { glLoadIdentity ( ) ; }
2014-03-25 15:40:35 +04: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 ) ; }
void rlMultMatrixf ( float * mat ) { glMultMatrixf ( mat ) ; }
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 15:40:35 +04: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 18:36:49 +04:00
//else if (mode == RL_TEXTURE) // Not supported
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
currentMatrixMode = mode ;
}
// Push the current matrix to stack
2014-09-03 19:06:10 +04:00
void rlPushMatrix ( void )
2014-03-25 15:40:35 +04:00
{
if ( stackCounter = = MATRIX_STACK_SIZE - 1 )
{
2014-04-09 22:25:26 +04:00
TraceLog ( ERROR , " Stack Buffer Overflow (MAX %i Matrix) " , MATRIX_STACK_SIZE ) ;
2014-03-25 15:40:35 +04:00
}
stack [ stackCounter ] = * currentMatrix ;
rlLoadIdentity ( ) ;
stackCounter + + ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
if ( currentMatrixMode = = RL_MODELVIEW ) useTempBuffer = true ;
}
// Pop lattest inserted matrix from stack
2014-09-03 19:06:10 +04:00
void rlPopMatrix ( void )
2014-03-25 15:40:35 +04:00
{
if ( stackCounter > 0 )
2014-09-03 18:51:28 +04:00
{
Matrix mat = stack [ stackCounter - 1 ] ;
2014-03-25 15:40:35 +04:00
* currentMatrix = mat ;
stackCounter - - ;
}
}
// Reset current matrix to identity matrix
2014-09-03 19:06:10 +04:00
void rlLoadIdentity ( void )
2014-03-25 15:40:35 +04:00
{
* currentMatrix = MatrixIdentity ( ) ;
}
// Multiply the current matrix by a translation matrix
void rlTranslatef ( float x , float y , float z )
{
2016-01-04 22:02:57 +03:00
Matrix matTranslation = MatrixTranslate ( x , y , z ) ;
MatrixTranspose ( & matTranslation ) ;
2014-09-03 18:51:28 +04:00
2016-01-04 22:02:57 +03:00
* currentMatrix = MatrixMultiply ( * currentMatrix , matTranslation ) ;
2014-03-25 15:40:35 +04:00
}
// Multiply the current matrix by a rotation matrix
void rlRotatef ( float angleDeg , float x , float y , float z )
{
2016-01-04 22:02:57 +03:00
Matrix matRotation = MatrixIdentity ( ) ;
2014-09-03 18:51:28 +04:00
2015-05-11 01:15:46 +03:00
Vector3 axis = ( Vector3 ) { x , y , z } ;
VectorNormalize ( & axis ) ;
2016-02-02 20:41:01 +03:00
matRotation = MatrixRotate ( axis , angleDeg * DEG2RAD ) ;
2016-01-04 22:02:57 +03:00
MatrixTranspose ( & matRotation ) ;
2014-09-03 18:51:28 +04:00
2016-01-04 22:02:57 +03:00
* currentMatrix = MatrixMultiply ( * currentMatrix , matRotation ) ;
2014-03-25 15:40:35 +04:00
}
// Multiply the current matrix by a scaling matrix
void rlScalef ( float x , float y , float z )
{
2016-01-04 22:02:57 +03:00
Matrix matScale = MatrixScale ( x , y , z ) ;
MatrixTranspose ( & matScale ) ;
2014-09-03 18:51:28 +04:00
2016-01-04 22:02:57 +03:00
* currentMatrix = MatrixMultiply ( * currentMatrix , matScale ) ;
2014-03-25 15:40:35 +04:00
}
// Multiply the current matrix by another matrix
void rlMultMatrixf ( float * m )
{
2015-02-09 20:29:32 +03:00
// Matrix creation from array
2014-03-25 15:40:35 +04:00
Matrix mat = { m [ 0 ] , m [ 1 ] , m [ 2 ] , m [ 3 ] ,
m [ 4 ] , m [ 5 ] , m [ 6 ] , m [ 7 ] ,
m [ 8 ] , m [ 9 ] , m [ 10 ] , m [ 11 ] ,
m [ 12 ] , m [ 13 ] , m [ 14 ] , m [ 15 ] } ;
* currentMatrix = MatrixMultiply ( * currentMatrix , mat ) ;
}
// 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 ) ;
MatrixTranspose ( & matPerps ) ;
* currentMatrix = MatrixMultiply ( * currentMatrix , matPerps ) ;
}
// Multiply the current matrix by an orthographic matrix generated by parameters
2014-09-03 18:51:28 +04:00
void rlOrtho ( double left , double right , double bottom , double top , double near , double far )
2014-03-25 15:40:35 +04:00
{
Matrix matOrtho = MatrixOrtho ( left , right , bottom , top , near , far ) ;
MatrixTranspose ( & matOrtho ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
* currentMatrix = MatrixMultiply ( * currentMatrix , matOrtho ) ;
}
# endif
2016-06-26 00:28:50 +03:00
// Set the viewport area (transformation from normalized device coordinates to window coordinates)
// NOTE: Updates global variables: screenWidth, screenHeight
2016-05-29 12:49:13 +03:00
void rlViewport ( int x , int y , int width , int height )
{
glViewport ( x , y , width , height ) ;
}
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Vertex level operations
//----------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
// Fallback to OpenGL 1.1 function calls
//---------------------------------------
2014-09-03 18:51:28 +04:00
void rlBegin ( int mode )
2014-03-25 15:40:35 +04: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-17 00:51:31 +04:00
void rlEnd ( ) { glEnd ( ) ; }
2014-03-25 15:40:35 +04: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-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-03-25 15:40:35 +04: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 19:06:10 +04:00
void rlEnd ( void )
2014-03-25 15:40:35 +04:00
{
if ( useTempBuffer )
{
2014-04-19 18:36:49 +04: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 15:40:35 +04:00
// Apply transformation matrix to all temp vertices
2014-04-19 18:36:49 +04:00
for ( int i = 0 ; i < tempBufferCount ; i + + ) VectorTransform ( & tempBuffer [ i ] , * currentMatrix ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Deactivate tempBuffer usage to allow rlVertex3f do its job
useTempBuffer = false ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Reset temp buffer
tempBufferCount = 0 ;
}
2014-04-19 18:36:49 +04:00
// Make sure vertexCount is the same for vertices-texcoords-normals-colors
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
lines . cCounter + + ;
}
}
} break ;
case RL_TRIANGLES :
{
if ( triangles . vCounter ! = triangles . cCounter )
{
int addColors = triangles . vCounter - triangles . cCounter ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
triangles . cCounter + + ;
}
2014-09-03 18:51:28 +04:00
}
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
quads . cCounter + + ;
}
}
// Make sure texcoords count match vertex count
if ( quads . vCounter ! = quads . tcCounter )
{
int addTexCoords = quads . vCounter - quads . tcCounter ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
quads . tcCounter + + ;
}
}
2014-09-03 18:51:28 +04:00
2015-02-09 20:29:32 +03:00
// TODO: Make sure normals count match vertex count... if normals support is added in a future... :P
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
} break ;
default : break ;
}
2015-09-21 13:48:43 +03: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 ) ;
2014-03-25 15:40:35 +04: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-17 00:51:31 +04:00
// Verify that MAX_LINES_BATCH limit not reached
if ( lines . vCounter / 2 < MAX_LINES_BATCH )
{
lines . vertices [ 3 * lines . vCounter ] = x ;
lines . vertices [ 3 * lines . vCounter + 1 ] = y ;
lines . vertices [ 3 * lines . vCounter + 2 ] = z ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
lines . vCounter + + ;
}
else TraceLog ( ERROR , " MAX_LINES_BATCH overflow " ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
} break ;
case RL_TRIANGLES :
{
2014-09-17 00:51:31 +04:00
// Verify that MAX_TRIANGLES_BATCH limit not reached
if ( triangles . vCounter / 3 < MAX_TRIANGLES_BATCH )
{
triangles . vertices [ 3 * triangles . vCounter ] = x ;
triangles . vertices [ 3 * triangles . vCounter + 1 ] = y ;
triangles . vertices [ 3 * triangles . vCounter + 2 ] = z ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
triangles . vCounter + + ;
}
else TraceLog ( ERROR , " MAX_TRIANGLES_BATCH overflow " ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
} break ;
case RL_QUADS :
{
2014-09-17 00:51:31 +04:00
// Verify that MAX_QUADS_BATCH limit not reached
if ( quads . vCounter / 4 < MAX_QUADS_BATCH )
{
quads . vertices [ 3 * quads . vCounter ] = x ;
quads . vertices [ 3 * quads . vCounter + 1 ] = y ;
quads . vertices [ 3 * quads . vCounter + 2 ] = z ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
quads . vCounter + + ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
draws [ drawsCounter - 1 ] . vertexCount + + ;
}
else TraceLog ( ERROR , " MAX_QUADS_BATCH overflow " ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
} break ;
default : break ;
}
}
}
// Define one vertex (position)
void rlVertex2f ( float x , float y )
{
2015-09-21 13:48:43 +03:00
rlVertex3f ( x , y , currentDepth ) ;
2014-03-25 15:40:35 +04:00
}
// Define one vertex (position)
void rlVertex2i ( int x , int y )
{
2015-09-21 13:48:43 +03:00
rlVertex3f ( ( float ) x , ( float ) y , currentDepth ) ;
2014-03-25 15:40:35 +04:00
}
// Define one vertex (texture coordinate)
2014-09-17 00:51:31 +04:00
// NOTE: Texture coordinates are limited to QUADS only
2014-03-25 15:40:35 +04: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 02:06:24 +04:00
void rlColor4ub ( byte x , byte y , byte z , byte w )
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
lines . cCounter + + ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
triangles . cCounter + + ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
quads . cCounter + + ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
} break ;
default : break ;
}
}
// Define one vertex (color)
2014-07-23 02:06:24 +04:00
void rlColor4f ( float r , float g , float b , float a )
2014-03-25 15:40:35 +04:00
{
2014-09-03 18:51:28 +04:00
rlColor4ub ( ( byte ) ( r * 255 ) , ( byte ) ( g * 255 ) , ( byte ) ( b * 255 ) , ( byte ) ( a * 255 ) ) ;
2014-03-25 15:40:35 +04:00
}
// Define one vertex (color)
void rlColor3f ( float x , float y , float z )
{
2014-07-23 02:06:24 +04:00
rlColor4ub ( ( byte ) ( x * 255 ) , ( byte ) ( y * 255 ) , ( byte ) ( z * 255 ) , 255 ) ;
2014-03-25 15:40:35 +04: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-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
glEnable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , id ) ;
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-04-19 18:36:49 +04:00
if ( draws [ drawsCounter - 1 ] . textureId ! = id )
2014-03-25 15:40:35 +04:00
{
2014-04-19 18:36:49 +04:00
if ( draws [ drawsCounter - 1 ] . vertexCount > 0 ) drawsCounter + + ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
draws [ drawsCounter - 1 ] . textureId = id ;
draws [ drawsCounter - 1 ] . vertexCount = 0 ;
2014-03-25 15:40:35 +04:00
}
# endif
}
// Disable texture usage
2014-09-03 19:06:10 +04:00
void rlDisableTexture ( void )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
glDisable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
# endif
}
2016-05-29 12:49:13 +03:00
// Enable rendering to texture (fbo)
2016-03-30 21:09:16 +03:00
void rlEnableRenderTexture ( unsigned int id )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer ( GL_FRAMEBUFFER , id ) ;
2016-05-29 12:49:13 +03:00
//glDisable(GL_CULL_FACE); // Allow double side drawing for texture flipping
//glCullFace(GL_FRONT);
2016-03-30 21:09:16 +03:00
# endif
}
2016-05-29 12:49:13 +03:00
// Disable rendering to texture
2016-03-30 21:09:16 +03:00
void rlDisableRenderTexture ( void )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2016-05-29 12:49:13 +03:00
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
2016-03-30 21:09:16 +03:00
# endif
}
2016-03-17 15:51:48 +03:00
// Enable depth test
void rlEnableDepthTest ( void )
{
glEnable ( GL_DEPTH_TEST ) ;
}
// Disable depth test
void rlDisableDepthTest ( void )
{
glDisable ( GL_DEPTH_TEST ) ;
}
2016-05-18 14:22:14 +03: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 15:40:35 +04:00
// Unload texture from GPU memory
void rlDeleteTextures ( unsigned int id )
{
2016-05-10 19:24:28 +03:00
if ( id ! = 0 ) glDeleteTextures ( 1 , & id ) ;
2014-03-25 15:40:35 +04:00
}
2016-03-30 21:09:16 +03:00
// Unload render texture from GPU memory
void rlDeleteRenderTextures ( RenderTexture2D target )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-10 19:24:28 +03: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 ) ;
2016-06-21 14:49:13 +03:00
TraceLog ( INFO , " [FBO ID %i] Unloaded render texture data from VRAM (GPU) " , target . id ) ;
2016-03-30 21:09:16 +03:00
# endif
}
2015-02-02 02:57:08 +03:00
// Unload shader from GPU memory
void rlDeleteShader ( unsigned int id )
{
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-10 19:24:28 +03:00
if ( id ! = 0 ) glDeleteProgram ( id ) ;
2015-03-01 18:00:52 +03:00
# endif
2015-04-06 15:02:29 +03:00
}
2015-02-02 02:57:08 +03:00
2014-09-17 00:51:31 +04:00
// Unload vertex data (VAO) from GPU memory
2014-04-04 22:11:57 +04:00
void rlDeleteVertexArrays ( unsigned int id )
{
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-03-27 19:33:30 +03:00
if ( vaoSupported )
{
2016-05-10 19:24:28 +03:00
if ( id ! = 0 ) glDeleteVertexArrays ( 1 , & id ) ;
2016-03-27 19:33:30 +03:00
TraceLog ( INFO , " [VAO ID %i] Unloaded model data from VRAM (GPU) " , id ) ;
}
2014-09-17 00:51:31 +04: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 16:24:02 +03:00
if ( id ! = 0 )
{
glDeleteBuffers ( 1 , & id ) ;
if ( ! vaoSupported ) TraceLog ( INFO , " [VBO ID %i] Unloaded model vertex data from VRAM (GPU) " , id ) ;
}
2014-04-04 22:11:57 +04:00
# endif
}
2014-03-25 15:40:35 +04: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 21:30:35 +03:00
float cr = ( float ) r / 255 ;
float cg = ( float ) g / 255 ;
float cb = ( float ) b / 255 ;
float ca = ( float ) a / 255 ;
2014-03-25 15:40:35 +04:00
glClearColor ( cr , cg , cb , ca ) ;
}
// Clear used screen buffers (color and depth)
2014-09-03 19:06:10 +04:00
void rlClearScreenBuffers ( void )
2014-03-25 15:40:35 +04: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...
}
2014-09-17 00:51:31 +04:00
// Returns current OpenGL version
int rlGetVersion ( void )
{
# if defined(GRAPHICS_API_OPENGL_11)
return OPENGL_11 ;
2016-06-16 21:25:50 +03:00
# elif defined(GRAPHICS_API_OPENGL_21)
return OPENGL_21 ;
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_33)
return OPENGL_33 ;
# elif defined(GRAPHICS_API_OPENGL_ES2)
return OPENGL_ES_20 ;
# endif
}
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Module Functions Definition - rlgl Functions
//----------------------------------------------------------------------------------
2016-06-26 00:28:50 +03:00
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
2016-06-26 15:13:11 +03:00
void rlglInit ( int width , int height )
2014-09-03 18:51:28 +04:00
{
2015-05-21 01:18:22 +03:00
// Check OpenGL information and capabilities
//------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
// Print current OpenGL and GLSL version
TraceLog ( INFO , " GPU: Vendor: %s " , glGetString ( GL_VENDOR ) ) ;
TraceLog ( INFO , " GPU: Renderer: %s " , glGetString ( GL_RENDERER ) ) ;
TraceLog ( INFO , " GPU: Version: %s " , glGetString ( GL_VERSION ) ) ;
2015-05-11 01:15:46 +03:00
TraceLog ( INFO , " GPU: GLSL: %s " , glGetString ( GL_SHADING_LANGUAGE_VERSION ) ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
// NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
//int maxTexSize;
//glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
//TraceLog(INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize);
2015-05-21 01:18:22 +03:00
//GL_MAX_TEXTURE_IMAGE_UNITS
//GL_MAX_VIEWPORT_DIMS
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
//int numAuxBuffers;
//glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
//TraceLog(INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers);
2015-05-21 01:18:22 +03:00
//GLint numComp = 0;
//GLint format[32] = { 0 };
//glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
//glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
//for (int i = 0; i < numComp; i++) TraceLog(INFO, "Supported compressed format: 0x%x", format[i]);
2014-09-17 00:51:31 +04:00
// NOTE: We don't need that much data on screen... right now...
2015-08-27 17:12:03 +03:00
# if defined(GRAPHICS_API_OPENGL_11)
2015-08-28 15:14:29 +03:00
//TraceLog(INFO, "OpenGL 1.1 (or driver default) profile initialized");
2015-08-27 17:12:03 +03:00
# endif
2015-04-13 21:15:28 +03:00
2015-05-21 01:18:22 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Get supported extensions list
2015-09-02 02:08:41 +03:00
GLint numExt = 0 ;
2015-05-21 01:18:22 +03:00
# if defined(GRAPHICS_API_OPENGL_33)
2015-08-27 17:12:03 +03:00
2016-01-21 14:24:35 +03:00
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
vaoSupported = true ;
npotSupported = true ;
2015-08-27 17:12:03 +03:00
2015-05-21 01:18:22 +03:00
// We get a list of available extensions and we check for some of them (compressed textures)
2016-06-02 19:20:59 +03:00
// NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that)
2014-09-17 00:51:31 +04:00
glGetIntegerv ( GL_NUM_EXTENSIONS , & numExt ) ;
2015-09-02 02:08:41 +03:00
const char * extList [ numExt ] ;
2015-05-21 01:18:22 +03:00
2015-09-02 02:08:41 +03:00
for ( int i = 0 ; i < numExt ; i + + ) extList [ i ] = ( char * ) glGetStringi ( GL_EXTENSIONS , i ) ;
2015-05-21 01:18:22 +03:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2015-09-02 02:08:41 +03:00
char * extensions = ( char * ) glGetString ( GL_EXTENSIONS ) ; // One big const string
// 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 20:20:25 +03: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 ) ;
2015-05-21 01:18:22 +03:00
// NOTE: String could be splitted using strtok() function (string.h)
2015-09-02 02:08:41 +03:00
// NOTE: strtok() modifies the received string, it can not be const
char * extList [ 512 ] ; // Allocate 512 strings pointers (2 KB)
2016-05-03 20:20:25 +03:00
2015-09-02 02:08:41 +03:00
extList [ numExt ] = strtok ( extensionsDup , " " ) ;
while ( extList [ numExt ] ! = NULL )
{
numExt + + ;
extList [ numExt ] = strtok ( NULL , " " ) ;
}
free ( extensionsDup ) ; // Duplicated string must be deallocated
numExt - = 1 ;
2015-05-21 01:18:22 +03:00
# endif
TraceLog ( INFO , " Number of supported extensions: %i " , numExt ) ;
2014-09-17 00:51:31 +04:00
2015-05-21 01:18:22 +03:00
// Show supported extensions
2015-09-02 02:08:41 +03:00
//for (int i = 0; i < numExt; i++) TraceLog(INFO, "Supported extension: %s", extList[i]);
2015-05-21 01:18:22 +03:00
// Check required extensions
2014-09-17 00:51:31 +04:00
for ( int i = 0 ; i < numExt ; i + + )
2014-03-25 15:40:35 +04:00
{
2015-05-21 01:18:22 +03: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 02:08:41 +03:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_vertex_array_object " ) = = 0 )
2015-04-13 21:15:28 +03:00
{
2015-05-21 01:18:22 +03:00
vaoSupported = true ;
// The extension is supported by our hardware and driver, try to get related functions pointers
// 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 21:15:28 +03:00
}
2015-05-21 01:18:22 +03:00
// Check NPOT textures support
// NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
2015-09-02 02:08:41 +03:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_OES_texture_npot " ) = = 0 ) npotSupported = true ;
2015-05-21 01:18:22 +03:00
# endif
// DDS texture compression support
2015-10-26 13:50:13 +03:00
if ( ( strcmp ( extList [ i ] , ( const char * ) " GL_EXT_texture_compression_s3tc " ) = = 0 ) | |
2016-05-01 02:09:48 +03:00
( strcmp ( extList [ i ] , ( const char * ) " GL_WEBGL_compressed_texture_s3tc " ) = = 0 ) | |
2015-10-26 13:50:13 +03:00
( strcmp ( extList [ i ] , ( const char * ) " GL_WEBKIT_WEBGL_compressed_texture_s3tc " ) = = 0 ) ) texCompDXTSupported = true ;
2015-05-21 01:18:22 +03:00
// ETC1 texture compression support
2016-05-01 02:09:48 +03: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-17 00:51:31 +04:00
2015-05-21 01:18:22 +03:00
// ETC2/EAC texture compression support
2015-09-02 02:08:41 +03:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_ARB_ES3_compatibility " ) = = 0 ) texCompETC2Supported = true ;
2015-05-21 01:18:22 +03:00
// PVR texture compression support
2015-09-02 02:08:41 +03:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_IMG_texture_compression_pvrtc " ) = = 0 ) texCompPVRTSupported = true ;
2015-05-21 01:18:22 +03:00
// ASTC texture compression support
2015-09-02 02:08:41 +03:00
if ( strcmp ( extList [ i ] , ( const char * ) " GL_KHR_texture_compression_astc_hdr " ) = = 0 ) texCompASTCSupported = true ;
2015-05-21 01:18:22 +03:00
}
2015-05-11 01:15:46 +03:00
2015-05-21 01:18:22 +03:00
# if defined(GRAPHICS_API_OPENGL_ES2)
if ( vaoSupported ) TraceLog ( INFO , " [EXTENSION] VAO extension detected, VAO functions initialized successfully " ) ;
else TraceLog ( WARNING , " [EXTENSION] VAO extension not found, VAO usage not supported " ) ;
2015-05-11 01:15:46 +03:00
2015-05-21 01:18:22 +03:00
if ( npotSupported ) TraceLog ( INFO , " [EXTENSION] NPOT textures extension detected, full NPOT textures supported " ) ;
2016-02-03 21:01:16 +03:00
else TraceLog ( WARNING , " [EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat) " ) ;
2015-05-21 01:18:22 +03:00
# endif
2014-09-17 00:51:31 +04:00
2015-05-21 01:18:22 +03:00
if ( texCompDXTSupported ) TraceLog ( INFO , " [EXTENSION] DXT compressed textures supported " ) ;
if ( texCompETC1Supported ) TraceLog ( INFO , " [EXTENSION] ETC1 compressed textures supported " ) ;
if ( texCompETC2Supported ) TraceLog ( INFO , " [EXTENSION] ETC2/EAC compressed textures supported " ) ;
if ( texCompPVRTSupported ) TraceLog ( INFO , " [EXTENSION] PVRT compressed textures supported " ) ;
if ( texCompASTCSupported ) TraceLog ( INFO , " [EXTENSION] ASTC compressed textures supported " ) ;
// Initialize buffers, default shaders and default textures
//----------------------------------------------------------
2016-06-24 20:37:52 +03:00
// Init default white texture
2015-09-02 02:08:41 +03:00
unsigned char pixels [ 4 ] = { 255 , 255 , 255 , 255 } ; // 1 pixel RGBA (4 bytes)
2014-03-25 15:40:35 +04:00
2015-09-02 02:08:41 +03:00
whiteTexture = rlglLoadTexture ( pixels , 1 , 1 , UNCOMPRESSED_R8G8B8A8 , 1 ) ;
if ( whiteTexture ! = 0 ) TraceLog ( INFO , " [TEX ID %i] Base white texture loaded successfully " , whiteTexture ) ;
else TraceLog ( WARNING , " Base white texture could not be loaded " ) ;
2016-04-03 21:14:07 +03:00
// Init default Shader (customized for GL 3.3 and ES2)
2015-03-01 18:00:52 +03:00
defaultShader = LoadDefaultShader ( ) ;
2015-05-05 00:46:31 +03:00
currentShader = defaultShader ;
2014-09-03 18:51:28 +04:00
2016-06-24 20:37:52 +03:00
// Init default vertex arrays buffers (lines, triangles, quads)
LoadDefaultBuffers ( ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Init temp vertex buffer, used when transformation required (translate, rotate, scale)
tempBuffer = ( Vector3 * ) malloc ( sizeof ( Vector3 ) * TEMP_VERTEX_BUFFER_SIZE ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
for ( int i = 0 ; i < TEMP_VERTEX_BUFFER_SIZE ; i + + ) tempBuffer [ i ] = VectorZero ( ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Init draw calls tracking system
draws = ( DrawCall * ) malloc ( sizeof ( DrawCall ) * MAX_DRAWS_BY_TEXTURE ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
for ( int i = 0 ; i < MAX_DRAWS_BY_TEXTURE ; i + + )
{
2014-04-19 18:36:49 +04:00
draws [ i ] . textureId = 0 ;
draws [ i ] . vertexCount = 0 ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
drawsCounter = 1 ;
2015-04-06 15:02:29 +03:00
draws [ drawsCounter - 1 ] . textureId = whiteTexture ;
2016-06-24 20:37:52 +03:00
currentDrawMode = RL_TRIANGLES ; // Set default draw mode
// Init internal matrix stack (emulating OpenGL 1.1)
for ( int i = 0 ; i < MATRIX_STACK_SIZE ; i + + ) stack [ i ] = MatrixIdentity ( ) ;
// Init internal projection and modelview matrices
projection = MatrixIdentity ( ) ;
modelview = MatrixIdentity ( ) ;
currentMatrix = & modelview ;
2016-06-26 00:28:50 +03: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+)
glHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ; // Improve quality of color and texture coordinate interpolation
glShadeModel ( GL_SMOOTH ) ; // Smooth shading between vertex (vertex colors interpolation)
2014-09-17 00:51:31 +04:00
# endif
2016-06-26 00:28:50 +03: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)
2016-06-26 15:13:11 +03:00
// Store screen size into global variables
screenWidth = width ;
screenHeight = height ;
2016-06-26 00:28:50 +03:00
TraceLog ( INFO , " OpenGL default states initialized successfully " ) ;
2014-03-25 15:40:35 +04:00
}
// Vertex Buffer Object deinitialization (memory free)
2014-09-03 19:06:10 +04:00
void rlglClose ( void )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-03 20:20:25 +03:00
UnloadDefaultShader ( ) ;
2016-05-20 18:18:07 +03:00
UnloadStandardShader ( ) ;
2016-05-03 20:20:25 +03:00
UnloadDefaultBuffers ( ) ;
// Delete default white texture
2014-03-25 15:40:35 +04:00
glDeleteTextures ( 1 , & whiteTexture ) ;
2015-09-02 02:08:41 +03:00
TraceLog ( INFO , " [TEX ID %i] Unloaded texture data (base white texture) from VRAM " , whiteTexture ) ;
2016-05-31 01:51:55 +03:00
// Unload lights
if ( lightsCount > 0 )
{
for ( int i = 0 ; i < lightsCount ; i + + ) free ( lights [ i ] ) ;
lightsCount = 0 ;
}
2015-04-06 15:02:29 +03:00
2014-04-19 18:36:49 +04:00
free ( draws ) ;
2014-09-17 00:51:31 +04:00
# endif
2014-03-25 15:40:35 +04:00
}
2015-05-05 00:46:31 +03:00
// Drawing batches: triangles, quads, lines
2014-09-03 19:06:10 +04:00
void rlglDraw ( void )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-07-04 02:29:23 +03:00
// NOTE: In a future version, models could be stored in a stack...
//for (int i = 0; i < modelsCount; i++) rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform);
// NOTE: Default buffers upload and draw
UpdateDefaultBuffers ( ) ;
if ( vrEnabled & & vrControl ) DrawDefaultBuffers ( 2 ) ;
else DrawDefaultBuffers ( 1 ) ;
2014-09-17 00:51:31 +04:00
# endif
2014-04-04 22:11:57 +04:00
}
2016-06-14 18:16:20 +03:00
// Load OpenGL extensions
// NOTE: External loader function could be passed as a pointer
void rlglLoadExtensions ( void * loader )
{
2016-06-17 01:29:46 +03:00
# if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
2016-06-14 18:16:20 +03:00
if ( ! gladLoadGLLoader ( ( GLADloadproc ) loader ) ) TraceLog ( WARNING , " GLAD: Cannot load OpenGL extensions " ) ;
else TraceLog ( INFO , " GLAD: OpenGL extensions loaded successfully " ) ;
2016-06-17 01:29:46 +03:00
# if defined(GRAPHICS_API_OPENGL_21)
2016-06-16 21:25:50 +03:00
if ( GLAD_GL_VERSION_2_1 ) TraceLog ( INFO , " OpenGL 2.1 profile supported " ) ;
2016-06-17 01:29:46 +03:00
# elif defined(GRAPHICS_API_OPENGL_33)
if ( GLAD_GL_VERSION_3_3 ) TraceLog ( INFO , " OpenGL 3.3 Core profile supported " ) ;
2016-06-14 18:16:20 +03:00
else TraceLog ( ERROR , " OpenGL 3.3 Core profile not supported " ) ;
2016-06-17 01:29:46 +03:00
# endif
2016-06-14 18:16:20 +03: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
}
2015-03-02 22:52:58 +03:00
// Get world coordinates from screen coordinates
Vector3 rlglUnproject ( Vector3 source , Matrix proj , Matrix view )
2015-04-06 15:02:29 +03:00
{
2016-03-02 19:13:31 +03:00
Vector3 result = { 0.0f , 0.0f , 0.0f } ;
2015-08-27 17:12:03 +03:00
2016-03-02 19:13:31 +03:00
// Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
Matrix matProjView = MatrixMultiply ( proj , view ) ;
MatrixInvert ( & matProjView ) ;
2015-08-27 17:12:03 +03:00
2016-03-02 19:13:31 +03:00
// Create quaternion from source point
Quaternion quat = { source . x , source . y , source . z , 1.0f } ;
2015-08-27 17:12:03 +03:00
2016-03-02 19:13:31 +03:00
// Multiply quat point by unproject matrix
QuaternionTransform ( & quat , matProjView ) ;
2015-08-27 17:12:03 +03:00
2016-03-02 19:13:31 +03:00
// Normalized world points in vectors
result . x = quat . x / quat . w ;
result . y = quat . y / quat . w ;
result . z = quat . z / quat . w ;
2015-04-06 15:02:29 +03:00
2015-08-27 17:12:03 +03:00
return result ;
2015-03-02 22:52:58 +03:00
}
2014-03-25 15:40:35 +04:00
// Convert image data to OpenGL texture (returns OpenGL valid Id)
2015-07-05 19:21:01 +03:00
unsigned int rlglLoadTexture ( void * data , int width , int height , int textureFormat , int mipmapCount )
2014-03-25 15:40:35 +04:00
{
2015-04-06 15:02:29 +03:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Free any old binding
2014-03-25 15:40:35 +04:00
2015-05-21 01:18:22 +03:00
GLuint id = 0 ;
2015-04-06 15:02:29 +03:00
2015-05-21 01:18:22 +03:00
// Check texture format support by OpenGL 1.1 (compressed textures not supported)
2016-06-14 16:42:04 +03:00
# if defined(GRAPHICS_API_OPENGL_11)
if ( textureFormat > = 8 )
2015-04-06 15:02:29 +03:00
{
2015-05-21 01:18:22 +03:00
TraceLog ( WARNING , " OpenGL 1.1 does not support GPU compressed texture formats " ) ;
return id ;
2015-04-06 15:02:29 +03:00
}
2016-06-14 16:42:04 +03:00
# endif
2015-04-06 15:02:29 +03:00
2015-05-21 15:13:51 +03:00
if ( ( ! texCompDXTSupported ) & & ( ( textureFormat = = COMPRESSED_DXT1_RGB ) | | ( textureFormat = = COMPRESSED_DXT1_RGBA ) | |
( textureFormat = = COMPRESSED_DXT3_RGBA ) | | ( textureFormat = = COMPRESSED_DXT5_RGBA ) ) )
{
TraceLog ( WARNING , " DXT compressed texture format not supported " ) ;
return id ;
}
2015-07-05 19:21:01 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-05-21 15:13:51 +03:00
if ( ( ! texCompETC1Supported ) & & ( textureFormat = = COMPRESSED_ETC1_RGB ) )
{
TraceLog ( WARNING , " ETC1 compressed texture format not supported " ) ;
return id ;
}
if ( ( ! texCompETC2Supported ) & & ( ( textureFormat = = COMPRESSED_ETC2_RGB ) | | ( textureFormat = = COMPRESSED_ETC2_EAC_RGBA ) ) )
{
TraceLog ( WARNING , " ETC2 compressed texture format not supported " ) ;
return id ;
}
if ( ( ! texCompPVRTSupported ) & & ( ( textureFormat = = COMPRESSED_PVRT_RGB ) | | ( textureFormat = = COMPRESSED_PVRT_RGBA ) ) )
{
TraceLog ( WARNING , " PVRT compressed texture format not supported " ) ;
return id ;
}
if ( ( ! texCompASTCSupported ) & & ( ( textureFormat = = COMPRESSED_ASTC_4x4_RGBA ) | | ( textureFormat = = COMPRESSED_ASTC_8x8_RGBA ) ) )
{
TraceLog ( WARNING , " ASTC compressed texture format not supported " ) ;
return id ;
}
2015-07-05 19:21:01 +03:00
# endif
2015-04-06 15:02:29 +03:00
glGenTextures ( 1 , & id ) ; // Generate Pointer to the texture
2014-09-03 18:51:28 +04:00
2015-05-18 14:12:24 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-05-21 15:13:51 +03:00
//glActiveTexture(GL_TEXTURE0); // If not defined, using GL_TEXTURE0 by default (shader texture)
2015-05-18 14:12:24 +03:00
# endif
2014-03-25 15:40:35 +04:00
glBindTexture ( GL_TEXTURE_2D , id ) ;
2014-09-03 18:51:28 +04:00
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-09-17 00:51:31 +04:00
// NOTE: We define internal (GPU) format as GL_RGBA8 (probably BGRA8 in practice, driver takes care)
2015-02-09 20:29:32 +03:00
// NOTE: On embedded systems, we let the driver choose the best internal format
2015-04-06 15:02:29 +03:00
// Support for multiple color modes (16bit color modes and grayscale)
// (sized)internalFormat format type
2015-02-09 20:29:32 +03:00
// GL_R GL_RED GL_UNSIGNED_BYTE
// GL_RGB565 GL_RGB GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5
2015-04-06 15:02:29 +03:00
// GL_RGB5_A1 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_5_5_1
2015-02-09 20:29:32 +03:00
// GL_RGBA4 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4
2015-04-06 15:02:29 +03:00
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
2015-03-01 18:00:52 +03:00
2015-04-06 15:02:29 +03:00
switch ( textureFormat )
2015-03-01 18:00:52 +03:00
{
2015-04-06 15:02:29 +03:00
case UNCOMPRESSED_GRAYSCALE :
{
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_R8 , width , height , 0 , GL_RED , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ;
// With swizzleMask we define how a one channel texture will be mapped to RGBA
// Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle
2015-05-05 00:46:31 +03:00
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , GL_ONE } ;
2015-04-06 15:02:29 +03:00
glTexParameteriv ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_RGBA , swizzleMask ) ;
2015-05-05 00:46:31 +03:00
TraceLog ( INFO , " [TEX ID %i] Grayscale texture loaded and swizzled " , id ) ;
} break ;
case UNCOMPRESSED_GRAY_ALPHA :
{
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RG8 , width , height , 0 , GL_RG , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ;
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , GL_GREEN } ;
glTexParameteriv ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_RGBA , swizzleMask ) ;
2015-04-06 15:02:29 +03:00
} break ;
2015-05-21 01:18:22 +03:00
2015-04-06 15:02:29 +03:00
case UNCOMPRESSED_R5G6B5 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB565 , width , height , 0 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB8 , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G5B5A1 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB5_A1 , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R4G4B4A4 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA4 , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8A8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
2015-05-21 01:18:22 +03:00
case COMPRESSED_DXT1_RGB : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT1_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT3_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) ; break ;
case COMPRESSED_DXT5_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ; break ;
case COMPRESSED_ETC1_RGB : if ( texCompETC1Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_ETC1_RGB8_OES ) ; break ; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB : if ( texCompETC2Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB8_ETC2 ) ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA : if ( texCompETC2Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA8_ETC2_EAC ) ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB : if ( texCompPVRTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG ) ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA : if ( texCompPVRTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ) ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA : if ( texCompASTCSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_ASTC_4x4_KHR ) ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA : if ( texCompASTCSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_ASTC_8x8_KHR ) ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
2015-04-06 15:02:29 +03:00
default : TraceLog ( WARNING , " Texture format not recognized " ) ; break ;
2015-03-01 18:00:52 +03:00
}
2015-05-11 01:15:46 +03:00
# elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2)
2015-04-06 15:02:29 +03:00
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
switch ( textureFormat )
{
case UNCOMPRESSED_GRAYSCALE : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_LUMINANCE , width , height , 0 , GL_LUMINANCE , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
2015-05-05 00:46:31 +03:00
case UNCOMPRESSED_GRAY_ALPHA : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_LUMINANCE_ALPHA , width , height , 0 , GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
2015-04-06 15:02:29 +03:00
case UNCOMPRESSED_R5G6B5 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , width , height , 0 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G5B5A1 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R4G4B4A4 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8A8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
2015-05-21 01:18:22 +03:00
# if defined(GRAPHICS_API_OPENGL_ES2)
case COMPRESSED_DXT1_RGB : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT1_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT3_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) ; break ; // NOTE: Not supported by WebGL
case COMPRESSED_DXT5_RGBA : if ( texCompDXTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ; break ; // NOTE: Not supported by WebGL
case COMPRESSED_ETC1_RGB : if ( texCompETC1Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_ETC1_RGB8_OES ) ; break ; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB : if ( texCompETC2Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB8_ETC2 ) ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA : if ( texCompETC2Supported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA8_ETC2_EAC ) ; break ; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_PVRT_RGB : if ( texCompPVRTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG ) ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA : if ( texCompPVRTSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ) ; break ; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA : if ( texCompASTCSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_ASTC_4x4_KHR ) ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA : if ( texCompASTCSupported ) LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_ASTC_8x8_KHR ) ; break ; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
# endif
2015-05-05 00:46:31 +03:00
default : TraceLog ( WARNING , " Texture format not supported " ) ; break ;
2015-04-06 15:02:29 +03:00
}
2015-05-11 01:15:46 +03:00
# endif
2015-07-05 19:21:01 +03: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
2015-09-02 21:36:05 +03:00
if ( npotSupported )
{
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 19:21:01 +03: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 18:27:53 +03: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
2015-07-05 19:21:01 +03:00
# if defined(GRAPHICS_API_OPENGL_33)
if ( mipmapCount > 1 )
{
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ; // Activate Trilinear filtering for mipmaps (must be available)
}
# endif
// At this point we have the texture loaded in GPU and texture parameters configured
// NOTE: If mipmaps were not in data, they are not generated automatically
// Unbind current texture
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
if ( id > 0 ) TraceLog ( INFO , " [TEX ID %i] Texture created successfully (%ix%i) " , id , width , height ) ;
else TraceLog ( WARNING , " Texture could not be created " ) ;
return id ;
}
2016-03-30 21:09:16 +03:00
// Load a texture to be used for rendering (fbo with color and depth attachments)
RenderTexture2D rlglLoadRenderTexture ( int width , int height )
{
RenderTexture2D target ;
target . id = 0 ;
target . texture . id = 0 ;
target . texture . width = width ;
target . texture . height = height ;
target . texture . format = UNCOMPRESSED_R8G8B8 ;
target . texture . mipmaps = 1 ;
target . depth . id = 0 ;
target . depth . width = width ;
target . depth . height = height ;
2016-04-10 20:38:57 +03:00
target . depth . format = 19 ; //DEPTH_COMPONENT_24BIT
2016-03-30 21:09:16 +03: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 ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , NULL ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-04-10 20:38:57 +03:00
# if defined(GRAPHICS_API_OPENGL_33)
# define USE_DEPTH_TEXTURE
# else
# define USE_DEPTH_RENDERBUFFER
# endif
2016-03-30 21:09:16 +03: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 12:25:04 +03:00
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT16 , width , height ) ; // GL_DEPTH_COMPONENT24 not supported on Android
2016-03-30 21:09:16 +03: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 20:38:57 +03:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT24 , width , height , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , NULL ) ;
2016-03-30 21:09:16 +03: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 )
{
TraceLog ( WARNING , " Framebuffer object could not be created... " ) ;
2016-05-21 19:22:15 +03:00
switch ( status )
2016-03-30 21:09:16 +03:00
{
case GL_FRAMEBUFFER_UNSUPPORTED : TraceLog ( WARNING , " Framebuffer is unsupported " ) ; break ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : TraceLog ( WARNING , " Framebuffer incomplete attachment " ) ; break ;
# if defined(GRAPHICS_API_OPENGL_ES2)
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS : TraceLog ( WARNING , " Framebuffer incomplete dimensions " ) ; break ;
# endif
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : TraceLog ( WARNING , " Framebuffer incomplete missing attachment " ) ; break ;
default : break ;
}
glDeleteTextures ( 1 , & target . texture . id ) ;
glDeleteTextures ( 1 , & target . depth . id ) ;
glDeleteFramebuffers ( 1 , & target . id ) ;
}
else TraceLog ( INFO , " [FBO ID %i] Framebuffer object created successfully " , target . id ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
# endif
return target ;
}
// Update already loaded texture in GPU with new data
2015-11-04 20:33:46 +03:00
void rlglUpdateTexture ( unsigned int id , int width , int height , int format , void * data )
{
glBindTexture ( GL_TEXTURE_2D , id ) ;
# if defined(GRAPHICS_API_OPENGL_33)
switch ( format )
{
case UNCOMPRESSED_GRAYSCALE : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RED , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_GRAY_ALPHA : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RG , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G6B5 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGB , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G5B5A1 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R4G4B4A4 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8A8 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
default : TraceLog ( WARNING , " Texture format updating not supported " ) ; break ;
}
# elif defined(GRAPHICS_API_OPENGL_11) || 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
switch ( format )
{
case UNCOMPRESSED_GRAYSCALE : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_LUMINANCE , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_GRAY_ALPHA : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G6B5 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGB , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
case UNCOMPRESSED_R5G5B5A1 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R4G4B4A4 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 , ( unsigned short * ) data ) ; break ;
case UNCOMPRESSED_R8G8B8A8 : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
default : TraceLog ( WARNING , " Texture format updating not supported " ) ; break ;
}
# endif
}
2015-07-05 19:21:01 +03:00
// Generate mipmap data for selected texture
2016-01-04 17:09:44 +03:00
void rlglGenerateMipmaps ( Texture2D texture )
2015-07-05 19:21:01 +03:00
{
2016-01-04 17:09:44 +03:00
glBindTexture ( GL_TEXTURE_2D , texture . id ) ;
2015-07-05 19:21:01 +03:00
2015-07-18 20:25:15 +03:00
// Check if texture is power-of-two (POT)
bool texIsPOT = false ;
2016-01-04 17:09:44 +03:00
if ( ( ( texture . width > 0 ) & & ( ( texture . width & ( texture . width - 1 ) ) = = 0 ) ) & &
( ( texture . height > 0 ) & & ( ( texture . height & ( texture . height - 1 ) ) = = 0 ) ) ) texIsPOT = true ;
2015-05-11 01:15:46 +03:00
2015-07-18 20:25:15 +03:00
if ( ( texIsPOT ) | | ( npotSupported ) )
2015-05-11 01:15:46 +03:00
{
# if defined(GRAPHICS_API_OPENGL_11)
// Compute required mipmaps
2016-01-04 17:09:44 +03:00
void * data = rlglReadTexturePixels ( texture ) ;
2015-07-05 19:21:01 +03:00
2015-05-11 01:15:46 +03:00
// NOTE: data size is reallocated to fit mipmaps data
2016-03-01 17:36:45 +03:00
// NOTE: CPU mipmap generation only supports RGBA 32bit data
2016-01-04 17:09:44 +03:00
int mipmapCount = GenerateMipmaps ( data , texture . width , texture . height ) ;
2015-05-11 01:15:46 +03:00
2016-02-12 14:22:56 +03:00
int size = texture . width * texture . height * 4 ; // RGBA 32bit only
2015-05-11 01:15:46 +03:00
int offset = size ;
2016-01-04 17:09:44 +03:00
int mipWidth = texture . width / 2 ;
int mipHeight = texture . height / 2 ;
2015-05-11 01:15:46 +03: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 , data + offset ) ;
2015-04-06 15:02:29 +03:00
2015-05-11 01:15:46 +03:00
size = mipWidth * mipHeight * 4 ;
offset + = size ;
mipWidth / = 2 ;
mipHeight / = 2 ;
}
2016-01-04 17:09:44 +03:00
TraceLog ( WARNING , " [TEX ID %i] Mipmaps generated manually on CPU side " , texture . id ) ;
2015-07-05 19:21:01 +03:00
2016-03-01 17:36:45 +03:00
// NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
2016-03-27 19:33:30 +03:00
free ( data ) ;
2016-03-01 17:36:45 +03:00
2016-05-03 20:20:25 +03:00
# endif
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-07-05 19:21:01 +03:00
glGenerateMipmap ( GL_TEXTURE_2D ) ; // Generate mipmaps automatically
2016-01-04 17:09:44 +03:00
TraceLog ( INFO , " [TEX ID %i] Mipmaps generated automatically " , texture . id ) ;
2015-05-11 01:15:46 +03:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ; // Activate Trilinear filtering for mipmaps (must be available)
# endif
2015-07-05 19:21:01 +03:00
}
2016-01-04 17:09:44 +03:00
else TraceLog ( WARNING , " [TEX ID %i] Mipmaps can not be generated " , texture . id ) ;
2016-03-01 17:36:45 +03:00
2014-03-25 15:40:35 +04:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2016-05-07 19:07:15 +03:00
// Upload vertex data into a VAO (if supported) and VBO
2016-05-20 10:36:02 +03:00
void rlglLoadMesh ( Mesh * mesh , bool dynamic )
2014-09-17 00:51:31 +04:00
{
2016-05-07 19:07:15 +03: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-09 00:50:35 +03: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 19:24:28 +03:00
mesh - > vboId [ 6 ] = 0 ; // Vertex indices VBO
2016-05-20 10:36:02 +03:00
2016-06-01 13:37:51 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-20 10:36:02 +03:00
int drawHint = GL_STATIC_DRAW ;
if ( dynamic ) drawHint = GL_DYNAMIC_DRAW ;
2016-05-08 16:24:02 +03:00
2016-07-04 19:34:28 +03:00
GLuint vaoId = 0 ; // Vertex Array Objects (VAO)
GLuint vboId [ 7 ] = { 0 } ; // Vertex Buffer Objects (VBOs)
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Quads VAO (Buffer A)
2016-05-07 19:07:15 +03:00
glGenVertexArrays ( 1 , & vaoId ) ;
glBindVertexArray ( vaoId ) ;
2014-09-17 00:51:31 +04:00
}
2016-05-07 19:07:15 +03:00
// NOTE: Attributes must be uploaded considering default locations points
// Enable vertex attributes: position (shader-location = 0)
2016-05-08 16:24:02 +03:00
glGenBuffers ( 1 , & vboId [ 0 ] ) ;
2016-05-07 19:07:15 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 0 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh - > vertexCount , mesh - > vertices , drawHint ) ;
2016-05-07 19:07:15 +03:00
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 0 ) ;
2014-09-17 00:51:31 +04:00
2016-05-07 19:07:15 +03:00
// Enable vertex attributes: texcoords (shader-location = 1)
2016-05-08 16:24:02 +03:00
glGenBuffers ( 1 , & vboId [ 1 ] ) ;
2016-05-07 19:07:15 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 1 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * mesh - > vertexCount , mesh - > texcoords , drawHint ) ;
2016-05-07 19:07:15 +03:00
glVertexAttribPointer ( 1 , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 1 ) ;
2014-09-17 00:51:31 +04:00
2016-05-07 19:07:15 +03:00
// Enable vertex attributes: normals (shader-location = 2)
2016-05-08 16:24:02 +03:00
if ( mesh - > normals ! = NULL )
{
glGenBuffers ( 1 , & vboId [ 2 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 2 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh - > vertexCount , mesh - > normals , drawHint ) ;
2016-05-08 16:24:02 +03: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 ) ;
}
2016-04-03 21:14:07 +03:00
2016-05-07 19:07:15 +03:00
// Default color vertex attribute (shader-location = 3)
2016-05-08 16:24:02 +03:00
if ( mesh - > colors ! = NULL )
{
glGenBuffers ( 1 , & vboId [ 3 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 3 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * mesh - > vertexCount , mesh - > colors , drawHint ) ;
2016-05-08 16:24:02 +03: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 ) ;
}
// Default tangent vertex attribute (shader-location = 4)
if ( mesh - > tangents ! = NULL )
{
glGenBuffers ( 1 , & vboId [ 4 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 4 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh - > vertexCount , mesh - > tangents , drawHint ) ;
2016-05-08 16:24:02 +03:00
glVertexAttribPointer ( 4 , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 4 ) ;
}
else
{
// Default tangents vertex attribute
glVertexAttrib3f ( 4 , 0.0f , 0.0f , 0.0f ) ;
glDisableVertexAttribArray ( 4 ) ;
}
// Default texcoord2 vertex attribute (shader-location = 5)
if ( mesh - > texcoords2 ! = NULL )
{
glGenBuffers ( 1 , & vboId [ 5 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , vboId [ 5 ] ) ;
2016-05-20 10:36:02 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * mesh - > vertexCount , mesh - > texcoords2 , drawHint ) ;
2016-05-08 16:24:02 +03:00
glVertexAttribPointer ( 5 , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( 5 ) ;
}
else
{
// Default tangents vertex attribute
glVertexAttrib2f ( 5 , 0.0f , 0.0f ) ;
glDisableVertexAttribArray ( 5 ) ;
}
2016-04-03 21:14:07 +03:00
2016-05-10 19:24:28 +03:00
if ( mesh - > indices ! = NULL )
{
glGenBuffers ( 1 , & vboId [ 6 ] ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , vboId [ 6 ] ) ;
2016-05-10 20:25:06 +03:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( unsigned short ) * mesh - > triangleCount * 3 , mesh - > indices , GL_STATIC_DRAW ) ;
2016-05-10 19:24:28 +03:00
}
2016-05-07 19:07:15 +03:00
mesh - > vboId [ 0 ] = vboId [ 0 ] ; // Vertex position VBO
mesh - > vboId [ 1 ] = vboId [ 1 ] ; // Texcoords VBO
mesh - > vboId [ 2 ] = vboId [ 2 ] ; // Normals VBO
2016-05-08 16:24:02 +03:00
mesh - > vboId [ 3 ] = vboId [ 3 ] ; // Colors VBO
mesh - > vboId [ 4 ] = vboId [ 4 ] ; // Tangents VBO
mesh - > vboId [ 5 ] = vboId [ 5 ] ; // Texcoords2 VBO
2016-05-10 19:24:28 +03:00
mesh - > vboId [ 6 ] = vboId [ 6 ] ; // Indices VBO
2015-02-02 02:57:08 +03:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
2016-05-07 19:07:15 +03:00
if ( vaoId > 0 )
2014-09-17 00:51:31 +04:00
{
2016-05-07 19:07:15 +03:00
mesh - > vaoId = vaoId ;
TraceLog ( INFO , " [VAO ID %i] Mesh uploaded successfully to VRAM (GPU) " , mesh - > vaoId ) ;
2014-09-17 00:51:31 +04:00
}
2016-05-07 19:07:15 +03:00
else TraceLog ( WARNING , " Mesh could not be uploaded to VRAM (GPU) " ) ;
2014-09-17 00:51:31 +04:00
}
else
{
2016-05-08 16:24:02 +03:00
TraceLog ( INFO , " [VBOs] Mesh uploaded successfully to VRAM (GPU) " ) ;
2014-09-17 00:51:31 +04:00
}
# endif
}
2014-04-09 22:25:26 +04:00
2016-05-18 14:22:14 +03:00
// Update vertex data on GPU (upload new data to one buffer)
void rlglUpdateMesh ( Mesh mesh , int buffer , int numVertex )
{
2016-06-01 13:37:51 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-18 14:22:14 +03:00
// Activate mesh VAO
if ( vaoSupported ) glBindVertexArray ( mesh . vaoId ) ;
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 ) ;
} 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 ) ;
} break ;
case 2 : // Update normals (vertex normals)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 0 ] ) ;
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 ) ;
} break ;
case 3 : // Update colors (vertex colors)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 2 ] ) ;
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 ) ;
} break ;
case 4 : // Update tangents (vertex tangents)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 0 ] ) ;
if ( numVertex > = mesh . vertexCount ) glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * numVertex , mesh . tangents , GL_DYNAMIC_DRAW ) ;
else glBufferSubData ( GL_ARRAY_BUFFER , 0 , sizeof ( float ) * 3 * numVertex , mesh . tangents ) ;
} break ;
case 5 : // Update texcoords2 (vertex second texture coordinates)
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 1 ] ) ;
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 ;
}
// 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 13:37:51 +03:00
# endif
2016-05-18 14:22:14 +03:00
}
// Draw a 3d mesh with material and transform
void rlglDrawMesh ( Mesh mesh , Material material , Matrix transform )
{
# if defined(GRAPHICS_API_OPENGL_11)
glEnable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , material . texDiffuse . id ) ;
// 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
rlPushMatrix ( ) ;
rlMultMatrixf ( MatrixToFloat ( transform ) ) ;
rlColor4ub ( material . colDiffuse . r , material . colDiffuse . g , material . colDiffuse . b , material . colDiffuse . a ) ;
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)
2016-07-04 02:29:23 +03:00
int eyesCount = 1 ;
if ( vrEnabled ) eyesCount = 2 ;
2016-05-18 14:22:14 +03:00
glUseProgram ( material . shader . id ) ;
2016-07-04 02:29:23 +03:00
// Upload to shader material.colDiffuse
float vColorDiffuse [ 4 ] = { ( float ) material . colDiffuse . r / 255 , ( float ) material . colDiffuse . g / 255 , ( float ) material . colDiffuse . b / 255 , ( float ) material . colDiffuse . a / 255 } ;
glUniform4fv ( material . shader . tintColorLoc , 1 , vColorDiffuse ) ;
2016-05-18 14:22:14 +03:00
// At this point the modelview matrix just contains the view matrix (camera)
// That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matView = modelview ; // View matrix (camera)
Matrix matProjection = projection ; // Projection matrix (perspective)
2016-07-04 02:29:23 +03:00
2016-05-18 14:22:14 +03:00
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply ( transform , matView ) ; // Transform to camera-space coordinates
2016-05-20 18:18:07 +03:00
// Check if using standard shader to get location points
// NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations)
2016-05-21 19:22:15 +03:00
if ( material . shader . id = = standardShader . id )
2016-05-20 18:18:07 +03:00
{
2016-06-10 01:49:51 +03:00
// Transpose and inverse model transformations matrix for fragment normal calculations
Matrix transInvTransform = transform ;
MatrixTranspose ( & transInvTransform ) ;
MatrixInvert ( & transInvTransform ) ;
2016-05-20 18:18:07 +03:00
// Send model transformations matrix to shader
2016-06-10 01:49:51 +03:00
glUniformMatrix4fv ( glGetUniformLocation ( material . shader . id , " modelMatrix " ) , 1 , false , MatrixToFloat ( transInvTransform ) ) ;
2016-05-20 18:18:07 +03:00
2016-05-21 19:16:39 +03:00
// Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position)
glUniform3f ( glGetUniformLocation ( material . shader . id , " viewDir " ) , matView . m8 , matView . m9 , matView . m10 ) ;
2016-05-20 18:18:07 +03:00
// Setup shader uniforms for lights
SetShaderLights ( material . shader ) ;
// Upload to shader material.colAmbient
glUniform4f ( glGetUniformLocation ( material . shader . id , " colAmbient " ) , ( float ) material . colAmbient . r / 255 , ( float ) material . colAmbient . g / 255 , ( float ) material . colAmbient . b / 255 , ( float ) material . colAmbient . a / 255 ) ;
// Upload to shader material.colSpecular
glUniform4f ( glGetUniformLocation ( material . shader . id , " colSpecular " ) , ( float ) material . colSpecular . r / 255 , ( float ) material . colSpecular . g / 255 , ( float ) material . colSpecular . b / 255 , ( float ) material . colSpecular . a / 255 ) ;
2016-05-20 13:28:07 +03:00
2016-05-21 19:16:39 +03:00
// Upload to shader glossiness
glUniform1f ( glGetUniformLocation ( material . shader . id , " glossiness " ) , material . glossiness ) ;
2016-05-20 18:18:07 +03:00
}
2016-07-04 19:34:28 +03:00
2016-05-18 14:22:14 +03:00
// Set shader textures (diffuse, normal, specular)
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , material . texDiffuse . id ) ;
2016-05-25 17:19:57 +03:00
glUniform1i ( material . shader . mapTexture0Loc , 0 ) ; // Diffuse texture fits in active texture unit 0
2016-07-04 19:34:28 +03:00
2016-05-25 17:19:57 +03:00
if ( ( material . texNormal . id ! = 0 ) & & ( material . shader . mapTexture1Loc ! = - 1 ) )
2016-05-18 14:22:14 +03:00
{
2016-05-30 20:18:55 +03:00
// Upload to shader specular map flag
glUniform1i ( glGetUniformLocation ( material . shader . id , " useNormal " ) , 1 ) ;
2016-05-18 14:22:14 +03:00
glActiveTexture ( GL_TEXTURE1 ) ;
glBindTexture ( GL_TEXTURE_2D , material . texNormal . id ) ;
2016-05-25 17:19:57 +03:00
glUniform1i ( material . shader . mapTexture1Loc , 1 ) ; // Normal texture fits in active texture unit 1
2016-05-18 14:22:14 +03:00
}
2016-05-25 17:19:57 +03:00
if ( ( material . texSpecular . id ! = 0 ) & & ( material . shader . mapTexture2Loc ! = - 1 ) )
2016-05-18 14:22:14 +03:00
{
2016-05-30 20:18:55 +03:00
// Upload to shader specular map flag
glUniform1i ( glGetUniformLocation ( material . shader . id , " useSpecular " ) , 1 ) ;
2016-05-18 14:22:14 +03:00
glActiveTexture ( GL_TEXTURE2 ) ;
glBindTexture ( GL_TEXTURE_2D , material . texSpecular . id ) ;
2016-05-25 17:19:57 +03:00
glUniform1i ( material . shader . mapTexture2Loc , 2 ) ; // Specular texture fits in active texture unit 2
2016-05-18 14:22:14 +03:00
}
2016-07-04 19:34:28 +03:00
2016-05-18 14:22:14 +03:00
if ( vaoSupported )
{
glBindVertexArray ( mesh . vaoId ) ;
}
else
{
// Bind mesh VBO data: vertex position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 0 ] ) ;
glVertexAttribPointer ( material . shader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . vertexLoc ) ;
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 1 ] ) ;
glVertexAttribPointer ( material . shader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . texcoordLoc ) ;
// Bind mesh VBO data: vertex normals (shader-location = 2, if available)
if ( material . shader . normalLoc ! = - 1 )
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 2 ] ) ;
glVertexAttribPointer ( material . shader . normalLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . normalLoc ) ;
}
2016-07-04 19:34:28 +03:00
// Bind mesh VBO data: vertex colors (shader-location = 3, if available)
2016-05-18 14:22:14 +03:00
if ( material . shader . colorLoc ! = - 1 )
{
2016-07-04 19:34:28 +03:00
if ( mesh . vboId [ 3 ] ! = 0 )
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 3 ] ) ;
glVertexAttribPointer ( material . shader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . colorLoc ) ;
}
else
{
// Set default value for unused attribute
// NOTE: Required when using default shader and no VAO support
glVertexAttrib4f ( material . shader . colorLoc , 1.0f , 1.0f , 1.0f , 1.0f ) ;
glDisableVertexAttribArray ( material . shader . colorLoc ) ;
}
2016-05-18 14:22:14 +03:00
}
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if ( material . shader . tangentLoc ! = - 1 )
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 4 ] ) ;
glVertexAttribPointer ( material . shader . tangentLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . tangentLoc ) ;
}
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if ( material . shader . texcoord2Loc ! = - 1 )
{
glBindBuffer ( GL_ARRAY_BUFFER , mesh . vboId [ 5 ] ) ;
glVertexAttribPointer ( material . shader . texcoord2Loc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( material . shader . texcoord2Loc ) ;
}
if ( mesh . indices ! = NULL ) glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quads . vboId [ 3 ] ) ;
}
2016-07-04 02:29:23 +03:00
for ( int eye = 0 ; eye < eyesCount ; eye + + )
{
2016-07-06 01:54:38 +03:00
if ( eyesCount = = 2 ) SetStereoView ( eye , matProjection , matModelView ) ;
2016-07-04 19:34:28 +03:00
else modelview = matModelView ;
2016-07-04 02:29:23 +03: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
glUniformMatrix4fv ( material . shader . mvpLoc , 1 , false , MatrixToFloat ( matMVP ) ) ;
// 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 ) ;
}
2016-05-18 14:22:14 +03:00
if ( material . texNormal . id ! = 0 )
{
glActiveTexture ( GL_TEXTURE1 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
if ( material . texSpecular . id ! = 0 )
{
glActiveTexture ( GL_TEXTURE2 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
glActiveTexture ( GL_TEXTURE0 ) ; // Set shader active texture to default 0
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind textures
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
else
{
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ; // Unbind VBOs
if ( mesh . indices ! = NULL ) glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
glUseProgram ( 0 ) ; // Unbind shader program
2016-07-04 02:29:23 +03:00
// Restore projection/modelview matrices
projection = matProjection ;
modelview = matView ;
2016-05-18 14:22:14 +03:00
# endif
}
// Unload mesh data from CPU and GPU
void rlglUnloadMesh ( Mesh * mesh )
{
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 19:20:16 +03:00
// Read screen pixel data (color buffer)
unsigned char * rlglReadScreenPixels ( int width , int height )
{
2015-08-29 18:01:36 +03:00
unsigned char * screenData = ( unsigned char * ) malloc ( width * height * sizeof ( unsigned char ) * 4 ) ;
2015-07-13 19:20:16 +03: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 18:01:36 +03:00
unsigned char * imgData = ( unsigned char * ) malloc ( width * height * sizeof ( unsigned char ) * 4 ) ;
2015-07-13 19:20:16 +03:00
2015-11-05 11:46:18 +03:00
for ( int y = height - 1 ; y > = 0 ; y - - )
2015-07-13 19:20:16 +03:00
{
for ( int x = 0 ; x < ( width * 4 ) ; x + + )
{
2015-11-05 11:46:18 +03:00
// Flip line
imgData [ ( ( height - 1 ) - y ) * width * 4 + x ] = screenData [ ( y * width * 4 ) + x ] ;
// 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 19:20:16 +03:00
}
}
free ( screenData ) ;
return imgData ; // NOTE: image data should be freed
}
// Read texture pixel data
2015-11-05 14:32:47 +03: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.
void * rlglReadTexturePixels ( Texture2D texture )
2015-07-13 19:20:16 +03:00
{
2015-07-18 20:25:15 +03:00
void * pixels = NULL ;
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
2015-11-05 14:32:47 +03:00
glBindTexture ( GL_TEXTURE_2D , texture . id ) ;
2015-08-07 18:24:28 +03:00
2015-11-05 14:32:47 +03: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 19:20:16 +03:00
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & width ) ;
glGetTexLevelParameteriv ( GL_TEXTURE_2D , 0 , GL_TEXTURE_HEIGHT , & height ) ;
2015-11-05 14:32:47 +03: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
*/
2015-07-13 19:20:16 +03:00
int glFormat = 0 , glType = 0 ;
2015-07-18 20:25:15 +03:00
2015-11-05 14:32:47 +03:00
unsigned int size = texture . width * texture . height ;
2015-10-06 18:25:27 +03:00
// NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1
2015-11-05 14:32:47 +03:00
// Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3
2015-07-13 19:20:16 +03:00
2015-11-09 15:13:26 +03:00
switch ( texture . format )
2015-07-13 19:20:16 +03:00
{
2015-10-06 18:25:27 +03:00
# if defined(GRAPHICS_API_OPENGL_11)
2015-07-13 19:20:16 +03:00
case UNCOMPRESSED_GRAYSCALE : pixels = ( unsigned char * ) malloc ( size ) ; glFormat = GL_LUMINANCE ; glType = GL_UNSIGNED_BYTE ; break ; // 8 bit per pixel (no alpha)
case UNCOMPRESSED_GRAY_ALPHA : pixels = ( unsigned char * ) malloc ( size * 2 ) ; glFormat = GL_LUMINANCE_ALPHA ; glType = GL_UNSIGNED_BYTE ; break ; // 16 bpp (2 channels)
2015-10-06 18:25:27 +03:00
# elif defined(GRAPHICS_API_OPENGL_33)
2015-11-05 14:32:47 +03:00
case UNCOMPRESSED_GRAYSCALE : pixels = ( unsigned char * ) malloc ( size ) ; glFormat = GL_RED ; glType = GL_UNSIGNED_BYTE ; break ;
case UNCOMPRESSED_GRAY_ALPHA : pixels = ( unsigned char * ) malloc ( size * 2 ) ; glFormat = GL_RG ; glType = GL_UNSIGNED_BYTE ; break ;
2015-10-06 18:25:27 +03:00
# endif
2015-07-13 19:20:16 +03:00
case UNCOMPRESSED_R5G6B5 : pixels = ( unsigned short * ) malloc ( size ) ; glFormat = GL_RGB ; glType = GL_UNSIGNED_SHORT_5_6_5 ; break ; // 16 bpp
case UNCOMPRESSED_R8G8B8 : pixels = ( unsigned char * ) malloc ( size * 3 ) ; glFormat = GL_RGB ; glType = GL_UNSIGNED_BYTE ; break ; // 24 bpp
case UNCOMPRESSED_R5G5B5A1 : pixels = ( unsigned short * ) malloc ( size ) ; glFormat = GL_RGBA ; glType = GL_UNSIGNED_SHORT_5_5_5_1 ; break ; // 16 bpp (1 bit alpha)
case UNCOMPRESSED_R4G4B4A4 : pixels = ( unsigned short * ) malloc ( size ) ; glFormat = GL_RGBA ; glType = GL_UNSIGNED_SHORT_4_4_4_4 ; break ; // 16 bpp (4 bit alpha)
case UNCOMPRESSED_R8G8B8A8 : pixels = ( unsigned char * ) malloc ( size * 4 ) ; glFormat = GL_RGBA ; glType = GL_UNSIGNED_BYTE ; break ; // 32 bpp
2015-11-05 14:32:47 +03:00
default : TraceLog ( WARNING , " Texture data retrieval, format not suported " ) ; break ;
2015-07-13 19:20:16 +03: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.
// 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.)
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2015-08-07 18:24:28 +03:00
2015-07-13 19:20:16 +03:00
glGetTexImage ( GL_TEXTURE_2D , 0 , glFormat , glType , pixels ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-07-18 20:25:15 +03:00
# endif
2015-10-06 18:25:27 +03:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2016-04-17 12:25:04 +03:00
RenderTexture2D fbo = rlglLoadRenderTexture ( texture . width , texture . height ) ;
2015-11-04 20:33:46 +03: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()
2015-11-05 14:32:47 +03:00
# define GET_TEXTURE_FBO_OPTION_1 // It works
2015-11-04 20:33:46 +03:00
# if defined(GET_TEXTURE_FBO_OPTION_1)
glBindFramebuffer ( GL_FRAMEBUFFER , fbo . id ) ;
2015-11-05 14:32:47 +03:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-11-04 20:33:46 +03:00
2015-11-05 14:32:47 +03:00
// Attach our texture to FBO -> Texture must be RGB
// NOTE: Previoust attached texture is automatically detached
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texture . id , 0 ) ;
2015-11-04 20:33:46 +03:00
2015-11-05 14:32:47 +03:00
pixels = ( unsigned char * ) malloc ( texture . width * texture . height * 4 * sizeof ( unsigned char ) ) ;
2015-10-06 18:25:27 +03:00
2015-11-05 14:32:47 +03:00
// NOTE: Despite FBO color texture is RGB, we read data as RGBA... reading as RGB doesn't work... o__O
glReadPixels ( 0 , 0 , texture . width , texture . height , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
// Re-attach internal FBO color texture before deleting it
2016-04-17 12:25:04 +03:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , fbo . texture . id , 0 ) ;
2015-11-04 20:33:46 +03:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
# elif defined(GET_TEXTURE_FBO_OPTION_2)
2015-10-06 18:25:27 +03:00
// Render texture to fbo
glBindFramebuffer ( GL_FRAMEBUFFER , fbo . id ) ;
2015-11-05 14:32:47 +03:00
2016-01-13 21:30:35 +03:00
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
2015-10-06 18:25:27 +03:00
glClearDepthf ( 1.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glViewport ( 0 , 0 , width , height ) ;
//glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
rlOrtho ( 0.0 , width , height , 0.0 , 0.0 , 1.0 ) ;
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
//glDisable(GL_TEXTURE_2D);
//glDisable(GL_BLEND);
glEnable ( GL_DEPTH_TEST ) ;
2015-11-04 20:33:46 +03:00
Model quad ;
//quad.mesh = GenMeshQuad(width, height);
quad . transform = MatrixIdentity ( ) ;
2016-04-03 21:14:07 +03:00
quad . shader = defaultShader ;
2015-11-04 20:33:46 +03:00
2016-01-13 21:30:35 +03:00
DrawModel ( quad , ( Vector3 ) { 0.0f , 0.0f , 0.0f } , 1.0f , WHITE ) ;
2015-10-06 18:25:27 +03:00
2015-11-05 14:32:47 +03:00
pixels = ( unsigned char * ) malloc ( texture . width * texture . height * 3 * sizeof ( unsigned char ) ) ;
2015-10-06 18:25:27 +03:00
2015-11-05 14:32:47 +03:00
glReadPixels ( 0 , 0 , texture . width , texture . height , GL_RGB , GL_UNSIGNED_BYTE , pixels ) ;
2015-10-06 18:25:27 +03:00
// Bind framebuffer 0, which means render to back buffer
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2015-11-05 14:32:47 +03:00
UnloadModel ( quad ) ;
2015-11-04 20:33:46 +03:00
# endif // GET_TEXTURE_FBO_OPTION
2015-10-06 18:25:27 +03:00
// Clean up temporal fbo
2016-04-17 12:25:04 +03:00
rlDeleteRenderTextures ( fbo ) ;
2015-10-06 18:25:27 +03:00
# endif
2015-07-13 19:20:16 +03:00
return pixels ;
}
2016-06-12 20:40:08 +03:00
/*
// TODO: Record draw calls to be processed in batch
// NOTE: Global state must be kept
void rlglRecordDraw ( void )
{
// TODO: Before adding a new draw, check if anything changed from last stored draw
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
draws [ drawsCounter ] . 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 ;
drawsCounter + + ;
# endif
}
*/
2015-07-13 19:20:16 +03:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Shaders Functions
// NOTE: Those functions are exposed directly to the user in raylib.h
//----------------------------------------------------------------------------------
2016-05-07 19:28:40 +03:00
// Get default internal texture (white texture)
Texture2D GetDefaultTexture ( void )
{
Texture2D texture ;
texture . id = whiteTexture ;
texture . width = 1 ;
texture . height = 1 ;
texture . mipmaps = 1 ;
texture . format = UNCOMPRESSED_R8G8B8A8 ;
return texture ;
}
2015-07-13 19:20:16 +03:00
// Load a custom shader and bind default locations
Shader LoadShader ( char * vsFileName , char * fsFileName )
{
2016-04-03 19:31:42 +03:00
Shader shader = { 0 } ;
2014-04-09 22:25:26 +04:00
2015-03-01 18:00:52 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-07-13 19:20:16 +03:00
// Shaders loading from external text file
2016-05-03 20:20:25 +03:00
char * vShaderStr = ReadTextFile ( vsFileName ) ;
char * fShaderStr = ReadTextFile ( fsFileName ) ;
2015-07-13 19:20:16 +03:00
2015-08-03 18:27:53 +03:00
if ( ( vShaderStr ! = NULL ) & & ( fShaderStr ! = NULL ) )
{
shader . id = LoadShaderProgram ( vShaderStr , fShaderStr ) ;
2016-04-03 21:14:07 +03:00
// After shader loading, we try to load default location names
if ( shader . id ! = 0 ) LoadDefaultShaderLocations ( & shader ) ;
2015-08-03 18:27:53 +03:00
// Shader strings must be freed
free ( vShaderStr ) ;
free ( fShaderStr ) ;
}
2016-05-02 01:16:32 +03:00
if ( shader . id = = 0 )
2015-08-03 18:27:53 +03:00
{
TraceLog ( WARNING , " Custom shader could not be loaded " ) ;
2016-04-03 21:14:07 +03:00
shader = defaultShader ;
2015-08-03 18:27:53 +03:00
}
2015-07-13 19:20:16 +03:00
# endif
return shader ;
}
// Unload a custom shader from memory
void UnloadShader ( Shader shader )
2014-03-25 15:40:35 +04:00
{
2015-09-02 00:15:26 +03:00
if ( shader . id ! = 0 )
{
rlDeleteShader ( shader . id ) ;
TraceLog ( INFO , " [SHDR ID %i] Unloaded shader program data " , shader . id ) ;
}
2015-07-13 19:20:16 +03:00
}
2014-03-25 15:40:35 +04:00
2016-06-02 21:23:09 +03:00
// Begin custom shader mode
2016-05-31 18:11:02 +03:00
void BeginShaderMode ( Shader shader )
2015-07-13 19:20:16 +03:00
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ( currentShader . id ! = shader . id )
{
rlglDraw ( ) ;
currentShader = shader ;
}
# endif
2014-03-25 15:40:35 +04:00
}
2016-06-02 21:23:09 +03:00
// End custom shader mode (returns to default shader)
2016-05-31 18:11:02 +03:00
void EndShaderMode ( void )
2015-02-02 02:57:08 +03:00
{
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-31 18:11:02 +03:00
BeginShaderMode ( defaultShader ) ;
2015-04-06 15:02:29 +03:00
# endif
2015-02-02 02:57:08 +03:00
}
2016-05-07 19:07:15 +03:00
// Get default shader
Shader GetDefaultShader ( void )
2015-02-02 02:57:08 +03:00
{
2016-05-07 19:28:40 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-05-07 19:07:15 +03:00
return defaultShader ;
2016-05-07 19:28:40 +03:00
# else
Shader shader = { 0 } ;
return shader ;
# endif
2015-02-02 02:57:08 +03:00
}
2016-05-20 18:18:07 +03:00
// Get default shader
2016-06-07 01:32:45 +03:00
// NOTE: Inits global variable standardShader
2016-05-20 18:18:07 +03:00
Shader GetStandardShader ( void )
{
Shader shader = { 0 } ;
2016-06-24 20:37:52 +03:00
2016-06-07 01:32:45 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ( standardShaderLoaded ) shader = standardShader ;
else
{
// Lazy initialization of standard shader
standardShader = LoadStandardShader ( ) ;
shader = standardShader ;
}
2016-05-20 18:18:07 +03:00
# endif
2016-06-07 01:32:45 +03:00
return shader ;
2016-05-20 18:18:07 +03:00
}
2015-07-13 19:20:16 +03:00
// Get shader uniform location
2015-05-21 15:13:51 +03:00
int GetShaderLocation ( Shader shader , const char * uniformName )
{
2015-07-05 19:21:01 +03:00
int location = - 1 ;
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
location = glGetUniformLocation ( shader . id , uniformName ) ;
2015-05-21 15:13:51 +03:00
2016-06-24 20:37:52 +03:00
if ( location = = - 1 ) TraceLog ( DEBUG , " [SHDR ID %i] Shader location for %s could not be found " , shader . id , uniformName ) ;
2015-07-05 19:21:01 +03:00
# endif
2015-05-21 15:13:51 +03:00
return location ;
}
2015-07-13 19:20:16 +03:00
// Set shader uniform value (float)
2015-05-21 15:13:51 +03:00
void SetShaderValue ( Shader shader , int uniformLoc , float * value , int size )
{
2015-07-05 19:21:01 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-05-21 15:13:51 +03: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
2015-07-13 19:20:16 +03:00
else TraceLog ( WARNING , " Shader value float array size not supported " ) ;
2015-05-21 15:13:51 +03:00
glUseProgram ( 0 ) ;
2015-07-05 19:21:01 +03:00
# endif
2015-05-21 15:13:51 +03:00
}
2015-07-13 19:20:16 +03:00
// Set shader uniform value (int)
void SetShaderValuei ( Shader shader , int uniformLoc , int * value , int size )
{
# 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 ( WARNING , " Shader value int array size not supported " ) ;
glUseProgram ( 0 ) ;
# endif
}
2016-01-25 15:54:09 +03:00
// 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
}
2016-06-02 21:23:09 +03:00
// Set a custom projection matrix (replaces internal projection matrix)
void SetMatrixProjection ( Matrix proj )
{
2016-06-06 00:51:41 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-06-02 21:23:09 +03:00
projection = proj ;
2016-06-06 00:51:41 +03:00
# endif
2016-06-02 21:23:09 +03:00
}
// Set a custom modelview matrix (replaces internal modelview matrix)
void SetMatrixModelview ( Matrix view )
{
2016-06-06 00:51:41 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-06-02 21:23:09 +03:00
modelview = view ;
2016-06-06 00:51:41 +03:00
# endif
2016-06-02 21:23:09 +03:00
}
2016-05-31 18:11:02 +03: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 18:24:28 +03:00
{
if ( ( blendMode ! = mode ) & & ( mode < 3 ) )
{
rlglDraw ( ) ;
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 ;
}
blendMode = mode ;
}
}
2016-05-31 18:11:02 +03:00
// End blending mode (reset to default: alpha blending)
void EndBlendMode ( void )
{
BeginBlendMode ( BLEND_ALPHA ) ;
}
2016-05-20 13:28:07 +03:00
// Create a new light, initialize it and add to pool
Light CreateLight ( int type , Vector3 position , Color diffuse )
{
2016-06-01 13:37:51 +03:00
Light light = NULL ;
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-07-06 21:33:46 +03:00
if ( lightsCount < MAX_LIGHTS )
{
// Allocate dynamic memory
light = ( Light ) malloc ( sizeof ( LightData ) ) ;
// Initialize light values with generic values
light - > id = lightsCount ;
light - > type = type ;
light - > enabled = true ;
light - > position = position ;
light - > target = ( Vector3 ) { 0.0f , 0.0f , 0.0f } ;
light - > intensity = 1.0f ;
light - > diffuse = diffuse ;
// Add new light to the array
lights [ lightsCount ] = light ;
// Increase enabled lights count
lightsCount + + ;
}
else TraceLog ( WARNING , " Too many lights, only supported up to %i lights " , MAX_LIGHTS ) ;
2016-06-01 13:37:51 +03:00
# else
// TODO: Support OpenGL 1.1 lighting system
TraceLog ( WARNING , " Lighting currently not supported on OpenGL 1.1 " ) ;
# endif
2016-05-20 13:28:07 +03:00
return light ;
}
// Destroy a light and take it out of the list
void DestroyLight ( Light light )
{
2016-06-01 13:37:51 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2016-07-06 21:33:46 +03:00
if ( light ! = NULL )
2016-05-20 13:28:07 +03:00
{
2016-07-06 21:33:46 +03:00
// Free dynamic memory allocation
free ( lights [ light - > id ] ) ;
// Remove *obj from the pointers array
for ( int i = light - > id ; i < lightsCount ; i + + )
2016-05-20 13:28:07 +03:00
{
2016-07-06 21:33:46 +03:00
// Resort all the following pointers of the array
if ( ( i + 1 ) < lightsCount )
{
lights [ i ] = lights [ i + 1 ] ;
lights [ i ] - > id = lights [ i + 1 ] - > id ;
}
else free ( lights [ i ] ) ;
2016-05-20 13:28:07 +03:00
}
2016-07-06 21:33:46 +03:00
// Decrease enabled physic objects count
lightsCount - - ;
2016-05-20 13:28:07 +03:00
}
2016-06-01 13:37:51 +03:00
# endif
2016-05-20 13:28:07 +03:00
}
2016-07-06 01:54:38 +03:00
// Init VR device (or simulator)
// NOTE: If device is not available, it fallbacks to default device (simulator)
void InitVrDevice ( int hmdDevice )
2016-06-14 18:16:20 +03:00
{
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-14 18:16:20 +03:00
// Initialize Oculus device
ovrResult result = ovr_Initialize ( NULL ) ;
if ( OVR_FAILURE ( result ) )
{
2016-06-19 20:12:47 +03:00
TraceLog ( WARNING , " OVR: Could not initialize Oculus device " ) ;
2016-06-26 16:36:12 +03:00
oculusReady = false ;
2016-06-19 20:12:47 +03:00
}
else
{
result = ovr_Create ( & session , & luid ) ;
if ( OVR_FAILURE ( result ) )
{
TraceLog ( WARNING , " OVR: Could not create Oculus session " ) ;
ovr_Shutdown ( ) ;
2016-06-26 16:36:12 +03:00
oculusReady = false ;
2016-06-19 20:12:47 +03:00
}
else
{
hmdDesc = ovr_GetHmdDesc ( session ) ;
2016-07-08 01:57:27 +03:00
2016-06-19 20:12:47 +03:00
TraceLog ( INFO , " OVR: Product Name: %s " , hmdDesc . ProductName ) ;
TraceLog ( INFO , " OVR: Manufacturer: %s " , hmdDesc . Manufacturer ) ;
TraceLog ( INFO , " OVR: Product ID: %i " , hmdDesc . ProductId ) ;
TraceLog ( INFO , " OVR: Product Type: %i " , hmdDesc . Type ) ;
//TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber);
TraceLog ( INFO , " OVR: Resolution: %ix%i " , hmdDesc . Resolution . w , hmdDesc . Resolution . h ) ;
// NOTE: Oculus mirror is set to defined screenWidth and screenHeight...
// ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2)
// Initialize Oculus Buffers
layer = InitOculusLayer ( session ) ;
buffer = LoadOculusBuffer ( session , layer . width , layer . height ) ;
mirror = LoadOculusMirror ( session , hmdDesc . Resolution . w / 2 , hmdDesc . Resolution . h / 2 ) ; // NOTE: hardcoded...
layer . eyeLayer . ColorTexture [ 0 ] = buffer . textureChain ; //SetOculusLayerTexture(eyeLayer, buffer.textureChain);
// Recenter OVR tracking origin
ovr_RecenterTrackingOrigin ( session ) ;
2016-06-21 14:49:13 +03:00
2016-06-26 16:36:12 +03:00
oculusReady = true ;
vrEnabled = true ;
2016-06-19 20:12:47 +03:00
}
2016-06-14 18:16:20 +03:00
}
2016-06-19 20:12:47 +03:00
# else
2016-06-26 16:36:12 +03:00
oculusReady = false ;
2016-06-19 20:12:47 +03:00
# endif
2016-06-14 18:16:20 +03:00
2016-06-26 16:36:12 +03:00
if ( ! oculusReady )
2016-06-19 20:12:47 +03:00
{
2016-07-06 01:54:38 +03:00
TraceLog ( WARNING , " HMD Device not found: Initializing VR simulator " ) ;
2016-06-26 15:13:11 +03:00
2016-06-21 14:49:13 +03:00
// Initialize framebuffer and textures for stereo rendering
stereoFbo = rlglLoadRenderTexture ( screenWidth , screenHeight ) ;
// Load oculus-distortion shader (oculus parameters setup internally)
// TODO: Embed coulus distortion shader (in this function like default shader?)
2016-07-04 02:29:23 +03:00
distortionShader = LoadShader ( " resources/shaders/glsl330/base.vs " , " resources/shaders/glsl330/distortion.fs " ) ;
2016-06-21 14:49:13 +03:00
oculusSimulator = true ;
2016-06-26 16:36:12 +03:00
vrEnabled = true ;
2016-06-19 20:12:47 +03:00
}
2016-06-14 18:16:20 +03:00
}
2016-07-06 01:54:38 +03:00
// Close VR device (or simulator)
void CloseVrDevice ( void )
2016-06-14 18:16:20 +03:00
{
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-26 16:36:12 +03:00
if ( oculusReady )
2016-06-21 14:49:13 +03:00
{
UnloadOculusMirror ( session , mirror ) ; // Unload Oculus mirror buffer
UnloadOculusBuffer ( session , buffer ) ; // Unload Oculus texture buffers
2016-06-14 18:16:20 +03:00
2016-06-21 14:49:13 +03:00
ovr_Destroy ( session ) ; // Free Oculus session data
ovr_Shutdown ( ) ; // Close Oculus device connection
}
else
2016-06-19 20:12:47 +03:00
# endif
{
2016-06-21 14:49:13 +03:00
// Unload stereo framebuffer and texture
rlDeleteRenderTextures ( stereoFbo ) ;
// Unload oculus-distortion shader
2016-07-04 02:29:23 +03:00
UnloadShader ( distortionShader ) ;
2016-06-19 20:12:47 +03:00
}
2016-06-21 09:59:29 +03:00
2016-06-26 16:36:12 +03:00
oculusReady = false ;
2016-06-21 09:59:29 +03:00
}
2016-07-06 01:54:38 +03:00
// Detect if VR device is available
bool IsVrDeviceReady ( void )
2016-06-21 09:59:29 +03:00
{
2016-06-26 16:36:12 +03:00
return ( oculusReady | | oculusSimulator ) & & vrEnabled ;
}
2016-07-06 01:54:38 +03:00
// Enable/Disable VR experience (device or simulator)
void ToggleVrMode ( void )
2016-06-26 16:36:12 +03:00
{
vrEnabled = ! vrEnabled ;
2016-06-14 18:16:20 +03:00
}
2016-07-06 01:54:38 +03:00
// Update VR tracking (position and orientation)
void UpdateVrTracking ( void )
2016-06-14 18:16:20 +03:00
{
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-26 16:36:12 +03:00
if ( oculusReady )
2016-06-21 14:49:13 +03:00
{
frameIndex + + ;
2016-06-14 18:16:20 +03:00
2016-06-21 14:49:13 +03:00
ovrPosef eyePoses [ 2 ] ;
ovr_GetEyePoses ( session , frameIndex , ovrTrue , layer . viewScaleDesc . HmdToEyeOffset , eyePoses , & layer . eyeLayer . SensorSampleTime ) ;
layer . eyeLayer . RenderPose [ 0 ] = eyePoses [ 0 ] ;
layer . eyeLayer . RenderPose [ 1 ] = eyePoses [ 1 ] ;
// Get session status information
ovrSessionStatus sessionStatus ;
ovr_GetSessionStatus ( session , & sessionStatus ) ;
if ( sessionStatus . ShouldQuit ) TraceLog ( WARNING , " OVR: Session should quit... " ) ;
if ( sessionStatus . ShouldRecenter ) ovr_RecenterTrackingOrigin ( session ) ;
//if (sessionStatus.HmdPresent) // HMD is present.
//if (sessionStatus.DisplayLost) // HMD was unplugged or the display driver was manually disabled or encountered a TDR.
//if (sessionStatus.HmdMounted) // HMD is on the user's head.
//if (sessionStatus.IsVisible) // the game or experience has VR focus and is visible in the HMD.
}
else
2016-06-19 20:12:47 +03:00
# endif
{
// TODO: Use alternative inputs (mouse, keyboard) to simulate tracking data (eyes position/orientation)
}
2016-06-14 18:16:20 +03:00
}
2016-06-19 20:12:47 +03:00
// Set internal projection and modelview matrix depending on eyes tracking data
2016-07-06 01:54:38 +03:00
static void SetStereoView ( int eye , Matrix matProjection , Matrix matModelView )
2016-07-04 02:29:23 +03:00
{
2016-06-26 16:36:12 +03:00
if ( vrEnabled )
2016-06-21 14:49:13 +03:00
{
2016-07-04 02:29:23 +03:00
Matrix eyeProjection = matProjection ;
Matrix eyeModelView = matModelView ;
2016-06-26 16:36:12 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
if ( oculusReady )
{
rlViewport ( layer . eyeLayer . Viewport [ eye ] . Pos . x , layer . eyeLayer . Viewport [ eye ] . Pos . y ,
layer . eyeLayer . Viewport [ eye ] . Size . w , layer . eyeLayer . Viewport [ eye ] . Size . h ) ;
Quaternion eyeRenderPose = ( Quaternion ) { layer . eyeLayer . RenderPose [ eye ] . Orientation . x ,
layer . eyeLayer . RenderPose [ eye ] . Orientation . y ,
layer . eyeLayer . RenderPose [ eye ] . Orientation . z ,
layer . eyeLayer . RenderPose [ eye ] . Orientation . w } ;
QuaternionInvert ( & eyeRenderPose ) ;
Matrix eyeOrientation = QuaternionToMatrix ( eyeRenderPose ) ;
Matrix eyeTranslation = MatrixTranslate ( - layer . eyeLayer . RenderPose [ eye ] . Position . x ,
- layer . eyeLayer . RenderPose [ eye ] . Position . y ,
- layer . eyeLayer . RenderPose [ eye ] . Position . z ) ;
Matrix eyeView = MatrixMultiply ( eyeTranslation , eyeOrientation ) ; // Matrix containing eye-head movement
2016-07-04 02:29:23 +03:00
eyeModelView = MatrixMultiply ( matModelView , eyeView ) ; // Combine internal camera matrix (modelview) wih eye-head movement
2016-06-26 16:36:12 +03:00
eyeProjection = layer . eyeProjections [ eye ] ;
}
else
2016-06-19 20:12:47 +03:00
# endif
2016-06-26 16:36:12 +03:00
{
// Setup viewport and projection/modelview matrices using tracking data
rlViewport ( eye * screenWidth / 2 , 0 , screenWidth / 2 , screenHeight ) ;
2016-07-06 01:54:38 +03:00
static float IPD = 0.064f ; // InterpupillaryDistance
2016-07-04 02:29:23 +03:00
float HScreenSize = 0.14976f ;
2016-07-08 01:57:27 +03:00
float VScreenSize = 0.09356f ; // HScreenSize/(1280.0f/800.0f) (DK2)
2016-07-06 01:54:38 +03:00
float VScreenCenter = 0.04675f ; // VScreenSize/2
2016-07-04 02:29:23 +03:00
float EyeToScreenDistance = 0.041f ;
2016-07-08 01:57:27 +03:00
float LensSeparationDistance = 0.0635f ; //0.0635f (DK2)
2016-06-27 21:10:28 +03:00
2016-07-04 02:29:23 +03:00
// NOTE: fovy value obtained from device parameters (Oculus Rift CV1)
float halfScreenDistance = VScreenSize / 2.0f ;
float fovy = 2.0f * atan ( halfScreenDistance / EyeToScreenDistance ) * RAD2DEG ;
float viewCenter = ( float ) HScreenSize * 0.25f ;
float eyeProjectionShift = viewCenter - LensSeparationDistance * 0.5f ;
2016-07-04 19:34:28 +03:00
float projectionCenterOffset = eyeProjectionShift / ( float ) HScreenSize ; //4.0f*eyeProjectionShift/(float)HScreenSize;
2016-07-04 02:29:23 +03:00
/*
static float scale [ 2 ] = { 0.25 , 0.45 } ;
if ( IsKeyDown ( KEY_RIGHT ) ) scale [ 0 ] + = 0.01 ;
else if ( IsKeyDown ( KEY_LEFT ) ) scale [ 0 ] - = 0.01 ;
else if ( IsKeyDown ( KEY_UP ) ) scale [ 1 ] + = 0.01 ;
else if ( IsKeyDown ( KEY_DOWN ) ) scale [ 1 ] - = 0.01 ;
2016-06-27 21:10:28 +03:00
2016-07-04 02:29:23 +03:00
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " Scale " ) , scale , 2 ) ;
if ( IsKeyDown ( KEY_N ) ) IPD + = 0.02 ;
else if ( IsKeyDown ( KEY_M ) ) IPD - = 0.02 ;
*/
2016-06-27 21:10:28 +03:00
// The matrixes for offsetting the projection and view for each eye, to achieve stereo effect
Vector3 projectionOffset = { - projectionCenterOffset , 0.0f , 0.0f } ;
2016-07-04 02:29:23 +03:00
// 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
// some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions.
Vector3 viewOffset = { - IPD / 2.0f , 0.075f , 0.045f } ;
2016-06-27 21:10:28 +03:00
// Negate the left eye versions
2016-07-04 02:29:23 +03:00
if ( eye = = 0 )
2016-06-27 21:10:28 +03:00
{
projectionOffset . x * = - 1.0f ;
viewOffset . x * = - 1.0f ;
}
// Adjust the view and projection matrixes
// View matrix is translated based on the eye offset
2016-07-04 02:29:23 +03:00
Matrix projCenter = MatrixPerspective ( fovy , ( double ) ( ( float ) screenWidth * 0.5f ) / ( double ) screenHeight , 0.01 , 1000.0 ) ;
2016-06-27 21:10:28 +03:00
Matrix projTranslation = MatrixTranslate ( projectionOffset . x , projectionOffset . y , projectionOffset . z ) ;
Matrix viewTranslation = MatrixTranslate ( viewOffset . x , viewOffset . y , viewOffset . z ) ;
eyeProjection = MatrixMultiply ( projCenter , projTranslation ) ; // projection
2016-07-04 02:29:23 +03:00
eyeModelView = MatrixMultiply ( matModelView , viewTranslation ) ; // modelview
2016-06-27 21:10:28 +03:00
MatrixTranspose ( & eyeProjection ) ;
2016-06-26 16:36:12 +03:00
}
2016-06-19 20:12:47 +03:00
2016-07-06 01:54:38 +03:00
SetMatrixModelview ( eyeModelView ) ;
2016-06-26 16:36:12 +03:00
SetMatrixProjection ( eyeProjection ) ;
}
2016-06-14 18:16:20 +03:00
}
2016-06-19 20:12:47 +03:00
// Begin Oculus drawing configuration
2016-07-06 01:54:38 +03:00
void BeginVrDrawing ( void )
2016-06-14 18:16:20 +03:00
{
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-26 16:36:12 +03:00
if ( oculusReady )
2016-06-21 14:49:13 +03:00
{
GLuint currentTexId ;
int currentIndex ;
ovr_GetTextureSwapChainCurrentIndex ( session , buffer . textureChain , & currentIndex ) ;
ovr_GetTextureSwapChainBufferGL ( session , buffer . textureChain , currentIndex , & currentTexId ) ;
2016-06-14 18:16:20 +03:00
2016-06-21 14:49:13 +03:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , buffer . fboId ) ;
glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , currentTexId , 0 ) ;
//glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded
}
else
2016-06-19 20:12:47 +03:00
# endif
{
2016-06-21 14:49:13 +03:00
// Setup framebuffer for stereo rendering
rlEnableRenderTexture ( stereoFbo . id ) ;
2016-06-19 20:12:47 +03:00
}
2016-06-14 18:16:20 +03: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);
2016-06-14 19:37:28 +03:00
2016-06-15 01:54:55 +03:00
//glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye)
2016-06-14 19:37:28 +03:00
rlClearScreenBuffers ( ) ; // Clear current framebuffer(s)
2016-07-04 02:29:23 +03:00
vrControl = true ;
2016-06-14 18:16:20 +03:00
}
2016-06-19 20:12:47 +03:00
// End Oculus drawing process (and desktop mirror)
2016-07-06 01:54:38 +03:00
void EndVrDrawing ( void )
2016-06-14 18:16:20 +03:00
{
2016-06-19 20:12:47 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-06-26 16:36:12 +03:00
if ( oculusReady )
2016-06-21 14:49:13 +03:00
{
// Unbind current framebuffer (Oculus buffer)
glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , 0 , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
ovr_CommitTextureSwapChain ( session , buffer . textureChain ) ;
ovrLayerHeader * layers = & layer . eyeLayer . Header ;
ovr_SubmitFrame ( session , frameIndex , & layer . viewScaleDesc , & layers , 1 ) ;
2016-06-14 18:16:20 +03:00
2016-06-21 14:49:13 +03:00
// Blit mirror texture to back buffer
BlitOculusMirror ( session , mirror ) ;
}
else
2016-06-19 20:12:47 +03:00
# endif
{
// Unbind current framebuffer
2016-06-21 14:49:13 +03:00
rlDisableRenderTexture ( ) ;
rlClearScreenBuffers ( ) ; // Clear current framebuffer
2016-06-19 20:12:47 +03:00
2016-06-21 14:49:13 +03:00
// Set viewport to default framebuffer size (screen size)
rlViewport ( 0 , 0 , screenWidth , screenHeight ) ;
// 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
// Draw RenderTexture (stereoFbo) using distortion shader
2016-07-04 02:29:23 +03:00
currentShader = distortionShader ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
rlEnableTexture ( stereoFbo . texture . id ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
rlPushMatrix ( ) ;
rlBegin ( RL_QUADS ) ;
rlColor4ub ( 255 , 255 , 255 , 255 ) ;
rlNormal3f ( 0.0f , 0.0f , 1.0f ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
// Bottom-left corner for texture and quad
rlTexCoord2f ( 0.0f , 1.0f ) ;
rlVertex2f ( 0.0f , 0.0f ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
// Bottom-right corner for texture and quad
rlTexCoord2f ( 0.0f , 0.0f ) ;
rlVertex2f ( 0.0f , stereoFbo . texture . height ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
// Top-right corner for texture and quad
rlTexCoord2f ( 1.0f , 0.0f ) ;
rlVertex2f ( stereoFbo . texture . width , stereoFbo . texture . height ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
// Top-left corner for texture and quad
rlTexCoord2f ( 1.0f , 1.0f ) ;
rlVertex2f ( stereoFbo . texture . width , 0.0f ) ;
rlEnd ( ) ;
rlPopMatrix ( ) ;
2016-06-21 14:49:13 +03:00
2016-07-04 02:29:23 +03:00
rlDisableTexture ( ) ;
UpdateDefaultBuffers ( ) ;
DrawDefaultBuffers ( 1 ) ;
currentShader = defaultShader ;
2016-06-19 20:12:47 +03:00
}
2016-06-17 01:29:46 +03:00
rlDisableDepthTest ( ) ;
2016-07-04 02:29:23 +03:00
vrControl = false ;
2016-06-14 18:16:20 +03:00
}
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-04-06 15:02:29 +03:00
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed image data and POT image
static void LoadCompressedTexture ( unsigned char * data , int width , int height , int mipmapCount , int compressedFormat )
{
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
int blockSize = 0 ; // Bytes every block
int offset = 0 ;
if ( ( compressedFormat = = GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) | |
( compressedFormat = = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) | |
# if defined(GRAPHICS_API_OPENGL_ES2)
( compressedFormat = = GL_ETC1_RGB8_OES ) | |
# endif
( compressedFormat = = GL_COMPRESSED_RGB8_ETC2 ) ) blockSize = 8 ;
else blockSize = 16 ;
// Load the mipmap levels
for ( int level = 0 ; level < mipmapCount & & ( width | | height ) ; level + + )
{
unsigned int size = 0 ;
size = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize ;
glCompressedTexImage2D ( GL_TEXTURE_2D , level , compressedFormat , width , height , 0 , size , data + offset ) ;
offset + = size ;
width / = 2 ;
height / = 2 ;
// Security check for NPOT textures
if ( width < 1 ) width = 1 ;
if ( height < 1 ) height = 1 ;
}
}
2014-03-25 15:40:35 +04:00
2016-05-07 19:07:15 +03:00
// Load custom shader strings and return program id
2016-06-08 23:52:54 +03:00
static unsigned int LoadShaderProgram ( const char * vShaderStr , const char * fShaderStr )
2016-05-07 19:07:15 +03:00
{
unsigned int program = 0 ;
2016-05-31 20:12:37 +03:00
2016-05-07 19:07:15 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
GLuint vertexShader ;
GLuint fragmentShader ;
vertexShader = glCreateShader ( GL_VERTEX_SHADER ) ;
fragmentShader = glCreateShader ( GL_FRAGMENT_SHADER ) ;
const char * pvs = vShaderStr ;
const char * pfs = fShaderStr ;
glShaderSource ( vertexShader , 1 , & pvs , NULL ) ;
glShaderSource ( fragmentShader , 1 , & pfs , NULL ) ;
GLint success = 0 ;
glCompileShader ( vertexShader ) ;
glGetShaderiv ( vertexShader , GL_COMPILE_STATUS , & success ) ;
if ( success ! = GL_TRUE )
{
TraceLog ( WARNING , " [VSHDR ID %i] Failed to compile vertex shader... " , vertexShader ) ;
int maxLength = 0 ;
int length ;
glGetShaderiv ( vertexShader , GL_INFO_LOG_LENGTH , & maxLength ) ;
char log [ maxLength ] ;
glGetShaderInfoLog ( vertexShader , maxLength , & length , log ) ;
TraceLog ( INFO , " %s " , log ) ;
}
else TraceLog ( INFO , " [VSHDR ID %i] Vertex shader compiled successfully " , vertexShader ) ;
glCompileShader ( fragmentShader ) ;
glGetShaderiv ( fragmentShader , GL_COMPILE_STATUS , & success ) ;
if ( success ! = GL_TRUE )
{
TraceLog ( WARNING , " [FSHDR ID %i] Failed to compile fragment shader... " , fragmentShader ) ;
int maxLength = 0 ;
int length ;
glGetShaderiv ( fragmentShader , GL_INFO_LOG_LENGTH , & maxLength ) ;
char log [ maxLength ] ;
glGetShaderInfoLog ( fragmentShader , maxLength , & length , log ) ;
TraceLog ( INFO , " %s " , log ) ;
}
else TraceLog ( INFO , " [FSHDR ID %i] Fragment shader compiled successfully " , fragmentShader ) ;
program = glCreateProgram ( ) ;
glAttachShader ( program , vertexShader ) ;
glAttachShader ( program , fragmentShader ) ;
// NOTE: Default attribute shader locations must be binded before linking
2016-05-09 13:41:53 +03: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 ) ;
2016-05-07 19:07:15 +03:00
// NOTE: If some attrib name is no found on the shader, it locations becomes -1
glLinkProgram ( program ) ;
// NOTE: All uniform variables are intitialised to 0 when a program links
glGetProgramiv ( program , GL_LINK_STATUS , & success ) ;
if ( success = = GL_FALSE )
{
TraceLog ( WARNING , " [SHDR ID %i] Failed to link shader program... " , program ) ;
int maxLength = 0 ;
int length ;
glGetProgramiv ( program , GL_INFO_LOG_LENGTH , & maxLength ) ;
char log [ maxLength ] ;
glGetProgramInfoLog ( program , maxLength , & length , log ) ;
TraceLog ( INFO , " %s " , log ) ;
glDeleteProgram ( program ) ;
program = 0 ;
}
else TraceLog ( INFO , " [SHDR ID %i] Shader program loaded successfully " , program ) ;
glDeleteShader ( vertexShader ) ;
glDeleteShader ( fragmentShader ) ;
# endif
return program ;
}
// Load default shader (just vertex positioning and texture coloring)
2016-03-06 04:05:16 +03:00
// NOTE: This shader program is used for batch buffers (lines, triangles, quads)
2015-03-01 18:00:52 +03:00
static Shader LoadDefaultShader ( void )
2014-03-25 15:40:35 +04:00
{
2015-03-01 18:00:52 +03:00
Shader shader ;
2015-04-06 15:02:29 +03:00
2014-03-25 15:40:35 +04:00
// Vertex shader directly defined, no external file required
2016-06-16 21:25:50 +03:00
char vDefaultShaderStr [ ] =
# if defined(GRAPHICS_API_OPENGL_21)
" #version 120 \n "
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-06-16 21:25:50 +03: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
" uniform mat4 mvpMatrix; \n "
" void main() \n "
" { \n "
" fragTexCoord = vertexTexCoord; \n "
" fragColor = vertexColor; \n "
" gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n "
" } \n " ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Fragment shader directly defined, no external file required
2016-06-16 21:25:50 +03:00
char fDefaultShaderStr [ ] =
# if defined(GRAPHICS_API_OPENGL_21)
" #version 120 \n "
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
2016-06-16 21:25:50 +03: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 15:39:27 +03:00
# endif
2016-06-16 21:25:50 +03:00
" } \n " ;
2014-03-25 15:40:35 +04:00
2016-06-16 21:25:50 +03:00
shader . id = LoadShaderProgram ( vDefaultShaderStr , fDefaultShaderStr ) ;
2015-03-01 18:00:52 +03:00
if ( shader . id ! = 0 ) TraceLog ( INFO , " [SHDR ID %i] Default shader loaded successfully " , shader . id ) ;
else TraceLog ( WARNING , " [SHDR ID %i] Default shader could not be loaded " , shader . id ) ;
2015-04-06 15:02:29 +03:00
2016-05-02 01:16:32 +03:00
if ( shader . id ! = 0 ) LoadDefaultShaderLocations ( & shader ) ;
2016-04-03 19:31:42 +03:00
return shader ;
}
2016-05-20 13:28:07 +03:00
// Load standard shader
// NOTE: This shader supports:
2016-06-07 01:32:45 +03:00
// - Up to 3 different maps: diffuse, normal, specular
// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness
// - Up to 8 lights: Point, Directional or Spot
2016-05-20 13:28:07 +03:00
static Shader LoadStandardShader ( void )
{
2016-06-07 01:32:45 +03:00
Shader shader ;
2016-06-24 20:37:52 +03:00
# if !defined(RLGL_NO_STANDARD_SHADER)
2016-06-07 01:32:45 +03:00
// Load standard shader (embeded in standard_shader.h)
shader . id = LoadShaderProgram ( vStandardShaderStr , fStandardShaderStr ) ;
2016-05-20 13:28:07 +03:00
2016-06-07 00:19:40 +03:00
if ( shader . id ! = 0 )
{
LoadDefaultShaderLocations ( & shader ) ;
TraceLog ( INFO , " [SHDR ID %i] Standard shader loaded successfully " , shader . id ) ;
2016-06-07 01:32:45 +03:00
standardShaderLoaded = true ;
2016-06-07 00:19:40 +03:00
}
else
{
TraceLog ( WARNING , " [SHDR ID %i] Standard shader could not be loaded, using default shader " , shader . id ) ;
shader = GetDefaultShader ( ) ;
}
2016-06-24 20:37:52 +03:00
# else
shader = defaultShader ;
TraceLog ( WARNING , " [SHDR ID %i] Standard shader not available, using default shader " , shader . id ) ;
# endif
2016-05-20 13:28:07 +03:00
return shader ;
}
2016-04-03 19:31:42 +03:00
// Get location handlers to for shader attributes and uniforms
2016-04-07 14:31:53 +03:00
// NOTE: If any location is not found, loc point becomes -1
2016-04-03 21:14:07 +03:00
static void LoadDefaultShaderLocations ( Shader * shader )
2016-04-03 19:31:42 +03:00
{
2016-05-07 19:07:15 +03:00
// NOTE: Default shader attrib locations have been fixed before linking:
// vertex position location = 0
// vertex texcoord location = 1
// vertex normal location = 2
// vertex color location = 3
2016-05-09 00:50:35 +03:00
// vertex tangent location = 4
// vertex texcoord2 location = 5
2016-05-07 19:07:15 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL input attibute locations
2016-05-19 14:50:29 +03:00
shader - > vertexLoc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_POSITION_NAME ) ;
shader - > texcoordLoc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TEXCOORD_NAME ) ;
2016-05-25 17:19:57 +03:00
shader - > texcoord2Loc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TEXCOORD2_NAME ) ;
2016-05-19 14:50:29 +03:00
shader - > normalLoc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_NORMAL_NAME ) ;
shader - > tangentLoc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_TANGENT_NAME ) ;
2016-05-25 17:19:57 +03:00
shader - > colorLoc = glGetAttribLocation ( shader - > id , DEFAULT_ATTRIB_COLOR_NAME ) ;
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (vertex shader)
2016-04-03 19:31:42 +03:00
shader - > mvpLoc = glGetUniformLocation ( shader - > id , " mvpMatrix " ) ;
2014-09-03 18:51:28 +04:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (fragment shader)
2016-05-21 19:16:39 +03:00
shader - > tintColorLoc = glGetUniformLocation ( shader - > id , " colDiffuse " ) ;
2016-05-25 17:19:57 +03:00
shader - > mapTexture0Loc = glGetUniformLocation ( shader - > id , " texture0 " ) ;
shader - > mapTexture1Loc = glGetUniformLocation ( shader - > id , " texture1 " ) ;
shader - > mapTexture2Loc = glGetUniformLocation ( shader - > id , " texture2 " ) ;
2014-03-25 15:40:35 +04:00
}
2016-05-03 20:20:25 +03:00
// Unload default shader
static void UnloadDefaultShader ( void )
2014-03-25 15:40:35 +04:00
{
2016-05-03 20:20:25 +03:00
glUseProgram ( 0 ) ;
2015-02-02 02:57:08 +03:00
2016-05-19 14:50:29 +03:00
//glDetachShader(defaultShader, vertexShader);
//glDetachShader(defaultShader, fragmentShader);
2016-05-03 20:20:25 +03:00
//glDeleteShader(vertexShader); // Already deleted on shader compilation
2016-05-20 18:18:07 +03:00
//glDeleteShader(fragmentShader); // Already deleted on shader compilation
2016-05-03 20:20:25 +03:00
glDeleteProgram ( defaultShader . id ) ;
2014-03-25 15:40:35 +04:00
}
2016-05-20 18:18:07 +03:00
// Unload standard shader
static void UnloadStandardShader ( void )
{
glUseProgram ( 0 ) ;
2016-06-24 20:37:52 +03:00
# if !defined(RLGL_NO_STANDARD_SHADER)
2016-05-20 18:18:07 +03:00
//glDetachShader(defaultShader, vertexShader);
//glDetachShader(defaultShader, fragmentShader);
//glDeleteShader(vertexShader); // Already deleted on shader compilation
//glDeleteShader(fragmentShader); // Already deleted on shader compilation
glDeleteProgram ( standardShader . id ) ;
2016-06-24 20:37:52 +03:00
# endif
2016-05-20 18:18:07 +03:00
}
2016-05-03 20:20:25 +03:00
// Load default internal buffers (lines, triangles, quads)
static void LoadDefaultBuffers ( void )
2014-03-25 15:40:35 +04:00
{
2016-05-03 20:20:25 +03:00
// [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
//--------------------------------------------------------------------------------------------
2016-05-07 19:07:15 +03:00
// Lines - Initialize arrays (vertex position and color data)
2014-07-23 02:06:24 +04: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 13:20:23 +03:00
lines . texcoords = NULL ;
lines . indices = NULL ;
2014-03-25 15:40:35 +04:00
2014-09-17 00:51:31 +04:00
for ( int i = 0 ; i < ( 3 * 2 * MAX_LINES_BATCH ) ; i + + ) lines . vertices [ i ] = 0.0f ;
2014-07-23 02:06:24 +04:00
for ( int i = 0 ; i < ( 4 * 2 * MAX_LINES_BATCH ) ; i + + ) lines . colors [ i ] = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
lines . vCounter = 0 ;
lines . cCounter = 0 ;
2016-05-12 13:20:23 +03:00
lines . tcCounter = 0 ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Triangles - Initialize arrays (vertex position and color data)
2014-07-23 02:06:24 +04: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 13:20:23 +03:00
triangles . texcoords = NULL ;
triangles . indices = NULL ;
2014-03-25 15:40:35 +04:00
2014-09-17 00:51:31 +04:00
for ( int i = 0 ; i < ( 3 * 3 * MAX_TRIANGLES_BATCH ) ; i + + ) triangles . vertices [ i ] = 0.0f ;
2014-07-23 02:06:24 +04:00
for ( int i = 0 ; i < ( 4 * 3 * MAX_TRIANGLES_BATCH ) ; i + + ) triangles . colors [ i ] = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
triangles . vCounter = 0 ;
triangles . cCounter = 0 ;
2016-05-12 13:20:23 +03:00
triangles . tcCounter = 0 ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Quads - Initialize arrays (vertex position, texcoord, color data and indexes)
2014-07-23 02:06:24 +04: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-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-07-23 02:06:24 +04:00
quads . indices = ( unsigned int * ) malloc ( sizeof ( int ) * 6 * MAX_QUADS_BATCH ) ; // 6 int by quad (indices)
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
quads . indices = ( unsigned short * ) malloc ( sizeof ( short ) * 6 * MAX_QUADS_BATCH ) ; // 6 int by quad (indices)
# endif
for ( int i = 0 ; i < ( 3 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . vertices [ i ] = 0.0f ;
for ( int i = 0 ; i < ( 2 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . texcoords [ i ] = 0.0f ;
2014-07-23 02:06:24 +04:00
for ( int i = 0 ; i < ( 4 * 4 * MAX_QUADS_BATCH ) ; i + + ) quads . colors [ i ] = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
int k = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
k + + ;
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
quads . vCounter = 0 ;
quads . tcCounter = 0 ;
quads . cCounter = 0 ;
2014-09-17 00:51:31 +04:00
2016-05-07 19:07:15 +03:00
TraceLog ( INFO , " [CPU] Default buffers initialized successfully (lines, triangles, quads) " ) ;
2016-05-03 20:20:25 +03:00
//--------------------------------------------------------------------------------------------
// [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads)
// NOTE: Default buffers are linked to use currentShader (defaultShader)
//--------------------------------------------------------------------------------------------
// Upload and link lines vertex buffers
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Lines VAO
2016-05-12 13:20:23 +03:00
glGenVertexArrays ( 1 , & lines . vaoId ) ;
glBindVertexArray ( lines . vaoId ) ;
2014-09-17 00:51:31 +04:00
}
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Lines - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 2 , & lines . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
2014-03-25 15:40:35 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 2 * MAX_LINES_BATCH , lines . vertices , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Vertex color buffer (shader-location = 3)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 2 , & lines . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
2014-07-23 02:06:24 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 2 * MAX_LINES_BATCH , lines . colors , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Default buffers VAO initialized successfully (lines) " , lines . vaoId ) ;
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines) " , lines.vboId[0], lines.vboId[1]) ;
2014-09-03 18:51:28 +04:00
2016-05-03 20:20:25 +03:00
// Upload and link triangles vertex buffers
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Triangles VAO
2016-05-12 13:20:23 +03:00
glGenVertexArrays ( 1 , & triangles . vaoId ) ;
glBindVertexArray ( triangles . vaoId ) ;
2014-09-17 00:51:31 +04:00
}
2015-02-02 02:57:08 +03:00
2016-05-07 19:07:15 +03:00
// Triangles - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & triangles . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
2014-03-25 15:40:35 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 3 * MAX_TRIANGLES_BATCH , triangles . vertices , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Vertex color buffer (shader-location = 3)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & triangles . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
2014-07-23 02:06:24 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 3 * MAX_TRIANGLES_BATCH , triangles . colors , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Default buffers VAO initialized successfully (triangles) " , triangles . vaoId ) ;
2016-07-04 19:34:28 +03:00
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (triangles) " , triangles.vboId[0], triangles.vboId[1]) ;
2014-09-03 18:51:28 +04:00
2016-05-03 20:20:25 +03:00
// Upload and link quads vertex buffers
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Quads VAO
2016-05-12 13:20:23 +03:00
glGenVertexArrays ( 1 , & quads . vaoId ) ;
glBindVertexArray ( quads . vaoId ) ;
2014-09-17 00:51:31 +04:00
}
2015-02-02 02:57:08 +03:00
2016-05-07 19:07:15 +03:00
// Quads - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & quads . vboId [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
2014-03-25 15:40:35 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 4 * MAX_QUADS_BATCH , quads . vertices , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Vertex texcoord buffer (shader-location = 1)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & quads . vboId [ 1 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
2014-09-03 18:51:28 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * 4 * MAX_QUADS_BATCH , quads . texcoords , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . texcoordLoc ) ;
glVertexAttribPointer ( currentShader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2016-05-07 19:07:15 +03:00
// Vertex color buffer (shader-location = 3)
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & quads . vboId [ 2 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
2014-09-03 18:51:28 +04:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( unsigned char ) * 4 * 4 * MAX_QUADS_BATCH , quads . colors , GL_DYNAMIC_DRAW ) ;
2015-05-05 00:46:31 +03:00
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Fill index buffer
2016-05-12 13:20:23 +03:00
glGenBuffers ( 1 , & quads . vboId [ 3 ] ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quads . vboId [ 3 ] ) ;
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-03-25 15:40:35 +04:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( int ) * 6 * MAX_QUADS_BATCH , quads . indices , GL_STATIC_DRAW ) ;
2014-09-17 00:51:31 +04: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 18:51:28 +04:00
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Default buffers VAO initialized successfully (quads) " , quads . vaoId ) ;
else TraceLog ( 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 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Unbind the current VAO
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2016-05-03 20:20:25 +03:00
//--------------------------------------------------------------------------------------------
2014-03-25 15:40:35 +04:00
}
2016-05-07 19:07:15 +03:00
// Update default internal buffers (VAOs/VBOs) with vertex array data
2015-02-09 20:29:32 +03:00
// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
2016-05-03 20:20:25 +03:00
// TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required)
2016-07-04 02:29:23 +03:00
static void UpdateDefaultBuffers ( void )
2014-03-25 15:40:35 +04:00
{
2016-05-03 20:20:25 +03:00
// Update lines vertex buffers
2015-01-02 22:59:54 +03:00
if ( lines . vCounter > 0 )
{
// Activate Lines VAO
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) glBindVertexArray ( lines . vaoId ) ;
2015-02-02 02:57:08 +03:00
2015-01-02 22:59:54 +03:00
// Lines - vertex positions buffer
2016-05-12 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
2015-01-02 22:59:54 +03: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 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
2015-01-02 22:59:54 +03: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 18:51:28 +04:00
2016-05-03 20:20:25 +03:00
// Update triangles vertex buffers
2015-01-02 22:59:54 +03:00
if ( triangles . vCounter > 0 )
{
// Activate Triangles VAO
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) glBindVertexArray ( triangles . vaoId ) ;
2015-02-02 02:57:08 +03:00
2015-01-02 22:59:54 +03:00
// Triangles - vertex positions buffer
2016-05-12 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
2015-01-02 22:59:54 +03: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 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
2015-01-02 22:59:54 +03: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 15:40:35 +04:00
2016-05-03 20:20:25 +03:00
// Update quads vertex buffers
2015-01-02 22:59:54 +03:00
if ( quads . vCounter > 0 )
{
// Activate Quads VAO
2016-05-12 13:20:23 +03:00
if ( vaoSupported ) glBindVertexArray ( quads . vaoId ) ;
2015-01-02 22:59:54 +03:00
// Quads - vertex positions buffer
2016-05-12 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
2015-01-02 22:59:54 +03: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 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
2015-01-02 22:59:54 +03: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 13:20:23 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
2015-01-02 22:59:54 +03: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 20:20:25 +03:00
//quads.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
2015-01-02 22:59:54 +03:00
// Now we can modify vertices
//glUnmapBuffer(GL_ARRAY_BUFFER);
}
2014-03-25 15:40:35 +04:00
//--------------------------------------------------------------
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Unbind the current VAO
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2014-03-25 15:40:35 +04:00
}
2016-05-03 20:20:25 +03:00
2016-05-07 19:07:15 +03:00
// Draw default internal buffers vertex data
// NOTE: We draw in this order: lines, triangles, quads
2016-07-04 02:29:23 +03:00
static void DrawDefaultBuffers ( int eyesCount )
2016-05-07 19:07:15 +03:00
{
2016-07-04 02:29:23 +03:00
Matrix matProjection = projection ;
Matrix matModelView = modelview ;
for ( int eye = 0 ; eye < eyesCount ; eye + + )
2016-05-07 19:07:15 +03:00
{
2016-07-06 01:54:38 +03:00
if ( eyesCount = = 2 ) SetStereoView ( eye , matProjection , matModelView ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
// Set current shader and upload current MVP matrix
if ( ( lines . vCounter > 0 ) | | ( triangles . vCounter > 0 ) | | ( quads . vCounter > 0 ) )
2016-05-07 19:07:15 +03:00
{
2016-07-04 02:29:23 +03:00
glUseProgram ( currentShader . id ) ;
// Create modelview-projection matrix
Matrix matMVP = MatrixMultiply ( modelview , projection ) ;
glUniformMatrix4fv ( currentShader . mvpLoc , 1 , false , MatrixToFloat ( matMVP ) ) ;
glUniform4f ( currentShader . tintColorLoc , 1.0f , 1.0f , 1.0f , 1.0f ) ;
glUniform1i ( currentShader . mapTexture0Loc , 0 ) ;
// NOTE: Additional map textures not considered for default buffers drawing
2016-05-07 19:07:15 +03:00
}
2016-07-04 02:29:23 +03:00
// Draw lines buffers
if ( lines . vCounter > 0 )
2016-05-07 19:07:15 +03:00
{
2016-07-04 02:29:23 +03:00
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( vaoSupported )
{
glBindVertexArray ( lines . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 0 ] ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , lines . vboId [ 1 ] ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
glDrawArrays ( GL_LINES , 0 , lines . vCounter ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-05-07 19:07:15 +03:00
}
2016-07-04 02:29:23 +03:00
// Draw triangles buffers
if ( triangles . vCounter > 0 )
{
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( vaoSupported )
{
glBindVertexArray ( triangles . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 0 ] ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , triangles . vboId [ 1 ] ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
glDrawArrays ( GL_TRIANGLES , 0 , triangles . vCounter ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2016-05-07 19:07:15 +03:00
}
2016-07-04 02:29:23 +03:00
// Draw quads buffers
if ( quads . vCounter > 0 )
2016-05-07 19:07:15 +03:00
{
2016-07-04 02:29:23 +03:00
int quadsCount = 0 ;
int numIndicesToProcess = 0 ;
int indicesOffset = 0 ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( vaoSupported )
{
glBindVertexArray ( quads . vaoId ) ;
}
else
{
// Bind vertex attrib: position (shader-location = 0)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 0 ] ) ;
glVertexAttribPointer ( currentShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . vertexLoc ) ;
// Bind vertex attrib: texcoord (shader-location = 1)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 1 ] ) ;
glVertexAttribPointer ( currentShader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . texcoordLoc ) ;
// Bind vertex attrib: color (shader-location = 3)
glBindBuffer ( GL_ARRAY_BUFFER , quads . vboId [ 2 ] ) ;
glVertexAttribPointer ( currentShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( currentShader . colorLoc ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quads . vboId [ 3 ] ) ;
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
//TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
for ( int i = 0 ; i < drawsCounter ; i + + )
{
quadsCount = draws [ i ] . vertexCount / 4 ;
numIndicesToProcess = quadsCount * 6 ; // Get number of Quads * 6 index by Quad
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
//TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount);
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
glBindTexture ( GL_TEXTURE_2D , draws [ i ] . textureId ) ;
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03: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;
//if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM!
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
indicesOffset + = draws [ i ] . vertexCount / 4 * 6 ;
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( ! vaoSupported )
{
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind textures
}
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
2016-05-07 19:07:15 +03:00
2016-07-04 02:29:23 +03:00
glUseProgram ( 0 ) ; // Unbind shader program
}
2016-05-07 19:07:15 +03: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 ;
// Reset depth for next draw
currentDepth = - 1.0f ;
2016-07-04 02:29:23 +03:00
// Restore projection/modelview matrices
projection = matProjection ;
modelview = matModelView ;
2016-05-07 19:07:15 +03:00
}
// Unload default internal buffers vertex data from CPU and GPU
2016-05-03 20:20:25 +03:00
static void UnloadDefaultBuffers ( void )
{
// 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 13:20:23 +03: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 20:20:25 +03:00
if ( vaoSupported )
{
// Delete VAOs from GPU (VRAM)
2016-05-12 13:20:23 +03:00
glDeleteVertexArrays ( 1 , & lines . vaoId ) ;
glDeleteVertexArrays ( 1 , & triangles . vaoId ) ;
glDeleteVertexArrays ( 1 , & quads . vaoId ) ;
2016-05-03 20:20:25 +03: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 ) ;
}
2016-06-02 21:23:09 +03:00
// Setup shader uniform values for lights array
2016-05-20 13:28:07 +03:00
// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f
static void SetShaderLights ( Shader shader )
{
2016-07-06 21:33:46 +03:00
int locPoint = - 1 ;
2016-05-20 13:28:07 +03:00
char locName [ 32 ] = " lights[x].position \0 " ;
2016-07-06 21:33:46 +03:00
for ( int i = 0 ; i < MAX_LIGHTS ; i + + )
2016-05-20 13:28:07 +03:00
{
locName [ 7 ] = ' 0 ' + i ;
2016-07-06 21:33:46 +03:00
if ( lights [ i ] ! = NULL ) // Only upload registered lights data
2016-05-21 19:16:39 +03:00
{
2016-07-06 21:33:46 +03:00
memcpy ( & locName [ 10 ] , " enabled \0 " , strlen ( " enabled \0 " ) + 1 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform1i ( locPoint , lights [ i ] - > enabled ) ;
memcpy ( & locName [ 10 ] , " type \0 " , strlen ( " type \0 " ) + 1 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform1i ( locPoint , lights [ i ] - > type ) ;
memcpy ( & locName [ 10 ] , " diffuse \0 " , strlen ( " diffuse \0 " ) + 2 ) ;
locPoint = glGetUniformLocation ( shader . id , locName ) ;
glUniform4f ( locPoint , ( float ) lights [ i ] - > diffuse . r / 255 , ( float ) lights [ i ] - > diffuse . g / 255 , ( float ) lights [ i ] - > diffuse . b / 255 , ( float ) lights [ i ] - > diffuse . a / 255 ) ;
memcpy ( & locName [ 10 ] , " intensity \0 " , strlen ( " intensity \0 " ) ) ;
locPoint = glGetUniformLocation ( shader . id , locName ) ;
glUniform1f ( locPoint , lights [ i ] - > intensity ) ;
switch ( lights [ i ] - > type )
2016-05-21 19:16:39 +03:00
{
2016-07-06 21:33:46 +03:00
case LIGHT_POINT :
{
memcpy ( & locName [ 10 ] , " position \0 " , strlen ( " position \0 " ) + 1 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform3f ( locPoint , lights [ i ] - > position . x , lights [ i ] - > position . y , lights [ i ] - > position . z ) ;
memcpy ( & locName [ 10 ] , " radius \0 " , strlen ( " radius \0 " ) + 2 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform1f ( locPoint , lights [ i ] - > radius ) ;
} break ;
case LIGHT_DIRECTIONAL :
{
memcpy ( & locName [ 10 ] , " direction \0 " , strlen ( " direction \0 " ) + 2 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
Vector3 direction = { lights [ i ] - > target . x - lights [ i ] - > position . x , lights [ i ] - > target . y - lights [ i ] - > position . y , lights [ i ] - > target . z - lights [ i ] - > position . z } ;
VectorNormalize ( & direction ) ;
glUniform3f ( locPoint , direction . x , direction . y , direction . z ) ;
} break ;
case LIGHT_SPOT :
{
memcpy ( & locName [ 10 ] , " position \0 " , strlen ( " position \0 " ) + 1 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform3f ( locPoint , lights [ i ] - > position . x , lights [ i ] - > position . y , lights [ i ] - > position . z ) ;
memcpy ( & locName [ 10 ] , " direction \0 " , strlen ( " direction \0 " ) + 2 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
Vector3 direction = { lights [ i ] - > target . x - lights [ i ] - > position . x , lights [ i ] - > target . y - lights [ i ] - > position . y , lights [ i ] - > target . z - lights [ i ] - > position . z } ;
VectorNormalize ( & direction ) ;
glUniform3f ( locPoint , direction . x , direction . y , direction . z ) ;
memcpy ( & locName [ 10 ] , " coneAngle \0 " , strlen ( " coneAngle \0 " ) ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform1f ( locPoint , lights [ i ] - > coneAngle ) ;
} break ;
default : break ;
}
// TODO: Pass to the shader any other required data from LightData struct
}
else // Not enabled lights
{
memcpy ( & locName [ 10 ] , " enabled \0 " , strlen ( " enabled \0 " ) + 1 ) ;
locPoint = GetShaderLocation ( shader , locName ) ;
glUniform1i ( locPoint , 0 ) ;
2016-05-21 19:16:39 +03:00
}
}
2016-05-20 13:28:07 +03:00
}
2016-05-03 20:20:25 +03:00
// Read text data from file
// NOTE: text chars array should be freed manually
static char * ReadTextFile ( 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 ) ;
}
else TraceLog ( WARNING , " [%s] Text file could not be opened " , fileName ) ;
}
return text ;
}
2014-09-17 00:51:31 +04:00
# endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-04-19 18:36:49 +04:00
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 18:36:49 +04:00
// Mipmaps data is generated after image data
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 17:36:45 +03:00
int size = baseWidth * baseHeight * 4 ; // Size in bytes (will include mipmaps...), RGBA only
2014-04-19 18:36:49 +04:00
// Count mipmap levels required
while ( ( width ! = 1 ) & & ( height ! = 1 ) )
{
if ( width ! = 1 ) width / = 2 ;
if ( height ! = 1 ) height / = 2 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
TraceLog ( DEBUG , " Next mipmap size: %i x %i " , width , height ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
mipmapCount + + ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
size + = ( width * height * 4 ) ; // Add mipmap size (in bytes)
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
TraceLog ( DEBUG , " Total mipmaps required: %i " , mipmapCount ) ;
TraceLog ( DEBUG , " Total size of data required: %i " , size ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
unsigned char * temp = realloc ( data , size ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( temp ! = NULL ) data = temp ;
else TraceLog ( WARNING , " Mipmaps required memory could not be allocated " ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
width = baseWidth ;
height = baseHeight ;
size = ( width * height * 4 ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// Generate mipmaps
// NOTE: Every mipmap data is stored after data
2016-04-01 11:39:33 +03:00
Color * image = ( Color * ) malloc ( width * height * sizeof ( Color ) ) ;
Color * mipmap = NULL ;
2014-04-19 18:36:49 +04: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 18:51:28 +04:00
2014-12-31 20:03:32 +03:00
TraceLog ( DEBUG , " Mipmap base (%ix%i) " , width , height ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
for ( int mip = 1 ; mip < mipmapCount ; mip + + )
{
mipmap = GenNextMipmap ( image , width , height ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
offset + = ( width * height * 4 ) ; // Size of last mipmap
j = 0 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04: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 18:51:28 +04:00
data [ offset + i + 3 ] = mipmap [ j ] . a ;
2014-04-19 18:36:49 +04:00
j + + ;
}
free ( image ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
image = mipmap ;
mipmap = NULL ;
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
free ( mipmap ) ; // free mipmap data
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
return mipmapCount ;
}
// Manual mipmap generation (basic scaling algorithm)
2016-04-01 11:39:33 +03:00
static Color * GenNextMipmap ( Color * srcData , int srcWidth , int srcHeight )
2014-04-19 18:36:49 +04:00
{
int x2 , y2 ;
2016-04-01 11:39:33 +03:00
Color prow , pcol ;
2014-04-19 18:36:49 +04:00
2016-01-13 21:30:35 +03:00
int width = srcWidth / 2 ;
int height = srcHeight / 2 ;
2014-04-19 18:36:49 +04:00
2016-04-01 11:39:33 +03:00
Color * mipmap = ( Color * ) malloc ( width * height * sizeof ( Color ) ) ;
2014-04-19 18:36:49 +04:00
// Scaling algorithm works perfectly (box-filter)
2014-09-03 18:51:28 +04:00
for ( int y = 0 ; y < height ; y + + )
2014-04-19 18:36:49 +04:00
{
2016-01-13 21:30:35 +03:00
y2 = 2 * y ;
2014-04-19 18:36:49 +04:00
2014-09-03 18:51:28 +04:00
for ( int x = 0 ; x < width ; x + + )
2014-04-19 18:36:49 +04:00
{
2016-01-13 21:30:35 +03:00
x2 = 2 * x ;
2014-04-19 18:36:49 +04: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 18:51:28 +04:00
2014-12-31 20:03:32 +03:00
TraceLog ( DEBUG , " Mipmap generated successfully (%ix%i) " , width , height ) ;
2014-04-19 18:36:49 +04:00
return mipmap ;
}
2014-04-09 22:25:26 +04:00
# endif
2016-07-08 01:57:27 +03:00
// Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetupVrDevice ( VrDeviceInfo hmd )
{
// Compute aspect ratio and FOV
float aspect = ( ( float ) hmd . hResolution / 2.0f ) / ( float ) hmd . vResolution ;
// Fov-y is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)*RAD2DEG
// ...but with lens distortion it is increased (see Oculus SDK Documentation)
float radius = - 1.0 - ( 4 * ( hmd . hScreenSize / 4 - hmd . lensSeparationDistance / 2 ) / hmd . hScreenSize ) ;
float distScale = ( hmd . distortionK [ 0 ] + hmd . distortionK [ 1 ] * pow ( radius , 2 ) + hmd . distortionK [ 2 ] * pow ( radius , 4 ) + hmd . distortionK [ 3 ] * pow ( radius , 6 ) ) ;
float fovy = 2 * atan2 ( hmd . vScreenSize * distScale , 2 * hmd . eyeToScreenDistance ) * RAD2DEG ;
// Compute camera projection matrices
Matrix proj = MatrixPerspective ( fovy , aspect , 0.1 , 10000 ) ;
float projOffset = 4 * ( hmd . hScreenSize / 4 - hmd . interpupillaryDistance / 2 ) / hmd . hScreenSize ;
//Matrix projLeft = MatrixMultiply(MatrixTranslation(projOffset, 0.0, 0.0), proj);
//matrix projRight = MatrixMultiply(MatrixTranslation(-projOffset, 0.0, 0.0)), proj);
// Compute camera transformation matrices
//Matrix viewTransformLeft = MatrixTranslation(-hmd.interpupillaryDistance/2, 0.0, 0.0 );
//Matrix viewTransformRight = MatrixTranslation(hmd.interpupillaryDistance/2, 0.0, 0.0 );
// Compute eyes Viewports
// Rectangle viewportLeft = { 0, 0, hmd.hResolution/2, hmd.vResolution };
// Rectangle viewportRight = { hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution };
// Distortion shader parameters
float lensShift = 4 * ( hmd . hScreenSize / 4 - hmd . lensSeparationDistance / 2 ) / hmd . hScreenSize ;
float leftLensCenter [ 2 ] = { lensShift , 0.0f } ;
float rightLensCenter [ 2 ] = { - lensShift , 0.0f } ;
float leftScreenCenter [ 2 ] = { 0.25f , 0.5f } ;
float rightScreenCenter [ 2 ] = { 0.75f , 0.5f } ;
float scaleIn [ 2 ] = { 1.0f , 1.0f / aspect } ;
float scale [ 2 ] = { 1.0f / distScale , 1.0f * aspect / distScale } ;
// Distortion shader parameters update
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " leftLensCenter " ) , leftLensCenter , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " rightLensCenter " ) , rightLensCenter , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " leftScreenCenter " ) , leftScreenCenter , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " rightScreenCenter " ) , rightScreenCenter , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " scale " ) , scale , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " scaleIn " ) , scaleIn , 2 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " hmdWarpParam " ) , hmd . distortionK , 4 ) ;
SetShaderValue ( distortionShader , GetShaderLocation ( distortionShader , " chromaAbParam " ) , hmd . chromaAbCorrection , 4 ) ;
}
2016-06-14 18:16:20 +03:00
# if defined(RLGL_OCULUS_SUPPORT)
2016-07-08 01:57:27 +03:00
static void InitOculusDevice ( void )
{
}
static void CloseOculusDevice ( void )
{
}
static void UpdateOculusTracking ( void )
{
}
static void BeginOculusDrawing ( void )
{
}
static void EndOculusDrawing ( void )
{
}
2016-06-14 18:16:20 +03:00
// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth
static OculusBuffer LoadOculusBuffer ( ovrSession session , int width , int height )
{
OculusBuffer buffer ;
buffer . width = width ;
buffer . height = height ;
// Create OVR texture chain
ovrTextureSwapChainDesc desc = { } ;
desc . Type = ovrTexture_2D ;
desc . ArraySize = 1 ;
desc . Width = width ;
desc . Height = height ;
desc . MipLevels = 1 ;
desc . Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB ; // Requires glEnable(GL_FRAMEBUFFER_SRGB);
desc . SampleCount = 1 ;
desc . StaticImage = ovrFalse ;
ovrResult result = ovr_CreateTextureSwapChainGL ( session , & desc , & buffer . textureChain ) ;
if ( ! OVR_SUCCESS ( result ) ) TraceLog ( WARNING , " OVR: Failed to create swap textures buffer " ) ;
int textureCount = 0 ;
ovr_GetTextureSwapChainLength ( session , buffer . textureChain , & textureCount ) ;
if ( ! OVR_SUCCESS ( result ) | | ! textureCount ) TraceLog ( WARNING , " OVR: Unable to count swap chain textures " ) ;
for ( int i = 0 ; i < textureCount ; + + i )
{
GLuint chainTexId ;
ovr_GetTextureSwapChainBufferGL ( session , buffer . textureChain , i , & chainTexId ) ;
glBindTexture ( GL_TEXTURE_2D , chainTexId ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
}
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
/*
// Setup framebuffer object (using depth texture)
glGenFramebuffers ( 1 , & buffer . fboId ) ;
glGenTextures ( 1 , & buffer . depthId ) ;
glBindTexture ( GL_TEXTURE_2D , buffer . depthId ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT16 , buffer . width , buffer . height , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , NULL ) ;
*/
// Setup framebuffer object (using depth renderbuffer)
glGenFramebuffers ( 1 , & buffer . fboId ) ;
glGenRenderbuffers ( 1 , & buffer . depthId ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , buffer . fboId ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , buffer . depthId ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT16 , buffer . width , buffer . height ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , 0 ) ;
glFramebufferRenderbuffer ( GL_DRAW_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , buffer . depthId ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
return buffer ;
}
// Unload texture required buffers
static void UnloadOculusBuffer ( ovrSession session , OculusBuffer buffer )
{
if ( buffer . textureChain )
{
ovr_DestroyTextureSwapChain ( session , buffer . textureChain ) ;
buffer . textureChain = NULL ;
}
if ( buffer . depthId ! = 0 ) glDeleteTextures ( 1 , & buffer . depthId ) ;
if ( buffer . fboId ! = 0 ) glDeleteFramebuffers ( 1 , & buffer . fboId ) ;
}
// Load Oculus mirror buffers
static OculusMirror LoadOculusMirror ( ovrSession session , int width , int height )
{
OculusMirror mirror ;
mirror . width = width ;
mirror . height = height ;
ovrMirrorTextureDesc mirrorDesc ;
memset ( & mirrorDesc , 0 , sizeof ( mirrorDesc ) ) ;
mirrorDesc . Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB ;
mirrorDesc . Width = mirror . width ;
mirrorDesc . Height = mirror . height ;
if ( ! OVR_SUCCESS ( ovr_CreateMirrorTextureGL ( session , & mirrorDesc , & mirror . texture ) ) ) TraceLog ( WARNING , " Could not create mirror texture " ) ;
glGenFramebuffers ( 1 , & mirror . fboId ) ;
return mirror ;
}
// Unload Oculus mirror buffers
static void UnloadOculusMirror ( ovrSession session , OculusMirror mirror )
{
if ( mirror . fboId ! = 0 ) glDeleteFramebuffers ( 1 , & mirror . fboId ) ;
if ( mirror . texture ) ovr_DestroyMirrorTexture ( session , mirror . texture ) ;
}
// Copy Oculus screen buffer to mirror texture
static void BlitOculusMirror ( ovrSession session , OculusMirror mirror )
{
GLuint mirrorTextureId ;
ovr_GetMirrorTextureBufferGL ( session , mirror . texture , & mirrorTextureId ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , mirror . fboId ) ;
glFramebufferTexture2D ( GL_READ_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , mirrorTextureId , 0 ) ;
2016-06-26 19:43:10 +03:00
# if defined(GRAPHICS_API_OPENGL_33)
// NOTE: glBlitFramebuffer() requires extension: GL_EXT_framebuffer_blit (not available in OpenGL ES 2.0)
2016-06-14 18:16:20 +03:00
glBlitFramebuffer ( 0 , 0 , mirror . width , mirror . height , 0 , mirror . height , mirror . width , 0 , GL_COLOR_BUFFER_BIT , GL_NEAREST ) ;
2016-06-26 19:43:10 +03:00
# endif
2016-06-14 18:16:20 +03:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
}
// Init Oculus layer (similar to photoshop)
static OculusLayer InitOculusLayer ( ovrSession session )
{
OculusLayer layer = { 0 } ;
layer . viewScaleDesc . HmdSpaceToWorldScaleInMeters = 1.0f ;
memset ( & layer . eyeLayer , 0 , sizeof ( ovrLayerEyeFov ) ) ;
layer . eyeLayer . Header . Type = ovrLayerType_EyeFov ;
layer . eyeLayer . Header . Flags = ovrLayerFlag_TextureOriginAtBottomLeft ;
ovrEyeRenderDesc eyeRenderDescs [ 2 ] ;
for ( int eye = 0 ; eye < 2 ; eye + + )
{
eyeRenderDescs [ eye ] = ovr_GetRenderDesc ( session , eye , hmdDesc . DefaultEyeFov [ eye ] ) ;
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection ( eyeRenderDescs [ eye ] . Fov , 0.01f , 10000.0f , ovrProjection_None ) ; //ovrProjection_ClipRangeOpenGL);
layer . eyeProjections [ eye ] = FromOvrMatrix ( ovrPerspectiveProjection ) ; // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix
layer . viewScaleDesc . HmdToEyeOffset [ eye ] = eyeRenderDescs [ eye ] . HmdToEyeOffset ;
layer . eyeLayer . Fov [ eye ] = eyeRenderDescs [ eye ] . Fov ;
ovrSizei eyeSize = ovr_GetFovTextureSize ( session , eye , layer . eyeLayer . Fov [ eye ] , 1.0f ) ;
layer . eyeLayer . Viewport [ eye ] . Size = eyeSize ;
layer . eyeLayer . Viewport [ eye ] . Pos . x = layer . width ;
layer . eyeLayer . Viewport [ eye ] . Pos . y = 0 ;
layer . height = eyeSize . h ; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h);
layer . width + = eyeSize . w ;
}
return layer ;
}
// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct
static Matrix FromOvrMatrix ( ovrMatrix4f ovrmat )
{
Matrix rmat ;
rmat . m0 = ovrmat . M [ 0 ] [ 0 ] ;
rmat . m1 = ovrmat . M [ 1 ] [ 0 ] ;
rmat . m2 = ovrmat . M [ 2 ] [ 0 ] ;
rmat . m3 = ovrmat . M [ 3 ] [ 0 ] ;
rmat . m4 = ovrmat . M [ 0 ] [ 1 ] ;
rmat . m5 = ovrmat . M [ 1 ] [ 1 ] ;
rmat . m6 = ovrmat . M [ 2 ] [ 1 ] ;
rmat . m7 = ovrmat . M [ 3 ] [ 1 ] ;
rmat . m8 = ovrmat . M [ 0 ] [ 2 ] ;
rmat . m9 = ovrmat . M [ 1 ] [ 2 ] ;
rmat . m10 = ovrmat . M [ 2 ] [ 2 ] ;
rmat . m11 = ovrmat . M [ 3 ] [ 2 ] ;
rmat . m12 = ovrmat . M [ 0 ] [ 3 ] ;
rmat . m13 = ovrmat . M [ 1 ] [ 3 ] ;
rmat . m14 = ovrmat . M [ 2 ] [ 3 ] ;
rmat . m15 = ovrmat . M [ 3 ] [ 3 ] ;
MatrixTranspose ( & rmat ) ;
return rmat ;
}
# endif
2014-09-17 00:51:31 +04:00
# if defined(RLGL_STANDALONE)
2014-04-09 22:25:26 +04:00
// Output a trace log message
// NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning
2016-06-08 00:44:53 +03:00
void TraceLog ( int msgType , const char * text , . . . )
2014-04-09 22:25:26 +04:00
{
va_list args ;
va_start ( args , text ) ;
2014-09-03 18:51:28 +04:00
2016-05-21 19:22:15 +03:00
switch ( msgType )
2014-04-09 22:25:26 +04:00
{
2014-04-19 18:36:49 +04:00
case INFO : fprintf ( stdout , " INFO: " ) ; break ;
case ERROR : fprintf ( stdout , " ERROR: " ) ; break ;
case WARNING : fprintf ( stdout , " WARNING: " ) ; break ;
case DEBUG : fprintf ( stdout , " DEBUG: " ) ; break ;
2014-04-09 22:25:26 +04:00
default : break ;
}
2014-09-03 18:51:28 +04:00
2014-04-09 22:25:26 +04:00
vfprintf ( stdout , text , args ) ;
fprintf ( stdout , " \n " ) ;
2014-09-03 18:51:28 +04:00
2014-04-09 22:25:26 +04:00
va_end ( args ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( msgType = = ERROR ) exit ( 1 ) ;
2014-04-09 22:25:26 +04:00
}
2016-03-20 15:39:27 +03:00
// Converts Matrix to float array
// NOTE: Returned vector is a transposed version of the Matrix struct,
// it should be this way because, despite raymath use OpenGL column-major convention,
// Matrix struct memory alignment and variables naming are not coherent
float * MatrixToFloat ( Matrix mat )
{
static float buffer [ 16 ] ;
buffer [ 0 ] = mat . m0 ;
buffer [ 1 ] = mat . m4 ;
buffer [ 2 ] = mat . m8 ;
buffer [ 3 ] = mat . m12 ;
buffer [ 4 ] = mat . m1 ;
buffer [ 5 ] = mat . m5 ;
buffer [ 6 ] = mat . m9 ;
buffer [ 7 ] = mat . m13 ;
buffer [ 8 ] = mat . m2 ;
buffer [ 9 ] = mat . m6 ;
buffer [ 10 ] = mat . m10 ;
buffer [ 11 ] = mat . m14 ;
buffer [ 12 ] = mat . m3 ;
buffer [ 13 ] = mat . m7 ;
buffer [ 14 ] = mat . m11 ;
buffer [ 15 ] = mat . m15 ;
return buffer ;
}
2015-05-21 01:18:22 +03:00
# endif