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 *
* OpenGL 3.3 + - Vertex data is stored in VAOs , call rlglDraw ( ) to render
* OpenGL ES 2 - Same behaviour as OpenGL 3.3 +
2014-09-03 18:51:28 +04:00
*
2014-03-25 15:40:35 +04:00
* Copyright ( c ) 2014 Ramon Santamaria ( Ray San - raysan @ raysanweb . com )
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"
# include <stdio.h> // Standard input / output lib
# include <stdlib.h> // Declares malloc() and free() for memory management, rand()
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2015-02-02 02:57:08 +03:00
# ifdef __APPLE__ // OpenGL include for OSX
# include <OpenGL/gl.h>
# else
# include <GL/gl.h> // Basic OpenGL include
# endif
2014-03-25 15:40:35 +04:00
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-09-03 18:51:28 +04:00
# define GLEW_STATIC
2015-02-02 02:57:08 +03:00
# ifdef __APPLE__ // OpenGL include for OSX
2014-11-22 02:13:09 +03:00
# include <OpenGL/gl3.h>
2015-02-02 02:57:08 +03:00
# else
# include <GL/glew.h> // Extensions loading lib
//#include "glad.h" // TODO: Other extensions loading lib? --> REVIEW
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)
# include <EGL/egl.h>
# include <GLES2/gl2.h>
# include <GLES2/gl2ext.h>
# 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)
2014-03-25 15:40:35 +04:00
2015-04-06 15:02:29 +03:00
# ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
# define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
# endif
# ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
# endif
# ifndef GL_ETC1_RGB8_OES
# define GL_ETC1_RGB8_OES 0x8D64
# endif
# ifndef GL_COMPRESSED_RGB8_ETC2
# define GL_COMPRESSED_RGB8_ETC2 0x9274
# endif
# ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
# define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
# endif
2014-03-25 15:40:35 +04:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2014-04-19 18:36:49 +04:00
// Vertex buffer (position + color arrays)
// NOTE: Used for lines and triangles VAOs
2014-03-25 15:40:35 +04:00
typedef struct {
int vCounter ;
int cCounter ;
float * vertices ; // 3 components per vertex
2014-07-23 02:06:24 +04:00
unsigned char * colors ; // 4 components per vertex
2014-03-25 15:40:35 +04:00
} VertexPositionColorBuffer ;
2014-04-19 18:36:49 +04:00
// Vertex buffer (position + texcoords + color arrays)
// NOTE: Not used
2014-03-25 15:40:35 +04:00
typedef struct {
int vCounter ;
int tcCounter ;
int cCounter ;
float * vertices ; // 3 components per vertex
float * texcoords ; // 2 components per vertex
2014-07-23 02:06:24 +04:00
unsigned char * colors ; // 4 components per vertex
2014-03-25 15:40:35 +04:00
} VertexPositionColorTextureBuffer ;
2014-04-19 18:36:49 +04:00
// Vertex buffer (position + texcoords + normals arrays)
// NOTE: Not used
2014-04-04 22:11:57 +04:00
typedef struct {
int vCounter ;
int tcCounter ;
int nCounter ;
float * vertices ; // 3 components per vertex
float * texcoords ; // 2 components per vertex
float * normals ; // 3 components per vertex
2014-09-17 00:51:31 +04:00
//short *normals; // NOTE: Less data load... but padding issues and normalizing required!
2014-04-04 22:11:57 +04:00
} VertexPositionTextureNormalBuffer ;
2014-04-19 18:36:49 +04:00
// Vertex buffer (position + texcoords + colors + indices arrays)
// NOTE: Used for quads VAO
2014-03-25 15:40:35 +04:00
typedef struct {
int vCounter ;
int tcCounter ;
int cCounter ;
float * vertices ; // 3 components per vertex
float * texcoords ; // 2 components per vertex
2014-07-23 02:06:24 +04:00
unsigned char * colors ; // 4 components per vertex
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
unsigned int * indices ; // 6 indices per quad (could be int)
# elif defined(GRAPHICS_API_OPENGL_ES2)
unsigned short * indices ; // 6 indices per quad (must be short)
// NOTE: 6*2 byte = 12 byte, not alignment problem!
# endif
2014-03-25 15:40:35 +04:00
} VertexPositionColorTextureIndexBuffer ;
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
GLuint textureId ;
int vertexCount ;
2014-03-25 15:40:35 +04:00
} DrawCall ;
2014-04-19 18:36:49 +04:00
// pixel type (same as Color type)
// NOTE: Used exclusively in mipmap generation functions
typedef struct {
unsigned char r ;
unsigned char g ;
unsigned char b ;
unsigned char a ;
} pixel ;
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 ;
// Vertex arrays for lines, triangles and quads
2014-04-04 22:11:57 +04:00
static VertexPositionColorBuffer lines ; // No texture support
static VertexPositionColorBuffer triangles ; // No texture support
2014-03-25 15:40:35 +04:00
static VertexPositionColorTextureIndexBuffer quads ;
2015-03-01 18:00:52 +03:00
// Shader Programs
static Shader defaultShader , simpleShader ;
2015-02-02 02:57:08 +03:00
2014-03-25 15:40:35 +04:00
// Vertex Array Objects (VAO)
static GLuint vaoLines , vaoTriangles , vaoQuads ;
// Vertex Buffer Objects (VBO)
static GLuint linesBuffer [ 2 ] ;
static GLuint trianglesBuffer [ 2 ] ;
static GLuint quadsBuffer [ 4 ] ;
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 ;
2014-09-17 00:51:31 +04:00
// Support for VAOs (OpenGL ES2 could not support VAO extensions)
static bool vaoSupported = false ;
2015-02-02 02:57:08 +03:00
// Framebuffer object and texture
2015-04-06 15:02:29 +03:00
static GLuint fbo , fboColorTexture , fboDepthTexture ;
static Model postproQuad ;
2014-09-17 00:51:31 +04:00
# endif
# if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: VAO functionality is exposed through extensions (OES)
2014-12-15 03:08:30 +03:00
// emscripten does not support VAOs
2014-09-17 00:51:31 +04:00
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays ;
static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray ;
static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays ;
static PFNGLISVERTEXARRAYOESPROC glIsVertexArray ;
2014-03-25 15:40:35 +04:00
# endif
2014-12-31 21:25:39 +03:00
// White texture useful for plain color polys (required by shader)
// NOTE: It's required in shapes and models modules!
unsigned int whiteTexture ;
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)
2015-03-01 18:00:52 +03:00
static Shader LoadDefaultShader ( void ) ;
static Shader LoadSimpleShader ( void ) ;
2014-09-03 19:06:10 +04:00
static void InitializeBuffers ( void ) ;
2014-09-17 00:51:31 +04:00
static void InitializeBuffersGPU ( void ) ;
2014-09-03 19:06:10 +04:00
static void UpdateBuffers ( void ) ;
2015-04-06 15:02:29 +03:00
static void LoadCompressedTexture ( unsigned char * data , int width , int height , int mipmapCount , int compressedFormat ) ;
2014-03-25 15:40:35 +04:00
2015-01-02 22:59:54 +03:00
// Custom shader files loading (external)
2014-03-25 15:40:35 +04:00
static char * TextFileRead ( char * fn ) ;
# 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 ) ;
static pixel * GenNextMipmap ( pixel * srcData , int srcWidth , int srcHeight ) ;
# 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 )
{
Matrix mat = MatrixTranslate ( x , y , z ) ;
2014-04-19 18:36:49 +04:00
MatrixTranspose ( & mat ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
* currentMatrix = MatrixMultiply ( * currentMatrix , mat ) ;
}
// Multiply the current matrix by a rotation matrix
void rlRotatef ( float angleDeg , float x , float y , float z )
{
2014-04-19 18:36:49 +04:00
// TODO: Support rotation in multiple axes
2015-03-02 22:52:58 +03:00
Matrix rotation = MatrixIdentity ( ) ;
2014-09-03 18:51:28 +04:00
2015-02-02 02:57:08 +03:00
// OPTION 1: It works...
2015-03-02 22:52:58 +03:00
//if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
//else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
//else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
2015-02-02 02:57:08 +03:00
// OPTION 2: Requires review...
2015-03-02 22:52:58 +03:00
Vector3 axis = ( Vector3 ) { x , y , z } ;
VectorNormalize ( & axis ) ;
rotation = MatrixRotateY ( angleDeg * DEG2RAD ) ; //MatrixFromAxisAngle(axis, angleDeg*DEG2RAD);
2015-02-02 02:57:08 +03:00
2014-12-16 13:15:56 +03:00
// OPTION 3: TODO: Review, it doesn't work!
//Vector3 vec = (Vector3){ x, y, z };
//VectorNormalize(&vec);
//rot = MatrixRotate(angleDeg*vec.x, angleDeg*vec.x, angleDeg*vec.x);
2015-02-02 02:57:08 +03:00
2015-03-02 22:52:58 +03:00
MatrixTranspose ( & rotation ) ;
2014-09-03 18:51:28 +04:00
2015-03-02 22:52:58 +03:00
* currentMatrix = MatrixMultiply ( * currentMatrix , rotation ) ;
2014-03-25 15:40:35 +04:00
}
// Multiply the current matrix by a scaling matrix
void rlScalef ( float x , float y , float z )
{
Matrix mat = MatrixScale ( x , y , z ) ;
2014-04-19 18:36:49 +04:00
MatrixTranspose ( & mat ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
* currentMatrix = MatrixMultiply ( * currentMatrix , mat ) ;
}
// 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
//----------------------------------------------------------------------------------
// 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 ;
}
}
// 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 )
{
2014-09-17 00:51:31 +04:00
rlVertex3f ( x , y , 0.0f ) ;
2014-03-25 15:40:35 +04:00
}
// Define one vertex (position)
void rlVertex2i ( int x , int y )
{
2014-09-17 00:51:31 +04:00
rlVertex3f ( ( float ) x , ( float ) y , 0.0f ) ;
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
}
// Unload texture from GPU memory
void rlDeleteTextures ( unsigned int id )
{
glDeleteTextures ( 1 , & id ) ;
}
2015-04-06 15:02:29 +03:00
// Enable rendering to postprocessing FBO
void rlEnableFBO ( void )
{
2015-03-01 18:00:52 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-04-06 15:02:29 +03:00
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
# 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)
2015-02-02 02:57:08 +03:00
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)
if ( vaoSupported ) glDeleteVertexArrays ( 1 , & id ) ;
# endif
}
// Unload vertex data (VBO) from GPU memory
void rlDeleteBuffers ( unsigned int id )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glDeleteBuffers ( 1 , & 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)
float cr = ( float ) r / 255 ;
float cg = ( float ) g / 255 ;
float cb = ( float ) b / 255 ;
float ca = ( float ) a / 255 ;
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 ;
# 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
//----------------------------------------------------------------------------------
// Init OpenGL 3.3+ required data
2014-09-03 19:06:10 +04:00
void rlglInit ( void )
2014-09-03 18:51:28 +04:00
{
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
// Loading extensions the hard way (Example)
/*
GLint numExt ;
glGetIntegerv ( GL_NUM_EXTENSIONS , & numExt ) ;
for ( int i = 0 ; i < numExt ; i + + )
{
const GLubyte * extensionName = glGetStringi ( GL_EXTENSIONS , i ) ;
if ( strcmp ( extensionName , ( const GLubyte * ) " GL_ARB_vertex_array_object " ) = = 0 )
{
// The extension is supported by our hardware and driver, try to get related functions popinters
glGenVertexArrays = ( PFNGLGENVERTEXARRAYSOESPROC ) wglGetProcAddress ( " glGenVertexArrays " ) ;
glBindVertexArray = ( PFNGLBINDVERTEXARRAYOESPROC ) wglGetProcAddress ( " glBindVertexArray " ) ;
glDeleteVertexArrays = ( PFNGLDELETEVERTEXARRAYSOESPROC ) wglGetProcAddress ( " glDeleteVertexArrays " ) ;
glIsVertexArray = ( PFNGLISVERTEXARRAYOESPROC ) wglGetProcAddress ( " glIsVertexArray " ) ;
}
}
*/
// Initialize extensions using GLEW
2014-03-25 15:40:35 +04:00
glewExperimental = 1 ; // Needed for core profile
GLenum error = glewInit ( ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( error ! = GLEW_OK ) TraceLog ( ERROR , " Failed to initialize GLEW - Error Code: %s \n " , glewGetErrorString ( error ) ) ;
if ( glewIsSupported ( " GL_VERSION_3_3 " ) ) TraceLog ( INFO , " OpenGL 3.3 extensions supported " ) ;
// NOTE: GLEW is a big library that loads ALL extensions, using glad we can only load required ones...
//if (!gladLoadGL()) TraceLog("ERROR: Failed to initialize glad\n");
vaoSupported = true ;
# endif
# if defined(GRAPHICS_API_OPENGL_ES2)
2015-02-02 02:57:08 +03:00
// NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
2014-12-15 03:08:30 +03:00
# if !defined(PLATFORM_WEB)
2014-09-17 00:51:31 +04:00
glGenVertexArrays = ( PFNGLGENVERTEXARRAYSOESPROC ) eglGetProcAddress ( " glGenVertexArraysOES " ) ;
glBindVertexArray = ( PFNGLBINDVERTEXARRAYOESPROC ) eglGetProcAddress ( " glBindVertexArrayOES " ) ;
glDeleteVertexArrays = ( PFNGLDELETEVERTEXARRAYSOESPROC ) eglGetProcAddress ( " glDeleteVertexArraysOES " ) ;
glIsVertexArray = ( PFNGLISVERTEXARRAYOESPROC ) eglGetProcAddress ( " glIsVertexArrayOES " ) ;
2014-12-15 03:08:30 +03:00
# endif
2014-09-17 00:51:31 +04:00
if ( glGenVertexArrays = = NULL ) TraceLog ( WARNING , " Could not initialize VAO extensions, VAOs not supported " ) ;
else
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
vaoSupported = true ;
TraceLog ( INFO , " VAO extensions initialized successfully " ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-17 00:51:31 +04:00
# endif
2014-03-25 15:40:35 +04:00
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 ) ) ;
TraceLog ( INFO , " GPU: GLSL: %s " , glGetString ( 0x8B8C ) ) ; //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);
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);
// Show supported extensions
// NOTE: We don't need that much data on screen... right now...
2014-03-25 15:40:35 +04:00
/*
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
GLint numExt ;
glGetIntegerv ( GL_NUM_EXTENSIONS , & numExt ) ;
for ( int i = 0 ; i < numExt ; i + + )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
TraceLog ( INFO , " Supported extension: %s " , glGetStringi ( GL_EXTENSIONS , i ) ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
char * extensions = ( char * ) glGetString ( GL_EXTENSIONS ) ; // One big string
// NOTE: String could be splitted using strtok() function (string.h)
TraceLog ( INFO , " Supported extension: %s " , extensions ) ;
# endif
2014-09-03 18:51:28 +04:00
*/
2015-04-06 15:02:29 +03:00
/*
GLint numComp = 0 ;
glGetIntegerv ( GL_NUM_COMPRESSED_TEXTURE_FORMATS , & numComp ) ;
GLint format [ 32 ] = { 0 } ;
glGetIntegerv ( GL_COMPRESSED_TEXTURE_FORMATS , format ) ;
2014-09-17 00:51:31 +04:00
2015-04-06 15:02:29 +03:00
for ( int i = 0 ; i < numComp ; i + + )
{
TraceLog ( INFO , " Supported compressed format: 0x%x " , format [ i ] ) ;
}
*/
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
// Set default draw mode
currentDrawMode = RL_TRIANGLES ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Reset projection and modelview matrices
projection = MatrixIdentity ( ) ;
modelview = MatrixIdentity ( ) ;
currentMatrix = & modelview ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Initialize matrix stack
for ( int i = 0 ; i < MATRIX_STACK_SIZE ; i + + ) stack [ i ] = MatrixIdentity ( ) ;
// Init default Shader (GLSL 110) -> Common for GL 3.3+ and ES2
2015-03-01 18:00:52 +03:00
defaultShader = LoadDefaultShader ( ) ;
simpleShader = LoadSimpleShader ( ) ;
//customShader = LoadShader("custom.vs", "custom.fs"); // Works ok
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
InitializeBuffers ( ) ; // Init vertex arrays
InitializeBuffersGPU ( ) ; // Init VBO and VAO
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
// Create default white texture for plain colors (required by shader)
unsigned char pixels [ 4 ] = { 255 , 255 , 255 , 255 } ; // 1 pixel RGBA (4 bytes)
2014-09-03 18:51:28 +04:00
2015-04-06 15:02:29 +03:00
whiteTexture = rlglLoadTexture ( pixels , 1 , 1 , UNCOMPRESSED_R8G8B8A8 , 1 , false ) ;
2014-09-03 18:51:28 +04:00
2014-12-15 03:08:30 +03:00
if ( whiteTexture ! = 0 ) TraceLog ( INFO , " [TEX ID %i] Base white texture loaded successfully " , whiteTexture ) ;
else TraceLog ( WARNING , " Base white texture could not be loaded " ) ;
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 ;
2014-09-17 00:51:31 +04:00
# endif
2014-03-25 15:40:35 +04:00
}
2015-02-02 02:57:08 +03:00
// Init postpro system
void rlglInitPostpro ( void )
{
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-02-02 02:57:08 +03:00
// Create the texture that will serve as the color attachment for the framebuffer
glGenTextures ( 1 , & fboColorTexture ) ;
glBindTexture ( GL_TEXTURE_2D , fboColorTexture ) ;
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_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , GetScreenWidth ( ) , GetScreenHeight ( ) , 0 , GL_RGB , GL_UNSIGNED_BYTE , NULL ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 02:57:08 +03:00
// Create the texture that will serve as the depth attachment for the framebuffer.
glGenTextures ( 1 , & fboDepthTexture ) ;
glBindTexture ( GL_TEXTURE_2D , fboDepthTexture ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
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_COMPONENT , GetScreenWidth ( ) , GetScreenHeight ( ) , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE , NULL ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
// Create the framebuffer object
glGenFramebuffers ( 1 , & fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
2015-03-01 18:00:52 +03:00
// Attach color texture and depth texture to FBO
2015-02-02 02:57:08 +03:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , fboColorTexture , 0 ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , fboDepthTexture , 0 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 02:57:08 +03:00
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) TraceLog ( WARNING , " Framebuffer object could not be created... " ) ;
else TraceLog ( INFO , " [FBO ID %i] Framebuffer object created successfully " , fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2015-04-06 15:02:29 +03:00
// Create a simple quad model to render fbo texture
VertexData quadData ;
quadData . vertexCount = 6 ;
float w = GetScreenWidth ( ) ;
float h = GetScreenHeight ( ) ;
2015-02-02 02:57:08 +03:00
2015-04-06 15:02:29 +03:00
float quadPositions [ 6 * 3 ] = { w , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , h , 0.0 , 0 , h , 0.0 , w , h , 0.0 , w , 0.0 , 0.0 } ;
float quadTexcoords [ 6 * 2 ] = { 1.0 , 1.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 } ;
float quadNormals [ 6 * 3 ] = { 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 } ;
unsigned char quadColors [ 6 * 4 ] = { 255 } ;
2015-02-02 02:57:08 +03:00
2015-04-06 15:02:29 +03:00
quadData . vertices = quadPositions ;
quadData . texcoords = quadTexcoords ;
quadData . normals = quadNormals ;
quadData . colors = quadColors ;
postproQuad = rlglLoadModel ( quadData ) ;
Texture2D texture ;
texture . id = fboColorTexture ;
texture . width = w ;
texture . height = h ;
SetModelTexture ( & postproQuad , texture ) ;
# endif
2015-02-02 02:57:08 +03:00
}
2015-04-06 15:02:29 +03:00
// Set postprocessing shader
void rlglSetPostproShader ( Shader shader )
{
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
SetModelShader ( & postproQuad , shader ) ;
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-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)
2014-03-25 15:40:35 +04:00
// Unbind everything
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ;
2014-03-25 15:40:35 +04:00
glDisableVertexAttribArray ( 0 ) ;
glDisableVertexAttribArray ( 1 ) ;
glDisableVertexAttribArray ( 2 ) ;
glDisableVertexAttribArray ( 3 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
glUseProgram ( 0 ) ;
2014-09-17 00:51:31 +04:00
// Delete VBOs
2014-03-25 15:40:35 +04:00
glDeleteBuffers ( 1 , & linesBuffer [ 0 ] ) ;
glDeleteBuffers ( 1 , & linesBuffer [ 1 ] ) ;
glDeleteBuffers ( 1 , & trianglesBuffer [ 0 ] ) ;
glDeleteBuffers ( 1 , & trianglesBuffer [ 1 ] ) ;
glDeleteBuffers ( 1 , & quadsBuffer [ 0 ] ) ;
glDeleteBuffers ( 1 , & quadsBuffer [ 1 ] ) ;
glDeleteBuffers ( 1 , & quadsBuffer [ 2 ] ) ;
glDeleteBuffers ( 1 , & quadsBuffer [ 3 ] ) ;
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Delete VAOs
glDeleteVertexArrays ( 1 , & vaoLines ) ;
glDeleteVertexArrays ( 1 , & vaoTriangles ) ;
glDeleteVertexArrays ( 1 , & vaoQuads ) ;
}
2014-03-25 15:40:35 +04:00
2015-01-02 22:59:54 +03:00
//glDetachShader(defaultShaderProgram, v);
//glDetachShader(defaultShaderProgram, f);
2014-03-25 15:40:35 +04:00
//glDeleteShader(v);
//glDeleteShader(f);
2015-03-01 18:00:52 +03:00
glDeleteProgram ( defaultShader . id ) ;
glDeleteProgram ( simpleShader . id ) ;
2014-03-25 15:40:35 +04:00
// Free vertex arrays memory
free ( lines . vertices ) ;
free ( lines . colors ) ;
free ( triangles . vertices ) ;
free ( triangles . colors ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
free ( quads . vertices ) ;
free ( quads . texcoords ) ;
free ( quads . colors ) ;
2014-09-17 00:51:31 +04:00
free ( quads . indices ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Free GPU texture
glDeleteTextures ( 1 , & whiteTexture ) ;
2015-04-06 15:02:29 +03:00
if ( fbo ! = 0 )
{
glDeleteFramebuffers ( 1 , & fbo ) ;
UnloadModel ( postproQuad ) ;
}
2014-09-03 18:51:28 +04: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
}
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)
2014-07-23 02:06:24 +04:00
UpdateBuffers ( ) ;
2014-09-03 18:51:28 +04:00
2015-01-02 22:59:54 +03:00
if ( ( lines . vCounter > 0 ) | | ( triangles . vCounter > 0 ) | | ( quads . vCounter > 0 ) )
{
2015-03-01 18:00:52 +03:00
glUseProgram ( defaultShader . id ) ;
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
glUniformMatrix4fv ( defaultShader . projectionLoc , 1 , false , GetMatrixVector ( projection ) ) ;
glUniformMatrix4fv ( defaultShader . modelviewLoc , 1 , false , GetMatrixVector ( modelview ) ) ;
glUniform1i ( defaultShader . textureLoc , 0 ) ;
2015-01-02 22:59:54 +03:00
}
2015-02-02 02:57:08 +03:00
2014-09-03 18:51:28 +04:00
// NOTE: We draw in this order: triangle shapes, textured quads and lines
2014-07-23 03:25:33 +04:00
if ( triangles . vCounter > 0 )
{
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
glBindVertexArray ( vaoTriangles ) ;
}
else
{
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 0 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 1 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
2014-09-17 00:51:31 +04:00
}
2014-07-23 03:25:33 +04:00
glDrawArrays ( GL_TRIANGLES , 0 , triangles . vCounter ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2014-07-23 03:25:33 +04:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
if ( quads . vCounter > 0 )
{
2014-04-19 18:36:49 +04:00
int quadsCount = 0 ;
2014-03-25 15:40:35 +04:00
int numIndicesToProcess = 0 ;
int indicesOffset = 0 ;
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
glBindVertexArray ( vaoQuads ) ;
}
else
{
// Enable vertex attributes
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 0 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 1 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . texcoordLoc ) ;
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 2 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quadsBuffer [ 3 ] ) ;
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
//TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
for ( int i = 0 ; i < drawsCounter ; i + + )
{
2014-04-19 18:36:49 +04:00
quadsCount = draws [ i ] . vertexCount / 4 ;
numIndicesToProcess = quadsCount * 6 ; // Get number of Quads * 6 index by Quad
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
//TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount);
2014-03-25 15:40:35 +04:00
2014-04-19 18:36:49 +04:00
glBindTexture ( GL_TEXTURE_2D , draws [ i ] . textureId ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04: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
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2014-03-25 15:40:35 +04:00
glDrawElements ( GL_TRIANGLES , numIndicesToProcess , GL_UNSIGNED_INT , ( GLvoid * ) ( sizeof ( GLuint ) * indicesOffset ) ) ;
2014-09-17 00:51:31 +04:00
# 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!
2014-03-25 15:40:35 +04:00
2014-04-19 18:36:49 +04:00
indicesOffset + = draws [ i ] . vertexCount / 4 * 6 ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( ! vaoSupported )
{
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
2014-09-03 18:51:28 +04:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind textures
2014-07-23 02:06:24 +04:00
}
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( lines . vCounter > 0 )
{
glBindTexture ( GL_TEXTURE_2D , whiteTexture ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
glBindVertexArray ( vaoLines ) ;
}
else
{
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 0 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 1 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( defaultShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
2014-09-17 00:51:31 +04:00
}
2014-07-23 02:06:24 +04:00
glDrawArrays ( GL_LINES , 0 , lines . vCounter ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( ! vaoSupported ) glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2014-07-23 02:06:24 +04:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
2014-09-03 18:51:28 +04:00
2015-03-01 18:00:52 +03:00
glUseProgram ( 0 ) ; // Unbind shader program
2014-03-25 15:40:35 +04:00
// Reset draws counter
drawsCounter = 1 ;
2014-04-19 18:36:49 +04:00
draws [ 0 ] . textureId = whiteTexture ;
draws [ 0 ] . vertexCount = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Reset vertex counters for next frame
lines . vCounter = 0 ;
lines . cCounter = 0 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
triangles . vCounter = 0 ;
2014-04-04 22:11:57 +04:00
triangles . cCounter = 0 ;
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
# endif
2014-03-25 15:40:35 +04:00
}
2015-04-06 15:02:29 +03:00
// Draw with postprocessing shader
void rlglDrawPostpro ( 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)
2015-02-02 02:57:08 +03:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2015-04-06 15:02:29 +03:00
rlglDrawModel ( postproQuad , ( Vector3 ) { 0 , 0 , 0 } , 0.0f , ( Vector3 ) { 0 , 0 , 0 } , ( Vector3 ) { 1.0f , 1.0f , 1.0f } , WHITE , false ) ;
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-04-09 22:25:26 +04:00
// Draw a 3d model
2015-03-02 22:52:58 +03:00
void rlglDrawModel ( Model model , Vector3 position , float rotationAngle , Vector3 rotationAxis , Vector3 scale , Color color , bool wires )
2014-04-04 22:11:57 +04:00
{
2014-09-17 00:51:31 +04:00
# if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
2014-04-04 22:11:57 +04:00
if ( wires ) glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
2014-09-17 00:51:31 +04:00
# endif
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 18:36:49 +04:00
glEnable ( GL_TEXTURE_2D ) ;
2015-03-02 22:52:58 +03:00
glBindTexture ( GL_TEXTURE_2D , model . texture . id ) ;
2014-04-19 18:36:49 +04:00
// NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
2014-04-04 22:11:57 +04:00
glEnableClientState ( GL_VERTEX_ARRAY ) ; // Enable vertex array
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ; // Enable texture coords array
glEnableClientState ( GL_NORMAL_ARRAY ) ; // Enable normals array
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
glVertexPointer ( 3 , GL_FLOAT , 0 , model . mesh . vertices ) ; // Pointer to vertex coords array
glTexCoordPointer ( 2 , GL_FLOAT , 0 , model . mesh . texcoords ) ; // Pointer to texture coords array
glNormalPointer ( GL_FLOAT , 0 , model . mesh . normals ) ; // Pointer to normals array
2014-07-23 02:06:24 +04:00
//glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.mesh.colors); // Pointer to colors array (NOT USED)
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
rlPushMatrix ( ) ;
rlTranslatef ( position . x , position . y , position . z ) ;
2014-04-19 18:36:49 +04:00
rlScalef ( scale . x , scale . y , scale . z ) ;
2015-03-02 22:52:58 +03:00
rlRotatef ( rotationAngle , rotationAxis . x , rotationAxis . y , rotationAxis . z ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// TODO: If rotate in multiple axis, get rotation matrix and use rlMultMatrix()
rlColor4ub ( color . r , color . g , color . b , color . a ) ;
2014-04-04 22:11:57 +04:00
2014-04-19 18:36:49 +04:00
glDrawArrays ( GL_TRIANGLES , 0 , model . mesh . vertexCount ) ;
2014-04-04 22:11:57 +04:00
rlPopMatrix ( ) ;
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
glDisableClientState ( GL_VERTEX_ARRAY ) ; // Disable vertex array
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ; // Disable texture coords array
glDisableClientState ( GL_NORMAL_ARRAY ) ; // Disable normals array
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
glDisable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2014-04-04 22:11:57 +04:00
# endif
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-03-01 18:00:52 +03:00
glUseProgram ( model . shader . id ) ;
2014-09-03 18:51:28 +04:00
2015-04-06 15:02:29 +03:00
// TODO: Use model.transform matrix
Vector3 rotation = { 0.0f , 0.0f , 0.0f } ;
2015-02-02 02:57:08 +03:00
2014-04-19 18:36:49 +04:00
// Get transform matrix (rotation -> scale -> translation)
2015-03-01 18:00:52 +03:00
Matrix transform = MatrixTransform ( position , rotation , scale ) ; // Object-space transformation
Matrix modelviewworld = MatrixMultiply ( transform , modelview ) ; // World-space transformation
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Projection: Screen-space transformation
2014-09-03 18:51:28 +04:00
2014-04-04 22:11:57 +04:00
// NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
2015-03-01 18:00:52 +03:00
glUniformMatrix4fv ( model . shader . projectionLoc , 1 , false , GetMatrixVector ( projection ) ) ;
glUniformMatrix4fv ( model . shader . modelviewLoc , 1 , false , GetMatrixVector ( modelviewworld ) ) ;
glUniform1i ( model . shader . textureLoc , 0 ) ;
2014-09-03 18:51:28 +04:00
2015-01-02 22:59:54 +03:00
// Apply color tinting to model
// NOTE: Just update one uniform on fragment shader
float vColor [ 4 ] = { ( float ) color . r / 255 , ( float ) color . g / 255 , ( float ) color . b / 255 , ( float ) color . a / 255 } ;
2015-02-02 02:57:08 +03:00
2015-03-01 18:00:52 +03:00
glUniform4fv ( model . shader . tintColorLoc , 1 , vColor ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
2015-04-06 15:02:29 +03:00
glBindVertexArray ( model . mesh . vaoId ) ;
2014-09-17 00:51:31 +04:00
}
else
{
// Bind model VBOs data
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model . mesh . vboId [ 0 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( model . shader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( model . shader . vertexLoc ) ;
2014-09-17 00:51:31 +04:00
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model . mesh . vboId [ 1 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( model . shader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( model . shader . texcoordLoc ) ;
2014-09-17 00:51:31 +04:00
2015-01-02 22:59:54 +03:00
// Add normals support
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model . mesh . vboId [ 2 ] ) ;
2015-03-01 18:00:52 +03:00
glVertexAttribPointer ( model . shader . normalLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
glEnableVertexAttribArray ( model . shader . normalLoc ) ;
2014-09-17 00:51:31 +04:00
}
2015-03-01 18:00:52 +03:00
glBindTexture ( GL_TEXTURE_2D , model . texture . id ) ;
2014-04-04 22:11:57 +04:00
2014-04-19 18:36:49 +04:00
glDrawArrays ( GL_TRIANGLES , 0 , model . mesh . vertexCount ) ;
2014-04-04 22:11:57 +04:00
2014-09-17 00:51:31 +04:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Unbind textures
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
else glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ; // Unbind VBOs
2015-02-02 02:57:08 +03:00
2015-01-02 22:59:54 +03:00
glUseProgram ( 0 ) ;
2014-04-04 22:11:57 +04:00
# endif
2014-09-17 00:51:31 +04:00
# if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
2014-04-04 22:11:57 +04:00
if ( wires ) glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
2014-09-17 00:51:31 +04:00
# endif
2014-04-04 22:11:57 +04:00
}
2014-03-25 15:40:35 +04:00
// Initialize Graphics Device (OpenGL stuff)
2014-09-17 00:51:31 +04:00
void rlglInitGraphics ( int offsetX , int offsetY , int width , int height )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
// NOTE: Required! viewport must be recalculated if screen resized!
glViewport ( offsetX / 2 , offsetY / 2 , width - offsetX , height - offsetY ) ; // Set viewport width and height
2014-03-25 15:40:35 +04:00
// NOTE: Don't confuse glViewport with the transformation matrix
// NOTE: glViewport just defines the area of the context that you will actually draw to.
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; // Clear used buffers, depth buffer is used for 3D
glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ; // Set background color (black)
//glClearDepth(1.0f); // Clear depth buffer (default)
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glEnable ( GL_DEPTH_TEST ) ; // Enables depth testing (required for 3D)
glDepthFunc ( GL_LEQUAL ) ; // Type of depth testing to apply
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glEnable ( GL_BLEND ) ; // Enable color blending (required to work with transparencies)
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ; // Color blending function (how colors are mixed)
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
glHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ; // Improve quality of color and texture coordinate interpolation (Deprecated in OGL 3.0)
// Other options: GL_FASTEST, GL_DONT_CARE (default)
# endif
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to PROJECTION matrix
rlLoadIdentity ( ) ; // Reset current matrix (PROJECTION)
2014-09-03 18:51:28 +04:00
2015-03-02 22:52:58 +03:00
rlOrtho ( 0 , width - offsetX , height - offsetY , 0 , 0 , 1 ) ; // Config orthographic mode: top-left corner --> (0,0)
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to MODELVIEW matrix
rlLoadIdentity ( ) ; // Reset current matrix (MODELVIEW)
2014-09-03 18:51:28 +04:00
2014-04-09 22:25:26 +04:00
// NOTE: All shapes/models triangles are drawn CCW
2014-03-25 15:40:35 +04:00
glEnable ( GL_CULL_FACE ) ; // Enable backface culling (Disabled by default)
//glCullFace(GL_BACK); // Cull the Back face (default)
//glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-03-25 15:40:35 +04:00
glShadeModel ( GL_SMOOTH ) ; // Smooth shading between vertex (vertex colors interpolation) (Deprecated on OpenGL 3.3+)
// Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation)
# endif
2014-04-09 22:25:26 +04:00
2015-01-21 02:12:30 +03:00
// TODO: Review this comment when called from window resize callback
2014-09-17 00:51:31 +04:00
TraceLog ( INFO , " OpenGL Graphics initialized successfully " ) ;
2014-03-25 15:40:35 +04:00
}
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
{
2015-03-02 22:52:58 +03:00
//GLint viewport[4];
//glGetIntegerv(GL_VIEWPORT, viewport);
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Viewport data
int x = 0 ;
int y = 0 ;
int width = GetScreenWidth ( ) ;
int height = GetScreenHeight ( ) ;
float minDepth = 0.0f ;
float maxDepth = 1.0f ;
2015-04-06 15:02:29 +03:00
/*
2015-03-02 22:52:58 +03:00
Matrix modelviewprojection = MatrixMultiply ( modelview , projection ) ;
MatrixInvert ( & modelviewprojection ) ;
Vector3 vector ;
vector . x = ( ( ( source . x - x ) / ( ( float ) width ) ) * 2.0f ) - 1.0f ;
vector . y = - ( ( ( ( source . y - y ) / ( ( float ) height ) ) * 2.0f ) - 1.0f ) ;
vector . z = ( source . z - minDepth ) / ( maxDepth - minDepth ) ;
//float a = (((vector.x * matrix.M14) + (vector.y * matrix.M24)) + (vector.z * matrix.M34)) + matrix.M44;
//float a = (((vector.x * modelviewprojection.m3) + (vector.y * modelviewprojection.m7)) + (vector.z * modelviewprojection.m11)) + modelviewprojection.m15;
VectorTransform ( & vector , modelviewprojection ) ;
//if (!MathUtil.IsOne(a)) vector = (vector / a);
//VectorScale(&vector, 1/a);
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
return vector ;
*/
/*
Vector3 worldPoint ;
// Transformation matrices
Matrix modelviewprojection = MatrixIdentity ( ) ;
Quaternion quat ;
// Calculation for inverting a matrix, compute projection x modelview
modelviewprojection = MatrixMultiply ( proj , view ) ;
MatrixInvert ( & modelviewprojection ) ;
// Transformation of normalized coordinates between -1 and 1
quat . x = ( ( source . x - ( float ) x ) / ( float ) width * 2.0 ) - 1.0f ;
quat . y = ( ( source . y - ( float ) y ) / ( float ) height * 2.0 ) - 1.0f ;
quat . z = 2.0 * source . z - 1.0 ;
quat . w = 1.0 ;
// Objects coordinates
QuaternionTransform ( & quat , modelviewprojection ) ;
//if (quat.w == 0.0) return 0;
worldPoint . x = quat . x / quat . w ;
worldPoint . y = quat . y / quat . w ;
worldPoint . z = quat . z / quat . w ;
return worldPoint ;
*/
/*
Quaternion quat ;
Vector3 vec ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
quat . x = 2.0f * GetMousePosition ( ) . x / ( float ) width - 1 ;
quat . y = - ( 2.0f * GetMousePosition ( ) . y / ( float ) height - 1 ) ;
quat . z = 0 ;
quat . w = 1 ;
2015-04-06 15:02:29 +03:00
Matrix invView ;
2015-03-02 22:52:58 +03:00
MatrixInvert ( & view ) ;
Matrix invProj ;
MatrixInvert ( & proj ) ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
quat . x = invProj . m0 * quat . x + invProj . m4 * quat . y + invProj . m8 * quat . z + invProj . m12 * quat . w ;
quat . y = invProj . m1 * quat . x + invProj . m5 * quat . y + invProj . m9 * quat . z + invProj . m13 * quat . w ;
quat . z = invProj . m2 * quat . x + invProj . m6 * quat . y + invProj . m10 * quat . z + invProj . m14 * quat . w ;
quat . w = invProj . m3 * quat . x + invProj . m7 * quat . y + invProj . m11 * quat . z + invProj . m15 * quat . w ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
quat . x = invView . m0 * quat . x + invView . m4 * quat . y + invView . m8 * quat . z + invView . m12 * quat . w ;
quat . y = invView . m1 * quat . x + invView . m5 * quat . y + invView . m9 * quat . z + invView . m13 * quat . w ;
quat . z = invView . m2 * quat . x + invView . m6 * quat . y + invView . m10 * quat . z + invView . m14 * quat . w ;
quat . w = invView . m3 * quat . x + invView . m7 * quat . y + invView . m11 * quat . z + invView . m15 * quat . w ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
vec . x / = quat . w ;
vec . y / = quat . w ;
vec . z / = quat . w ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
return vec ;
*/
/*
Vector3 worldPoint ;
// Transformation matrices
Matrix modelviewprojection ;
Quaternion quat ;
// Calculation for inverting a matrix, compute projection x modelview
modelviewprojection = MatrixMultiply ( view , proj ) ;
// Now compute the inverse of matrix A
MatrixInvert ( & modelviewprojection ) ;
// Transformation of normalized coordinates between -1 and 1
quat . x = ( ( source . x - ( float ) x ) / ( float ) width * 2.0 ) - 1.0f ;
quat . y = ( ( source . y - ( float ) y ) / ( float ) height * 2.0 ) - 1.0f ;
quat . z = 2.0 * source . z - 1.0 ;
quat . w = 1.0 ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Traspose quaternion and multiply
Quaternion result ;
result . x = modelviewprojection . m0 * quad . x + modelviewprojection . m4 * quad . y + modelviewprojection . m8 * quad . z + modelviewprojection . m12 * quad . w ;
result . y = modelviewprojection . m1 * quad . x + modelviewprojection . m5 * quad . y + modelviewprojection . m9 * quad . z + modelviewprojection . m13 * quad . w ;
result . z = modelviewprojection . m2 * quad . x + modelviewprojection . m6 * quad . y + modelviewprojection . m10 * quad . z + modelviewprojection . m14 * quad . w ;
result . w = modelviewprojection . m3 * quad . x + modelviewprojection . m7 * quad . y + modelviewprojection . m11 * quad . z + modelviewprojection . m15 * quad . w ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Invert
result . w = 1.0f / result . w ;
//if (quat.w == 0.0) return 0;
worldPoint . x = quat . x * quat . w ;
worldPoint . y = quat . y * quat . w ;
worldPoint . z = quat . z * quat . w ;
return worldPoint ;
*/
/*
// Needed Vectors
Vector3 normalDeviceCoordinates ;
Quaternion rayClip ;
Quaternion rayEye ;
Vector3 rayWorld ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Getting normal device coordinates
float x = ( 2.0 * mousePosition . x ) / GetScreenWidth ( ) - 1.0 ;
float y = 1.0 - ( 2.0 * mousePosition . y ) / GetScreenHeight ( ) ;
float z = 1.0 ;
normalDeviceCoordinates = ( Vector3 ) { x , y , z } ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
// Getting clip vector
rayClip = ( Quaternion ) { normalDeviceCoordinates . x , normalDeviceCoordinates . y , - 1 , 1 } ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
Matrix invProjection = projection ;
MatrixInvert ( & invProjection ) ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
rayEye = MatrixQuaternionMultiply ( invProjection , rayClip ) ;
rayEye = ( Quaternion ) { rayEye . x , rayEye . y , - 1 , 0 } ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
Matrix invModelview = modelview ;
MatrixInvert ( & invModelview ) ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
rayWorld = MatrixVector3Multiply ( invModelview , ( Vector3 ) { rayEye . x , rayEye . y , rayEye . z } ) ;
VectorNormalize ( & rayWorld ) ;
2015-04-06 15:02:29 +03:00
2015-03-02 22:52:58 +03:00
return rayWorld ;
*/
2015-04-06 15:02:29 +03:00
return ( Vector3 ) { 0 , 0 , 0 } ;
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-04-06 15:02:29 +03:00
unsigned int rlglLoadTexture ( void * data , int width , int height , int textureFormat , int mipmapCount , bool genMipmaps )
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
GLuint id ;
2015-04-06 15:02:29 +03:00
// TODO: Review compressed textures support by OpenGL version
/* (rlGetVersion() == OPENGL_11)
if ( ( textureFormat = = COMPRESSED_DXT1_RGB ) | | ( textureFormat = = COMPRESSED_DXT3_RGBA ) | | ( textureFormat = = COMPRESSED_DXT5_RGBA ) | |
( textureFormat = = COMPRESSED_ETC1_RGB8 ) | | ( textureFormat = = COMPRESSED_ETC2_RGB8 ) | | ( textureFormat = = COMPRESSED_ETC2_EAC_RGBA8 ) )
{
id = 0 ;
TraceLog ( WARNING , " GPU compressed textures not supported on OpenGL 1.1 " ) ;
return id ;
}
*/
glGenTextures ( 1 , & id ) ; // Generate Pointer to the texture
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
//glActiveTexture(GL_TEXTURE0);
glBindTexture ( GL_TEXTURE_2D , id ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_ES2)
2015-02-09 20:29:32 +03:00
// 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-04-06 15:02:29 +03:00
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
# 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
2014-03-25 15:40:35 +04:00
2014-04-19 18:36:49 +04:00
bool texIsPOT = false ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
// Check if width and height are power-of-two (POT)
if ( ( ( width > 0 ) & & ( ( width & ( width - 1 ) ) = = 0 ) ) & & ( ( height > 0 ) & & ( ( height & ( height - 1 ) ) = = 0 ) ) ) texIsPOT = true ;
2014-09-03 18:51:28 +04:00
2014-07-23 02:06:24 +04:00
if ( genMipmaps & & ! texIsPOT )
2014-04-19 18:36:49 +04:00
{
2014-09-17 00:51:31 +04:00
TraceLog ( WARNING , " [TEX ID %i] Texture is not power-of-two, mipmaps can not be generated " , id ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
genMipmaps = false ;
}
2014-09-03 18:51:28 +04:00
2015-04-06 15:02:29 +03:00
// TODO: Support mipmaps --> if (mipmapCount > 1)
2014-04-19 18:36:49 +04:00
// If mipmaps are being used, we configure mag-min filters accordingly
2015-02-09 20:29:32 +03:00
// NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so only GL_LINEAR or GL_NEAREST can be used
2014-04-19 18:36:49 +04:00
if ( genMipmaps )
{
// Trilinear filtering with mipmaps
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ; // Activate use of mipmaps (must be available)
}
else
{
// Not using mipmappings
2014-09-03 18:51:28 +04:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ; // Filter for pixel-perfect drawing, alternative: GL_LINEAR
2014-04-19 18:36:49 +04:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ; // Filter for pixel-perfect drawing, alternative: GL_LINEAR
}
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2014-04-19 18:36:49 +04:00
if ( genMipmaps )
{
2014-09-17 00:51:31 +04:00
TraceLog ( WARNING , " [TEX ID %i] Mipmaps generated manually on CPU side " , id ) ;
2014-04-19 18:36:49 +04:00
// Compute required mipmaps
// NOTE: data size is reallocated to fit mipmaps data
int mipmapCount = GenerateMipmaps ( data , width , height ) ;
int offset = 0 ;
int size = 0 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
int mipWidth = width ;
int mipHeight = height ;
2014-09-03 18:51:28 +04:00
// Load the mipmaps
2014-04-19 18:36:49 +04:00
for ( int level = 0 ; level < mipmapCount ; level + + )
{
glTexImage2D ( GL_TEXTURE_2D , level , GL_RGBA8 , mipWidth , mipHeight , 0 , GL_RGBA , GL_UNSIGNED_BYTE , data + offset ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
size = mipWidth * mipHeight * 4 ;
offset + = size ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
mipWidth / = 2 ;
mipHeight / = 2 ;
}
}
else glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , data ) ;
# endif
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
GLint swizzleMask [ ] = { GL_RED , GL_RED , GL_RED , 1.0f } ;
glTexParameteriv ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_RGBA , swizzleMask ) ;
TraceLog ( INFO , " Grayscale texture loaded and swizzled! " ) ;
} break ;
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 ;
case COMPRESSED_DXT1_RGB : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT1_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT3_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) ; break ;
case COMPRESSED_DXT5_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ; break ;
case COMPRESSED_ETC1_RGB : TraceLog ( WARNING , " ETC compression not supported " ) ; break ; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB8_ETC2 ) ; break ; //TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA8_ETC2_EAC ) ; break ; //TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
//case COMPRESSED_ASTC_RGBA_4x4: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default : TraceLog ( WARNING , " Texture format not recognized " ) ; break ;
2015-03-01 18:00:52 +03:00
}
2014-09-03 18:51:28 +04:00
2015-04-06 15:02:29 +03:00
if ( ( mipmapCount = = 1 ) & & ( genMipmaps ) )
{
glGenerateMipmap ( GL_TEXTURE_2D ) ; // Generate mipmaps automatically
TraceLog ( INFO , " [TEX ID %i] Mipmaps generated automatically for new texture " , id ) ;
}
# elif 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 ( textureFormat )
{
case UNCOMPRESSED_GRAYSCALE : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_LUMINANCE , width , height , 0 , GL_LUMINANCE , GL_UNSIGNED_BYTE , ( unsigned char * ) data ) ; break ;
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 ;
case COMPRESSED_DXT1_RGB : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT1_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGB_S3TC_DXT1_EXT ) ; break ;
case COMPRESSED_DXT3_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ) ; break ; // NOTE: Not supported by WebGL
case COMPRESSED_DXT5_RGBA : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ; break ; // NOTE: Not supported by WebGL
case COMPRESSED_ETC1_RGB : LoadCompressedTexture ( ( unsigned char * ) data , width , height , mipmapCount , GL_ETC1_RGB8_OES ) ; break ;
case COMPRESSED_ETC2_RGB : 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 : 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_ASTC_RGBA_4x4: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default : TraceLog ( WARNING , " Texture format not recognized " ) ; break ;
}
if ( ( mipmapCount = = 1 ) & & ( genMipmaps ) )
2014-04-19 18:36:49 +04:00
{
glGenerateMipmap ( GL_TEXTURE_2D ) ; // Generate mipmaps automatically
2014-09-17 00:51:31 +04:00
TraceLog ( INFO , " [TEX ID %i] Mipmaps generated automatically for new texture " , id ) ;
2014-04-19 18:36:49 +04:00
}
# endif
2014-03-25 15:40:35 +04:00
// At this point we have the image converted to texture and uploaded to GPU
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Unbind current texture
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-12-31 20:03:32 +03:00
TraceLog ( INFO , " [TEX ID %i] Texture created successfully (%ix%i) " , id , width , height ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
return id ;
}
2014-09-17 00:51:31 +04:00
// Load vertex data into a VAO (if supported) and VBO
Model rlglLoadModel ( VertexData mesh )
{
Model model ;
model . mesh = mesh ;
2015-04-06 15:02:29 +03:00
model . transform = MatrixIdentity ( ) ;
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
2015-04-06 15:02:29 +03:00
model . mesh . vaoId = 0 ; // Vertex Array Object
model . mesh . vboId [ 0 ] = 0 ; // Vertex position VBO
model . mesh . vboId [ 1 ] = 0 ; // Texcoords VBO
model . mesh . vboId [ 2 ] = 0 ; // Normals VBO
2015-03-01 18:00:52 +03:00
model . texture . id = 0 ; // No texture required
2015-04-06 15:02:29 +03:00
model . shader . id = 0 ; // No shader used
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-03-01 18:00:52 +03:00
model . texture . id = whiteTexture ; // Default whiteTexture
model . texture . width = 1 ; // Default whiteTexture width
model . texture . height = 1 ; // Default whiteTexture height
2014-09-17 00:51:31 +04:00
2015-03-01 18:00:52 +03:00
GLuint vaoModel = 0 ; // Vertex Array Objects (VAO)
GLuint vertexBuffer [ 3 ] ; // Vertex Buffer Objects (VBO)
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Quads VAO (Buffer A)
glGenVertexArrays ( 1 , & vaoModel ) ;
glBindVertexArray ( vaoModel ) ;
}
// Create buffers for our vertex data (positions, texcoords, normals)
glGenBuffers ( 3 , vertexBuffer ) ;
// Enable vertex attributes: position
glBindBuffer ( GL_ARRAY_BUFFER , vertexBuffer [ 0 ] ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh . vertexCount , mesh . vertices , GL_STATIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( simpleShader . vertexLoc ) ;
glVertexAttribPointer ( simpleShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-17 00:51:31 +04:00
// Enable vertex attributes: texcoords
glBindBuffer ( GL_ARRAY_BUFFER , vertexBuffer [ 1 ] ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 2 * mesh . vertexCount , mesh . texcoords , GL_STATIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( simpleShader . texcoordLoc ) ;
glVertexAttribPointer ( simpleShader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-17 00:51:31 +04:00
// Enable vertex attributes: normals
glBindBuffer ( GL_ARRAY_BUFFER , vertexBuffer [ 2 ] ) ;
2015-01-02 22:59:54 +03:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * mesh . vertexCount , mesh . normals , GL_STATIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( simpleShader . normalLoc ) ;
glVertexAttribPointer ( simpleShader . normalLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
model . shader = simpleShader ; // By default, simple shader will be used
2014-09-17 00:51:31 +04:00
2015-04-06 15:02:29 +03:00
model . mesh . vboId [ 0 ] = vertexBuffer [ 0 ] ; // Vertex position VBO
model . mesh . vboId [ 1 ] = vertexBuffer [ 1 ] ; // Texcoords VBO
model . mesh . vboId [ 2 ] = vertexBuffer [ 2 ] ; // Normals VBO
2015-02-02 02:57:08 +03:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
if ( vaoModel > 0 )
{
2015-04-06 15:02:29 +03:00
model . mesh . vaoId = vaoModel ;
2014-09-17 00:51:31 +04:00
TraceLog ( INFO , " [VAO ID %i] Model uploaded successfully to VRAM (GPU) " , vaoModel ) ;
}
else TraceLog ( WARNING , " Model could not be uploaded to VRAM (GPU) " ) ;
}
else
{
2015-04-06 15:02:29 +03:00
TraceLog ( INFO , " [VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU) " , model . mesh . vboId [ 0 ] , model . mesh . vboId [ 1 ] , model . mesh . vboId [ 2 ] ) ;
2014-09-17 00:51:31 +04:00
}
# endif
2014-04-09 22:25:26 +04:00
2014-09-17 00:51:31 +04:00
return model ;
}
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-02-02 02:57:08 +03:00
// Load a shader (vertex shader + fragment shader) from text data
unsigned int rlglLoadShader ( char * vShaderStr , char * fShaderStr )
{
unsigned int program ;
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 ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 02:57:08 +03:00
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 ) ;
glLinkProgram ( program ) ;
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 ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 02:57:08 +03:00
glDeleteProgram ( program ) ;
2015-04-06 15:02:29 +03:00
2015-02-02 02:57:08 +03:00
program = 0 ;
}
else TraceLog ( INFO , " [SHDR ID %i] Shader program loaded successfully " , program ) ;
glDeleteShader ( vertexShader ) ;
glDeleteShader ( fragmentShader ) ;
return program ;
}
2015-03-01 18:00:52 +03:00
# endif
2015-02-02 02:57:08 +03:00
2014-03-25 15:40:35 +04:00
// Read screen pixel data (color buffer)
unsigned char * rlglReadScreenPixels ( int width , int height )
{
unsigned char * screenData = ( unsigned char * ) malloc ( width * height * sizeof ( unsigned char ) * 4 ) ;
// 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 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Flip image vertically!
unsigned char * imgData = ( unsigned char * ) malloc ( width * height * sizeof ( unsigned char ) * 4 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
for ( int y = height - 1 ; y > = 0 ; y - - )
{
for ( int x = 0 ; x < ( width * 4 ) ; x + + )
{
imgData [ x + ( height - y - 1 ) * width * 4 ] = screenData [ x + ( y * width * 4 ) ] ;
}
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
free ( screenData ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
return imgData ; // NOTE: image data should be freed
}
2015-03-01 18:00:52 +03:00
// Load a shader (vertex shader + fragment shader) from text data
Shader LoadShader ( char * vsFileName , char * fsFileName )
2015-02-02 02:57:08 +03:00
{
2015-03-01 18:00:52 +03:00
Shader shader ;
2015-04-06 15:02:29 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2015-02-02 02:57:08 +03:00
// Shaders loading from external text file
char * vShaderStr = TextFileRead ( vsFileName ) ;
char * fShaderStr = TextFileRead ( fsFileName ) ;
2015-03-01 18:00:52 +03:00
shader . id = rlglLoadShader ( vShaderStr , fShaderStr ) ;
2015-02-02 02:57:08 +03:00
2015-03-01 18:00:52 +03:00
if ( shader . id ! = 0 ) TraceLog ( INFO , " [SHDR ID %i] Custom shader loaded successfully " , shader . id ) ;
else TraceLog ( WARNING , " [SHDR ID %i] Custom shader could not be loaded " , shader . id ) ;
2015-02-02 02:57:08 +03:00
// Shader strings must be freed
free ( vShaderStr ) ;
free ( fShaderStr ) ;
2015-03-01 18:00:52 +03:00
// Get handles to GLSL input attibute locations
//-------------------------------------------------------------------
shader . vertexLoc = glGetAttribLocation ( shader . id , " vertexPosition " ) ;
shader . texcoordLoc = glGetAttribLocation ( shader . id , " vertexTexCoord " ) ;
shader . normalLoc = glGetAttribLocation ( shader . id , " vertexNormal " ) ;
// NOTE: custom shader does not use colorLoc
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (vertex shader)
shader . modelviewLoc = glGetUniformLocation ( shader . id , " modelviewMatrix " ) ;
shader . projectionLoc = glGetUniformLocation ( shader . id , " projectionMatrix " ) ;
// Get handles to GLSL uniform locations (fragment shader)
shader . textureLoc = glGetUniformLocation ( shader . id , " texture0 " ) ;
shader . tintColorLoc = glGetUniformLocation ( shader . id , " tintColor " ) ;
//--------------------------------------------------------------------
2015-04-06 15:02:29 +03:00
# endif
2015-03-01 18:00:52 +03:00
return shader ;
2015-02-02 02:57:08 +03:00
}
// Link shader to model
2015-03-01 18:00:52 +03:00
void SetModelShader ( Model * model , Shader shader )
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)
2015-03-01 18:00:52 +03:00
model - > shader = shader ;
2015-04-06 15:02:29 +03:00
if ( vaoSupported ) glBindVertexArray ( model - > mesh . vaoId ) ;
2015-02-02 02:57:08 +03:00
// Enable vertex attributes: position
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model - > mesh . vboId [ 0 ] ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( shader . vertexLoc ) ;
glVertexAttribPointer ( shader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2015-02-02 02:57:08 +03:00
// Enable vertex attributes: texcoords
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model - > mesh . vboId [ 1 ] ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( shader . texcoordLoc ) ;
glVertexAttribPointer ( shader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
2015-02-02 02:57:08 +03:00
// Enable vertex attributes: normals
2015-04-06 15:02:29 +03:00
glBindBuffer ( GL_ARRAY_BUFFER , model - > mesh . vboId [ 2 ] ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( shader . normalLoc ) ;
glVertexAttribPointer ( shader . normalLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2015-02-02 02:57:08 +03:00
if ( vaoSupported ) glBindVertexArray ( 0 ) ; // Unbind VAO
2015-04-06 15:02:29 +03:00
# endif
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)
2014-09-17 00:51:31 +04:00
void PrintProjectionMatrix ( )
2014-03-25 15:40:35 +04:00
{
PrintMatrix ( projection ) ;
}
2014-09-17 00:51:31 +04:00
void PrintModelviewMatrix ( )
2014-03-25 15:40:35 +04:00
{
PrintMatrix ( modelview ) ;
}
# endif
//----------------------------------------------------------------------------------
// 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
2015-01-02 22:59:54 +03:00
// Load Shader (Vertex and Fragment)
// NOTE: This shader program is used only 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-09-03 18:51:28 +04:00
// NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2
2015-02-02 02:57:08 +03:00
// NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+
// Just defined #version 330 despite shader is #version 110
2014-03-25 15:40:35 +04:00
// Vertex shader directly defined, no external file required
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2015-04-06 15:02:29 +03:00
char vShaderStr [ ] = " #version 110 \n " // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
char vShaderStr [ ] = " #version 100 \n " // NOTE: Must be defined this way! 110 doesn't work!
# endif
2014-03-25 15:40:35 +04:00
" uniform mat4 projectionMatrix; \n "
" uniform mat4 modelviewMatrix; \n "
" attribute vec3 vertexPosition; \n "
" attribute vec2 vertexTexCoord; \n "
" attribute vec4 vertexColor; \n "
" varying vec2 fragTexCoord; \n "
" varying vec4 fragColor; \n "
" void main() \n "
" { \n "
" fragTexCoord = vertexTexCoord; \n "
" fragColor = vertexColor; \n "
" gl_Position = projectionMatrix * modelviewMatrix * 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
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_33)
2015-04-06 15:02:29 +03:00
char fShaderStr [ ] = " #version 110 \n " // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
char fShaderStr [ ] = " #version 100 \n " // NOTE: Must be defined this way! 110 doesn't work!
2014-12-09 15:21:55 +03:00
" precision mediump float; \n " // WebGL, required for emscripten
2014-09-17 00:51:31 +04:00
# endif
2014-03-25 15:40:35 +04:00
" uniform sampler2D texture0; \n "
" varying vec2 fragTexCoord; \n "
" varying vec4 fragColor; \n "
" void main() \n "
" { \n "
" gl_FragColor = texture2D(texture0, fragTexCoord) * fragColor; \n "
" } \n " ;
2015-03-01 18:00:52 +03:00
shader . id = rlglLoadShader ( vShaderStr , fShaderStr ) ;
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
2015-03-01 18:00:52 +03:00
// Get handles to GLSL input attibute locations
//-------------------------------------------------------------------
shader . vertexLoc = glGetAttribLocation ( shader . id , " vertexPosition " ) ;
shader . texcoordLoc = glGetAttribLocation ( shader . id , " vertexTexCoord " ) ;
shader . colorLoc = glGetAttribLocation ( shader . id , " vertexColor " ) ;
// NOTE: default shader does not use normalLoc
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (vertex shader)
shader . modelviewLoc = glGetUniformLocation ( shader . id , " modelviewMatrix " ) ;
shader . projectionLoc = glGetUniformLocation ( shader . id , " projectionMatrix " ) ;
2014-09-17 00:51:31 +04:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (fragment shader)
shader . textureLoc = glGetUniformLocation ( shader . id , " texture0 " ) ;
//--------------------------------------------------------------------
2014-09-03 18:51:28 +04:00
2015-03-01 18:00:52 +03:00
return shader ;
2014-03-25 15:40:35 +04:00
}
2015-01-02 22:59:54 +03:00
// Load Simple Shader (Vertex and Fragment)
// NOTE: This shader program is used to render models
2015-03-01 18:00:52 +03:00
static Shader LoadSimpleShader ( void )
2015-01-02 22:59:54 +03:00
{
2015-03-01 18:00:52 +03:00
Shader shader ;
2015-04-06 15:02:29 +03:00
2015-01-02 22:59:54 +03:00
// NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2
2015-02-02 02:57:08 +03:00
// NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+
// Just defined #version 330 despite shader is #version 110
2015-01-02 22:59:54 +03:00
// Vertex shader directly defined, no external file required
# if defined(GRAPHICS_API_OPENGL_33)
2015-02-02 02:57:08 +03:00
char vShaderStr [ ] = " #version 330 \n " // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
2015-01-02 22:59:54 +03:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
char vShaderStr [ ] = " #version 100 \n " // NOTE: Must be defined this way! 110 doesn't work!
# endif
" uniform mat4 projectionMatrix; \n "
" uniform mat4 modelviewMatrix; \n "
" attribute vec3 vertexPosition; \n "
" attribute vec2 vertexTexCoord; \n "
" attribute vec3 vertexNormal; \n "
" varying vec2 fragTexCoord; \n "
" void main() \n "
" { \n "
" fragTexCoord = vertexTexCoord; \n "
" gl_Position = projectionMatrix * modelviewMatrix * vec4(vertexPosition, 1.0); \n "
" } \n " ;
// Fragment shader directly defined, no external file required
# if defined(GRAPHICS_API_OPENGL_33)
2015-02-02 02:57:08 +03:00
char fShaderStr [ ] = " #version 330 \n " // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
2015-01-02 22:59:54 +03:00
# elif defined(GRAPHICS_API_OPENGL_ES2)
char fShaderStr [ ] = " #version 100 \n " // NOTE: Must be defined this way! 110 doesn't work!
2015-01-18 12:57:30 +03:00
" precision mediump float; \n " // precision required for OpenGL ES2 (WebGL)
2015-01-02 22:59:54 +03:00
# endif
" uniform sampler2D texture0; \n "
" varying vec2 fragTexCoord; \n "
2015-03-01 18:00:52 +03:00
" uniform vec4 tintColor; \n "
2015-01-02 22:59:54 +03:00
" void main() \n "
" { \n "
2015-03-01 18:00:52 +03:00
" gl_FragColor = texture2D(texture0, fragTexCoord) * tintColor; \n "
2015-01-02 22:59:54 +03:00
" } \n " ;
2015-03-01 18:00:52 +03:00
shader . id = rlglLoadShader ( vShaderStr , fShaderStr ) ;
if ( shader . id ! = 0 ) TraceLog ( INFO , " [SHDR ID %i] Simple shader loaded successfully " , shader . id ) ;
else TraceLog ( WARNING , " [SHDR ID %i] Simple shader could not be loaded " , shader . id ) ;
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL input attibute locations
//-------------------------------------------------------------------
shader . vertexLoc = glGetAttribLocation ( shader . id , " vertexPosition " ) ;
shader . texcoordLoc = glGetAttribLocation ( shader . id , " vertexTexCoord " ) ;
shader . normalLoc = glGetAttribLocation ( shader . id , " vertexNormal " ) ;
// NOTE: simple shader does not use colorLoc
2015-04-06 15:02:29 +03:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (vertex shader)
shader . modelviewLoc = glGetUniformLocation ( shader . id , " modelviewMatrix " ) ;
shader . projectionLoc = glGetUniformLocation ( shader . id , " projectionMatrix " ) ;
2014-09-03 18:51:28 +04:00
2015-03-01 18:00:52 +03:00
// Get handles to GLSL uniform locations (fragment shader)
shader . textureLoc = glGetUniformLocation ( shader . id , " texture0 " ) ;
shader . tintColorLoc = glGetUniformLocation ( shader . id , " tintColor " ) ;
//--------------------------------------------------------------------
2014-09-03 18:51:28 +04:00
2015-03-01 18:00:52 +03:00
return shader ;
2014-03-25 15:40:35 +04:00
}
2015-02-02 02:57:08 +03:00
// Read text file
2015-01-02 22:59:54 +03:00
// NOTE: text chars array should be freed manually
2014-12-31 20:03:32 +03:00
static char * TextFileRead ( char * fileName )
2014-03-25 15:40:35 +04:00
{
2014-12-31 20:03:32 +03:00
FILE * textFile ;
2014-04-09 22:25:26 +04:00
char * text = NULL ;
2014-03-25 15:40:35 +04:00
2015-02-02 02:57:08 +03:00
int count = 0 ;
2014-03-25 15:40:35 +04:00
2014-12-31 20:03:32 +03:00
if ( fileName ! = NULL )
2014-03-25 15:40:35 +04:00
{
2014-12-31 20:03:32 +03:00
textFile = fopen ( fileName , " rt " ) ;
2014-03-25 15:40:35 +04:00
2014-12-31 20:03:32 +03:00
if ( textFile ! = NULL )
2014-03-25 15:40:35 +04:00
{
2014-12-31 20:03:32 +03:00
fseek ( textFile , 0 , SEEK_END ) ;
count = ftell ( textFile ) ;
rewind ( textFile ) ;
2014-03-25 15:40:35 +04:00
2014-09-03 18:51:28 +04:00
if ( count > 0 )
2014-03-25 15:40:35 +04:00
{
2015-02-02 02:57:08 +03:00
text = ( char * ) malloc ( sizeof ( char ) * ( count + 1 ) ) ;
2014-12-31 20:03:32 +03:00
count = fread ( text , sizeof ( char ) , count , textFile ) ;
2014-04-09 22:25:26 +04:00
text [ count ] = ' \0 ' ;
2014-03-25 15:40:35 +04:00
}
2014-09-03 18:51:28 +04:00
2014-12-31 20:03:32 +03:00
fclose ( textFile ) ;
2014-03-25 15:40:35 +04:00
}
2014-12-31 20:03:32 +03:00
else TraceLog ( WARNING , " [%s] Text file could not be opened " , fileName ) ;
2014-03-25 15:40:35 +04:00
}
2015-02-02 02:57:08 +03:00
2014-04-09 22:25:26 +04:00
return text ;
2014-03-25 15:40:35 +04:00
}
// Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
2014-09-03 19:06:10 +04:00
static void InitializeBuffers ( void )
2014-03-25 15:40:35 +04:00
{
// Initialize lines 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
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 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Initialize triangles 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
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 ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Initialize quads arrays (vertex position, texcoord and 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
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
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
TraceLog ( INFO , " CPU buffers (lines, triangles, quads) initialized successfully " ) ;
2014-03-25 15:40:35 +04:00
}
// Initialize Vertex Array Objects (Contain VBO)
2015-03-01 18:00:52 +03:00
// NOTE: lines, triangles and quads buffers use defaultShader
2014-09-17 00:51:31 +04:00
static void InitializeBuffersGPU ( void )
2014-03-25 15:40:35 +04:00
{
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Lines VAO
glGenVertexArrays ( 1 , & vaoLines ) ;
glBindVertexArray ( vaoLines ) ;
}
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Create buffers for our vertex data
glGenBuffers ( 2 , linesBuffer ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Lines - Vertex positions buffer binding and attributes enable
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 0 ] ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 2 * MAX_LINES_BATCH , lines . vertices , GL_DYNAMIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Lines - colors buffer
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 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-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
glVertexAttribPointer ( defaultShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Lines VAO initialized successfully " , vaoLines ) ;
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i] Lines VBOs initialized successfully " , linesBuffer [ 0 ] , linesBuffer [ 1 ] ) ;
2014-09-03 18:51:28 +04:00
//--------------------------------------------------------------
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Triangles VAO
glGenVertexArrays ( 1 , & vaoTriangles ) ;
glBindVertexArray ( vaoTriangles ) ;
}
2015-02-02 02:57:08 +03:00
2014-03-25 15:40:35 +04:00
// Create buffers for our vertex data
glGenBuffers ( 2 , trianglesBuffer ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Enable vertex attributes
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 0 ] ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 3 * MAX_TRIANGLES_BATCH , triangles . vertices , GL_DYNAMIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 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-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
glVertexAttribPointer ( defaultShader . colorLoc , 4 , GL_UNSIGNED_BYTE , GL_TRUE , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Triangles VAO initialized successfully " , vaoTriangles ) ;
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i] Triangles VBOs initialized successfully " , trianglesBuffer [ 0 ] , trianglesBuffer [ 1 ] ) ;
2014-09-03 18:51:28 +04:00
//--------------------------------------------------------------
2014-09-17 00:51:31 +04:00
if ( vaoSupported )
{
// Initialize Quads VAO
glGenVertexArrays ( 1 , & vaoQuads ) ;
glBindVertexArray ( vaoQuads ) ;
}
2015-02-02 02:57:08 +03:00
2014-03-25 15:40:35 +04:00
// Create buffers for our vertex data
glGenBuffers ( 4 , quadsBuffer ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
// Enable vertex attributes
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 0 ] ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 3 * 4 * MAX_QUADS_BATCH , quads . vertices , GL_DYNAMIC_DRAW ) ;
2015-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . vertexLoc ) ;
glVertexAttribPointer ( defaultShader . vertexLoc , 3 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 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-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . texcoordLoc ) ;
glVertexAttribPointer ( defaultShader . texcoordLoc , 2 , GL_FLOAT , 0 , 0 , 0 ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 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-03-01 18:00:52 +03:00
glEnableVertexAttribArray ( defaultShader . colorLoc ) ;
glVertexAttribPointer ( defaultShader . 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
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , quadsBuffer [ 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
2014-09-17 00:51:31 +04:00
if ( vaoSupported ) TraceLog ( INFO , " [VAO ID %i] Quads VAO initialized successfully " , vaoQuads ) ;
else TraceLog ( INFO , " [VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Quads VBOs initialized successfully " , quadsBuffer [ 0 ] , quadsBuffer [ 1 ] , quadsBuffer [ 2 ] , quadsBuffer [ 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 ) ;
2014-03-25 15:40:35 +04:00
}
// Update 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)
2014-12-15 03:08:30 +03:00
// TODO: If no data changed on the CPU arrays --> No need to update GPU arrays every frame!
2014-09-03 19:06:10 +04:00
static void UpdateBuffers ( void )
2014-03-25 15:40:35 +04:00
{
2015-01-02 22:59:54 +03:00
if ( lines . vCounter > 0 )
{
// Activate Lines VAO
if ( vaoSupported ) glBindVertexArray ( vaoLines ) ;
2015-02-02 02:57:08 +03:00
2015-01-02 22:59:54 +03:00
// Lines - vertex positions buffer
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 0 ] ) ;
//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
glBindBuffer ( GL_ARRAY_BUFFER , linesBuffer [ 1 ] ) ;
//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
//--------------------------------------------------------------
2015-01-02 22:59:54 +03:00
if ( triangles . vCounter > 0 )
{
// Activate Triangles VAO
if ( vaoSupported ) glBindVertexArray ( vaoTriangles ) ;
2015-02-02 02:57:08 +03:00
2015-01-02 22:59:54 +03:00
// Triangles - vertex positions buffer
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 0 ] ) ;
//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
glBindBuffer ( GL_ARRAY_BUFFER , trianglesBuffer [ 1 ] ) ;
//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
//--------------------------------------------------------------
2015-01-02 22:59:54 +03:00
if ( quads . vCounter > 0 )
{
// Activate Quads VAO
if ( vaoSupported ) glBindVertexArray ( vaoQuads ) ;
// Quads - vertex positions buffer
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 0 ] ) ;
//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
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 1 ] ) ;
//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
glBindBuffer ( GL_ARRAY_BUFFER , quadsBuffer [ 2 ] ) ;
//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...
//triangles.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
// 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
}
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 ;
int size = baseWidth * baseHeight * 4 ; // Size in bytes (will include mipmaps...)
// 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
pixel * image = ( pixel * ) malloc ( width * height * sizeof ( pixel ) ) ;
pixel * mipmap = NULL ;
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)
static pixel * GenNextMipmap ( pixel * srcData , int srcWidth , int srcHeight )
{
int x2 , y2 ;
pixel prow , pcol ;
int width = srcWidth / 2 ;
int height = srcHeight / 2 ;
pixel * mipmap = ( pixel * ) malloc ( width * height * sizeof ( pixel ) ) ;
// 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
{
y2 = 2 * y ;
2014-09-03 18:51:28 +04:00
for ( int x = 0 ; x < width ; x + + )
2014-04-19 18:36:49 +04:00
{
x2 = 2 * x ;
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
2014-09-17 00:51:31 +04:00
# if defined(RLGL_STANDALONE)
2014-04-09 22:25:26 +04:00
typedef enum { INFO = 0 , ERROR , WARNING , DEBUG , OTHER } TraceLogType ;
// Output a trace log message
// NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning
void TraceLog ( int msgType , const char * text , . . . )
{
va_list args ;
va_start ( args , text ) ;
2014-09-03 18:51:28 +04:00
2014-04-09 22:25:26 +04:00
switch ( msgType )
{
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
}
2014-03-25 15:40:35 +04:00
# endif