mirror of
				https://github.com/raysan5/raylib.git
				synced 2025-10-26 12:27:01 +00:00 
			
		
		
		
	raymath module review and other changes
Complete review of matrix rotation math Check compressed textures support WIP: LoadImageFromData()
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 raysan5
					raysan5