raymath module review and other changes
Complete review of matrix rotation math Check compressed textures support WIP: LoadImageFromData()
This commit is contained in:
parent
eae98e1c34
commit
a7714c842f
8 changed files with 417 additions and 411 deletions
|
@ -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
|
||||||
|
|
10
src/makefile
10
src/makefile
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
282
src/raymath.c
282
src/raymath.c
|
@ -431,70 +431,76 @@ 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
|
// Create rotation matrix from axis and angle
|
||||||
// TODO: Review this function
|
// NOTE: Angle should be provided in radians
|
||||||
Matrix MatrixRotate(float angleX, float angleY, float angleZ)
|
Matrix MatrixRotate(float angle, Vector3 axis)
|
||||||
{
|
{
|
||||||
Matrix result;
|
Matrix result;
|
||||||
|
|
||||||
Matrix rotX = MatrixRotateX(angleX);
|
Matrix mat = MatrixIdentity();
|
||||||
Matrix rotY = MatrixRotateY(angleY);
|
|
||||||
Matrix rotZ = MatrixRotateZ(angleZ);
|
|
||||||
|
|
||||||
result = MatrixMultiply(MatrixMultiply(rotX, rotY), rotZ);
|
float x = axis.x, y = axis.y, z = axis.z;
|
||||||
|
|
||||||
|
float length = sqrt(x*x + y*y + z*z);
|
||||||
|
|
||||||
|
if ((length != 1) && (length != 0))
|
||||||
|
{
|
||||||
|
length = 1/length;
|
||||||
|
x *= length;
|
||||||
|
y *= length;
|
||||||
|
z *= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
float s = sinf(angle);
|
||||||
|
float c = cosf(angle);
|
||||||
|
float t = 1.0f - c;
|
||||||
|
|
||||||
|
// Cache some matrix values (speed optimization)
|
||||||
|
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
|
||||||
|
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
|
||||||
|
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
|
||||||
|
|
||||||
|
// Construct the elements of the rotation matrix
|
||||||
|
float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s;
|
||||||
|
float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s;
|
||||||
|
float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c;
|
||||||
|
|
||||||
|
// Perform rotation-specific matrix multiplication
|
||||||
|
result.m0 = a00*b00 + a10*b01 + a20*b02;
|
||||||
|
result.m1 = a01*b00 + a11*b01 + a21*b02;
|
||||||
|
result.m2 = a02*b00 + a12*b01 + a22*b02;
|
||||||
|
result.m3 = a03*b00 + a13*b01 + a23*b02;
|
||||||
|
result.m4 = a00*b10 + a10*b11 + a20*b12;
|
||||||
|
result.m5 = a01*b10 + a11*b11 + a21*b12;
|
||||||
|
result.m6 = a02*b10 + a12*b11 + a22*b12;
|
||||||
|
result.m7 = a03*b10 + a13*b11 + a23*b12;
|
||||||
|
result.m8 = a00*b20 + a10*b21 + a20*b22;
|
||||||
|
result.m9 = a01*b20 + a11*b21 + a21*b22;
|
||||||
|
result.m10 = a02*b20 + a12*b21 + a22*b22;
|
||||||
|
result.m11 = a03*b20 + a13*b21 + a23*b22;
|
||||||
|
result.m12 = mat.m12;
|
||||||
|
result.m13 = mat.m13;
|
||||||
|
result.m14 = mat.m14;
|
||||||
|
result.m15 = mat.m15;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
// Another implementation for MatrixRotate...
|
||||||
Matrix MatrixRotate(float angle, float x, float y, float z)
|
Matrix MatrixRotate(float angle, float x, float y, float z)
|
||||||
{
|
{
|
||||||
Matrix result = MatrixIdentity();
|
Matrix result = MatrixIdentity();
|
||||||
|
|
||||||
float c = cosf(angle*DEG2RAD); // cosine
|
float c = cosf(angle); // cosine
|
||||||
float s = sinf(angle*DEG2RAD); // sine
|
float s = sinf(angle); // sine
|
||||||
float c1 = 1.0f - c; // 1 - c
|
float c1 = 1.0f - c; // 1 - c
|
||||||
|
|
||||||
float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
|
float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
|
||||||
|
@ -530,124 +536,6 @@ Matrix MatrixRotate(float angle, float x, float y, float z)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Create rotation matrix from axis and angle
|
|
||||||
// TODO: Test this function
|
|
||||||
// NOTE: NO prototype defined!
|
|
||||||
Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
|
|
||||||
{
|
|
||||||
Matrix result;
|
|
||||||
|
|
||||||
Matrix mat = MatrixIdentity();
|
|
||||||
|
|
||||||
float x = axis.x, y = axis.y, z = axis.z;
|
|
||||||
|
|
||||||
float length = sqrt(x*x + y*y + z*z);
|
|
||||||
|
|
||||||
if ((length != 1) && (length != 0))
|
|
||||||
{
|
|
||||||
length = 1 / length;
|
|
||||||
x *= length;
|
|
||||||
y *= length;
|
|
||||||
z *= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
float s = sin(angle);
|
|
||||||
float c = cos(angle);
|
|
||||||
float t = 1-c;
|
|
||||||
|
|
||||||
// Cache some matrix values (speed optimization)
|
|
||||||
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
|
|
||||||
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
|
|
||||||
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
|
|
||||||
|
|
||||||
// Construct the elements of the rotation matrix
|
|
||||||
float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s;
|
|
||||||
float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s;
|
|
||||||
float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c;
|
|
||||||
|
|
||||||
// Perform rotation-specific matrix multiplication
|
|
||||||
result.m0 = a00*b00 + a10*b01 + a20*b02;
|
|
||||||
result.m1 = a01*b00 + a11*b01 + a21*b02;
|
|
||||||
result.m2 = a02*b00 + a12*b01 + a22*b02;
|
|
||||||
result.m3 = a03*b00 + a13*b01 + a23*b02;
|
|
||||||
result.m4 = a00*b10 + a10*b11 + a20*b12;
|
|
||||||
result.m5 = a01*b10 + a11*b11 + a21*b12;
|
|
||||||
result.m6 = a02*b10 + a12*b11 + a22*b12;
|
|
||||||
result.m7 = a03*b10 + a13*b11 + a23*b12;
|
|
||||||
result.m8 = a00*b20 + a10*b21 + a20*b22;
|
|
||||||
result.m9 = a01*b20 + a11*b21 + a21*b22;
|
|
||||||
result.m10 = a02*b20 + a12*b21 + a22*b22;
|
|
||||||
result.m11 = a03*b20 + a13*b21 + a23*b22;
|
|
||||||
result.m12 = mat.m12;
|
|
||||||
result.m13 = mat.m13;
|
|
||||||
result.m14 = mat.m14;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns rotation matrix for a given quaternion
|
|
||||||
Matrix MatrixFromQuaternion(Quaternion q)
|
|
||||||
{
|
|
||||||
Matrix result = MatrixIdentity();
|
|
||||||
|
|
||||||
Vector3 axis;
|
|
||||||
float angle;
|
|
||||||
|
|
||||||
QuaternionToAxisAngle(q, &axis, &angle);
|
|
||||||
|
|
||||||
result = MatrixFromAxisAngle2(axis, angle);
|
|
||||||
|
|
||||||
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 from a given rotation matrix
|
// Returns a quaternion 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
|
// Returns a matrix for a given quaternion
|
||||||
// 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
|
|
||||||
Matrix QuaternionToMatrix(Quaternion q)
|
Matrix QuaternionToMatrix(Quaternion q)
|
||||||
{
|
{
|
||||||
Matrix result;
|
Matrix result;
|
||||||
|
@ -1069,8 +919,30 @@ Matrix QuaternionToMatrix(Quaternion q)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the axis and the angle for a given quaternion
|
// Returns rotation quaternion for an angle and axis
|
||||||
void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the rotation angle and axis for a given quaternion
|
||||||
|
void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis)
|
||||||
{
|
{
|
||||||
if (fabs(q.w) > 1.0f) QuaternionNormalize(&q);
|
if (fabs(q.w) > 1.0f) QuaternionNormalize(&q);
|
||||||
|
|
||||||
|
|
|
@ -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 MatrixRotate(float angle, Vector3 axis); // Returns rotation matrix for an angle around an specified axis (angle in radians)
|
||||||
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 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 from a given rotation matrix
|
Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix
|
||||||
Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns rotation quaternion for an angle around an axis
|
Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion
|
||||||
Matrix QuaternionToMatrix(Quaternion q); // Calculates the matrix from the given quaternion
|
Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis); // Returns rotation quaternion for an angle and axis
|
||||||
void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the axis and the angle for a given quaternion
|
void QuaternionToAxisAngle(Quaternion q, 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
|
||||||
|
|
295
src/rlgl.c
295
src/rlgl.c
|
@ -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,6 +64,10 @@
|
||||||
#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
|
||||||
|
@ -84,7 +89,24 @@
|
||||||
#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
|
#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
|
||||||
|
|
||||||
|
#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...
|
Vector3 axis = (Vector3){ x, y, z };
|
||||||
if (x == 1) rotation = MatrixRotateX(angleDeg*DEG2RAD);
|
VectorNormalize(&axis);
|
||||||
else if (y == 1) rotation = MatrixRotateY(angleDeg*DEG2RAD);
|
rotation = MatrixRotate(angleDeg*DEG2RAD, axis);
|
||||||
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);
|
|
||||||
|
|
||||||
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(0x8B8C)); //GL_SHADING_LANGUAGE_VERSION
|
TraceLog(INFO, "GPU: GLSL: %s", glGetString(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;
|
||||||
|
@ -854,6 +865,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;
|
||||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
|
glGetIntegerv(GL_NUM_EXTENSIONS, &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((char *)glGetStringi(GL_EXTENSIONS, i), "GL_EXT_texture_compression_s3tc") == 0)
|
||||||
{
|
{
|
||||||
// DDS texture compression support
|
// DDS texture compression support
|
||||||
|
supportedTextureFormat[COMPRESSED_DXT1_RGB] = true;
|
||||||
// TODO: Check required tokens
|
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((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((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((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((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);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
//char** ext = StringSplit(extensions, ' ');
|
||||||
|
//for (int i = 0; i < numExt; i++) printf("%s", ext[i]);
|
||||||
|
|
||||||
|
#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
|
// Apply transformation provided in model.transform matrix
|
||||||
|
Matrix modelviewworld = MatrixMultiply(model.transform, modelview); // World-space transformation
|
||||||
Vector3 rotation = { 0.0f, 0.0f, 0.0f };
|
|
||||||
|
|
||||||
|
// 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 rotation = MatrixRotate(rotationAngle*DEG2RAD, rotationAxis);
|
||||||
Matrix modelviewworld = MatrixMultiply(transform, modelview); // World-space transformation
|
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_RGB: if (supportedTextureFormat[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_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: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT3_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: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT5_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: TraceLog(WARNING, "ETC compression not supported"); break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
|
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: 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_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: 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_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_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_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;
|
||||||
}
|
}
|
||||||
|
#elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
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
|
// 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_RGB: if (supportedTextureFormat[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_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: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); break; // NOTE: Not supported by WebGL
|
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: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_COMPRESSED_RGBA_S3TC_DXT5_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: LoadCompressedTexture((unsigned char *)data, width, height, mipmapCount, GL_ETC1_RGB8_OES); 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: 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_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: 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_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_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_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)
|
||||||
{
|
{
|
||||||
|
|
32
src/text.c
32
src/text.c
|
@ -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;
|
||||||
|
|
||||||
for (int i = 0; i < image.width*image.height; i++) imagePixels[i] = BLANK; // Initialize array
|
Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
137
src/textures.c
137
src/textures.c
|
@ -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
|
// NOTE: Data is transformed to desired format
|
||||||
// TODO: Review to support different color modes (TextureFormat)
|
Image LoadImageFromData(Color *pixels, int width, int height, int format)
|
||||||
void SetPixelData(Image *image, Color *pixels, int format)
|
|
||||||
{
|
{
|
||||||
free(image->data);
|
Image image;
|
||||||
image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char));
|
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;
|
case UNCOMPRESSED_GRAYSCALE:
|
||||||
((unsigned char *)image->data)[i + 1] = pixels[k].g;
|
{
|
||||||
((unsigned char *)image->data)[i + 2] = pixels[k].b;
|
image.data = (unsigned char *)malloc(image.width*image.height*sizeof(unsigned char));
|
||||||
((unsigned char *)image->data)[i + 3] = pixels[k].a;
|
|
||||||
|
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++;
|
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue