Big batch of changes! Check description:

Support multiple texture formats (uncompressed and compressed)
Postprocessing shaders support
Model struct redefined and improved
Extended loading functions for Textures and Models
Simplified functions: DrawPlane(), DrawQuad()
Deleted functions: DrawPlaneEx(), DrawGizmoEx()
Now Text module only depends on Textures module
Shapes: Reviewed functions to low lines/triangles usage
Removed useless tabs and spaces around code
This commit is contained in:
raysan5 2015-04-06 14:02:29 +02:00
parent 2b4a1f295a
commit a632a04a30
9 changed files with 662 additions and 723 deletions

View File

@ -267,7 +267,6 @@ static bool cameraUseGravity = true;
// Shaders variables
static bool enabledPostpro = false;
static unsigned int fboShader = 0;
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
@ -327,7 +326,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
// Initialize Window and Graphics Context (OpenGL)
void InitWindow(int width, int height, const char *title)
{
TraceLog(INFO, "Initializing raylib (v1.2.2)");
TraceLog(INFO, "Initializing raylib (v1.3.0)");
// Store window title (could be useful...)
windowTitle = title;
@ -366,7 +365,7 @@ void InitWindow(int width, int height, const char *title)
// Android activity initialization
void InitWindow(int width, int height, struct android_app *state)
{
TraceLog(INFO, "Initializing raylib (v1.2.2)");
TraceLog(INFO, "Initializing raylib (v1.3.0)");
app_dummy();
@ -555,8 +554,7 @@ void EndDrawing(void)
{
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
// TODO: Set postprocessing shader to be passed: SetPostproShader()?
if (enabledPostpro) rlglDrawPostpro(fboShader); // Draw postprocessing effect (shader)
if (enabledPostpro) rlglDrawPostpro(); // Draw postprocessing effect (shader)
SwapBuffers(); // Copy back buffer to front buffer
PollInputEvents(); // Poll user events
@ -1114,16 +1112,23 @@ Vector2 GetTouchPosition(void)
}*/
#endif
void InitPostShader(void)
// Set postprocessing shader
void SetPostproShader(Shader shader)
{
if (rlGetVersion() == OPENGL_11) TraceLog(WARNING, "Postprocessing shaders not supported on OpenGL 1.1");
else
{
if (!enabledPostpro)
{
rlglInitPostpro();
enabledPostpro = true;
rlglInitPostpro();
rlglSetPostproShader(shader);
}
void SetPostShader(unsigned int shader)
else
{
fboShader = shader;
rlglSetPostproShader(shader);
}
}
}
//----------------------------------------------------------------------------------

View File

@ -444,48 +444,17 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
rlPopMatrix();
}
// Draw a quad
void DrawQuad(Vector3 vertices[4], Vector2 textcoords[4], Vector3 normals[4], Color colors[4])
{
rlBegin(RL_QUADS);
rlColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a);
rlNormal3f(normals[0].x, normals[0].y, normals[0].z);
rlTexCoord2f(textcoords[0].x, textcoords[0].y);
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a);
rlNormal3f(normals[1].x, normals[1].y, normals[1].z);
rlTexCoord2f(textcoords[1].x, textcoords[1].y);
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
rlColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a);
rlNormal3f(normals[2].x, normals[2].y, normals[2].z);
rlTexCoord2f(textcoords[2].x, textcoords[2].y);
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
rlColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a);
rlNormal3f(normals[3].x, normals[3].y, normals[3].z);
rlTexCoord2f(textcoords[3].x, textcoords[3].y);
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
rlEnd();
}
// Draw a plane
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
{
// NOTE: QUADS usage require defining a texture on OpenGL 3.3+
if (rlGetVersion() != OPENGL_11) rlEnableTexture(whiteTexture); // Default white texture
// NOTE: Plane is always created on XZ ground and then rotated
// NOTE: Plane is always created on XZ ground
rlPushMatrix();
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
rlScalef(size.x, 1.0f, size.y);
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
rlRotatef(rotation.x, 1, 0, 0);
rlRotatef(rotation.y, 0, 1, 0);
rlRotatef(rotation.z, 0, 0, 1);
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 1.0f, 0.0f);
@ -499,53 +468,23 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
if (rlGetVersion() != OPENGL_11) rlDisableTexture();
}
// Draw a plane with divisions
// TODO: Test this function
void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color)
// Draw a quad
void DrawQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Color color)
{
float quadWidth = size.x / slicesX;
float quadLenght = size.y / slicesZ;
float texPieceW = 1 / size.x;
float texPieceH = 1 / size.y;
// NOTE: Plane is always created on XZ ground and then rotated
rlPushMatrix();
rlTranslatef(-size.x / 2, 0.0f, -size.y / 2);
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
rlRotatef(rotation.x, 1, 0, 0);
rlRotatef(rotation.y, 0, 1, 0);
rlRotatef(rotation.z, 0, 0, 1);
// TODO: Calculate normals from vertex position
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 1.0f, 0.0f);
//rlNormal3f(0.0f, 0.0f, 0.0f);
for (int z = 0; z < slicesZ; z++)
{
for (int x = 0; x < slicesX; x++)
{
// Draw the plane quad by quad (with textcoords)
rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH);
rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght);
rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH);
rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght);
rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH + texPieceH);
rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH + texPieceH);
rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
}
}
rlVertex3f(v1.x, v1.y, v1.z);
rlVertex3f(v2.x, v2.y, v2.z);
rlVertex3f(v3.x, v3.y, v3.z);
rlVertex3f(v4.x, v4.y, v4.z);
rlEnd();
rlPopMatrix();
}
// Draw a ray line
void DrawRay(Ray ray, Color color)
{
float scale = 10000;
@ -615,76 +554,7 @@ void DrawGizmo(Vector3 position)
rlPopMatrix();
}
void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale)
{
// NOTE: RGB = XYZ
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
rlScalef(scale, scale, scale);
rlRotatef(rotation.y, 0, 1, 0);
rlBegin(RL_LINES);
// X Axis
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x, position.y, position.z);
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1, position.y, position.z);
// ArrowX
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1.1, position.y, position.z);
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + .9, position.y, position.z + .1);
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1.1, position.y, position.z);
rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + .9, position.y, position.z - .1);
// Y Axis
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y, position.z);
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1, position.z);
// ArrowY
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1.1, position.z);
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + .1, position.y + .9, position.z);
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1.1, position.z);
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x - .1, position.y + .9, position.z);
// Z Axis
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z);
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1);
// ArrowZ
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1.1);
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + .1, position.y, position.z - .9);
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1.1);
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9);
// Extra
int n = 3;
// X Axis
for (int i=0; i < 360; i += 6)
{
rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n);
rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n);
}
// Y Axis
for (int i=0; i < 360; i += 6)
{
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, 0, position.y + cos(DEG2RAD*i) * scale/n);
rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, 0, position.y + cos(DEG2RAD*(i+6)) * scale/n);
}
// Z Axis
for (int i=0; i < 360; i += 6)
{
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0);
rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0);
}
rlEnd();
rlPopMatrix();
}
// Load a 3d model
// Load a 3d model (from file)
Model LoadModel(const char *fileName)
{
VertexData vData;
@ -694,6 +564,7 @@ Model LoadModel(const char *fileName)
// NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
Model model = rlglLoadModel(vData); // Upload vertex data to GPU
// Now that vertex data is uploaded to GPU, we can free arrays
@ -708,6 +579,19 @@ Model LoadModel(const char *fileName)
return model;
}
// Load a 3d model (from vertex data)
Model LoadModelEx(VertexData data)
{
Model model;
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
model = rlglLoadModel(data); // Upload vertex data to GPU
// NOTE: Vertex data is managed externally, must be deallocated manually
return model;
}
// Load a heightmap image as a 3d model
Model LoadHeightmap(Image heightmap, float maxHeight)
{
@ -1208,11 +1092,11 @@ void UnloadModel(Model model)
free(model.mesh.normals);
}
rlDeleteBuffers(model.vboId[0]);
rlDeleteBuffers(model.vboId[1]);
rlDeleteBuffers(model.vboId[2]);
rlDeleteBuffers(model.mesh.vboId[0]);
rlDeleteBuffers(model.mesh.vboId[1]);
rlDeleteBuffers(model.mesh.vboId[2]);
rlDeleteVertexArrays(model.vaoId);
rlDeleteVertexArrays(model.mesh.vaoId);
rlDeleteTextures(model.texture.id);
rlDeleteShader(model.shader.id);
}
@ -1227,17 +1111,15 @@ void SetModelTexture(Model *model, Texture2D texture)
void DrawModel(Model model, Vector3 position, float scale, Color tint)
{
Vector3 vScale = { scale, scale, scale };
float rotAngle = 0.0f;
Vector3 rotAxis = { 0, 0, 0 };
Vector3 rotationAxis = { 0, 0, 0 };
rlglDrawModel(model, position, rotAngle, rotAxis, vScale, tint, false);
DrawModelEx(model, position, 0.0f, rotationAxis, vScale, tint);
}
// Draw a model with extended parameters
void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint)
{
// NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
rlglDrawModel(model, position, rotationAngle, rotationAxis, scale, tint, false);
}
@ -1245,10 +1127,9 @@ void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rot
void DrawModelWires(Model model, Vector3 position, float scale, Color color)
{
Vector3 vScale = { scale, scale, scale };
float rotAngle = 0.0f;
Vector3 rotAxis = { 0, 0, 0 };
Vector3 rotationAxis = { 0, 0, 0 };
rlglDrawModel(model, position, rotAngle, rotAxis, vScale, color, true);
rlglDrawModel(model, position, 0.0f, rotationAxis, vScale, color, true);
}
// Draw a billboard

