aboutsummaryrefslogtreecommitdiff
path: root/src/rlgl.c
diff options
context:
space:
mode:
authorraysan5 <raysan5@gmail.com>2014-04-19 16:36:49 +0200
committerraysan5 <raysan5@gmail.com>2014-04-19 16:36:49 +0200
commitf06a15ac8b3fe92d101ae795225fbf56fa670dba (patch)
treecdfba90ee24fd078a15c89d8753ee3e11d8e229b /src/rlgl.c
parent650a8f7f159d3ce2addb1b0fdb31c3f460005391 (diff)
downloadraylib-f06a15ac8b3fe92d101ae795225fbf56fa670dba.tar.gz
raylib-f06a15ac8b3fe92d101ae795225fbf56fa670dba.zip
raylib 1.1
View CHANGELOG for a detailed list of changes
Diffstat (limited to 'src/rlgl.c')
-rw-r--r--src/rlgl.c473
1 files changed, 359 insertions, 114 deletions
diff --git a/src/rlgl.c b/src/rlgl.c
index 8a758a22..34b45ba2 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -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()
+
+ rlColor4ub(color.r, color.g, color.b, color.a);
- glDrawArrays(GL_TRIANGLES, 0, model.data.numVertices);
+ 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 \ No newline at end of file