Bläddra i källkod

raymath module review and other changes

Complete review of matrix rotation math
Check compressed textures support
WIP: LoadImageFromData()
pull/23/head
raysan5 10 år sedan
förälder
incheckning
a7714c842f
8 ändrade filer med 393 tillägg och 387 borttagningar
  1. +2
    -1
      src/core.c
  2. +9
    -1
      src/makefile
  3. +1
    -2
      src/raylib.h
  4. +67
    -195
      src/raymath.c
  5. +6
    -10
      src/raymath.h
  6. +166
    -143
      src/rlgl.c
  7. +11
    -21
      src/text.c
  8. +131
    -14
      src/textures.c

+ 2
- 1
src/core.c Visa fil

@ -180,9 +180,9 @@ static int currentMouseWheelY = 0; // Required to track mouse wheel var
static int exitKey = KEY_ESCAPE; // Default exit key (ESC) static int exitKey = KEY_ESCAPE; // Default exit key (ESC)
static int lastKeyPressed = -1; static int lastKeyPressed = -1;
#endif
static bool cursorHidden; static bool cursorHidden;
#endif
static double currentTime, previousTime; // Used to track timmings static double currentTime, previousTime; // Used to track timmings
static double updateTime, drawTime; // Time measures for update and draw static double updateTime, drawTime; // Time measures for update and draw
@ -227,6 +227,7 @@ static void SwapBuffers(void); // Copy back buffer to f
static void PollInputEvents(void); // Register user events static void PollInputEvents(void); // Register user events
static void LogoAnimation(void); // Plays raylib logo appearing animation static void LogoAnimation(void); // Plays raylib logo appearing animation
static void SetupFramebufferSize(int displayWidth, int displayHeight); static void SetupFramebufferSize(int displayWidth, int displayHeight);
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
static void InitMouse(void); // Mouse initialization (including mouse thread) static void InitMouse(void); // Mouse initialization (including mouse thread)
static void *MouseThread(void *arg); // Mouse reading thread static void *MouseThread(void *arg); // Mouse reading thread

+ 9
- 1
src/makefile Visa fil

@ -93,7 +93,7 @@ else
endif endif
# define all object files required # define all object files required
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o stb_vorbis.o
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o stb_vorbis.o camera.o gestures.o
# typing 'make' will invoke the first target entry in the file, # typing 'make' will invoke the first target entry in the file,
# in this case, the 'default' target entry is raylib # in this case, the 'default' target entry is raylib
@ -148,6 +148,14 @@ utils.o: utils.c
stb_vorbis.o: stb_vorbis.c stb_vorbis.o: stb_vorbis.c
$(CC) -c stb_vorbis.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM) $(CC) -c stb_vorbis.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
# compile camera module
camera.o: camera.c
$(CC) -c camera.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
# compile gestures module
gestures.o: gestures.c
$(CC) -c gestures.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
# clean everything # clean everything
clean: clean:
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)

+ 1
- 2
src/raylib.h Visa fil

@ -515,16 +515,15 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) 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) Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource)
Image LoadImageFromData(Color *pixels, int width, int height, int format); // Load image from Color array data
Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory 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 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 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 LoadTextureFromImage(Image image, bool genMipmaps); // Load a texture from image data (and generate mipmaps)
Texture2D CreateTexture(Image image, bool genMipmaps); // [DEPRECATED] Same as LoadTextureFromImage()
void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadImage(Image image); // Unload image from CPU memory (RAM)
void UnloadTexture(Texture2D texture); // Unload texture from GPU memory void UnloadTexture(Texture2D texture); // Unload texture from GPU memory
void ConvertToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) void ConvertToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
Color *GetPixelData(Image image); // Get pixel data from image as a Color struct array Color *GetPixelData(Image image); // Get pixel data from image as a Color struct array
void SetPixelData(Image *image, Color *pixels, int format); // Set image data from Color struct array
void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2

+ 67
- 195
src/raymath.c Visa fil