View File

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* raylib 1.2 (www.raylib.com)
* raylib 1.3.0 (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming
*
@ -199,6 +199,14 @@ typedef struct Vector3 {
float z;
} Vector3;
// Matrix type (OpenGL style 4x4 - right handed, column major)
typedef struct Matrix {
float m0, m4, m8, m12;
float m1, m5, m9, m13;
float m2, m6, m10, m14;
float m3, m7, m11, m15;
} Matrix;
// Color type, RGBA (32bit)
typedef struct Color {
unsigned char r;
@ -258,12 +266,15 @@ typedef struct Camera {
typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode;
// Vertex data definning a mesh
// NOTE: If using OpenGL 1.1, data loaded in CPU; if OpenGL 3.3+ data loaded in GPU (vaoId)
typedef struct VertexData {
int vertexCount;
float *vertices; // 3 components per vertex
float *texcoords; // 2 components per vertex
float *normals; // 3 components per vertex
unsigned char *colors; // 4 components per vertex
unsigned int vaoId;
unsigned int vboId[4];
} VertexData;
// Shader type
@ -284,14 +295,11 @@ typedef struct Shader {
} Shader;
// 3d Model type
// NOTE: If using OpenGL 1.1, loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId)
typedef struct Model {
VertexData mesh;
unsigned int vaoId;
unsigned int vboId[4];
Matrix transform;
Texture2D texture;
Shader shader;
//Matrix transform;
} Model;
// Ray type (useful for raycast)
@ -315,6 +323,24 @@ typedef struct Wave {
short channels;
} Wave;
// Texture formats (support depends on OpenGL version)
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
/*COMPRESSED_ASTC_RGBA_4x4*/ // 8 bpp
} TextureFormat;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
@ -366,8 +392,7 @@ Camera UpdateCamera(Vector3 *position); // Update camera wit
void SetConfigFlags(char flags); // Enable some window configurations
void ShowLogo(void); // Activates raylib logo at startup (can be done with flags)
void InitPostShader(void); // Initialize fullscreen postproduction shaders system
void SetPostShader(unsigned int shader); // Set fullscreen postproduction shader
void SetPostproShader(Shader shader); // Set fullscreen postproduction shader
Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Gives the rayTrace from mouse position
@ -448,6 +473,7 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM)
Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource)
Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory
Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount, bool genMipmaps); // Load a texture from raw data into GPU memory
Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource)
Texture2D LoadTextureFromImage(Image image, bool genMipmaps); // Load a texture from image data (and generate mipmaps)
Texture2D CreateTexture(Image image, bool genMipmaps); // [DEPRECATED] Same as LoadTextureFromImage()
@ -490,19 +516,18 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
void DrawQuad(Vector3 vertices[4], Vector2 textcoords[4], Vector3 normals[4], Color colors[4]); // Draw a quad
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color); // Draw a plane
void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions
void DrawRay(Ray ray, Color color);
void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ
void DrawQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Color color); // Draw a quad
void DrawRay(Ray ray, Color color); // Draw a ray line
void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
void DrawGizmo(Vector3 position); // Draw simple gizmo
void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale); // Draw gizmo with extended parameters
//DrawTorus(), DrawTeapot() are useless...
//------------------------------------------------------------------------------------
// Model 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
Model LoadModelEx(VertexData data); // Load a 3d model (from vertex data)
//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource)
Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model
Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based)

