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
//----------------------------------------------------------------------------------
// 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
static GLuint fbo , fboColorTexture , fboDepthTexture , fboShader = 0 ;
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 ) ;
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
2014-03-25 15:40:35 +04:00
Matrix rot = MatrixIdentity ( ) ;
2014-09-03 18:51:28 +04:00
2015-02-02 02:57:08 +03:00
// OPTION 1: It works...
2014-03-25 15:40:35 +04: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...
//Vector3 vec = (Vector3){ 0, 1, 0 };
2014-12-09 15:21:55 +03:00
//VectorNormalize(&vec);
2014-12-16 13:15:56 +03:00
//rot = MatrixFromAxisAngle(vec, angleDeg*DEG2RAD); // Working?
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
2014-04-19 18:36:49 +04:00
MatrixTranspose ( & rot ) ;
2014-09-03 18:51:28 +04:00
2014-03-25 15:40:35 +04:00
* currentMatrix = MatrixMultiply ( * currentMatrix , rot ) ;
}
// 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-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
// Unload shader from GPU memory
void rlDeleteShader ( unsigned int id )
{
glDeleteProgram ( id ) ;
}
void rlEnableFBO ( void )
{
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
}
2015-03-01 18:00:52 +03:00
# endif
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
*/
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-03-01 18:00:52 +03:00
whiteTexture = rlglLoadTexture ( pixels , 1 , 1 , R8G8B8A8 , 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-02-02 02:57:08 +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-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
// Init postpro system
void rlglInitPostpro ( void )
{
// 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 ) ;
// 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 ) ;
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 ) ;
fboShader = 0 ;
// TODO: Init simple quad VAO and data here?
}
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
// 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-02-02 02:57:08 +03:00
if ( fbo ! = 0 ) glDeleteFramebuffers ( 1 , & fbo ) ;
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-02-02 02:57:08 +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-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
void rlglDrawPostpro ( unsigned int shaderId )
{
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
// TODO: Draw screen quad with texture
/*
const float quadPositions [ ] = { 1.0 , 1.0 , 0.0 , - 1.0 , 1.0 , 0.0 , - 1.0 , - 1.0 , 0.0 ,
- 1.0 , - 1.0 , 0.0 , 1.0 , - 1.0 , 0.0 , 1.0 , 1.0 , 0.0 } ;
const float quadTexcoords [ ] = { 1.0 , 1.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 } ;
glBindBuffer ( GL_ARRAY_BUFFER , quadVbo ) ;
glVertexAttribPointer ( ATTRIB_VERTEX , 3 , GL_FLOAT , GL_FALSE , 3 * sizeof ( float ) , quadPositions ) ;
glVertexAttribPointer ( ATTRIB_TEXCOORD0 , 2 , GL_FLOAT , GL_FALSE , 2 * sizeof ( float ) , quadTexcoords ) ;
glEnableVertexAttribArray ( ATTRIB_VERTEX ) ;
glEnableVertexAttribArray ( ATTRIB_TEXCOORD0 ) ;
glBindTexture ( GL_TEXTURE_2D , fboColorTexture ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 2 * 3 ) ;
// Quad render using triangle strip
glBindBuffer ( GL_ARRAY_BUFFER , uiVBO [ 1 ] ) ;
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 0 , 0 ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glUseProgram ( 0 ) ;
*/
rlEnableTexture ( fboColorTexture ) ;
rlPushMatrix ( ) ;
rlBegin ( RL_QUADS ) ;
rlColor4ub ( 255 , 255 , 255 , 255 ) ;
rlNormal3f ( 0.0f , 0.0f , 1.0f ) ; // Normal vector pointing towards viewer
// Bottom-left corner for texture and quad
rlTexCoord2f ( 0.0f , 1.0f ) ;
rlVertex2f ( 0.0f , 0.0f ) ;
// Bottom-right corner for texture and quad
rlTexCoord2f ( 0.0f , 0.0f ) ;
rlVertex2f ( 0.0f , GetScreenHeight ( ) ) ;
// Top-right corner for texture and quad
rlTexCoord2f ( 1.0f , 0.0f ) ;
rlVertex2f ( GetScreenWidth ( ) , GetScreenHeight ( ) ) ;
// Top-left corner for texture and quad
rlTexCoord2f ( 1.0f , 1.0f ) ;
rlVertex2f ( GetScreenWidth ( ) , 0.0f ) ;
rlEnd ( ) ;
rlPopMatrix ( ) ;
fboShader = shaderId ;
rlglDraw ( ) ;
}
2015-03-01 18:00:52 +03:00
# endif
2015-02-02 02:57:08 +03:00
2014-04-09 22:25:26 +04:00
// Draw a 3d model
2014-04-19 18:36:49 +04:00
void rlglDrawModel ( Model model , Vector3 position , Vector3 rotation , 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 ) ;
glBindTexture ( GL_TEXTURE_2D , model . textureId ) ;
// 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 ) ;
2014-10-17 23:11:58 +04:00
rlRotatef ( rotation . y , 0 , 1 , 0 ) ;
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
2014-12-31 20:03:32 +03:00
VectorScale ( & rotation , DEG2RAD ) ;
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
// 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 )
{
glBindVertexArray ( model . vaoId ) ;
}
else
{
// Bind model VBOs data
glBindBuffer ( GL_ARRAY_BUFFER , model . 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
glBindBuffer ( GL_ARRAY_BUFFER , model . 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
2014-09-17 00:51:31 +04:00
glBindBuffer ( GL_ARRAY_BUFFER , model . 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
2014-09-17 00:51:31 +04: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
}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
2015-03-01 18:00:52 +03:00
unsigned int rlglLoadTexture ( unsigned char * data , int width , int height , int colorMode , bool genMipmaps )
2014-03-25 15:40:35 +04:00
{
glBindTexture ( GL_TEXTURE_2D , 0 ) ; // Free any old binding
GLuint 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-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
2014-03-25 15:40:35 +04:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ; // Set texture to repead on x-axis
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ; // Set texture to repead on y-axis
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
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-02-09 20:29:32 +03:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
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
2014-12-09 15:21:55 +03:00
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // OpenGL
2015-03-01 18:00:52 +03:00
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // WebGL
2015-02-09 20:29:32 +03:00
// TODO: Add support for multiple color modes (16bit color modes and grayscale)
// Ref: https://www.khronos.org/opengles/sdk/docs/man3/html/glTexImage2D.xhtml
// On WebGL, internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
// (sized)internalFormat format type
// GL_R GL_RED GL_UNSIGNED_BYTE
// GL_RGB565 GL_RGB GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5
// GL_RGB5_A1 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_5_5_1
// GL_RGBA4 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
2015-03-01 18:00:52 +03:00
switch ( colorMode )
{
case GRAYSCALE : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_R , width , height , 0 , GL_RED , GL_UNSIGNED_BYTE , data ) ; break ;
case R5G6B5 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB565 , width , height , 0 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , data ) ; break ;
case R8G8B8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB8 , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , data ) ; break ;
case R5G5B5A1 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB5_A1 , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 , data ) ; break ;
case R4G4B4A4 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA4 , width , height , 0 , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 , data ) ; break ;
case R8G8B8A8 : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , data ) ; break ;
default : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , data ) ; break ;
}
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( genMipmaps )
{
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 ;
# if defined(GRAPHICS_API_OPENGL_11)
2015-03-01 18:00:52 +03:00
model . texture . id = 0 ; // No texture required
2014-09-17 00:51:31 +04:00
model . vaoId = 0 ; // Vertex Array Object
model . vboId [ 0 ] = 0 ; // Vertex position VBO
model . vboId [ 1 ] = 0 ; // Texcoords VBO
2015-01-02 22:59:54 +03:00
model . vboId [ 2 ] = 0 ; // Normals VBO
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 ) ;
model . shader = simpleShader ; // By default, simple shader will be used
2014-09-17 00:51:31 +04:00
2015-01-02 22:59:54 +03:00
model . vboId [ 0 ] = vertexBuffer [ 0 ] ; // Vertex position VBO
model . vboId [ 1 ] = vertexBuffer [ 1 ] ; // Texcoords VBO
model . 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 )
{
model . vaoId = vaoModel ;
TraceLog ( INFO , " [VAO ID %i] Model uploaded successfully to VRAM (GPU) " , vaoModel ) ;
}
else TraceLog ( WARNING , " Model could not be uploaded to VRAM (GPU) " ) ;
}
else
{
TraceLog ( INFO , " [VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU) " , model . vboId [ 0 ] , model . vboId [ 1 ] , model . vboId [ 2 ] ) ;
}
# 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
// Convert image data to OpenGL texture (returns OpenGL valid Id)
2014-04-19 18:36:49 +04:00
// NOTE: Expected compressed image data and POT image
unsigned int rlglLoadCompressedTexture ( unsigned char * data , int width , int height , int mipmapCount , int compFormat )
2014-04-09 22:25:26 +04:00
{
GLuint id ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
# if defined(GRAPHICS_API_OPENGL_11)
id = 0 ;
TraceLog ( WARNING , " GPU compressed textures not supported on OpenGL 1.1 " ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
# elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
2014-04-09 22:25:26 +04:00
TraceLog ( DEBUG , " Compressed texture width: %i " , width ) ;
TraceLog ( DEBUG , " Compressed texture height: %i " , height ) ;
TraceLog ( DEBUG , " Compressed texture mipmap levels: %i " , mipmapCount ) ;
2014-04-19 18:36:49 +04:00
TraceLog ( DEBUG , " Compressed texture format: 0x%x " , compFormat ) ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( compFormat = = 0 )
2014-04-09 22:25:26 +04:00
{
id = 0 ;
2014-09-17 00:51:31 +04:00
TraceLog ( WARNING , " Texture compressed format not recognized " , id ) ;
2014-04-09 22:25:26 +04:00
}
else
{
2014-09-17 00:51:31 +04:00
glGenTextures ( 1 , & id ) ;
2014-04-09 22:25:26 +04:00
// Bind the texture
glBindTexture ( GL_TEXTURE_2D , id ) ;
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
// Set texture parameters
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
// If mipmaps are being used, we configure mag-min filters accordingly
if ( mipmapCount > 1 )
{
// 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
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ; // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ; // Filter for pixel-perfect drawing, alternative: GL_LINEAR
}
2014-04-19 18:36:49 +04:00
int blockSize = 0 ;
int offset = 0 ;
2014-09-03 18:51:28 +04:00
2014-04-19 18:36:49 +04:00
if ( compFormat = = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) blockSize = 8 ;
else blockSize = 16 ;
2014-09-03 18:51:28 +04:00
// Load the mipmaps
for ( int level = 0 ; level < mipmapCount & & ( width | | height ) ; level + + )
{
2014-09-17 00:51:31 +04:00
unsigned int size = 0 ;
2014-09-03 18:51:28 +04:00
2014-09-17 00:51:31 +04:00
// NOTE: size specifies the number of bytes of image data (S3TC/DXTC)
if ( compFormat = = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) size = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize ; // S3TC/DXTC
# if defined(GRAPHICS_API_OPENGL_ES2)
else if ( compFormat = = GL_ETC1_RGB8_OES ) size = 8 * ( ( width + 3 ) > > 2 ) * ( ( height + 3 ) > > 2 ) ; // ETC1
# endif
2014-09-03 18:51:28 +04:00
glCompressedTexImage2D ( GL_TEXTURE_2D , level , compFormat , width , height , 0 , size , data + offset ) ;
2014-04-09 22:25:26 +04:00
offset + = size ;
2014-09-03 18:51:28 +04:00
width / = 2 ;
height / = 2 ;
2014-04-09 22:25:26 +04:00
// Security check for NPOT textures
if ( width < 1 ) width = 1 ;
if ( height < 1 ) height = 1 ;
}
}
2014-09-17 00:51:31 +04:00
# endif
2014-04-09 22:25:26 +04:00
return id ;
}
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 ) ;
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 ) ;
glDeleteProgram ( program ) ;
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
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// 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-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-02-02 02:57:08 +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 " ) ;
//--------------------------------------------------------------------
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-03-01 18:00:52 +03:00
model - > shader = shader ;
2015-02-02 02:57:08 +03:00
if ( vaoSupported ) glBindVertexArray ( model - > vaoId ) ;
// Enable vertex attributes: position
glBindBuffer ( GL_ARRAY_BUFFER , model - > 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
glBindBuffer ( GL_ARRAY_BUFFER , model - > 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
glBindBuffer ( GL_ARRAY_BUFFER , model - > 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
}
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)
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 ;
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-02-02 02:57:08 +03:00
char vShaderStr [ ] = " #version 330 \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-02-02 02:57:08 +03:00
char fShaderStr [ ] = " #version 330 \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 ) ;
// 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
// 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-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 ) ;
// 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
// 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