@ -431,109 +431,16 @@ Matrix MatrixSubstract(Matrix left, Matrix right)
} }
// Returns translation matrix // Returns translation matrix
// TODO: Review this function
Matrix MatrixTranslate(float x, float y, float z) Matrix MatrixTranslate(float x, float y, float z)
{ {
/*
For OpenGL
1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
x, y, z, 1
Is the correct Translation Matrix. Why? Opengl Uses column-major matrix ordering.
Which is the Transpose of the Matrix you initially presented, which is in row-major ordering.
Row major is used in most math text-books and also DirectX, so it is a common
point of confusion for those new to OpenGL.
* matrix notation used in opengl documentation does not describe in-memory layout for OpenGL matrices
Translation matrix should be laid out in memory like this:
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, trabsX, transY, transZ, 1 }
9.005 Are OpenGL matrices column-major or row-major?
For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out
contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements
of the 16-element matrix, where indices are numbered from 1 to 16 as described in section
2.11.2 of the OpenGL 2.1 Specification.
Column-major versus row-major is purely a notational convention. Note that post-multiplying
with column-major matrices produces the same result as pre-multiplying with row-major matrices.
The OpenGL Specification and the OpenGL Reference Manual both use column-major notation.
You can use any notation, as long as it's clearly stated.
Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion
in the OpenGL programming community. Column-major notation suggests that matrices
are not laid out in memory as a programmer would expect.
*/
Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }; Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
return result; return result;
} }
// Returns rotation matrix
// TODO: Review this function
Matrix MatrixRotate(float angleX, float angleY, float angleZ)
{
Matrix result;
Matrix rotX = MatrixRotateX(angleX);
Matrix rotY = MatrixRotateY(angleY);
Matrix rotZ = MatrixRotateZ(angleZ);
result = MatrixMultiply(MatrixMultiply(rotX, rotY), rotZ);
return result;
}
/*
Matrix MatrixRotate(float angle, float x, float y, float z)
{
Matrix result = MatrixIdentity();
float c = cosf(angle*DEG2RAD); // cosine
float s = sinf(angle*DEG2RAD); // sine
float c1 = 1.0f - c; // 1 - c
float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
m1 = result.m1, m5 = result.m5, m9 = result.m9, m13 = result.m13,
m2 = result.m2, m6 = result.m6, m10 = result.m10, m14 = result.m14;
// build rotation matrix
float r0 = x * x * c1 + c;
float r1 = x * y * c1 + z * s;
float r2 = x * z * c1 - y * s;
float r4 = x * y * c1 - z * s;
float r5 = y * y * c1 + c;
float r6 = y * z * c1 + x * s;
float r8 = x * z * c1 + y * s;
float r9 = y * z * c1 - x * s;
float r10= z * z * c1 + c;
// multiply rotation matrix
result.m0 = r0*m0 + r4*m1 + r8*m2;
result.m1 = r1*m0 + r5*m1 + r9*m2;
result.m2 = r2*m0 + r6*m1 + r10*m2;
result.m4 = r0*m4 + r4*m5 + r8*m6;
result.m5 = r1*m4 + r5*m5 + r9*m6;
result.m6 = r2*m4 + r6*m5 + r10*m6;
result.m8 = r0*m8 + r4*m9 + r8*m10;
result.m9 = r1*m8 + r5*m9 + r9*m10;
result.m10 = r2*m8 + r6*m9 + r10*m10;
result.m12 = r0*m12+ r4*m13 + r8*m14;
result.m13 = r1*m12+ r5*m13 + r9*m14;
result.m14 = r2*m12+ r6*m13 + r10*m14;
return result;
}
*/
// Create rotation matrix from axis and angle // Create rotation matrix from axis and angle
// TODO: Test this function
// NOTE: NO prototype defined!
Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
// NOTE: Angle should be provided in radians
Matrix MatrixRotate(float angle, Vector3 axis)
{ {
Matrix result; Matrix result;
@ -545,15 +452,15 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
if ((length != 1) && (length != 0)) if ((length != 1) && (length != 0))
{ {
length = 1 / length;
length = 1/length;
x *= length; x *= length;
y *= length; y *= length;
z *= length; z *= length;
} }
float s = sin(angle);
float c = cos(angle);
float t = i">1-c;
float s = sinf(angle);
float c = cosf(angle);
float t = f">1.0f - c;
// Cache some matrix values (speed optimization) // Cache some matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
@ -583,70 +490,51 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
result.m14 = mat.m14; result.m14 = mat.m14;
result.m15 = mat.m15; result.m15 = mat.m15;
return result;
};
// Create rotation matrix from axis and angle (version 2)
// TODO: Test this function
// NOTE: NO prototype defined!
Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
{
Matrix result;
VectorNormalize(&axis);
float axisX = axis.x, axisY = axis.y, axisZ = axis.y;
// Calculate angles
float cosres = (float)cos(angle);
float sinres = (float)sin(angle);
float t = 1.0f - cosres;
// Do the conversion math once
float tXX = t * axisX * axisX;
float tXY = t * axisX * axisY;
float tXZ = t * axisX * axisZ;
float tYY = t * axisY * axisY;
float tYZ = t * axisY * axisZ;
float tZZ = t * axisZ * axisZ;
float sinX = sinres * axisX;
float sinY = sinres * axisY;
float sinZ = sinres * axisZ;
result.m0 = tXX + cosres;
result.m1 = tXY + sinZ;
result.m2 = tXZ - sinY;
result.m3 = 0;
result.m4 = tXY - sinZ;
result.m5 = tYY + cosres;
result.m6 = tYZ + sinX;
result.m7 = 0;
result.m8 = tXZ + sinY;
result.m9 = tYZ - sinX;
result.m10 = tZZ + cosres;
result.m11 = 0;
result.m12 = 0;
result.m13 = 0;
result.m14 = 0;
result.m15 = 1;
return result; return result;
} }
// Returns rotation matrix for a given quaternion
Matrix MatrixFromQuaternion(Quaternion q)
/*
// Another implementation for MatrixRotate...
Matrix MatrixRotate(float angle, float x, float y, float z)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
Vector3 axis;
float angle;
float c = cosf(angle); // cosine
float s = sinf(angle); // sine
float c1 = 1.0f - c; // 1 - c
QuaternionToAxisAngle(q, &axis, &angle);
float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
m1 = result.m1, m5 = result.m5, m9 = result.m9, m13 = result.m13,
m2 = result.m2, m6 = result.m6, m10 = result.m10, m14 = result.m14;
result = MatrixFromAxisAngle2(axis, angle);
// build rotation matrix
float r0 = x * x * c1 + c;
float r1 = x * y * c1 + z * s;
float r2 = x * z * c1 - y * s;
float r4 = x * y * c1 - z * s;
float r5 = y * y * c1 + c;
float r6 = y * z * c1 + x * s;
float r8 = x * z * c1 + y * s;
float r9 = y * z * c1 - x * s;
float r10= z * z * c1 + c;
// multiply rotation matrix
result.m0 = r0*m0 + r4*m1 + r8*m2;
result.m1 = r1*m0 + r5*m1 + r9*m2;
result.m2 = r2*m0 + r6*m1 + r10*m2;
result.m4 = r0*m4 + r4*m5 + r8*m6;
result.m5 = r1*m4 + r5*m5 + r9*m6;
result.m6 = r2*m4 + r6*m5 + r10*m6;
result.m8 = r0*m8 + r4*m9 + r8*m10;
result.m9 = r1*m8 + r5*m9 + r9*m10;
result.m10 = r2*m8 + r6*m9 + r10*m10;
result.m12 = r0*m12+ r4*m13 + r8*m14;
result.m13 = r1*m12+ r5*m13 + r9*m14;
result.m14 = r2*m12+ r6*m13 + r10*m14;
return result; return result;
} }
*/
// Returns x-rotation matrix (angle in radians) // Returns x-rotation matrix (angle in radians)
Matrix MatrixRotateX(float angle) Matrix MatrixRotateX(float angle)
@ -704,22 +592,6 @@ Matrix MatrixScale(float x, float y, float z)
return result; return result;
} }
// Returns transformation matrix for a given translation, rotation and scale
// NOTE: Transformation order is rotation -> scale -> translation
// NOTE: Rotation angles should come in radians
Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale)
{
Matrix result = MatrixIdentity();
Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z);
Matrix mScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z);
result = MatrixMultiply(MatrixMultiply(mRotation, mScale), mTranslate);
return result;
}
// Returns two matrix multiplication // Returns two matrix multiplication
// NOTE: When multiplying matrices... the order matters! // NOTE: When multiplying matrices... the order matters!
Matrix MatrixMultiply(Matrix left, Matrix right) Matrix MatrixMultiply(Matrix left, Matrix right)
@ -874,7 +746,7 @@ void PrintMatrix(Matrix m)
// Module Functions Definition - Quaternion math // Module Functions Definition - Quaternion math
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Calculates the length of a quaternion
// Computes the length of a quaternion
float QuaternionLength(Quaternion quat) float QuaternionLength(Quaternion quat)
{ {
return sqrt(quat.x*quat.x + quat.y*quat.y + quat.z*quat.z + quat.w*quat.w); return sqrt(quat.x*quat.x + quat.y*quat.y + quat.z*quat.z + quat.w*quat.w);
@ -948,7 +820,7 @@ Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
return result; return result;
} }
// Returns a quaternion n">from a given rotation matrix
// Returns a quaternion k">for a given rotation matrix
Quaternion QuaternionFromMatrix(Matrix matrix) Quaternion QuaternionFromMatrix(Matrix matrix)
{ {
Quaternion result; Quaternion result;
@ -1004,29 +876,7 @@ Quaternion QuaternionFromMatrix(Matrix matrix)
return result; return result;
} }
// Returns rotation quaternion for an angle around an axis
// NOTE: angle must be provided in radians
Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
{
Quaternion result = { 0, 0, 0, 1 };
if (VectorLength(axis) != 0.0)
angle *= 0.5;
VectorNormalize(&axis);
result.x = axis.x * (float)sin(angle);
result.y = axis.y * (float)sin(angle);
result.z = axis.z * (float)sin(angle);
result.w = (float)cos(angle);
QuaternionNormalize(&result);
return result;
}
// Calculates the matrix from the given quaternion
// Returns a matrix for a given quaternion
Matrix QuaternionToMatrix(Quaternion q) Matrix QuaternionToMatrix(Quaternion q)
{ {
Matrix result; Matrix result;
@ -1065,12 +915,34 @@ Matrix QuaternionToMatrix(Quaternion q)
result.m13 = 0; result.m13 = 0;
result.m14 = 0; result.m14 = 0;
result.m15 = 1; result.m15 = 1;
return result;
}
// Returns rotation quaternion for an angle and axis
// NOTE: angle must be provided in radians
Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis)
{
Quaternion result = { 0, 0, 0, 1 };
if (VectorLength(axis) != 0.0)
angle *= 0.5;
VectorNormalize(&axis);
result.x = axis.x * (float)sin(angle);
result.y = axis.y * (float)sin(angle);
result.z = axis.z * (float)sin(angle);
result.w = (float)cos(angle);
QuaternionNormalize(&result);
return result; return result;
} }
// Returns the axis and the angle for a given quaternion
void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
// Returns the rotation angle and axis for a given quaternion
void QuaternionToAxisAngle(Quaternion q, kt">float *outAngle, Vector3 *outAxis)
{ {
if (fabs(q.w) > 1.0f) QuaternionNormalize(&q); if (fabs(q.w) > 1.0f) QuaternionNormalize(&q);

+ 6
- 10
src/raymath.h Visa fil

@ -107,15 +107,11 @@ Matrix MatrixIdentity(void); // Returns identity matr
Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices
Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right) Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right)
Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix
Matrix MatrixRotate(float axisX, float axisY, float axisZ); // Returns rotation matrix
Matrix MatrixFromAxisAngle(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis
Matrix MatrixFromAxisAngle2(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis (test another implemntation)
Matrix MatrixFromQuaternion(Quaternion q); // Returns rotation matrix for a given quaternion
Matrix MatrixRotate(float angle, Vector3 axis); // Returns rotation matrix for an angle around an specified axis (angle in radians)
Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians) Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians)
Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians) Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians)
Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians) Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians)
Matrix MatrixScale(float x, float y, float z); // Returns scaling matrix Matrix MatrixScale(float x, float y, float z); // Returns scaling matrix
Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale); // Returns transformation matrix for a given translation, rotation and scale
Matrix MatrixMultiply(Matrix left, Matrix right); // Returns two matrix multiplication Matrix MatrixMultiply(Matrix left, Matrix right); // Returns two matrix multiplication
Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far); // Returns perspective projection matrix Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far); // Returns perspective projection matrix
Matrix MatrixPerspective(double fovy, double aspect, double near, double far); // Returns perspective projection matrix Matrix MatrixPerspective(double fovy, double aspect, double near, double far); // Returns perspective projection matrix
@ -126,14 +122,14 @@ void PrintMatrix(Matrix m); // Print matrix utility
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration to work with Quaternions // Functions Declaration to work with Quaternions
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
float QuaternionLength(Quaternion quat); // Calculates the length of a quaternion
float QuaternionLength(Quaternion quat); // Compute the length of a quaternion
void QuaternionNormalize(Quaternion *q); // Normalize provided quaternion void QuaternionNormalize(Quaternion *q); // Normalize provided quaternion
Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication
Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions
Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion n">from a given rotation matrix
Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns rotation quaternion for an angle around an axis
Matrix QuaternionToMatrix(Quaternion q); // Calculates the matrix from the given quaternion
void QuaternionToAxisAngle(Quaternion q, n">Vector3 *outAxis, float *outAngle); // Returns the axis and the angle for a given quaternion
Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion k">for a given rotation matrix
Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion
Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis); // Returns rotation quaternion for an angle and axis
void QuaternionToAxisAngle(Quaternion q, kt">float *outAngle, Vector3 *outAxis); // Returns the rotation angle and axis for a given quaternion
void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix
#ifdef __cplusplus #ifdef __cplusplus

+ 166
- 143
src/rlgl.c Visa fil

@ -30,6 +30,7 @@
#include <stdio.h> // Standard input / output lib #include <stdio.h> // Standard input / output lib
#include <stdlib.h> // Declares malloc() and free() for memory management, rand() #include <stdlib.h> // Declares malloc() and free() for memory management, rand()
#include <string.h> // Declares strcmp(), strlen(), strtok(), strdup()
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
#ifdef __APPLE__ // OpenGL include for OSX #ifdef __APPLE__ // OpenGL include for OSX
@ -63,28 +64,49 @@
#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations) #define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
// NOTE: Every vertex are 3 floats (12 bytes) // NOTE: Every vertex are 3 floats (12 bytes)
#ifndef GL_SHADING_LANGUAGE_VERSION
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
#endif
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT #ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#endif #endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif #endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#endif #endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif #endif
#ifndef GL_ETC1_RGB8_OES #ifndef GL_ETC1_RGB8_OES
#define GL_ETC1_RGB8_OES 0x8D64
#define GL_ETC1_RGB8_OES 0x8D64
#endif #endif
#ifndef GL_COMPRESSED_RGB8_ETC2 #ifndef GL_COMPRESSED_RGB8_ETC2
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#endif #endif
#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC #ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#endif
#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
#endif
#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
#endif
#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR
#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0
#endif
#ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR
#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7
#endif #endif
#if defined(GRAPHICS_API_OPENGL_11)
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -215,6 +237,8 @@ static PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
// NOTE: It's required in shapes and models modules! // NOTE: It's required in shapes and models modules!
unsigned int whiteTexture; unsigned int whiteTexture;
static bool supportedTextureFormat[32];
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -224,9 +248,6 @@ static Shader LoadSimpleShader(void);
static void InitializeBuffers(void); static void InitializeBuffers(void);
static void InitializeBuffersGPU(void); static void InitializeBuffersGPU(void);
static void UpdateBuffers(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); static char *TextFileRead(char *fn);
#endif #endif
@ -235,6 +256,8 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight); static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight);
#endif #endif
static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Matrix operations // Module Functions Definition - Matrix operations
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -328,23 +351,11 @@ void rlTranslatef(float x, float y, float z)
// Multiply the current matrix by a rotation matrix // Multiply the current matrix by a rotation matrix
void rlRotatef(float angleDeg, float x, float y, float z) void rlRotatef(float angleDeg, float x, float y, float z)
{ {
// TODO: Support rotation in multiple axes
Matrix rotation = MatrixIdentity(); Matrix rotation = MatrixIdentity();
// OPTION 1: It works...
if (x == 1) rotation = MatrixRotateX(angleDeg*DEG2RAD);
else if (y == 1) rotation = MatrixRotateY(angleDeg*DEG2RAD);
else if (z == 1) rotation = MatrixRotateZ(angleDeg*DEG2RAD);
// OPTION 2: Requires review...
//Vector3 axis = (Vector3){ x, y, z };
//VectorNormalize(&axis);
//rotation = MatrixRotateY(angleDeg*DEG2RAD); //MatrixFromAxisAngle(axis, angleDeg*DEG2RAD);
// OPTION 3: TODO: Review, it doesn't work!
//Vector3 vec = (Vector3){ x, y, z };
//VectorNormalize(&vec);
//rot = MatrixRotate(angleDeg*vec.x, angleDeg*vec.x, angleDeg*vec.x);
Vector3 axis = (Vector3){ x, y, z };
VectorNormalize(&axis);
rotation = MatrixRotate(angleDeg*DEG2RAD, axis);
MatrixTranspose(&rotation); MatrixTranspose(&rotation);
@ -840,7 +851,7 @@ void rlglInit(void)
TraceLog(INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR)); TraceLog(INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR));
TraceLog(INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER)); TraceLog(INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER));
TraceLog(INFO, "GPU: Version: %s", glGetString(GL_VERSION)); TraceLog(INFO, "GPU: Version: %s", glGetString(GL_VERSION));
TraceLog(INFO, "GPU: GLSL: %s", glGetString(mh">0x8B8C)); //GL_SHADING_LANGUAGE_VERSION
TraceLog(INFO, "GPU: GLSL: %s", glGetString(n">GL_SHADING_LANGUAGE_VERSION));
// NOTE: We can get a bunch of extra information about GPU capabilities (glGet*) // NOTE: We can get a bunch of extra information about GPU capabilities (glGet*)
//int maxTexSize; //int maxTexSize;
@ -853,6 +864,9 @@ void rlglInit(void)
// Show supported extensions // Show supported extensions
// NOTE: We don't need that much data on screen... right now... // NOTE: We don't need that much data on screen... right now...
// Check available extensions for compressed textures support
for (int i = 0; i < 32; i++) supportedTextureFormat[i] = false;
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
GLint numExt; GLint numExt;
@ -861,40 +875,49 @@ void rlglInit(void)
for (int i = 0; i < numExt; i++) for (int i = 0; i < numExt; i++)
{ {
//TraceLog(INFO, "Supported extension: %s", glGetStringi(GL_EXTENSIONS, i)); //TraceLog(INFO, "Supported extension: %s", glGetStringi(GL_EXTENSIONS, i));
/*
if (strcmp(glGetStringi(GL_EXTENSIONS, i),"GL_EXT_texture_compression_s3tc") == 0)
if (strcmp(p">(char *)glGetStringi(GL_EXTENSIONS, i), "GL_EXT_texture_compression_s3tc") == 0)
{ {
// DDS texture compression support // DDS texture compression support
// TODO: Check required tokens
supportedTextureFormat[COMPRESSED_DXT1_RGB] = true;
supportedTextureFormat[COMPRESSED_DXT1_RGBA] = true;
supportedTextureFormat[COMPRESSED_DXT3_RGBA] = true;
supportedTextureFormat[COMPRESSED_DXT5_RGBA] = true;
} }
else if (strcmp(glGetStringi(GL_EXTENSIONS, i),"GL_OES_compressed_ETC1_RGB8_texture") == 0)
else if (strcmp(p">(char *)glGetStringi(GL_EXTENSIONS, i), "GL_OES_compressed_ETC1_RGB8_texture") == 0)
{ {
// ETC1 texture compression support // ETC1 texture compression support
supportedTextureFormat[COMPRESSED_ETC1_RGB] = true;
} }
else if (strcmp(glGetStringi(GL_EXTENSIONS, i),"GL_ARB_ES3_compatibility") == 0)
else if (strcmp(p">(char *)glGetStringi(GL_EXTENSIONS, i),"GL_ARB_ES3_compatibility") == 0)
{ {
//OES_compressed_ETC2_RGB8_texture,
//OES_compressed_ETC2_RGBA8_texture,
// ETC2/EAC texture compression support // ETC2/EAC texture compression support
supportedTextureFormat[COMPRESSED_ETC2_RGB] = true;
supportedTextureFormat[COMPRESSED_ETC2_EAC_RGBA] = true;
} }
else if (strcmp(glGetStringi(GL_EXTENSIONS, i),"GL_IMG_texture_compression_pvrtc") == 0)
else if (strcmp(p">(char *)glGetStringi(GL_EXTENSIONS, i),"GL_IMG_texture_compression_pvrtc") == 0)
{ {
// PVR texture compression support // PVR texture compression support
supportedTextureFormat[COMPRESSED_PVRT_RGB] = true;
supportedTextureFormat[COMPRESSED_PVRT_RGBA] = true;
} }
else if (strcmp(glGetStringi(GL_EXTENSIONS, i),"GL_KHR_texture_compression_astc_hdr") == 0)
else if (strcmp(p">(char *)glGetStringi(GL_EXTENSIONS, i),"GL_KHR_texture_compression_astc_hdr") == 0)
{ {
// ASTC texture compression support // ASTC texture compression support
supportedTextureFormat[COMPRESSED_ASTC_4x4_RGBA] = true;
supportedTextureFormat[COMPRESSED_ASTC_8x8_RGBA] = true;
} }
*/
} }
#elif defined(GRAPHICS_API_OPENGL_ES2) #elif defined(GRAPHICS_API_OPENGL_ES2)
char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big string char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big string
// NOTE: String could be splitted using strtok() function (string.h) // NOTE: String could be splitted using strtok() function (string.h)
TraceLog(INFO, "Supported extension: %s", extensions); TraceLog(INFO, "Supported extension: %s", extensions);
//char** ext = StringSplit(extensions, ' ');
//for (int i = 0; i < numExt; i++) printf("%s", ext[i]);
#endif #endif
/* /*
GLint numComp = 0; GLint numComp = 0;
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp); glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
@ -1258,6 +1281,7 @@ void rlglDrawPostpro(void)
} }
// Draw a 3d model // Draw a 3d model
// NOTE: Model transform can come within model struct
void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires) void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires)
{ {
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) #if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
@ -1284,8 +1308,6 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
rlScalef(scale.x, scale.y, scale.z); rlScalef(scale.x, scale.y, scale.z);
rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
// TODO: If rotate in multiple axis, get rotation matrix and use rlMultMatrix()
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
@ -1302,13 +1324,17 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram(model.shader.id); glUseProgram(model.shader.id);
// TODO: Use model.transform matrix
Vector3 rotation = { 0.0f, 0.0f, 0.0f };
// Apply transformation provided in model.transform matrix
Matrix modelviewworld = MatrixMultiply(model.transform, modelview); // World-space transformation
// Apply transformations provided in function
// Get transform matrix (rotation -> scale -> translation) // Get transform matrix (rotation -> scale -> translation)
Matrix transform = MatrixTransform(position, rotation, scale); // Object-space transformation
Matrix modelviewworld = MatrixMultiply(transform, modelview); // World-space transformation
Matrix rotation = MatrixRotate(rotationAngle*DEG2RAD, rotationAxis);
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix translation = MatrixTranslate(position.x, position.y, position.z);
Matrix transform = MatrixMultiply(MatrixMultiply(rotation, matScale), translation); // Object-space transformation matrix
modelviewworld = MatrixMultiply(transform, modelview); // World-space transformation
// Projection: Screen-space transformation // Projection: Screen-space transformation
@ -1405,7 +1431,6 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height)
// Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation) // Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation)
#endif #endif
// TODO: Review this comment when called from window resize callback
TraceLog(INFO, "OpenGL Graphics initialized successfully"); TraceLog(INFO, "OpenGL Graphics initialized successfully");
} }
@ -1596,75 +1621,6 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
//glActiveTexture(GL_TEXTURE0); //glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id); 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_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;
// 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 (genMipmaps && !texIsPOT)
{
TraceLog(WARNING, "[TEX ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
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)
{
// 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
}
#if defined(GRAPHICS_API_OPENGL_11)
if (genMipmaps)
{
TraceLog(WARNING, "[TEX 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(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
// NOTE: We define internal (GPU) format as GL_RGBA8 (probably BGRA8 in practice, driver takes care) // 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 // NOTE: On embedded systems, we let the driver choose the best internal format
@ -1703,24 +1659,20 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
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_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_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 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
case COMPRESSED_DXT1_RGB: if (supportedTextureFormat[COMPRESSED_DXT1_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT1_RGBA: if (supportedTextureFormat[COMPRESSED_DXT1_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT3_RGBA: if (supportedTextureFormat[COMPRESSED_DXT3_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); break;
case COMPRESSED_DXT5_RGBA: if (supportedTextureFormat[COMPRESSED_DXT5_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); break;
case COMPRESSED_ETC1_RGB: if (supportedTextureFormat[COMPRESSED_ETC1_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_ETC1_RGB8_OES); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: if (supportedTextureFormat[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: if (supportedTextureFormat[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_PVRT_RGB: if (supportedTextureFormat[COMPRESSED_PVRT_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA: if (supportedTextureFormat[COMPRESSED_PVRT_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA: if (supportedTextureFormat[COMPRESSED_ASTC_4x4_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA: if (supportedTextureFormat[COMPRESSED_ASTC_8x8_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_8x8_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(WARNING, "Texture format not recognized"); break; 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);
}
#elif defined(GRAPHICS_API_OPENGL_ES2)
#elif defined(GRAPHICS_API_OPENGL_11) || 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 // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
switch (textureFormat) switch (textureFormat)
{ {
@ -1731,17 +1683,63 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
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_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_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 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
case COMPRESSED_DXT1_RGB: if (supportedTextureFormat[COMPRESSED_DXT1_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT1_RGBA: if (supportedTextureFormat[COMPRESSED_DXT1_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); break;
case COMPRESSED_DXT3_RGBA: if (supportedTextureFormat[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: if (supportedTextureFormat[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: if (supportedTextureFormat[COMPRESSED_ETC1_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_ETC1_RGB8_OES); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
case COMPRESSED_ETC2_RGB: if (supportedTextureFormat[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: if (supportedTextureFormat[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_PVRT_RGB: if (supportedTextureFormat[COMPRESSED_PVRT_RGB]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_PVRT_RGBA: if (supportedTextureFormat[COMPRESSED_PVRT_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG); break; // NOTE: Requires PowerVR GPU
case COMPRESSED_ASTC_4x4_RGBA: if (supportedTextureFormat[COMPRESSED_ASTC_4x4_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_4x4_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
case COMPRESSED_ASTC_8x8_RGBA: if (supportedTextureFormat[COMPRESSED_ASTC_8x8_RGBA]) LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_ASTC_8x8_KHR); break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
default: TraceLog(WARNING, "Texture format not supported"); break; default: TraceLog(WARNING, "Texture format not supported"); break;
} }
#endif
// Check if texture is power-of-two (POT) to enable mipmap generation
bool texIsPOT = false;
if (((width > 0) && ((width & (width - 1)) == 0)) && ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true;
if (genMipmaps && !texIsPOT)
{
TraceLog(WARNING, "[TEX ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
genMipmaps = false;
}
// Generate mipmaps if required
// TODO: Improve mipmaps support
#if defined(GRAPHICS_API_OPENGL_11)
if (genMipmaps)
{
// Compute required mipmaps
// NOTE: data size is reallocated to fit mipmaps data
int mipmapCount = GenerateMipmaps(data, width, height);
// TODO: Adjust mipmap size depending on texture format!
int size = width*height*4;
int offset = size;
int mipWidth = width/2;
int mipHeight = height/2;
// Load the mipmaps
for (int level = 1; 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;
}
TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", id);
}
#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ((mipmapCount == 1) && (genMipmaps)) if ((mipmapCount == 1) && (genMipmaps))
{ {
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
@ -1749,7 +1747,30 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
} }
#endif #endif
// At this point we have the image converted to texture and uploaded to GPU
// Texture parameters configuration
// 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_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
// Magnification and minification filters
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(GRAPHICS_API_OPENGL_33)
if ((mipmapCount > 1) || (genMipmaps))
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps (must be available)
}
#endif
// At this point we have the texture loaded in GPU, with mipmaps generated (if desired) and texture parameters configured
// Unbind current texture // Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
@ -2027,6 +2048,7 @@ void rlglSetModelShader(Model *model, Shader shader)
// Set custom shader to be used on batch draw // Set custom shader to be used on batch draw
void rlglSetCustomShader(Shader shader) void rlglSetCustomShader(Shader shader)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (currentShader.id != shader.id) if (currentShader.id != shader.id)
{ {
rlglDraw(); rlglDraw();
@ -2053,12 +2075,15 @@ void rlglSetCustomShader(Shader shader)
if (vaoSupported) glBindVertexArray(0); // Unbind VAO if (vaoSupported) glBindVertexArray(0); // Unbind VAO
*/ */
} }
#endif
} }
// Set default shader to be used on batch draw // Set default shader to be used on batch draw
void rlglSetDefaultShader(void) void rlglSetDefaultShader(void)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
rlglSetCustomShader(defaultShader); rlglSetCustomShader(defaultShader);
#endif
} }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
@ -2441,7 +2466,7 @@ static void InitializeBuffersGPU(void)
// Update VBOs with vertex array data // Update VBOs with vertex array data
// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
// TODO: If no data changed on the CPU arrays --> No need to update GPU arrays every frame!
// TODO: If no data changed on the CPU arrays --> No need to update GPU arrays
static void UpdateBuffers(void) static void UpdateBuffers(void)
{ {
if (lines.vCounter > 0) if (lines.vCounter > 0)
@ -2508,11 +2533,9 @@ static void UpdateBuffers(void)
// Unbind the current VAO // Unbind the current VAO
if (vaoSupported) glBindVertexArray(0); if (vaoSupported) glBindVertexArray(0);
} }
#endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
// Mipmaps data is generated after image data // Mipmaps data is generated after image data
static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight)
{ {

+ 11
- 21
src/text.c Visa fil

@ -84,12 +84,6 @@ extern void LoadDefaultFont(void)
defaultFont.numChars = 224; // Number of chars included in our default font defaultFont.numChars = 224; // Number of chars included in our default font
Image image;
image.width = 128; // We know our default font image is 128 pixels width
image.height = 128; // We know our default font image is 128 pixels height
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8;
// Default font is directly defined here (data generated from a sprite font image) // Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables // This way, we reconstruct SpriteFont without creating large global variables
// This data is automatically allocated to Stack and automatically deallocated at the end of this function // This data is automatically allocated to Stack and automatically deallocated at the end of this function
@ -151,14 +145,17 @@ extern void LoadDefaultFont(void)
// Re-construct image from defaultFontData and generate OpenGL texture // Re-construct image from defaultFontData and generate OpenGL texture
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Color *imagePixels = (Color *)malloc(image.width*image.height*sizeof(Color));
int imWidth = 128;
int imHeight = 128;
Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color));
for (int i = 0; i < image.width*image.height; i++) imagePixels[i] = BLANK; // Initialize array
for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter int counter = 0; // Font data elements counter
// Fill imgData with defaultFontData (convert from bit to pixel!) // Fill imgData with defaultFontData (convert from bit to pixel!)
for (int i = 0; i < image.width * image.height; i += 32)
for (int i = 0; i < imWidth*imHeight; i += 32)
{ {
for (int j = 31; j >= 0; j--) for (int j = 31; j >= 0; j--)
{ {
@ -174,7 +171,7 @@ extern void LoadDefaultFont(void)
//fwrite(image.pixels, 1, 128*128*4, myimage); //fwrite(image.pixels, 1, 128*128*4, myimage);
//fclose(myimage); //fclose(myimage);
SetPixelData(&image, imagePixels, 0);
Image image = LoadImageFromData(imagePixels, imWidth, imHeight, UNCOMPRESSED_GRAY_ALPHA);
free(imagePixels); free(imagePixels);
@ -507,7 +504,6 @@ static SpriteFont LoadRBMF(const char *fileName)
} rbmfInfoHeader; } rbmfInfoHeader;
SpriteFont spriteFont; SpriteFont spriteFont;
Image image;
rbmfInfoHeader rbmfHeader; rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL; unsigned int *rbmfFileData = NULL;
@ -529,11 +525,6 @@ static SpriteFont LoadRBMF(const char *fileName)
spriteFont.numChars = (int)rbmfHeader.numChars; spriteFont.numChars = (int)rbmfHeader.numChars;
image.width = (int)rbmfHeader.imgWidth;
image.height = (int)rbmfHeader.imgHeight;
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8;
int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32; int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int)); rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int));
@ -546,14 +537,14 @@ static SpriteFont LoadRBMF(const char *fileName)
// Re-construct image from rbmfFileData // Re-construct image from rbmfFileData
//----------------------------------------- //-----------------------------------------
Color *imagePixels = (Color *)malloc(image.width*image.height*sizeof(Color));
Color *imagePixels = (Color *)malloc(rbmfHeader.imgWidth*rbmfHeader.imgHeight*sizeof(Color));
for (int i = 0; i < image.width*image.height; i++) imagePixels[i] = BLANK; // Initialize array
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter int counter = 0; // Font data elements counter
// Fill image data (convert from bit to pixel!) // Fill image data (convert from bit to pixel!)
for (int i = 0; i < image.width * image.height; i += 32)
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i += 32)
{ {
for (int j = 31; j >= 0; j--) for (int j = 31; j >= 0; j--)
{ {
@ -563,7 +554,7 @@ static SpriteFont LoadRBMF(const char *fileName)
counter++; counter++;
} }
SetPixelData(&image, imagePixels, 0);
Image image = LoadImageFromData(imagePixels, rbmfHeader.imgWidth, rbmfHeader.imgHeight, UNCOMPRESSED_GRAY_ALPHA);
free(imagePixels); free(imagePixels);
@ -694,7 +685,6 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize)
print(100,160, 0, "This is a test"); print(100,160, 0, "This is a test");
*/ */
font.numChars = 95; font.numChars = 95;
font.charSet = (Character *)malloc(font.numChars*sizeof(Character)); font.charSet = (Character *)malloc(font.numChars*sizeof(Character));
font.texture = LoadTextureFromImage(image, false); font.texture = LoadTextureFromImage(image, false);

+ 131
- 14
src/textures.c Visa fil

@ -280,7 +280,7 @@ Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
texture.format = 0; texture.format = 0;
texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps, false); texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps, false);
texture.width = image.width; texture.width = image.width;
texture.height = image.height; texture.height = image.height;
texture.mipmaps = image.mipmaps; texture.mipmaps = image.mipmaps;
@ -439,24 +439,141 @@ Color *GetPixelData(Image image)
} }
// Fill image data with pixels Color data (RGBA - 32bit) // Fill image data with pixels Color data (RGBA - 32bit)
// NOTE: Pixels color array size must be coherent with image size
// TODO: Review to support different color modes (TextureFormat)
void SetPixelData(Image *image, Color *pixels, int format)
// NOTE: Data is transformed to desired format
Image LoadImageFromData(Color *pixels, int width, int height, int format)
{ {
free(image->data);
image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char));
Image image;
image.data = NULL;
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = format;
int k = 0; int k = 0;
for (int i = 0; i < image->width*image->height*4; i += 4)
switch (format)
{ {
((unsigned char *)image->data)[i] = pixels[k].r;
((unsigned char *)image->data)[i + 1] = pixels[k].g;
((unsigned char *)image->data)[i + 2] = pixels[k].b;
((unsigned char *)image->data)[i + 3] = pixels[k].a;
k++;
case UNCOMPRESSED_GRAYSCALE:
{
image.data = (unsigned char *)malloc(image.width*image.height*sizeof(unsigned char));
for (int i = 0; i < image.width*image.height; i++)
{
((unsigned char *)image.data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
k++;
}
} break;
case UNCOMPRESSED_GRAY_ALPHA:
{
image.data = (unsigned char *)malloc(image.width*image.height*2*sizeof(unsigned char));
for (int i = 0; i < image.width*image.height*2; i += 2)
{
((unsigned char *)image.data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
((unsigned char *)image.data)[i + 1] = pixels[k].a;
k++;
}
} break;
case UNCOMPRESSED_R5G6B5:
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
unsigned char r;
unsigned char g;
unsigned char b;
for (int i = 0; i < image.width*image.height; i++)
{
r = (unsigned char)(round((float)pixels[k].r*31/255));
g = (unsigned char)(round((float)pixels[k].g*63/255));
b = (unsigned char)(round((float)pixels[k].b*31/255));
((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
k++;
}
} break;
case UNCOMPRESSED_R8G8B8:
{
image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char));
for (int i = 0; i < image.width*image.height*3; i += 3)
{
((unsigned char *)image.data)[i] = pixels[k].r;
((unsigned char *)image.data)[i + 1] = pixels[k].g;
((unsigned char *)image.data)[i + 2] = pixels[k].b;
k++;
}
} break;
case UNCOMPRESSED_R5G5B5A1:
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a = 1;
for (int i = 0; i < image.width*image.height; i++)
{
r = (unsigned char)(round((float)pixels[k].r*31/255));
g = (unsigned char)(round((float)pixels[k].g*31/255));
b = (unsigned char)(round((float)pixels[k].b*31/255));
a = (pixels[k].a > 50) ? 1 : 0;
((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a;
k++;
}
} break;
case UNCOMPRESSED_R4G4B4A4:
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
for (int i = 0; i < image.width*image.height; i++)
{
r = (unsigned char)(round((float)pixels[k].r*15/255));
g = (unsigned char)(round((float)pixels[k].g*15/255));
b = (unsigned char)(round((float)pixels[k].b*15/255));
a = (unsigned char)(round((float)pixels[k].a*15/255));
((unsigned short *)image.data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a;
k++;
}
} break;
case UNCOMPRESSED_R8G8B8A8:
{
image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char));
for (int i = 0; i < image.width*image.height*4; i += 4)
{
((unsigned char *)image.data)[i] = pixels[k].r;
((unsigned char *)image.data)[i + 1] = pixels[k].g;
((unsigned char *)image.data)[i + 2] = pixels[k].b;
((unsigned char *)image.data)[i + 3] = pixels[k].a;
k++;
}
} break;
default:
{
TraceLog(WARNING, "Format not recognized, image could not be loaded");
return image;
} break;
} }
return image;
} }
// Draw a Texture2D // Draw a Texture2D

Laddar…
Avbryt
Spara