View File

@ -53,7 +53,6 @@
float y;
float z;
} Vector3;
#endif
// Matrix type (OpenGL style 4x4 - right handed, column major)
typedef struct Matrix {
@ -62,6 +61,7 @@ typedef struct Matrix {
float m2, m6, m10, m14;
float m3, m7, m11, m15;
} Matrix;
#endif
// Quaternion type
typedef struct Quaternion {

View File

@ -63,6 +63,28 @@
#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
// NOTE: Every vertex are 3 floats (12 bytes)
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
#ifndef GL_ETC1_RGB8_OES
#define GL_ETC1_RGB8_OES 0x8D64
#endif
#ifndef GL_COMPRESSED_RGB8_ETC2
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#endif
#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -174,7 +196,8 @@ static bool useTempBuffer = false;
static bool vaoSupported = false;
// Framebuffer object and texture
static GLuint fbo, fboColorTexture, fboDepthTexture, fboShader = 0;
static GLuint fbo, fboColorTexture, fboDepthTexture;
static Model postproQuad;
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
@ -199,6 +222,7 @@ static Shader LoadSimpleShader(void);
static void InitializeBuffers(void);
static void InitializeBuffersGPU(void);
static void UpdateBuffers(void);
static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat);
// Custom shader files loading (external)
static char *TextFileRead(char *fn);
@ -688,18 +712,21 @@ void rlDeleteTextures(unsigned int id)
glDeleteTextures(1, &id);
}
// Enable rendering to postprocessing FBO
void rlEnableFBO(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
#endif
}
// Unload shader from GPU memory
void rlDeleteShader(unsigned int id)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glDeleteProgram(id);
}
void rlEnableFBO(void)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}
#endif
}
// Unload vertex data (VAO) from GPU memory
void rlDeleteVertexArrays(unsigned int id)
@ -840,7 +867,18 @@ void rlglInit(void)
TraceLog(INFO, "Supported extension: %s", extensions);
#endif
*/
/*
GLint numComp = 0;
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
GLint format[32] = { 0 };
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format);
for (int i = 0; i < numComp; i++)
{
TraceLog(INFO, "Supported compressed format: 0x%x", format[i]);
}
*/
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Set default draw mode
currentDrawMode = RL_TRIANGLES;
@ -869,7 +907,7 @@ void rlglInit(void)
// 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(pixels, 1, 1, R8G8B8A8, false);
whiteTexture = rlglLoadTexture(pixels, 1, 1, UNCOMPRESSED_R8G8B8A8, 1, false);
if (whiteTexture != 0) TraceLog(INFO, "[TEX ID %i] Base white texture loaded successfully", whiteTexture);
else TraceLog(WARNING, "Base white texture could not be loaded");
@ -888,10 +926,10 @@ void rlglInit(void)
#endif
}
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Init postpro system
void rlglInitPostpro(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the texture that will serve as the color attachment for the framebuffer
glGenTextures(1, &fboColorTexture);
glBindTexture(GL_TEXTURE_2D, fboColorTexture);
@ -927,11 +965,42 @@ void rlglInitPostpro(void)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
fboShader = 0;
// Create a simple quad model to render fbo texture
VertexData quadData;
// TODO: Init simple quad VAO and data here?
}
quadData.vertexCount = 6;
float w = GetScreenWidth();
float h = GetScreenHeight();
float quadPositions[6*3] = { w, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, h, 0.0, 0, h, 0.0, w, h, 0.0, w, 0.0, 0.0 };
float quadTexcoords[6*2] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 };
float quadNormals[6*3] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 };
unsigned char quadColors[6*4] = { 255 };
quadData.vertices = quadPositions;
quadData.texcoords = quadTexcoords;
quadData.normals = quadNormals;
quadData.colors = quadColors;
postproQuad = rlglLoadModel(quadData);
Texture2D texture;
texture.id = fboColorTexture;
texture.width = w;
texture.height = h;
SetModelTexture(&postproQuad, texture);
#endif
}
// Set postprocessing shader
void rlglSetPostproShader(Shader shader)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
SetModelShader(&postproQuad, shader);
#endif
}
// Vertex Buffer Object deinitialization (memory free)
void rlglClose(void)
@ -988,7 +1057,12 @@ void rlglClose(void)
// Free GPU texture
glDeleteTextures(1, &whiteTexture);
if (fbo != 0) glDeleteFramebuffers(1, &fbo);
if (fbo != 0)
{
glDeleteFramebuffers(1, &fbo);
UnloadModel(postproQuad);
}
free(draws);
#endif
@ -1142,68 +1216,15 @@ void rlglDraw(void)
#endif
}
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
void rlglDrawPostpro(unsigned int shaderId)
// Draw with postprocessing shader
void rlglDrawPostpro(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
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();
}
rlglDrawModel(postproQuad, (Vector3){0,0,0}, 0.0f, (Vector3){0,0,0}, (Vector3){1.0f, 1.0f, 1.0f}, WHITE, false);
#endif
}
// Draw a 3d model
void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires)
@ -1250,6 +1271,8 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram(model.shader.id);
// TODO: Use model.transform matrix
Vector3 rotation = { 0.0f, 0.0f, 0.0f };
// Get transform matrix (rotation -> scale -> translation)
@ -1271,21 +1294,21 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
if (vaoSupported)
{
glBindVertexArray(model.vaoId);
glBindVertexArray(model.mesh.vaoId);
}
else
{
// Bind model VBOs data
glBindBuffer(GL_ARRAY_BUFFER, model.vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[0]);
glVertexAttribPointer(model.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(model.shader.vertexLoc);
glBindBuffer(GL_ARRAY_BUFFER, model.vboId[1]);
glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[1]);
glVertexAttribPointer(model.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(model.shader.texcoordLoc);
// Add normals support
glBindBuffer(GL_ARRAY_BUFFER, model.vboId[2]);
glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]);
glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(model.shader.normalLoc);
}
@ -1512,23 +1535,41 @@ Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view)
return rayWorld;
*/
return (Vector3){ 0, 0, 0 };
}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
unsigned int rlglLoadTexture(unsigned char *data, int width, int height, int colorMode, bool genMipmaps)
unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount, bool genMipmaps)
{
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
GLuint id;
// TODO: Review compressed textures support by OpenGL version
/* (rlGetVersion() == OPENGL_11)
if ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA) ||
(textureFormat == COMPRESSED_ETC1_RGB8) || (textureFormat == COMPRESSED_ETC2_RGB8) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA8))
{
id = 0;
TraceLog(WARNING, "GPU compressed textures not supported on OpenGL 1.1");
return id;
}
*/
glGenTextures(1, &id); // Generate Pointer to the texture
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id);
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
#if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used
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_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis
#else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis
#endif
bool texIsPOT = false;
@ -1542,6 +1583,8 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, int col
genMipmaps = false;
}
// TODO: Support mipmaps --> if (mipmapCount > 1)
// If mipmaps are being used, we configure mag-min filters accordingly
// 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
if (genMipmaps)
@ -1587,15 +1630,11 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, int col
else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
#if defined(GRAPHICS_API_OPENGL_33)
// NOTE: We define internal (GPU) format as GL_RGBA8 (probably BGRA8 in practice, driver takes care)
// NOTE: On embedded systems, we let the driver choose the best internal format
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // OpenGL
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // WebGL
// 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
// Support for multiple color modes (16bit color modes and grayscale)
// (sized)internalFormat format type
// GL_R GL_RED GL_UNSIGNED_BYTE
// GL_RGB565 GL_RGB GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5
@ -1604,18 +1643,63 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, int col
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
switch (colorMode)
switch (textureFormat)
{
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;
case UNCOMPRESSED_GRAYSCALE:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data);
// With swizzleMask we define how a one channel texture will be mapped to RGBA
// Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, 1.0f };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
TraceLog(INFO, "Grayscale texture loaded and swizzled!");
} break;
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case COMPRESSED_DXT1_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT1_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT3_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); break;
case COMPRESSED_DXT5_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); break;
case COMPRESSED_ETC1_RGB: TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB8_ETC2); break;//TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA8_ETC2_EAC); break;//TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
//case COMPRESSED_ASTC_RGBA_4x4: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(WARNING, "Texture format not recognized"); break;
}
if (genMipmaps)
if ((mipmapCount == 1) && (genMipmaps))
{
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically for new texture", id);
}
#elif defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
switch (textureFormat)
{
case UNCOMPRESSED_GRAYSCALE: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G6B5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case UNCOMPRESSED_R5G5B5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break;
case UNCOMPRESSED_R4G4B4A4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break;
case UNCOMPRESSED_R8G8B8A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break;
case COMPRESSED_DXT1_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT1_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT3_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); break; // NOTE: Not supported by WebGL
case COMPRESSED_DXT5_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); break; // NOTE: Not supported by WebGL
case COMPRESSED_ETC1_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_ETC1_RGB8_OES); break;
case COMPRESSED_ETC2_RGB: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB8_ETC2); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
case COMPRESSED_ETC2_EAC_RGBA: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA8_ETC2_EAC); break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
//case COMPRESSED_ASTC_RGBA_4x4: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(WARNING, "Texture format not recognized"); break;
}
if ((mipmapCount == 1) && (genMipmaps))
{
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically for new texture", id);
@ -1638,13 +1722,15 @@ Model rlglLoadModel(VertexData mesh)
Model model;
model.mesh = mesh;
model.transform = MatrixIdentity();
#if defined(GRAPHICS_API_OPENGL_11)
model.mesh.vaoId = 0; // Vertex Array Object
model.mesh.vboId[0] = 0; // Vertex position VBO
model.mesh.vboId[1] = 0; // Texcoords VBO
model.mesh.vboId[2] = 0; // Normals VBO
model.texture.id = 0; // No texture required
model.vaoId = 0; // Vertex Array Object
model.vboId[0] = 0; // Vertex position VBO
model.vboId[1] = 0; // Texcoords VBO
model.vboId[2] = 0; // Normals VBO
model.shader.id = 0; // No shader used
#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
model.texture.id = whiteTexture; // Default whiteTexture
@ -1684,106 +1770,28 @@ Model rlglLoadModel(VertexData mesh)
model.shader = simpleShader; // By default, simple shader will be used
model.vboId[0] = vertexBuffer[0]; // Vertex position VBO
model.vboId[1] = vertexBuffer[1]; // Texcoords VBO
model.vboId[2] = vertexBuffer[2]; // Normals VBO
model.mesh.vboId[0] = vertexBuffer[0]; // Vertex position VBO
model.mesh.vboId[1] = vertexBuffer[1]; // Texcoords VBO
model.mesh.vboId[2] = vertexBuffer[2]; // Normals VBO
if (vaoSupported)
{
if (vaoModel > 0)
{
model.vaoId = vaoModel;
model.mesh.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]);
TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU)", model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]);
}
#endif
return model;
}
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed image data and POT image
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat)
{
GLuint id;
#if defined(GRAPHICS_API_OPENGL_11)
id = 0;
TraceLog(WARNING, "GPU compressed textures not supported on OpenGL 1.1");
#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
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", compFormat);
if (compFormat == 0)
{
id = 0;
TraceLog(WARNING, "Texture compressed format not recognized", id);
}
else
{
glGenTextures(1, &id);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 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
}
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 = 0;
// 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
glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);
offset += size;
width /= 2;
height /= 2;
// Security check for NPOT textures
if (width < 1) width = 1;
if (height < 1) height = 1;
}
}
#endif
return id;
}
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Load a shader (vertex shader + fragment shader) from text data
@ -1907,12 +1915,12 @@ unsigned char *rlglReadScreenPixels(int width, int height)
return imgData; // NOTE: image data should be freed
}
#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)
{
Shader shader;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Shaders loading from external text file
char *vShaderStr = TextFileRead(vsFileName);
char *fShaderStr = TextFileRead(fsFileName);
@ -1941,6 +1949,7 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
shader.textureLoc = glGetUniformLocation(shader.id, "texture0");
shader.tintColorLoc = glGetUniformLocation(shader.id, "tintColor");
//--------------------------------------------------------------------
#endif
return shader;
}
@ -1948,28 +1957,31 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
// Link shader to model
void SetModelShader(Model *model, Shader shader)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
model->shader = shader;
if (vaoSupported) glBindVertexArray(model->vaoId);
if (vaoSupported) glBindVertexArray(model->mesh.vaoId);
// Enable vertex attributes: position
glBindBuffer(GL_ARRAY_BUFFER, model->vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[0]);
glEnableVertexAttribArray(shader.vertexLoc);
glVertexAttribPointer(shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
// Enable vertex attributes: texcoords
glBindBuffer(GL_ARRAY_BUFFER, model->vboId[1]);
glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[1]);
glEnableVertexAttribArray(shader.texcoordLoc);
glVertexAttribPointer(shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
// Enable vertex attributes: normals
glBindBuffer(GL_ARRAY_BUFFER, model->vboId[2]);
glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[2]);
glEnableVertexAttribArray(shader.normalLoc);
glVertexAttribPointer(shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
if (vaoSupported) glBindVertexArray(0); // Unbind VAO
#endif
}
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
void PrintProjectionMatrix()
{
PrintMatrix(projection);
@ -1979,7 +1991,6 @@ void PrintModelviewMatrix()
{
PrintMatrix(modelview);
}
#endif
//----------------------------------------------------------------------------------
@ -1987,6 +1998,41 @@ void PrintModelviewMatrix()
//----------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Convert image data to OpenGL texture (returns OpenGL valid Id)
// NOTE: Expected compressed image data and POT image
static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int blockSize = 0; // Bytes every block
int offset = 0;
if ((compressedFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ||
(compressedFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
#if defined(GRAPHICS_API_OPENGL_ES2)
(compressedFormat == GL_ETC1_RGB8_OES) ||
#endif
(compressedFormat == GL_COMPRESSED_RGB8_ETC2)) blockSize = 8;
else blockSize = 16;
// Load the mipmap levels
for (int level = 0; level < mipmapCount && (width || height); level++)
{
unsigned int size = 0;
size = ((width + 3)/4)*((height + 3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset);
offset += size;
width /= 2;
height /= 2;
// Security check for NPOT textures
if (width < 1) width = 1;
if (height < 1) height = 1;
}
}
// Load Shader (Vertex and Fragment)
// NOTE: This shader program is used only for batch buffers (lines, triangles, quads)
@ -2000,7 +2046,7 @@ static Shader LoadDefaultShader(void)
// Vertex shader directly defined, no external file required
#if defined(GRAPHICS_API_OPENGL_33)
char vShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
char vShaderStr[] = " #version 110 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
#elif defined(GRAPHICS_API_OPENGL_ES2)
char vShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work!
#endif
@ -2020,7 +2066,7 @@ static Shader LoadDefaultShader(void)
// Fragment shader directly defined, no external file required
#if defined(GRAPHICS_API_OPENGL_33)
char fShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
char fShaderStr[] = " #version 110 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2)
#elif defined(GRAPHICS_API_OPENGL_ES2)
char fShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work!
"precision mediump float; \n" // WebGL, required for emscripten

View File

@ -88,25 +88,37 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
typedef enum { GRAYSCALE = 0, R5G6B5, R8G8B8, R5G5B5A1, R4G4B4A4, R8G8B8A8 } ColorMode;
#ifdef RLGL_STANDALONE
// Texture formats (support depends on OpenGL version)
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
/*COMPRESSED_ASTC_RGBA_4x4*/ // 8 bpp
} TextureFormat;
// VertexData type
// NOTE: If using OpenGL 1.1, data loaded in CPU; if OpenGL 3.3+ data loaded in GPU (vaoId)
typedef struct VertexData {
int vertexCount;
float *vertices; // 3 components per vertex
float *texcoords; // 2 components per vertex
float *normals; // 3 components per vertex
unsigned char *colors;
unsigned int vaoId;
unsigned int vboId[4];
} VertexData;
// Texture2D type
typedef struct Texture2D {
unsigned int id; // Texture id
int width;
int height;
} Texture2D;
// Shader type
typedef struct Shader {
unsigned int id; // Shader program id
@ -125,15 +137,19 @@ typedef enum { GRAYSCALE = 0, R5G6B5, R8G8B8, R5G5B5A1, R4G4B4A4, R8G8B8A8 } Col
} Shader;
// 3d Model type
// NOTE: If using OpenGL 1.1, loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId)
typedef struct Model {
VertexData mesh;
unsigned int vaoId;
unsigned int vboId[4];
Matrix transform;
Texture2D texture;
Shader shader;
//Matrix transform;
} Model;
// Texture2D type
typedef struct Texture2D {
unsigned int id; // Texture id
int width;
int height;
} Texture2D;
#endif
#ifdef __cplusplus
@ -181,28 +197,27 @@ void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
int rlGetVersion(void); // Returns current OpenGL version
void rlEnableFBO(void);
void rlEnableFBO(void); // Enable rendering to postprocessing FBO
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
void rlglInit(void); // Initialize rlgl (shaders, VAO, VBO...)
void rlglInitPostpro(void); // Initialize postprocessing system
void rlglClose(void); // De-init rlgl
void rlglDraw(void); // Draw VAO/VBO
void rlglDrawPostpro(unsigned int shaderId); // Draw with postpro shader
void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff)
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
unsigned int rlglLoadTexture(unsigned char *data, int width, int height, int colorMode, bool genMipmaps); // Load in GPU OpenGL texture
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format);
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount, bool genMipmaps); // Load in GPU OpenGL texture
unsigned int rlglLoadShader(char *vShaderStr, char *fShaderStr); // Load a shader from text data
#endif
void rlglInitPostpro(void); // Initialize postprocessing system
void rlglDrawPostpro(void); // Draw with postprocessing shader
void rlglSetPostproShader(Shader shader); // Set postprocessing shader
Model rlglLoadModel(VertexData mesh); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires);
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
byte *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)

