raylib 1.1

View CHANGELOG for a detailed list of changes
This commit is contained in:
raysan5
2014-04-19 16:36:49 +02:00
parent 650a8f7f15
commit f06a15ac8b
17 changed files with 1573 additions and 1114 deletions

View File

@@ -31,10 +31,24 @@
#include <stdio.h> // Standard input / output lib
#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
// TODO: Security check in case multiple USE_OPENGL_* defined
// Security check in case no USE_OPENGL_* defined
#if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2)
#define USE_OPENGL_11
#endif
// Security check in case multiple USE_OPENGL_* defined
#ifdef USE_OPENGL_11
#ifdef USE_OPENGL_33
#undef USE_OPENGL_33
#endif
#ifdef USE_OPENGL_ES2
#undef USE_OPENGL_ES2
#endif
#endif
#ifdef USE_OPENGL_11
#include <GL/gl.h> // Extensions loading lib
#include <GL/gl.h> // Basic OpenGL include
#endif
#ifdef USE_OPENGL_33
@@ -42,7 +56,7 @@
#include <GL/glew.h> // Extensions loading lib
#endif
//#include "glad.h" // Extensions loading lib? --> REVIEW
//#include "glad.h" // Other extensions loading lib? --> REVIEW
#define USE_VBO_DOUBLE_BUFFERS // Enable VBO double buffers usage --> REVIEW!
@@ -56,18 +70,18 @@
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef struct {
int numQuads;
int texId;
} QuadsByTexture;
// Vertex buffer (position + color arrays)
// NOTE: Used for lines and triangles VAOs
typedef struct {
int vCounter;
int cCounter;
float *vertices; // 3 components per vertex
float *colors; // 4 components per vertex
} VertexPositionColorBuffer;
/*
// Vertex buffer (position + texcoords + color arrays)
// NOTE: Not used
typedef struct {
int vCounter;
int tcCounter;
@@ -76,8 +90,9 @@ typedef struct {
float *texcoords; // 2 components per vertex
float *colors; // 4 components per vertex
} VertexPositionColorTextureBuffer;
*/
/*
// Vertex buffer (position + texcoords + normals arrays)
// NOTE: Not used
typedef struct {
int vCounter;
int tcCounter;
@@ -86,7 +101,9 @@ typedef struct {
float *texcoords; // 2 components per vertex
float *normals; // 3 components per vertex
} VertexPositionTextureNormalBuffer;
*/
// Vertex buffer (position + texcoords + colors + indices arrays)
// NOTE: Used for quads VAO
typedef struct {
int vCounter;
int tcCounter;
@@ -97,12 +114,22 @@ typedef struct {
unsigned int *indices; // 6 indices per quad
} VertexPositionColorTextureIndexBuffer;
// Draw call type
// NOTE: Used to track required draw-calls, organized by texture
typedef struct {
GLuint texId;
int firstVertex; // Actually, when using glDrawElements, this parameter is useless..
int vCount;
GLuint textureId;
int vertexCount;
} DrawCall;
// 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;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
@@ -140,7 +167,6 @@ static GLuint quadsBuffer[4];
#ifdef USE_VBO_DOUBLE_BUFFERS
// Double buffering
// TODO: REVIEW -> Not getting any performance improvement... why?
static GLuint vaoQuadsB;
static GLuint quadsBufferB[4];
static bool useBufferB = false;
@@ -172,6 +198,11 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName);
static char *TextFileRead(char *fn);
#endif
#ifdef USE_OPENGL_11
static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight);
#endif
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix operations
//----------------------------------------------------------------------------------
@@ -216,7 +247,7 @@ void rlMatrixMode(int mode)
{
if (mode == RL_PROJECTION) currentMatrix = &projection;
else if (mode == RL_MODELVIEW) currentMatrix = &modelview;
//else if (mode == GL_TEXTURE) TODO: NEVER USED!
//else if (mode == RL_TEXTURE) // Not supported
currentMatrixMode = mode;
}
@@ -257,6 +288,7 @@ void rlLoadIdentity()
void rlTranslatef(float x, float y, float z)
{
Matrix mat = MatrixTranslate(x, y, z);
MatrixTranspose(&mat);
*currentMatrix = MatrixMultiply(*currentMatrix, mat);
}
@@ -264,13 +296,15 @@ void rlTranslatef(float x, float y, float z)
// Multiply the current matrix by a rotation matrix
void rlRotatef(float angleDeg, float x, float y, float z)
{
// TODO: Rotation matrix --> REVIEW!
// TODO: Support rotation in multiple axes
Matrix rot = MatrixIdentity();
if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
MatrixTranspose(&rot);
*currentMatrix = MatrixMultiply(*currentMatrix, rot);
}
@@ -278,6 +312,7 @@ void rlRotatef(float angleDeg, float x, float y, float z)
void rlScalef(float x, float y, float z)
{
Matrix mat = MatrixScale(x, y, z);
MatrixTranspose(&mat);
*currentMatrix = MatrixMultiply(*currentMatrix, mat);
}
@@ -356,12 +391,12 @@ void rlEnd()
{
if (useTempBuffer)
{
// IT WORKS!!! --> Refactor...
Matrix mat = *currentMatrix;
MatrixTranspose(&mat);
// 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
// Apply transformation matrix to all temp vertices
for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], mat);
for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], *currentMatrix);
// Deactivate tempBuffer usage to allow rlVertex3f do its job
useTempBuffer = false;
@@ -373,7 +408,7 @@ void rlEnd()
tempBufferCount = 0;
}
// Make sure vertexCounter is the same for vertices-texcoords-normals-colors
// Make sure vertexCount is the same for vertices-texcoords-normals-colors
// NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls.
switch (currentDrawMode)
{
@@ -490,7 +525,7 @@ void rlVertex3f(float x, float y, float z)
quads.vCounter++;
draws[drawsCounter - 1].vCount++;
draws[drawsCounter - 1].vertexCount++;
} break;
default: break;
@@ -596,13 +631,12 @@ void rlEnableTexture(unsigned int id)
#endif
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
if (draws[drawsCounter - 1].texId != id)
if (draws[drawsCounter - 1].textureId != id)
{
if (draws[drawsCounter - 1].vCount > 0) drawsCounter++;
if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++;
draws[drawsCounter - 1].texId = id;
draws[drawsCounter - 1].firstVertex = draws[drawsCounter - 2].vCount;
draws[drawsCounter - 1].vCount = 0;
draws[drawsCounter - 1].textureId = id;
draws[drawsCounter - 1].vertexCount = 0;
}
#endif
}
@@ -708,9 +742,7 @@ void rlglInit()
projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
// Get handles to GLSL uniform vars locations (fragment-shader)
textureLoc = glGetUniformLocation(shaderProgram, "texture0");
TraceLog(INFO, "Default shader loaded");
textureLoc = glGetUniformLocation(shaderProgram, "texture0");
InitializeBuffers(); // Init vertex arrays
InitializeVAOs(); // Init VBO and VAO
@@ -723,9 +755,9 @@ void rlglInit()
// Create default white texture for plain colors (required by shader)
unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
whiteTexture = rlglLoadTexture(1, 1, pixels);
whiteTexture = rlglLoadTexture(pixels, 1, 1, false);
if (whiteTexture != 0) TraceLog(INFO, "Base white texture successfully created, id: %i", whiteTexture);
if (whiteTexture != 0) TraceLog(INFO, "[ID %i] Base white texture created successfully", whiteTexture);
else TraceLog(WARNING, "Base white texture could not be created");
// Init draw calls tracking system
@@ -733,13 +765,12 @@ void rlglInit()
for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++)
{
draws[i].texId = 0;
draws[i].firstVertex = 0;
draws[i].vCount = 0;
draws[i].textureId = 0;
draws[i].vertexCount = 0;
}
drawsCounter = 1;
draws[drawsCounter - 1].texId = whiteTexture;
draws[drawsCounter - 1].textureId = whiteTexture;
}
// Vertex Buffer Object deinitialization (memory free)
@@ -789,6 +820,8 @@ void rlglClose()
// Free GPU texture
glDeleteTextures(1, &whiteTexture);
free(draws);
}
void rlglDraw()
@@ -823,7 +856,7 @@ void rlglDraw()
if (quads.vCounter > 0)
{
int numQuads = 0;
int quadsCount = 0;
int numIndicesToProcess = 0;
int indicesOffset = 0;
@@ -836,21 +869,21 @@ void rlglDraw()
glBindVertexArray(vaoQuads);
}
//TraceLog(INFO, "Draws required per frame: %i", drawsCounter);
//TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
for (int i = 0; i < drawsCounter; i++)
{
numQuads = draws[i].vCount/4;
numIndicesToProcess = numQuads*6; // Get number of Quads * 6 index by Quad
quadsCount = draws[i].vertexCount/4;
numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad
//TraceLog(INFO, "Quads to render: %i - Vertex Count: %i", numQuads, draws[i].vCount);
//TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount);
glBindTexture(GL_TEXTURE_2D, draws[i].texId);
glBindTexture(GL_TEXTURE_2D, draws[i].textureId);
// 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
glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset));
indicesOffset += draws[i].vCount/4*6;
indicesOffset += draws[i].vertexCount/4*6;
}
}
@@ -859,9 +892,8 @@ void rlglDraw()
// Reset draws counter
drawsCounter = 1;
draws[0].texId = whiteTexture;
draws[0].firstVertex = 0;
draws[0].vCount = 0;
draws[0].textureId = whiteTexture;
draws[0].vertexCount = 0;
// Reset vertex counters for next frame
lines.vCounter = 0;
@@ -883,52 +915,71 @@ void rlglDraw()
#endif // End for OpenGL 3.3+ and ES2 only functions
// Draw a 3d model
void rlglDrawModel(Model model, Vector3 position, float scale, bool wires)
void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires)
{
if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#ifdef USE_OPENGL_11
// NOTE: For models we use Vertex Arrays (OpenGL 1.1)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, model.textureId);
// NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
glVertexPointer(3, GL_FLOAT, 0, model.data.vertices); // Pointer to vertex coords array
glTexCoordPointer(2, GL_FLOAT, 0, model.data.texcoords); // Pointer to texture coords array
glNormalPointer(GL_FLOAT, 0, model.data.normals); // Pointer to normals array
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
//glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors); // Pointer to colors array (NOT USED)
//TraceLog(DEBUG, "Drawing model.mesh, VertexCount: %i", model.mesh.vertexCount);
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
//rlRotatef(rotation * GetFrameTime(), 0, 1, 0);
rlScalef(scale, scale, scale);
rlScalef(scale.x, scale.y, scale.z);
//rlRotatef(rotation, 0, 1, 0);
rlColor4ub(1.0f, 1.0f, 1.0f, 1.0f);
// TODO: If rotate in multiple axis, get rotation matrix and use rlMultMatrix()
glDrawArrays(GL_TRIANGLES, 0, model.data.numVertices);
rlColor4ub(color.r, color.g, color.b, color.a);
glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
rlPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
glUseProgram(shaderProgram); // Use our shader
Matrix modelview2 = MatrixMultiply(model.transform, modelview);
// Get transform matrix (rotation -> scale -> translation)
Matrix transform = MatrixTransform(position, rotation, scale);
Matrix modelviewworld = MatrixMultiply(transform, modelview);
// NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview2));
glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld));
glUniform1i(textureLoc, 0);
//TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount);
glBindVertexArray(model.vaoId);
//glBindTexture(GL_TEXTURE_2D, model.textureId);
// TODO: Update vertex color
glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*model.mesh.vertexCount, model.mesh.colors);
glBindTexture(GL_TEXTURE_2D, model.textureId);
glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
//glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
glBindVertexArray(0); // Unbind VAO
#endif
@@ -982,8 +1033,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Image is not unloaded, it should be done manually...
unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps)
{
glBindTexture(GL_TEXTURE_2D,0); // Free any old binding
@@ -996,27 +1046,82 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
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
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
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
// Trilinear filtering
//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)
//glGenerateMipmap(GL_TEXTURE_2D); // OpenGL 3.3!
#endif
// NOTE: Not using mipmappings (texture for 2D drawing)
// At this point we have the image converted to texture and uploaded to GPU
bool texIsPOT = false;
// 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;
if (!texIsPOT)
{
TraceLog(WARNING, "[ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
genMipmaps = false;
}
// If mipmaps are being used, we configure mag-min filters accordingly
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
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
}
#ifdef USE_OPENGL_11
if (genMipmaps)
{
TraceLog(WARNING, "[ID %i] Mipmaps generated manually on CPU side", id);
// Compute required mipmaps
// NOTE: data size is reallocated to fit mipmaps data
int mipmapCount = GenerateMipmaps(data, width, height);
int offset = 0;
int size = 0;
int mipWidth = width;
int mipHeight = height;
// Load the mipmaps
for (int level = 0; level < mipmapCount; level++)
{
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + offset);
size = mipWidth*mipHeight*4;
offset += size;
mipWidth /= 2;
mipHeight /= 2;
}
}
else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
#endif
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
if (genMipmaps)
{
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
TraceLog(INFO, "[ID %i] Mipmaps generated automatically for new texture", id);
}
#endif
// At this point we have the image converted to texture and uploaded to GPU
// Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0);
TraceLog(INFO, "New texture created, id: %i (%i x %i)", id, width, height);
TraceLog(INFO, "[ID %i] New texture created (%i x %i)", id, width, height);
return id;
}
@@ -1024,51 +1129,42 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
#ifdef USE_OPENGL_33
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed data from DDS file
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format)
// NOTE: Expected compressed image data and POT image
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat)
{
// Create one OpenGL texture
GLuint id;
int compFormat = 0;
glGenTextures(1, &id);
TraceLog(DEBUG, "Compressed texture width: %i", width);
TraceLog(DEBUG, "Compressed texture height: %i", height);
TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount);
TraceLog(DEBUG, "Compressed texture format: 0x%x", format);
switch(format)
{
case FOURCC_DXT1: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
case FOURCC_DXT3: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
case FOURCC_DXT5: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
default: compFormat = -1; break;
}
if (compFormat == -1)
TraceLog(DEBUG, "Compressed texture format: 0x%x", compFormat);
if (compFormat == 0)
{
TraceLog(WARNING, "Texture compressed format not recognized");
TraceLog(WARNING, "[ID %i] Texture compressed format not recognized", id);
id = 0;
}
else
{
glGenTextures(1, &id);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned int blockSize = (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
unsigned int offset = 0;
int blockSize = 0;
int offset = 0;
if (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) blockSize = 8;
else blockSize = 16;
// Load the mipmaps
for (int level = 0; level < mipmapCount && (width || height); level++)
{
unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
// NOTE: size specifies the number of bytes of image data (S3TC/DXTC)
unsigned int size = ((width + 3)/4)*((height + 3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);
@@ -1100,20 +1196,28 @@ unsigned int rlglLoadModel(VertexData mesh)
// Enable vertex attributes
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(vertexLoc);
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.numVertices, mesh.texcoords, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(texcoordLoc);
glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.normals, GL_STATIC_DRAW);
//glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);
//glEnableVertexAttribArray(normalLoc);
//glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
if (vaoModel > 0) TraceLog(INFO, "[ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel);
else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)");
return vaoModel;
}
#endif
@@ -1208,6 +1312,9 @@ static GLuint LoadDefaultShaders()
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
TraceLog(INFO, "[ID %i] Default vertex shader compiled succesfully", vertexShader);
TraceLog(INFO, "[ID %i] Default fragment shader compiled succesfully", fragmentShader);
program = glCreateProgram();
@@ -1218,6 +1325,8 @@ static GLuint LoadDefaultShaders()
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
TraceLog(INFO, "[ID %i] Default shader program loaded succesfully", program);
return program;
}
@@ -1245,6 +1354,9 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
TraceLog(INFO, "[ID %i] Vertex shader compiled succesfully", vertexShader);
TraceLog(INFO, "[ID %i] Fragment shader compiled succesfully", fragmentShader);
program = glCreateProgram();
@@ -1255,6 +1367,8 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
TraceLog(INFO, "[ID %i] Shader program loaded succesfully", program);
return program;
}
@@ -1364,7 +1478,8 @@ static void InitializeVAOs()
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
TraceLog(INFO, "[ID %i] Lines VAO successfully initialized", vaoLines);
//--------------------------------------------------------------
// Initialize Triangles VAO
@@ -1384,7 +1499,8 @@ static void InitializeVAOs()
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
TraceLog(INFO, "[ID %i] Triangles VAO successfully initialized", vaoTriangles);
//--------------------------------------------------------------
// Initialize Quads VAO (Buffer A)
@@ -1414,6 +1530,8 @@ static void InitializeVAOs()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
TraceLog(INFO, "[ID %i] Quads VAO successfully initialized", vaoQuads);
#ifdef USE_VBO_DOUBLE_BUFFERS
// Initialize Quads VAO (Buffer B)
glGenVertexArrays(1, &vaoQuadsB);
@@ -1442,11 +1560,9 @@ static void InitializeVAOs()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
TraceLog(INFO, "Using VBO double buffering");
TraceLog(INFO, "[ID %i] Second Quads VAO successfully initilized (double buffering)", vaoQuadsB);
#endif
TraceLog(INFO, "Vertex buffers successfully initialized (lines, triangles, quads)\n");
// Unbind the current VAO
glBindVertexArray(0);
}
@@ -1540,6 +1656,135 @@ static void UpdateBuffers()
glBindVertexArray(0);
}
#endif //defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
#ifdef USE_OPENGL_11
// 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;
TraceLog(DEBUG, "Next mipmap size: %i x %i", width, height);
mipmapCount++;
size += (width*height*4); // Add mipmap size (in bytes)
}
TraceLog(DEBUG, "Total mipmaps required: %i", mipmapCount);
TraceLog(DEBUG, "Total size of data required: %i", size);
unsigned char *temp = realloc(data, size);
if (temp != NULL) data = temp;
else TraceLog(WARNING, "Mipmaps required memory could not be allocated");
width = baseWidth;
height = baseHeight;
size = (width*height*4);
// 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++;
}
TraceLog(DEBUG, "Mipmap base (%i, %i)", width, height);
for (int mip = 1; mip < mipmapCount; mip++)
{
mipmap = GenNextMipmap(image, width, height);
offset += (width*height*4); // Size of last mipmap
j = 0;
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;
data[offset + i + 3] = mipmap[j].a;
j++;
}
free(image);
image = mipmap;
mipmap = NULL;
}
free(mipmap); // free mipmap data
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)
for (int y = 0; y < height; y++)
{
y2 = 2 * y;
for (int x = 0; x < width; x++)
{
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;
}
}
TraceLog(DEBUG, "Mipmap generated successfully (%i, %i)", width, height);
return mipmap;
}
#endif
#ifdef RLGL_STANDALONE
@@ -1555,10 +1800,10 @@ void TraceLog(int msgType, const char *text, ...)
switch(msgType)
{
case 0: fprintf(stdout, "INFO: "); break;
case 1: fprintf(stdout, "ERROR: "); break;
case 2: fprintf(stdout, "WARNING: "); break;
case 3: fprintf(logstream, "DEBUG: "); break;
case INFO: fprintf(stdout, "INFO: "); break;
case ERROR: fprintf(stdout, "ERROR: "); break;
case WARNING: fprintf(stdout, "WARNING: "); break;
case DEBUG: fprintf(stdout, "DEBUG: "); break;
default: break;
}
@@ -1567,6 +1812,6 @@ void TraceLog(int msgType, const char *text, ...)
va_end(args);
if (msgType == 1) exit(1);
if (msgType == ERROR) exit(1);
}
#endif