View File

@ -98,7 +98,7 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
// Draw a color-filled circle
void DrawCircle(int centerX, int centerY, float radius, Color color)
{
DrawPoly((Vector2){centerX, centerY}, 360, radius, 0, color);
DrawPoly((Vector2){ centerX, centerY }, 36, radius, 0, color);
}
// Draw a gradient-filled circle
@ -106,14 +106,14 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
{
rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 2)
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2i(centerX, centerY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius);
rlVertex2f(centerX + sin(DEG2RAD*(i + 10)) * radius, centerY + cos(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
@ -122,12 +122,12 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
void DrawCircleV(Vector2 center, float radius, Color color)
{
rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 2)
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(center.x, center.y);
rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius);
rlVertex2f(center.x + sin(DEG2RAD*(i+2)) * radius, center.y + cos(DEG2RAD*(i+2)) * radius);
rlVertex2f(center.x + sin(DEG2RAD*(i + 10)) * radius, center.y + cos(DEG2RAD*(i + 10)) * radius);
}
rlEnd();
}
@ -139,10 +139,10 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color)
rlColor4ub(color.r, color.g, color.b, color.a);
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i=0; i < 360; i++)
for (int i = 0; i < 360; i += 10)
{
rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius);
rlVertex2f(centerX + sin(DEG2RAD*(i+1)) * radius, centerY + cos(DEG2RAD*(i+1)) * radius);
rlVertex2f(centerX + sin(DEG2RAD*(i + 10)) * radius, centerY + cos(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
@ -201,7 +201,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlNormal3f(0.0f, 0.0f, 1.0f);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.y);

View File

@ -30,10 +30,9 @@
#include <stdarg.h> // Used for functions with variable number of parameters (FormatText())
#include <stdio.h> // Standard input / output lib
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
#include "utils.h" // Required for function GetExtendion()
#include "utils.h" // Required for function GetExtension()
// Following libs will be used on LoadTTF()
// Following libs are used on LoadTTF()
#define STB_TRUETYPE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"
@ -44,7 +43,7 @@
//----------------------------------------------------------------------------------
#define FONT_FIRST_CHAR 32
#define MAX_FONTCHARS 128
#define MAX_FORMATTEXT_LENGTH 50
#define MAX_FORMATTEXT_LENGTH 64
#define BIT_CHECK(a,b) ((a) & (1<<(b)))
@ -211,7 +210,7 @@ extern void LoadDefaultFont(void)
extern void UnloadDefaultFont(void)
{
rlDeleteTextures(defaultFont.texture.id);
UnloadTexture(defaultFont.texture);
free(defaultFont.charSet);
}
@ -258,7 +257,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
// Unload SpriteFont from GPU memory
void UnloadSpriteFont(SpriteFont spriteFont)
{
rlDeleteTextures(spriteFont.texture.id);
UnloadTexture(spriteFont.texture);
free(spriteFont.charSet);
}
@ -284,7 +283,7 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int fontSize, int spacing, Color tint)
{
int length = strlen(text);
int positionX = (int)position.x;
int offsetX = 0;
float scaleFactor;
unsigned char letter;
@ -293,9 +292,6 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
rlEnableTexture(spriteFont.texture.id);
rlBegin(RL_QUADS);
for(int i = 0; i < length; i++)
{
if ((unsigned char)text[i] == 0xc2)
@ -312,26 +308,10 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f
}
else c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR];
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
DrawTexturePro(spriteFont.texture, (Rectangle){ c.x, c.y, c.w, c.h }, (Rectangle){ position.x + offsetX, position.y, c.w*scaleFactor, c.h*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint);
rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height);
rlVertex2f(positionX, position.y);
rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height);
rlVertex2f(positionX, position.y + c.h*scaleFactor);
rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height);
rlVertex2f(positionX + c.w*scaleFactor, position.y + (c.h) * scaleFactor);
rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height);
rlVertex2f(positionX + c.w*scaleFactor, position.y);
positionX += (c.w*scaleFactor + spacing);
offsetX += (c.w*scaleFactor + spacing);
}
rlEnd();
rlDisableTexture();
}
// Formatting of text with variables to 'embed'

View File

@ -51,10 +51,8 @@ typedef struct {
unsigned char *data; // Image raw data
int width; // Image base width
int height; // Image base height
//int bpp; // bytes per pixel
//int components; // num color components
int mipmaps; // Mipmap levels, 1 by default
int compFormat; // Compressed data format, 0 if no compression
int format; // Data format
} ImageEx;
//----------------------------------------------------------------------------------
@ -134,7 +132,7 @@ Image LoadImage(const char *fileName)
ImageEx imageDDS = LoadDDS(fileName);
if (imageDDS.compFormat == 0)
if (imageDDS.format == 0)
{
image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color));
image.width = imageDDS.width;
@ -304,14 +302,7 @@ Texture2D LoadTexture(const char *fileName)
{
ImageEx image = LoadDDS(fileName);
if (image.compFormat == 0)
{
texture.id = rlglLoadTexture(image.data, image.width, image.height, R8G8B8A8, false);
}
else
{
texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
}
texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps, false);
texture.width = image.width;
texture.height = image.height;
@ -325,7 +316,7 @@ Texture2D LoadTexture(const char *fileName)
{
ImageEx image = LoadPKM(fileName);
texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps, false);
texture.width = image.width;
texture.height = image.height;
@ -352,7 +343,17 @@ Texture2D LoadTexture(const char *fileName)
return texture;
}
// TODO: Texture2D LoadTextureEx(const char *imageData, int width, int height, int colorMode)
Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount, bool genMipmaps)
{
Texture2D texture;
texture.width = width;
texture.height = height;
texture.id = rlglLoadTexture(data, width, height, textureFormat, mipmapCount, genMipmaps);
return texture;
}
// Load a texture from image data
// NOTE: image is not unloaded, it must be done manually
@ -382,7 +383,7 @@ Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
}
// NOTE: rlglLoadTexture() can generate mipmaps (POT image required)
texture.id = rlglLoadTexture(imgData, image.width, image.height, R8G8B8A8, genMipmaps);
texture.id = rlglLoadTexture(imgData, image.width, image.height, UNCOMPRESSED_R8G8B8A8, 1, genMipmaps);
texture.width = image.width;
texture.height = image.height;
@ -494,7 +495,7 @@ void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Co
Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height };
Vector2 origin = { 0, 0 };
DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint);
DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
}
// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
@ -545,18 +546,6 @@ static ImageEx LoadDDS(const char *fileName)
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
// DDS Pixel Format
typedef struct {
unsigned int size;
@ -594,7 +583,7 @@ static ImageEx LoadDDS(const char *fileName)
image.width = 0;
image.height = 0;
image.mipmaps = 0;
image.compFormat = 0;
image.format = 0;
FILE *ddsFile = fopen(fileName, "rb");
@ -626,8 +615,6 @@ static ImageEx LoadDDS(const char *fileName)
image.width = header.width;
image.height = header.height;
image.mipmaps = 1;
image.compFormat = 0;
if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
{
@ -651,6 +638,9 @@ static ImageEx LoadDDS(const char *fileName)
}
free(buffer);
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8;
}
else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
{
@ -659,12 +649,12 @@ static ImageEx LoadDDS(const char *fileName)
fread(image.data, image.width*image.height*4, 1, ddsFile);
image.mipmaps = 1;
image.compFormat = 0;
image.format = UNCOMPRESSED_R8G8B8A8;
}
else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0))
else if (((header.ddspf.flags == 0x04) || (header.ddspf.flags == 0x05)) && (header.ddspf.fourCC > 0))
{
TraceLog(WARNING, "[%s] DDS image uses compression, not supported on OpenGL 1.1", fileName);
TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName);
//TraceLog(WARNING, "[%s] DDS image uses compression, not supported on OpenGL 1.1", fileName);
//TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName);
int bufsize;
@ -672,6 +662,8 @@ static ImageEx LoadDDS(const char *fileName)
if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2;
else bufsize = header.pitchOrLinearSize;
TraceLog(DEBUG, "Pitch or linear size: %i", header.pitchOrLinearSize);
image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
fread(image.data, 1, bufsize, ddsFile);
@ -680,19 +672,18 @@ static ImageEx LoadDDS(const char *fileName)
fclose(ddsFile);
image.mipmaps = header.mipMapCount;
image.compFormat = 0;
switch(header.ddspf.fourCC)
{
case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
case FOURCC_DXT3: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
case FOURCC_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
case FOURCC_DXT1:
{
if (header.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
else image.format = COMPRESSED_DXT1_RGBA;
} break;
case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break;
case FOURCC_DXT5: image.format = COMPRESSED_DXT5_RGBA; break;
default: break;
}
// NOTE: Image num color components not required... for now...
//if (fourCC == FOURCC_DXT1) image.components = 3;
//else image.components = 4;
}
}
}
@ -708,10 +699,6 @@ static ImageEx LoadPKM(const char *fileName)
// If OpenGL ES 2.0. the following format could be supported (ETC1):
//GL_ETC1_RGB8_OES
#ifndef GL_ETC1_RGB8_OES
#define GL_ETC1_RGB8_OES 0x8D64
#endif
// If OpenGL ES 3.0, the following formats are supported (ETC2/EAC):
//GL_COMPRESSED_RGB8_ETC2
//GL_COMPRESSED_RGBA8_ETC2
@ -780,7 +767,7 @@ static ImageEx LoadPKM(const char *fileName)
image.width = width;
image.height = height;
image.mipmaps = 1;
image.compFormat = GL_ETC1_RGB8_OES;
image.format = COMPRESSED_ETC1_RGB;
}
}