]> git.sesse.net Git - pistorm/blob - raylib/textures.c
Add Meson build files.
[pistorm] / raylib / textures.c
1 /**********************************************************************************************
2 *
3 *   raylib.textures - Basic functions to load and draw Textures (2d)
4 *
5 *   CONFIGURATION:
6 *
7 *   #define SUPPORT_FILEFORMAT_BMP
8 *   #define SUPPORT_FILEFORMAT_PNG
9 *   #define SUPPORT_FILEFORMAT_TGA
10 *   #define SUPPORT_FILEFORMAT_JPG
11 *   #define SUPPORT_FILEFORMAT_GIF
12 *   #define SUPPORT_FILEFORMAT_PSD
13 *   #define SUPPORT_FILEFORMAT_PIC
14 *   #define SUPPORT_FILEFORMAT_HDR
15 *   #define SUPPORT_FILEFORMAT_DDS
16 *   #define SUPPORT_FILEFORMAT_PKM
17 *   #define SUPPORT_FILEFORMAT_KTX
18 *   #define SUPPORT_FILEFORMAT_PVR
19 *   #define SUPPORT_FILEFORMAT_ASTC
20 *       Select desired fileformats to be supported for image data loading. Some of those formats are
21 *       supported by default, to remove support, just comment unrequired #define in this module
22 *
23 *   #define SUPPORT_IMAGE_EXPORT
24 *       Support image export in multiple file formats
25 *
26 *   #define SUPPORT_IMAGE_MANIPULATION
27 *       Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
28 *       If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
29 *
30 *   #define SUPPORT_IMAGE_GENERATION
31 *       Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
32 *
33 *   DEPENDENCIES:
34 *       stb_image        - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
35 *                          NOTE: stb_image has been slightly modified to support Android platform.
36 *       stb_image_resize - Multiple image resize algorythms
37 *
38 *
39 *   LICENSE: zlib/libpng
40 *
41 *   Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
42 *
43 *   This software is provided "as-is", without any express or implied warranty. In no event
44 *   will the authors be held liable for any damages arising from the use of this software.
45 *
46 *   Permission is granted to anyone to use this software for any purpose, including commercial
47 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
48 *
49 *     1. The origin of this software must not be misrepresented; you must not claim that you
50 *     wrote the original software. If you use this software in a product, an acknowledgment
51 *     in the product documentation would be appreciated but is not required.
52 *
53 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
54 *     as being the original software.
55 *
56 *     3. This notice may not be removed or altered from any source distribution.
57 *
58 **********************************************************************************************/
59
60 #include "raylib.h"             // Declares module functions
61
62 // Check if config flags have been externally provided on compilation line
63 #if !defined(EXTERNAL_CONFIG_FLAGS)
64     #include "config.h"         // Defines module configuration flags
65 #endif
66
67 #include <stdlib.h>             // Required for: malloc(), free()
68 #include <string.h>             // Required for: strlen() [Used in ImageTextEx()]
69 #include <math.h>               // Required for: fabsf()
70
71 #include "utils.h"              // Required for: fopen() Android mapping
72
73 #include "rlgl.h"               // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
74                                 // Required for: rlLoadTexture() rlUnloadTexture(),
75                                 // rlGenerateMipmaps(), some funcs for DrawTexturePro()
76
77 // Support only desired texture formats on stb_image
78 #if !defined(SUPPORT_FILEFORMAT_BMP)
79     #define STBI_NO_BMP
80 #endif
81 #if !defined(SUPPORT_FILEFORMAT_PNG)
82     #define STBI_NO_PNG
83 #endif
84 #if !defined(SUPPORT_FILEFORMAT_TGA)
85     #define STBI_NO_TGA
86 #endif
87 #if !defined(SUPPORT_FILEFORMAT_JPG)
88     #define STBI_NO_JPEG        // Image format .jpg and .jpeg
89 #endif
90 #if !defined(SUPPORT_FILEFORMAT_PSD)
91     #define STBI_NO_PSD
92 #endif
93 #if !defined(SUPPORT_FILEFORMAT_GIF)
94     #define STBI_NO_GIF
95 #endif
96 #if !defined(SUPPORT_FILEFORMAT_PIC)
97     #define STBI_NO_PIC
98 #endif
99 #if !defined(SUPPORT_FILEFORMAT_HDR)
100     #define STBI_NO_HDR
101 #endif
102
103 // Image fileformats not supported by default
104 #define STBI_NO_PIC
105 #define STBI_NO_PNM             // Image format .ppm and .pgm
106
107 #if (defined(SUPPORT_FILEFORMAT_BMP) || \
108      defined(SUPPORT_FILEFORMAT_PNG) || \
109      defined(SUPPORT_FILEFORMAT_TGA) || \
110      defined(SUPPORT_FILEFORMAT_JPG) || \
111      defined(SUPPORT_FILEFORMAT_PSD) || \
112      defined(SUPPORT_FILEFORMAT_GIF) || \
113      defined(SUPPORT_FILEFORMAT_PIC) || \
114      defined(SUPPORT_FILEFORMAT_HDR))
115
116     #define STBI_MALLOC RL_MALLOC
117     #define STBI_FREE RL_FREE
118     #define STBI_REALLOC RL_REALLOC
119
120     #define STB_IMAGE_IMPLEMENTATION
121     #include "external/stb_image.h"         // Required for: stbi_load_from_file()
122                                             // NOTE: Used to read image data (multiple formats support)
123 #endif
124
125 #if (defined(SUPPORT_IMAGE_EXPORT) || defined(SUPPORT_COMPRESSION_API))
126     #define STBIW_MALLOC RL_MALLOC
127     #define STBIW_FREE RL_FREE
128     #define STBIW_REALLOC RL_REALLOC
129
130     #define STB_IMAGE_WRITE_IMPLEMENTATION
131     #include "external/stb_image_write.h"   // Required for: stbi_write_*()
132 #endif
133
134 #if defined(SUPPORT_IMAGE_MANIPULATION)
135     #define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
136     #define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
137
138     #define STB_IMAGE_RESIZE_IMPLEMENTATION
139     #include "external/stb_image_resize.h"  // Required for: stbir_resize_uint8() [ImageResize()]
140 #endif
141
142 #if defined(SUPPORT_IMAGE_GENERATION)
143     #define STB_PERLIN_IMPLEMENTATION
144     #include "external/stb_perlin.h"        // Required for: stb_perlin_fbm_noise3
145 #endif
146
147 //----------------------------------------------------------------------------------
148 // Defines and Macros
149 //----------------------------------------------------------------------------------
150 #ifndef PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD
151     #define PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD  50    // Threshold over 255 to set alpha as 0
152 #endif
153
154 //----------------------------------------------------------------------------------
155 // Types and Structures Definition
156 //----------------------------------------------------------------------------------
157 // ...
158
159 //----------------------------------------------------------------------------------
160 // Global Variables Definition
161 //----------------------------------------------------------------------------------
162 // It's lonely here...
163
164 //----------------------------------------------------------------------------------
165 // Other Modules Functions Declaration (required by text)
166 //----------------------------------------------------------------------------------
167 // ...
168
169 //----------------------------------------------------------------------------------
170 // Module specific Functions Declaration
171 //----------------------------------------------------------------------------------
172 #if defined(SUPPORT_FILEFORMAT_DDS)
173 static Image LoadDDS(const unsigned char *fileData, unsigned int fileSize);   // Load DDS file data
174 #endif
175 #if defined(SUPPORT_FILEFORMAT_PKM)
176 static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize);   // Load PKM file data
177 #endif
178 #if defined(SUPPORT_FILEFORMAT_KTX)
179 static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize);   // Load KTX file data
180 static int SaveKTX(Image image, const char *fileName);  // Save image data as KTX file
181 #endif
182 #if defined(SUPPORT_FILEFORMAT_PVR)
183 static Image LoadPVR(const unsigned char *fileData, unsigned int fileSize);   // Load PVR file data
184 #endif
185 #if defined(SUPPORT_FILEFORMAT_ASTC)
186 static Image LoadASTC(const unsigned char *fileData, unsigned int fileSize);  // Load ASTC file data
187 #endif
188 static Vector4 *LoadImageDataNormalized(Image image);    // Load pixel data from image as Vector4 array (float normalized)
189
190 //----------------------------------------------------------------------------------
191 // Module Functions Definition
192 //----------------------------------------------------------------------------------
193
194 // Load image from file into CPU memory (RAM)
195 Image LoadImage(const char *fileName)
196 {
197     Image image = { 0 };
198
199 #if defined(SUPPORT_FILEFORMAT_PNG) || \
200     defined(SUPPORT_FILEFORMAT_BMP) || \
201     defined(SUPPORT_FILEFORMAT_TGA) || \
202     defined(SUPPORT_FILEFORMAT_JPG) || \
203     defined(SUPPORT_FILEFORMAT_GIF) || \
204     defined(SUPPORT_FILEFORMAT_PIC) || \
205     defined(SUPPORT_FILEFORMAT_HDR) || \
206     defined(SUPPORT_FILEFORMAT_PSD)
207 #define STBI_REQUIRED
208 #endif
209
210     // Loading file to memory
211     unsigned int fileSize = 0;
212     unsigned char *fileData = LoadFileData(fileName, &fileSize);
213
214     if (fileData != NULL)
215     {
216         // Loading image from memory data
217         image = LoadImageFromMemory(GetFileExtension(fileName), fileData, fileSize);
218
219         if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: [%s] Data loaded successfully (%ix%i)", fileName, image.width, image.height);
220         else TRACELOG(LOG_WARNING, "IMAGE: [%s] Failed to load data", fileName);
221
222         RL_FREE(fileData);
223     }
224
225     return image;
226 }
227
228 // Load an image from RAW file data
229 Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize)
230 {
231     Image image = { 0 };
232
233     unsigned int dataSize = 0;
234     unsigned char *fileData = LoadFileData(fileName, &dataSize);
235
236     if (fileData != NULL)
237     {
238         unsigned char *dataPtr = fileData;
239         unsigned int size = GetPixelDataSize(width, height, format);
240
241         if (headerSize > 0) dataPtr += headerSize;
242
243         image.data = RL_MALLOC(size);      // Allocate required memory in bytes
244         memcpy(image.data, dataPtr, size); // Copy required data to image
245         image.width = width;
246         image.height = height;
247         image.mipmaps = 1;
248         image.format = format;
249
250         RL_FREE(fileData);
251     }
252
253     return image;
254 }
255
256 // Load animated image data
257 //  - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
258 //  - Number of frames is returned through 'frames' parameter
259 //  - All frames are returned in RGBA format
260 //  - Frames delay data is discarded
261 Image LoadImageAnim(const char *fileName, int *frames)
262 {
263     Image image = { 0 };
264     int framesCount = 1;
265
266 #if defined(SUPPORT_FILEFORMAT_GIF)
267     if (IsFileExtension(fileName, ".gif"))
268     {
269         unsigned int dataSize = 0;
270         unsigned char *fileData = LoadFileData(fileName, &dataSize);
271
272         if (fileData != NULL)
273         {
274             int comp = 0;
275             int **delays = NULL;
276             image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, &framesCount, &comp, 4);
277
278             image.mipmaps = 1;
279             image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
280
281             RL_FREE(fileData);
282             RL_FREE(delays);        // NOTE: Frames delays are discarded
283         }
284     }
285 #else
286     if (false) { }
287 #endif
288     else image = LoadImage(fileName);
289
290     // TODO: Support APNG animated images?
291
292     *frames = framesCount;
293     return image;
294 }
295
296 // Load image from memory buffer, fileType refers to extension: i.e. ".png"
297 Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
298 {
299     Image image = { 0 };
300
301     char fileExtLower[16] = { 0 };
302     strcpy(fileExtLower, TextToLower(fileType));
303
304 #if defined(SUPPORT_FILEFORMAT_PNG)
305     if ((TextIsEqual(fileExtLower, ".png"))
306 #else
307     if ((false)
308 #endif
309 #if defined(SUPPORT_FILEFORMAT_BMP)
310         || (TextIsEqual(fileExtLower, ".bmp"))
311 #endif
312 #if defined(SUPPORT_FILEFORMAT_TGA)
313         || (TextIsEqual(fileExtLower, ".tga"))
314 #endif
315 #if defined(SUPPORT_FILEFORMAT_JPG)
316         || (TextIsEqual(fileExtLower, ".jpg") ||
317             TextIsEqual(fileExtLower, ".jpeg"))
318 #endif
319 #if defined(SUPPORT_FILEFORMAT_GIF)
320         || (TextIsEqual(fileExtLower, ".gif"))
321 #endif
322 #if defined(SUPPORT_FILEFORMAT_PIC)
323         || (TextIsEqual(fileExtLower, ".pic"))
324 #endif
325 #if defined(SUPPORT_FILEFORMAT_PSD)
326         || (TextIsEqual(fileExtLower, ".psd"))
327 #endif
328        )
329     {
330 #if defined(STBI_REQUIRED)
331         // NOTE: Using stb_image to load images (Supports multiple image formats)
332
333         if (fileData != NULL)
334         {
335             int comp = 0;
336             image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
337
338             image.mipmaps = 1;
339
340             if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
341             else if (comp == 2) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
342             else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
343             else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
344         }
345 #endif
346     }
347 #if defined(SUPPORT_FILEFORMAT_HDR)
348     else if (TextIsEqual(fileExtLower, ".hdr"))
349     {
350 #if defined(STBI_REQUIRED)
351         if (fileData != NULL)
352         {
353             int comp = 0;
354             image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
355
356             image.mipmaps = 1;
357
358             if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_R32;
359             else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
360             else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
361             else
362             {
363                 TRACELOG(LOG_WARNING, "IMAGE: HDR file format not supported");
364                 UnloadImage(image);
365             }
366         }
367 #endif
368     }
369 #endif
370 #if defined(SUPPORT_FILEFORMAT_DDS)
371     else if (TextIsEqual(fileExtLower, ".dds")) image = LoadDDS(fileData, dataSize);
372 #endif
373 #if defined(SUPPORT_FILEFORMAT_PKM)
374     else if (TextIsEqual(fileExtLower, ".pkm")) image = LoadPKM(fileData, dataSize);
375 #endif
376 #if defined(SUPPORT_FILEFORMAT_KTX)
377     else if (TextIsEqual(fileExtLower, ".ktx")) image = LoadKTX(fileData, dataSize);
378 #endif
379 #if defined(SUPPORT_FILEFORMAT_PVR)
380     else if (TextIsEqual(fileExtLower, ".pvr")) image = LoadPVR(fileData, dataSize);
381 #endif
382 #if defined(SUPPORT_FILEFORMAT_ASTC)
383     else if (TextIsEqual(fileExtLower, ".astc")) image = LoadASTC(fileData, dataSize);
384 #endif
385     else TRACELOG(LOG_WARNING, "IMAGE: File format not supported");
386
387     return image;
388 }
389
390 // Unload image from CPU memory (RAM)
391 void UnloadImage(Image image)
392 {
393     RL_FREE(image.data);
394 }
395
396 // Export image data to file
397 // NOTE: File format depends on fileName extension
398 bool ExportImage(Image image, const char *fileName)
399 {
400     int success = 0;
401
402 #if defined(SUPPORT_IMAGE_EXPORT)
403     int channels = 4;
404     bool allocatedData = false;
405     unsigned char *imgData = (unsigned char *)image.data;
406
407     if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1;
408     else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2;
409     else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
410     else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
411     else
412     {
413         // NOTE: Getting Color array as RGBA unsigned char values
414         imgData = (unsigned char *)LoadImageColors(image);
415         allocatedData = true;
416     }
417
418 #if defined(SUPPORT_FILEFORMAT_PNG)
419     if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, channels, imgData, image.width*channels);
420 #else
421     if (false) {}
422 #endif
423 #if defined(SUPPORT_FILEFORMAT_BMP)
424     else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, channels, imgData);
425 #endif
426 #if defined(SUPPORT_FILEFORMAT_TGA)
427     else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, channels, imgData);
428 #endif
429 #if defined(SUPPORT_FILEFORMAT_JPG)
430     else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90);  // JPG quality: between 1 and 100
431 #endif
432 #if defined(SUPPORT_FILEFORMAT_KTX)
433     else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
434 #endif
435     else if (IsFileExtension(fileName, ".raw"))
436     {
437         // Export raw pixel data (without header)
438         // NOTE: It's up to the user to track image parameters
439         success = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
440     }
441
442     if (allocatedData) RL_FREE(imgData);
443 #endif      // SUPPORT_IMAGE_EXPORT
444
445     if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
446     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
447
448     return success;
449 }
450
451 // Export image as code file (.h) defining an array of bytes
452 bool ExportImageAsCode(Image image, const char *fileName)
453 {
454     bool success = false;
455
456 #ifndef TEXT_BYTES_PER_LINE
457     #define TEXT_BYTES_PER_LINE     20
458 #endif
459
460     int dataSize = GetPixelDataSize(image.width, image.height, image.format);
461
462     // NOTE: Text data buffer size is estimated considering image data size in bytes
463     // and requiring 6 char bytes for every byte: "0x00, "
464     char *txtData = (char *)RL_CALLOC(6*dataSize + 2000, sizeof(char));
465
466     int bytesCount = 0;
467     bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
468     bytesCount += sprintf(txtData + bytesCount, "//                                                                                    //\n");
469     bytesCount += sprintf(txtData + bytesCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes         //\n");
470     bytesCount += sprintf(txtData + bytesCount, "//                                                                                    //\n");
471     bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
472     bytesCount += sprintf(txtData + bytesCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
473     bytesCount += sprintf(txtData + bytesCount, "//                                                                                    //\n");
474     bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2020 Ramon Santamaria (@raysan5)                                     //\n");
475     bytesCount += sprintf(txtData + bytesCount, "//                                                                                    //\n");
476     bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
477
478     // Get file name from path and convert variable name to uppercase
479     char varFileName[256] = { 0 };
480     strcpy(varFileName, GetFileNameWithoutExt(fileName));
481     for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
482
483     // Add image information
484     bytesCount += sprintf(txtData + bytesCount, "// Image data information\n");
485     bytesCount += sprintf(txtData + bytesCount, "#define %s_WIDTH    %i\n", varFileName, image.width);
486     bytesCount += sprintf(txtData + bytesCount, "#define %s_HEIGHT   %i\n", varFileName, image.height);
487     bytesCount += sprintf(txtData + bytesCount, "#define %s_FORMAT   %i          // raylib internal pixel format\n\n", varFileName, image.format);
488
489     bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
490     for (int i = 0; i < dataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
491     bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
492
493     // NOTE: Text data length exported is determined by '\0' (NULL) character
494     success = SaveFileText(fileName, txtData);
495
496     RL_FREE(txtData);
497
498     return success;
499 }
500
501 //------------------------------------------------------------------------------------
502 // Image generation functions
503 //------------------------------------------------------------------------------------
504 // Generate image: plain color
505 Image GenImageColor(int width, int height, Color color)
506 {
507     Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color));
508
509     for (int i = 0; i < width*height; i++) pixels[i] = color;
510
511     Image image = {
512         .data = pixels,
513         .width = width,
514         .height = height,
515         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
516         .mipmaps = 1
517     };
518
519     return image;
520 }
521
522 #if defined(SUPPORT_IMAGE_GENERATION)
523 // Generate image: vertical gradient
524 Image GenImageGradientV(int width, int height, Color top, Color bottom)
525 {
526     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
527
528     for (int j = 0; j < height; j++)
529     {
530         float factor = (float)j/(float)height;
531         for (int i = 0; i < width; i++)
532         {
533             pixels[j*width + i].r = (int)((float)bottom.r*factor + (float)top.r*(1.f - factor));
534             pixels[j*width + i].g = (int)((float)bottom.g*factor + (float)top.g*(1.f - factor));
535             pixels[j*width + i].b = (int)((float)bottom.b*factor + (float)top.b*(1.f - factor));
536             pixels[j*width + i].a = (int)((float)bottom.a*factor + (float)top.a*(1.f - factor));
537         }
538     }
539
540     Image image = {
541         .data = pixels,
542         .width = width,
543         .height = height,
544         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
545         .mipmaps = 1
546     };
547
548     return image;
549 }
550
551 // Generate image: horizontal gradient
552 Image GenImageGradientH(int width, int height, Color left, Color right)
553 {
554     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
555
556     for (int i = 0; i < width; i++)
557     {
558         float factor = (float)i/(float)width;
559         for (int j = 0; j < height; j++)
560         {
561             pixels[j*width + i].r = (int)((float)right.r*factor + (float)left.r*(1.f - factor));
562             pixels[j*width + i].g = (int)((float)right.g*factor + (float)left.g*(1.f - factor));
563             pixels[j*width + i].b = (int)((float)right.b*factor + (float)left.b*(1.f - factor));
564             pixels[j*width + i].a = (int)((float)right.a*factor + (float)left.a*(1.f - factor));
565         }
566     }
567
568     Image image = {
569         .data = pixels,
570         .width = width,
571         .height = height,
572         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
573         .mipmaps = 1
574     };
575
576     return image;
577 }
578
579 // Generate image: radial gradient
580 Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer)
581 {
582     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
583     float radius = (width < height)? (float)width/2.0f : (float)height/2.0f;
584
585     float centerX = (float)width/2.0f;
586     float centerY = (float)height/2.0f;
587
588     for (int y = 0; y < height; y++)
589     {
590         for (int x = 0; x < width; x++)
591         {
592             float dist = hypotf((float)x - centerX, (float)y - centerY);
593             float factor = (dist - radius*density)/(radius*(1.0f - density));
594
595             factor = (float)fmax(factor, 0.0f);
596             factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check
597
598             pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
599             pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
600             pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
601             pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor));
602         }
603     }
604
605     Image image = {
606         .data = pixels,
607         .width = width,
608         .height = height,
609         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
610         .mipmaps = 1
611     };
612
613     return image;
614 }
615
616 // Generate image: checked
617 Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2)
618 {
619     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
620
621     for (int y = 0; y < height; y++)
622     {
623         for (int x = 0; x < width; x++)
624         {
625             if ((x/checksX + y/checksY)%2 == 0) pixels[y*width + x] = col1;
626             else pixels[y*width + x] = col2;
627         }
628     }
629
630     Image image = {
631         .data = pixels,
632         .width = width,
633         .height = height,
634         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
635         .mipmaps = 1
636     };
637
638     return image;
639 }
640
641 // Generate image: white noise
642 Image GenImageWhiteNoise(int width, int height, float factor)
643 {
644     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
645
646     for (int i = 0; i < width*height; i++)
647     {
648         if (GetRandomValue(0, 99) < (int)(factor*100.0f)) pixels[i] = WHITE;
649         else pixels[i] = BLACK;
650     }
651
652     Image image = {
653         .data = pixels,
654         .width = width,
655         .height = height,
656         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
657         .mipmaps = 1
658     };
659
660     return image;
661 }
662
663 // Generate image: perlin noise
664 Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale)
665 {
666     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
667
668     for (int y = 0; y < height; y++)
669     {
670         for (int x = 0; x < width; x++)
671         {
672             float nx = (float)(x + offsetX)*scale/(float)width;
673             float ny = (float)(y + offsetY)*scale/(float)height;
674
675             // Typical values to start playing with:
676             //   lacunarity = ~2.0   -- spacing between successive octaves (use exactly 2.0 for wrapping output)
677             //   gain       =  0.5   -- relative weighting applied to each successive octave
678             //   octaves    =  6     -- number of "octaves" of noise3() to sum
679
680             // NOTE: We need to translate the data from [-1..1] to [0..1]
681             float p = (stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6) + 1.0f)/2.0f;
682
683             int intensity = (int)(p*255.0f);
684             pixels[y*width + x] = (Color){intensity, intensity, intensity, 255};
685         }
686     }
687
688     Image image = {
689         .data = pixels,
690         .width = width,
691         .height = height,
692         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
693         .mipmaps = 1
694     };
695
696     return image;
697 }
698
699 // Generate image: cellular algorithm. Bigger tileSize means bigger cells
700 Image GenImageCellular(int width, int height, int tileSize)
701 {
702     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
703
704     int seedsPerRow = width/tileSize;
705     int seedsPerCol = height/tileSize;
706     int seedsCount = seedsPerRow*seedsPerCol;
707
708     Vector2 *seeds = (Vector2 *)RL_MALLOC(seedsCount*sizeof(Vector2));
709
710     for (int i = 0; i < seedsCount; i++)
711     {
712         int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
713         int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
714         seeds[i] = (Vector2){ (float)x, (float)y};
715     }
716
717     for (int y = 0; y < height; y++)
718     {
719         int tileY = y/tileSize;
720
721         for (int x = 0; x < width; x++)
722         {
723             int tileX = x/tileSize;
724
725             float minDistance = (float)strtod("Inf", NULL);
726
727             // Check all adjacent tiles
728             for (int i = -1; i < 2; i++)
729             {
730                 if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue;
731
732                 for (int j = -1; j < 2; j++)
733                 {
734                     if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue;
735
736                     Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i];
737
738                     float dist = (float)hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y);
739                     minDistance = (float)fmin(minDistance, dist);
740                 }
741             }
742
743             // I made this up but it seems to give good results at all tile sizes
744             int intensity = (int)(minDistance*256.0f/tileSize);
745             if (intensity > 255) intensity = 255;
746
747             pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 };
748         }
749     }
750
751     RL_FREE(seeds);
752
753     Image image = {
754         .data = pixels,
755         .width = width,
756         .height = height,
757         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
758         .mipmaps = 1
759     };
760
761     return image;
762 }
763 #endif      // SUPPORT_IMAGE_GENERATION
764
765 //------------------------------------------------------------------------------------
766 // Image manipulation functions
767 //------------------------------------------------------------------------------------
768 // Copy an image to a new image
769 Image ImageCopy(Image image)
770 {
771     Image newImage = { 0 };
772
773     int width = image.width;
774     int height = image.height;
775     int size = 0;
776
777     for (int i = 0; i < image.mipmaps; i++)
778     {
779         size += GetPixelDataSize(width, height, image.format);
780
781         width /= 2;
782         height /= 2;
783
784         // Security check for NPOT textures
785         if (width < 1) width = 1;
786         if (height < 1) height = 1;
787     }
788
789     newImage.data = RL_MALLOC(size);
790
791     if (newImage.data != NULL)
792     {
793         // NOTE: Size must be provided in bytes
794         memcpy(newImage.data, image.data, size);
795
796         newImage.width = image.width;
797         newImage.height = image.height;
798         newImage.mipmaps = image.mipmaps;
799         newImage.format = image.format;
800     }
801
802     return newImage;
803 }
804
805 // Create an image from another image piece
806 Image ImageFromImage(Image image, Rectangle rec)
807 {
808     Image result = { 0 };
809
810     int bytesPerPixel = GetPixelDataSize(1, 1, image.format);
811
812     // TODO: Check rec is valid?
813
814     result.width = (int)rec.width;
815     result.height = (int)rec.height;
816     result.data = RL_CALLOC((int)(rec.width*rec.height)*bytesPerPixel, 1);
817     result.format = image.format;
818     result.mipmaps = 1;
819
820     for (int y = 0; y < rec.height; y++)
821     {
822         memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel);
823     }
824
825     return result;
826 }
827
828 // Crop an image to area defined by a rectangle
829 // NOTE: Security checks are performed in case rectangle goes out of bounds
830 void ImageCrop(Image *image, Rectangle crop)
831 {
832     // Security check to avoid program crash
833     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
834
835     // Security checks to validate crop rectangle
836     if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
837     if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
838     if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
839     if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
840     if ((crop.x > image->width) || (crop.y > image->height))
841     {
842         TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds");
843         return;
844     }
845
846     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
847     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
848     else
849     {
850         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
851
852         unsigned char *croppedData = (unsigned char *)RL_MALLOC((int)(crop.width*crop.height)*bytesPerPixel);
853
854         // OPTION 1: Move cropped data line-by-line
855         for (int y = (int)crop.y, offsetSize = 0; y < (int)(crop.y + crop.height); y++)
856         {
857             memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + (int)crop.x)*bytesPerPixel, (int)crop.width*bytesPerPixel);
858             offsetSize += ((int)crop.width*bytesPerPixel);
859         }
860
861         /*
862         // OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte
863         for (int y = (int)crop.y; y < (int)(crop.y + crop.height); y++)
864         {
865             for (int x = (int)crop.x; x < (int)(crop.x + crop.width); x++)
866             {
867                 //memcpy(croppedData + ((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
868                 for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
869             }
870         }
871         */
872
873         RL_FREE(image->data);
874         image->data = croppedData;
875         image->width = (int)crop.width;
876         image->height = (int)crop.height;
877     }
878 }
879
880 // Convert image data to desired format
881 void ImageFormat(Image *image, int newFormat)
882 {
883     // Security check to avoid program crash
884     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
885
886     if ((newFormat != 0) && (image->format != newFormat))
887     {
888         if ((image->format < PIXELFORMAT_COMPRESSED_DXT1_RGB) && (newFormat < PIXELFORMAT_COMPRESSED_DXT1_RGB))
889         {
890             Vector4 *pixels = LoadImageDataNormalized(*image);     // Supports 8 to 32 bit per channel
891
892             RL_FREE(image->data);      // WARNING! We loose mipmaps data --> Regenerated at the end...
893             image->data = NULL;
894             image->format = newFormat;
895
896             int k = 0;
897
898             switch (image->format)
899             {
900                 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
901                 {
902                     image->data = (unsigned char *)RL_MALLOC(image->width*image->height*sizeof(unsigned char));
903
904                     for (int i = 0; i < image->width*image->height; i++)
905                     {
906                         ((unsigned char *)image->data)[i] = (unsigned char)((pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)*255.0f);
907                     }
908
909                 } break;
910                 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
911                 {
912                     image->data = (unsigned char *)RL_MALLOC(image->width*image->height*2*sizeof(unsigned char));
913
914                     for (int i = 0; i < image->width*image->height*2; i += 2, k++)
915                     {
916                         ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f);
917                         ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f);
918                     }
919
920                 } break;
921                 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
922                 {
923                     image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
924
925                     unsigned char r = 0;
926                     unsigned char g = 0;
927                     unsigned char b = 0;
928
929                     for (int i = 0; i < image->width*image->height; i++)
930                     {
931                         r = (unsigned char)(round(pixels[i].x*31.0f));
932                         g = (unsigned char)(round(pixels[i].y*63.0f));
933                         b = (unsigned char)(round(pixels[i].z*31.0f));
934
935                         ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
936                     }
937
938                 } break;
939                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
940                 {
941                     image->data = (unsigned char *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned char));
942
943                     for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
944                     {
945                         ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
946                         ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
947                         ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
948                     }
949                 } break;
950                 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
951                 {
952                     image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
953
954                     unsigned char r = 0;
955                     unsigned char g = 0;
956                     unsigned char b = 0;
957                     unsigned char a = 0;
958
959                     for (int i = 0; i < image->width*image->height; i++)
960                     {
961                         r = (unsigned char)(round(pixels[i].x*31.0f));
962                         g = (unsigned char)(round(pixels[i].y*31.0f));
963                         b = (unsigned char)(round(pixels[i].z*31.0f));
964                         a = (pixels[i].w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
965
966                         ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
967                     }
968
969                 } break;
970                 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
971                 {
972                     image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
973
974                     unsigned char r = 0;
975                     unsigned char g = 0;
976                     unsigned char b = 0;
977                     unsigned char a = 0;
978
979                     for (int i = 0; i < image->width*image->height; i++)
980                     {
981                         r = (unsigned char)(round(pixels[i].x*15.0f));
982                         g = (unsigned char)(round(pixels[i].y*15.0f));
983                         b = (unsigned char)(round(pixels[i].z*15.0f));
984                         a = (unsigned char)(round(pixels[i].w*15.0f));
985
986                         ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
987                     }
988
989                 } break;
990                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
991                 {
992                     image->data = (unsigned char *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned char));
993
994                     for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
995                     {
996                         ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
997                         ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
998                         ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
999                         ((unsigned char *)image->data)[i + 3] = (unsigned char)(pixels[k].w*255.0f);
1000                     }
1001                 } break;
1002                 case PIXELFORMAT_UNCOMPRESSED_R32:
1003                 {
1004                     // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit
1005
1006                     image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float));
1007
1008                     for (int i = 0; i < image->width*image->height; i++)
1009                     {
1010                         ((float *)image->data)[i] = (float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f);
1011                     }
1012                 } break;
1013                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
1014                 {
1015                     image->data = (float *)RL_MALLOC(image->width*image->height*3*sizeof(float));
1016
1017                     for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
1018                     {
1019                         ((float *)image->data)[i] = pixels[k].x;
1020                         ((float *)image->data)[i + 1] = pixels[k].y;
1021                         ((float *)image->data)[i + 2] = pixels[k].z;
1022                     }
1023                 } break;
1024                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
1025                 {
1026                     image->data = (float *)RL_MALLOC(image->width*image->height*4*sizeof(float));
1027
1028                     for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
1029                     {
1030                         ((float *)image->data)[i] = pixels[k].x;
1031                         ((float *)image->data)[i + 1] = pixels[k].y;
1032                         ((float *)image->data)[i + 2] = pixels[k].z;
1033                         ((float *)image->data)[i + 3] = pixels[k].w;
1034                     }
1035                 } break;
1036                 default: break;
1037             }
1038
1039             RL_FREE(pixels);
1040             pixels = NULL;
1041
1042             // In case original image had mipmaps, generate mipmaps for formated image
1043             // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
1044             if (image->mipmaps > 1)
1045             {
1046                 image->mipmaps = 1;
1047             #if defined(SUPPORT_IMAGE_MANIPULATION)
1048                 if (image->data != NULL) ImageMipmaps(image);
1049             #endif
1050             }
1051         }
1052         else TRACELOG(LOG_WARNING, "IMAGE: Data format is compressed, can not be converted");
1053     }
1054 }
1055
1056 // Convert image to POT (power-of-two)
1057 // NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
1058 void ImageToPOT(Image *image, Color fill)
1059 {
1060     // Security check to avoid program crash
1061     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1062
1063     // Calculate next power-of-two values
1064     // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
1065     int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
1066     int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
1067
1068     // Check if POT texture generation is required (if texture is not already POT)
1069     if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill);
1070 }
1071
1072 #if defined(SUPPORT_IMAGE_MANIPULATION)
1073 // Create an image from text (default font)
1074 Image ImageText(const char *text, int fontSize, Color color)
1075 {
1076     int defaultFontSize = 10;   // Default Font chars height in pixel
1077     if (fontSize < defaultFontSize) fontSize = defaultFontSize;
1078     int spacing = fontSize/defaultFontSize;
1079
1080     Image imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color);
1081
1082     return imText;
1083 }
1084
1085 // Create an image from text (custom sprite font)
1086 Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
1087 {
1088     int length = (int)strlen(text);
1089
1090     int textOffsetX = 0;            // Image drawing position X
1091     int textOffsetY = 0;            // Offset between lines (on line break '\n')
1092
1093     // NOTE: Text image is generated at font base size, later scaled to desired font size
1094     Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);
1095
1096     // Create image to store text
1097     Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
1098
1099     for (int i = 0; i < length; i++)
1100     {
1101         // Get next codepoint from byte string and glyph index in font
1102         int codepointByteCount = 0;
1103         int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
1104         int index = GetGlyphIndex(font, codepoint);
1105
1106         // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
1107         // but we need to draw all of the bad bytes using the '?' symbol moving one byte
1108         if (codepoint == 0x3f) codepointByteCount = 1;
1109
1110         if (codepoint == '\n')
1111         {
1112             // NOTE: Fixed line spacing of 1.5 line-height
1113             // TODO: Support custom line spacing defined by user
1114             textOffsetY += (font.baseSize + font.baseSize/2);
1115             textOffsetX = 0;
1116         }
1117         else
1118         {
1119             if ((codepoint != ' ') && (codepoint != '\t'))
1120             {
1121                 Rectangle rec = { (float)(textOffsetX + font.chars[index].offsetX), (float)(textOffsetY + font.chars[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height };
1122                 ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, (float)font.chars[index].image.width, (float)font.chars[index].image.height }, rec, tint);
1123             }
1124
1125             if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing);
1126             else textOffsetX += font.chars[index].advanceX + (int)spacing;
1127         }
1128
1129         i += (codepointByteCount - 1);   // Move text bytes counter to next codepoint
1130     }
1131
1132     // Scale image depending on text size
1133     if (fontSize > imSize.y)
1134     {
1135         float scaleFactor = fontSize/imSize.y;
1136         TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
1137
1138         // Using nearest-neighbor scaling algorithm for default font
1139         if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
1140         else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
1141     }
1142
1143     return imText;
1144 }
1145
1146 // Crop image depending on alpha value
1147 // NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f
1148 void ImageAlphaCrop(Image *image, float threshold)
1149 {
1150     // Security check to avoid program crash
1151     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1152
1153     Rectangle crop = GetImageAlphaBorder(*image, threshold);
1154
1155     // Crop if rectangle is valid
1156     if (((int)crop.width != 0) && ((int)crop.height != 0)) ImageCrop(image, crop);
1157 }
1158
1159 // Clear alpha channel to desired color
1160 // NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
1161 void ImageAlphaClear(Image *image, Color color, float threshold)
1162 {
1163     // Security check to avoid program crash
1164     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1165
1166     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1167     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1168     else
1169     {
1170         switch (image->format)
1171         {
1172             case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
1173             {
1174                 unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
1175                 for (int i = 1; i < image->width*image->height*2; i += 2)
1176                 {
1177                     if (((unsigned char *)image->data)[i] <= thresholdValue)
1178                     {
1179                         ((unsigned char *)image->data)[i - 1] = color.r;
1180                         ((unsigned char *)image->data)[i] = color.a;
1181                     }
1182                 }
1183             } break;
1184             case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
1185             {
1186                 unsigned char thresholdValue = ((threshold < 0.5f)? 0 : 1);
1187
1188                 unsigned char r = (unsigned char)(round((float)color.r*31.0f));
1189                 unsigned char g = (unsigned char)(round((float)color.g*31.0f));
1190                 unsigned char b = (unsigned char)(round((float)color.b*31.0f));
1191                 unsigned char a = (color.a < 128)? 0 : 1;
1192
1193                 for (int i = 0; i < image->width*image->height; i++)
1194                 {
1195                     if ((((unsigned short *)image->data)[i] & 0b0000000000000001) <= thresholdValue)
1196                     {
1197                         ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
1198                     }
1199                 }
1200             } break;
1201             case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
1202             {
1203                 unsigned char thresholdValue = (unsigned char)(threshold*15.0f);
1204
1205                 unsigned char r = (unsigned char)(round((float)color.r*15.0f));
1206                 unsigned char g = (unsigned char)(round((float)color.g*15.0f));
1207                 unsigned char b = (unsigned char)(round((float)color.b*15.0f));
1208                 unsigned char a = (unsigned char)(round((float)color.a*15.0f));
1209
1210                 for (int i = 0; i < image->width*image->height; i++)
1211                 {
1212                     if ((((unsigned short *)image->data)[i] & 0x000f) <= thresholdValue)
1213                     {
1214                         ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
1215                     }
1216                 }
1217             } break;
1218             case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
1219             {
1220                 unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
1221                 for (int i = 3; i < image->width*image->height*4; i += 4)
1222                 {
1223                     if (((unsigned char *)image->data)[i] <= thresholdValue)
1224                     {
1225                         ((unsigned char *)image->data)[i - 3] = color.r;
1226                         ((unsigned char *)image->data)[i - 2] = color.g;
1227                         ((unsigned char *)image->data)[i - 1] = color.b;
1228                         ((unsigned char *)image->data)[i] = color.a;
1229                     }
1230                 }
1231             } break;
1232             case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
1233             {
1234                 for (int i = 3; i < image->width*image->height*4; i += 4)
1235                 {
1236                     if (((float *)image->data)[i] <= threshold)
1237                     {
1238                         ((float *)image->data)[i - 3] = (float)color.r/255.0f;
1239                         ((float *)image->data)[i - 2] = (float)color.g/255.0f;
1240                         ((float *)image->data)[i - 1] = (float)color.b/255.0f;
1241                         ((float *)image->data)[i] = (float)color.a/255.0f;
1242                     }
1243                 }
1244             } break;
1245             default: break;
1246         }
1247     }
1248 }
1249
1250 // Apply alpha mask to image
1251 // NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit)
1252 // NOTE 2: alphaMask should be same size as image
1253 void ImageAlphaMask(Image *image, Image alphaMask)
1254 {
1255     if ((image->width != alphaMask.width) || (image->height != alphaMask.height))
1256     {
1257         TRACELOG(LOG_WARNING, "IMAGE: Alpha mask must be same size as image");
1258     }
1259     else if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
1260     {
1261         TRACELOG(LOG_WARNING, "IMAGE: Alpha mask can not be applied to compressed data formats");
1262     }
1263     else
1264     {
1265         // Force mask to be Grayscale
1266         Image mask = ImageCopy(alphaMask);
1267         if (mask.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
1268
1269         // In case image is only grayscale, we just add alpha channel
1270         if (image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
1271         {
1272             unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
1273
1274             // Apply alpha mask to alpha channel
1275             for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
1276             {
1277                 data[k] = ((unsigned char *)image->data)[i];
1278                 data[k + 1] = ((unsigned char *)mask.data)[i];
1279             }
1280
1281             RL_FREE(image->data);
1282             image->data = data;
1283             image->format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
1284         }
1285         else
1286         {
1287             // Convert image to RGBA
1288             if (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
1289
1290             // Apply alpha mask to alpha channel
1291             for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4)
1292             {
1293                 ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i];
1294             }
1295         }
1296
1297         UnloadImage(mask);
1298     }
1299 }
1300
1301 // Premultiply alpha channel
1302 void ImageAlphaPremultiply(Image *image)
1303 {
1304     // Security check to avoid program crash
1305     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1306
1307     float alpha = 0.0f;
1308     Color *pixels = LoadImageColors(*image);
1309
1310     for (int i = 0; i < image->width*image->height; i++)
1311     {
1312         if (pixels[i].a == 0)
1313         {
1314             pixels[i].r = 0;
1315             pixels[i].g = 0;
1316             pixels[i].b = 0;
1317         }
1318         else if (pixels[i].a < 255)
1319         {
1320             alpha = (float)pixels[i].a/255.0f;
1321             pixels[i].r = (unsigned char)((float)pixels[i].r*alpha);
1322             pixels[i].g = (unsigned char)((float)pixels[i].g*alpha);
1323             pixels[i].b = (unsigned char)((float)pixels[i].b*alpha);
1324         }
1325     }
1326
1327     RL_FREE(image->data);
1328
1329     int format = image->format;
1330     image->data = pixels;
1331     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1332
1333     ImageFormat(image, format);
1334 }
1335
1336 // Resize and image to new size
1337 // NOTE: Uses stb default scaling filters (both bicubic):
1338 // STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
1339 // STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
1340 void ImageResize(Image *image, int newWidth, int newHeight)
1341 {
1342     // Security check to avoid program crash
1343     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1344
1345     bool fastPath = true;
1346     if ((image->format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && (image->format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) fastPath = true;
1347
1348     if (fastPath)
1349     {
1350         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1351         unsigned char *output = RL_MALLOC(newWidth*newHeight*bytesPerPixel);
1352
1353         switch (image->format)
1354         {
1355             case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break;
1356             case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break;
1357             case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break;
1358             case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break;
1359             default: break;
1360         }
1361
1362         RL_FREE(image->data);
1363         image->data = output;
1364         image->width = newWidth;
1365         image->height = newHeight;
1366     }
1367     else
1368     {
1369         // Get data as Color pixels array to work with it
1370         Color *pixels = LoadImageColors(*image);
1371         Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
1372
1373         // NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem...
1374         stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4);
1375
1376         int format = image->format;
1377
1378         UnloadImageColors(pixels);
1379         RL_FREE(image->data);
1380
1381         image->data = output;
1382         image->width = newWidth;
1383         image->height = newHeight;
1384         image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1385
1386         ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
1387     }
1388 }
1389
1390 // Resize and image to new size using Nearest-Neighbor scaling algorithm
1391 void ImageResizeNN(Image *image,int newWidth,int newHeight)
1392 {
1393     // Security check to avoid program crash
1394     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1395
1396     Color *pixels = LoadImageColors(*image);
1397     Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
1398
1399     // EDIT: added +1 to account for an early rounding problem
1400     int xRatio = (int)((image->width << 16)/newWidth) + 1;
1401     int yRatio = (int)((image->height << 16)/newHeight) + 1;
1402
1403     int x2, y2;
1404     for (int y = 0; y < newHeight; y++)
1405     {
1406         for (int x = 0; x < newWidth; x++)
1407         {
1408             x2 = ((x*xRatio) >> 16);
1409             y2 = ((y*yRatio) >> 16);
1410
1411             output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
1412         }
1413     }
1414
1415     int format = image->format;
1416
1417     RL_FREE(image->data);
1418
1419     image->data = output;
1420     image->width = newWidth;
1421     image->height = newHeight;
1422     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1423
1424     ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
1425
1426     UnloadImageColors(pixels);
1427 }
1428
1429 // Resize canvas and fill with color
1430 // NOTE: Resize offset is relative to the top-left corner of the original image
1431 void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill)
1432 {
1433     // Security check to avoid program crash
1434     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1435
1436     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1437     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1438     else if ((newWidth != image->width) || (newHeight != image->height))
1439     {
1440         Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height };
1441         Vector2 dstPos = { (float)offsetX, (float)offsetY };
1442
1443         if (offsetX < 0)
1444         {
1445             srcRec.x = (float)-offsetX;
1446             srcRec.width += (float)offsetX;
1447             dstPos.x = 0;
1448         }
1449         else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX);
1450
1451         if (offsetY < 0)
1452         {
1453             srcRec.y = (float)-offsetY;
1454             srcRec.height += (float)offsetY;
1455             dstPos.y = 0;
1456         }
1457         else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY);
1458
1459         if (newWidth < srcRec.width) srcRec.width = (float)newWidth;
1460         if (newHeight < srcRec.height) srcRec.height = (float)newHeight;
1461
1462         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1463         unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
1464
1465         // TODO: Fill resizedData with fill color (must be formatted to image->format)
1466
1467         int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
1468
1469         for (int y = 0; y < (int)srcRec.height; y++)
1470         {
1471             memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel);
1472             dstOffsetSize += (newWidth*bytesPerPixel);
1473         }
1474
1475         RL_FREE(image->data);
1476         image->data = resizedData;
1477         image->width = newWidth;
1478         image->height = newHeight;
1479     }
1480 }
1481
1482 // Generate all mipmap levels for a provided image
1483 // NOTE 1: Supports POT and NPOT images
1484 // NOTE 2: image.data is scaled to include mipmap levels
1485 // NOTE 3: Mipmaps format is the same as base image
1486 void ImageMipmaps(Image *image)
1487 {
1488     // Security check to avoid program crash
1489     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1490
1491     int mipCount = 1;                   // Required mipmap levels count (including base level)
1492     int mipWidth = image->width;        // Base image width
1493     int mipHeight = image->height;      // Base image height
1494     int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);  // Image data size (in bytes)
1495
1496     // Count mipmap levels required
1497     while ((mipWidth != 1) || (mipHeight != 1))
1498     {
1499         if (mipWidth != 1) mipWidth /= 2;
1500         if (mipHeight != 1) mipHeight /= 2;
1501
1502         // Security check for NPOT textures
1503         if (mipWidth < 1) mipWidth = 1;
1504         if (mipHeight < 1) mipHeight = 1;
1505
1506         TRACELOGD("IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
1507
1508         mipCount++;
1509         mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format);       // Add mipmap size (in bytes)
1510     }
1511
1512     if (image->mipmaps < mipCount)
1513     {
1514         void *temp = RL_REALLOC(image->data, mipSize);
1515
1516         if (temp != NULL) image->data = temp;      // Assign new pointer (new size) to store mipmaps data
1517         else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps required memory could not be allocated");
1518
1519         // Pointer to allocated memory point where store next mipmap level data
1520         unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format);
1521
1522         mipWidth = image->width/2;
1523         mipHeight = image->height/2;
1524         mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
1525         Image imCopy = ImageCopy(*image);
1526
1527         for (int i = 1; i < mipCount; i++)
1528         {
1529             TRACELOGD("IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
1530
1531             ImageResize(&imCopy, mipWidth, mipHeight);  // Uses internally Mitchell cubic downscale filter
1532
1533             memcpy(nextmip, imCopy.data, mipSize);
1534             nextmip += mipSize;
1535             image->mipmaps++;
1536
1537             mipWidth /= 2;
1538             mipHeight /= 2;
1539
1540             // Security check for NPOT textures
1541             if (mipWidth < 1) mipWidth = 1;
1542             if (mipHeight < 1) mipHeight = 1;
1543
1544             mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
1545         }
1546
1547         UnloadImage(imCopy);
1548     }
1549     else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps already available");
1550 }
1551
1552 // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
1553 // NOTE: In case selected bpp do not represent an known 16bit format,
1554 // dithered data is stored in the LSB part of the unsigned short
1555 void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
1556 {
1557     // Security check to avoid program crash
1558     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1559
1560     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
1561     {
1562         TRACELOG(LOG_WARNING, "IMAGE: Compressed data formats can not be dithered");
1563         return;
1564     }
1565
1566     if ((rBpp + gBpp + bBpp + aBpp) > 16)
1567     {
1568         TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
1569     }
1570     else
1571     {
1572         Color *pixels = LoadImageColors(*image);
1573
1574         RL_FREE(image->data);      // free old image data
1575
1576         if ((image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
1577         {
1578             TRACELOG(LOG_WARNING, "IMAGE: Format is already 16bpp or lower, dithering could have no effect");
1579         }
1580
1581         // Define new image format, check if desired bpp match internal known format
1582         if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
1583         else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
1584         else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
1585         else
1586         {
1587             image->format = 0;
1588             TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
1589         }
1590
1591         // NOTE: We will store the dithered data as unsigned short (16bpp)
1592         image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
1593
1594         Color oldPixel = WHITE;
1595         Color newPixel = WHITE;
1596
1597         int rError, gError, bError;
1598         unsigned short rPixel, gPixel, bPixel, aPixel;   // Used for 16bit pixel composition
1599
1600         #define MIN(a,b) (((a)<(b))?(a):(b))
1601
1602         for (int y = 0; y < image->height; y++)
1603         {
1604             for (int x = 0; x < image->width; x++)
1605             {
1606                 oldPixel = pixels[y*image->width + x];
1607
1608                 // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
1609                 newPixel.r = oldPixel.r >> (8 - rBpp);     // R bits
1610                 newPixel.g = oldPixel.g >> (8 - gBpp);     // G bits
1611                 newPixel.b = oldPixel.b >> (8 - bBpp);     // B bits
1612                 newPixel.a = oldPixel.a >> (8 - aBpp);     // A bits (not used on dithering)
1613
1614                 // NOTE: Error must be computed between new and old pixel but using same number of bits!
1615                 // We want to know how much color precision we have lost...
1616                 rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
1617                 gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
1618                 bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
1619
1620                 pixels[y*image->width + x] = newPixel;
1621
1622                 // NOTE: Some cases are out of the array and should be ignored
1623                 if (x < (image->width - 1))
1624                 {
1625                     pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
1626                     pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
1627                     pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
1628                 }
1629
1630                 if ((x > 0) && (y < (image->height - 1)))
1631                 {
1632                     pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
1633                     pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
1634                     pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
1635                 }
1636
1637                 if (y < (image->height - 1))
1638                 {
1639                     pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
1640                     pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
1641                     pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
1642                 }
1643
1644                 if ((x < (image->width - 1)) && (y < (image->height - 1)))
1645                 {
1646                     pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
1647                     pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
1648                     pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
1649                 }
1650
1651                 rPixel = (unsigned short)newPixel.r;
1652                 gPixel = (unsigned short)newPixel.g;
1653                 bPixel = (unsigned short)newPixel.b;
1654                 aPixel = (unsigned short)newPixel.a;
1655
1656                 ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
1657             }
1658         }
1659
1660         UnloadImageColors(pixels);
1661     }
1662 }
1663
1664 // Flip image vertically
1665 void ImageFlipVertical(Image *image)
1666 {
1667     // Security check to avoid program crash
1668     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1669
1670     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1671     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1672     else
1673     {
1674         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1675         unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
1676
1677         for (int i = (image->height - 1), offsetSize = 0; i >= 0; i--)
1678         {
1679             memcpy(flippedData + offsetSize, ((unsigned char *)image->data) + i*image->width*bytesPerPixel, image->width*bytesPerPixel);
1680             offsetSize += image->width*bytesPerPixel;
1681         }
1682
1683         RL_FREE(image->data);
1684         image->data = flippedData;
1685     }
1686 }
1687
1688 // Flip image horizontally
1689 void ImageFlipHorizontal(Image *image)
1690 {
1691     // Security check to avoid program crash
1692     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1693
1694     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1695     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1696     else
1697     {
1698         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1699         unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
1700
1701         for (int y = 0; y < image->height; y++)
1702         {
1703             for (int x = 0; x < image->width; x++)
1704             {
1705                 // OPTION 1: Move pixels with memcopy()
1706                 //memcpy(flippedData + (y*image->width + x)*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - 1 - x))*bytesPerPixel, bytesPerPixel);
1707
1708                 // OPTION 2: Just copy data pixel by pixel
1709                 for (int i = 0; i < bytesPerPixel; i++) flippedData[(y*image->width + x)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - 1 - x))*bytesPerPixel + i];
1710             }
1711         }
1712
1713         RL_FREE(image->data);
1714         image->data = flippedData;
1715
1716         /*
1717         // OPTION 3: Faster implementation (specific for 32bit pixels)
1718         // NOTE: It does not require additional allocations
1719         uint32_t *ptr = (uint32_t *)image->data;
1720         for (int y = 0; y < image->height; y++)
1721         {
1722             for (int x = 0; x < image->width/2; x++)
1723             {
1724                 uint32_t backup = ptr[y*image->width + x];
1725                 ptr[y*image->width + x] = ptr[y*image->width + (image->width - 1 - x)];
1726                 ptr[y*image->width + (image->width - 1 - x)] = backup;
1727             }
1728         }
1729         */
1730     }
1731 }
1732
1733 // Rotate image clockwise 90deg
1734 void ImageRotateCW(Image *image)
1735 {
1736     // Security check to avoid program crash
1737     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1738
1739     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1740     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1741     else
1742     {
1743         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1744         unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
1745
1746         for (int y = 0; y < image->height; y++)
1747         {
1748             for (int x = 0; x < image->width; x++)
1749             {
1750                 //memcpy(rotatedData + (x*image->height + (image->height - y - 1))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
1751                 for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + (image->height - y - 1))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
1752             }
1753         }
1754
1755         RL_FREE(image->data);
1756         image->data = rotatedData;
1757         int width = image->width;
1758         int height = image-> height;
1759
1760         image->width = height;
1761         image->height = width;
1762     }
1763 }
1764
1765 // Rotate image counter-clockwise 90deg
1766 void ImageRotateCCW(Image *image)
1767 {
1768     // Security check to avoid program crash
1769     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1770
1771     if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
1772     if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
1773     else
1774     {
1775         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
1776         unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
1777
1778         for (int y = 0; y < image->height; y++)
1779         {
1780             for (int x = 0; x < image->width; x++)
1781             {
1782                 //memcpy(rotatedData + (x*image->height + y))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - x - 1))*bytesPerPixel, bytesPerPixel);
1783                 for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + y)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - x - 1))*bytesPerPixel + i];
1784             }
1785         }
1786
1787         RL_FREE(image->data);
1788         image->data = rotatedData;
1789         int width = image->width;
1790         int height = image-> height;
1791
1792         image->width = height;
1793         image->height = width;
1794     }
1795 }
1796
1797 // Modify image color: tint
1798 void ImageColorTint(Image *image, Color color)
1799 {
1800     // Security check to avoid program crash
1801     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1802
1803     Color *pixels = LoadImageColors(*image);
1804
1805     float cR = (float)color.r/255;
1806     float cG = (float)color.g/255;
1807     float cB = (float)color.b/255;
1808     float cA = (float)color.a/255;
1809
1810     for (int y = 0; y < image->height; y++)
1811     {
1812         for (int x = 0; x < image->width; x++)
1813         {
1814             int index = y*image->width + x;
1815             unsigned char r = (unsigned char)(((float)pixels[index].r/255*cR)*255.0f);
1816             unsigned char g = (unsigned char)(((float)pixels[index].g/255*cG)*255.0f);
1817             unsigned char b = (unsigned char)(((float)pixels[index].b/255*cB)*255.0f);
1818             unsigned char a = (unsigned char)(((float)pixels[index].a/255*cA)*255.0f);
1819
1820             pixels[y*image->width + x].r = r;
1821             pixels[y*image->width + x].g = g;
1822             pixels[y*image->width + x].b = b;
1823             pixels[y*image->width + x].a = a;
1824         }
1825     }
1826
1827     int format = image->format;
1828     RL_FREE(image->data);
1829
1830     image->data = pixels;
1831     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1832
1833     ImageFormat(image, format);
1834 }
1835
1836 // Modify image color: invert
1837 void ImageColorInvert(Image *image)
1838 {
1839     // Security check to avoid program crash
1840     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1841
1842     Color *pixels = LoadImageColors(*image);
1843
1844     for (int y = 0; y < image->height; y++)
1845     {
1846         for (int x = 0; x < image->width; x++)
1847         {
1848             pixels[y*image->width + x].r = 255 - pixels[y*image->width + x].r;
1849             pixels[y*image->width + x].g = 255 - pixels[y*image->width + x].g;
1850             pixels[y*image->width + x].b = 255 - pixels[y*image->width + x].b;
1851         }
1852     }
1853
1854     int format = image->format;
1855     RL_FREE(image->data);
1856
1857     image->data = pixels;
1858     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1859
1860     ImageFormat(image, format);
1861 }
1862
1863 // Modify image color: grayscale
1864 void ImageColorGrayscale(Image *image)
1865 {
1866     ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
1867 }
1868
1869 // Modify image color: contrast
1870 // NOTE: Contrast values between -100 and 100
1871 void ImageColorContrast(Image *image, float contrast)
1872 {
1873     // Security check to avoid program crash
1874     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1875
1876     if (contrast < -100) contrast = -100;
1877     if (contrast > 100) contrast = 100;
1878
1879     contrast = (100.0f + contrast)/100.0f;
1880     contrast *= contrast;
1881
1882     Color *pixels = LoadImageColors(*image);
1883
1884     for (int y = 0; y < image->height; y++)
1885     {
1886         for (int x = 0; x < image->width; x++)
1887         {
1888             float pR = (float)pixels[y*image->width + x].r/255.0f;
1889             pR -= 0.5;
1890             pR *= contrast;
1891             pR += 0.5;
1892             pR *= 255;
1893             if (pR < 0) pR = 0;
1894             if (pR > 255) pR = 255;
1895
1896             float pG = (float)pixels[y*image->width + x].g/255.0f;
1897             pG -= 0.5;
1898             pG *= contrast;
1899             pG += 0.5;
1900             pG *= 255;
1901             if (pG < 0) pG = 0;
1902             if (pG > 255) pG = 255;
1903
1904             float pB = (float)pixels[y*image->width + x].b/255.0f;
1905             pB -= 0.5;
1906             pB *= contrast;
1907             pB += 0.5;
1908             pB *= 255;
1909             if (pB < 0) pB = 0;
1910             if (pB > 255) pB = 255;
1911
1912             pixels[y*image->width + x].r = (unsigned char)pR;
1913             pixels[y*image->width + x].g = (unsigned char)pG;
1914             pixels[y*image->width + x].b = (unsigned char)pB;
1915         }
1916     }
1917
1918     int format = image->format;
1919     RL_FREE(image->data);
1920
1921     image->data = pixels;
1922     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1923
1924     ImageFormat(image, format);
1925 }
1926
1927 // Modify image color: brightness
1928 // NOTE: Brightness values between -255 and 255
1929 void ImageColorBrightness(Image *image, int brightness)
1930 {
1931     // Security check to avoid program crash
1932     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1933
1934     if (brightness < -255) brightness = -255;
1935     if (brightness > 255) brightness = 255;
1936
1937     Color *pixels = LoadImageColors(*image);
1938
1939     for (int y = 0; y < image->height; y++)
1940     {
1941         for (int x = 0; x < image->width; x++)
1942         {
1943             int cR = pixels[y*image->width + x].r + brightness;
1944             int cG = pixels[y*image->width + x].g + brightness;
1945             int cB = pixels[y*image->width + x].b + brightness;
1946
1947             if (cR < 0) cR = 1;
1948             if (cR > 255) cR = 255;
1949
1950             if (cG < 0) cG = 1;
1951             if (cG > 255) cG = 255;
1952
1953             if (cB < 0) cB = 1;
1954             if (cB > 255) cB = 255;
1955
1956             pixels[y*image->width + x].r = (unsigned char)cR;
1957             pixels[y*image->width + x].g = (unsigned char)cG;
1958             pixels[y*image->width + x].b = (unsigned char)cB;
1959         }
1960     }
1961
1962     int format = image->format;
1963     RL_FREE(image->data);
1964
1965     image->data = pixels;
1966     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
1967
1968     ImageFormat(image, format);
1969 }
1970
1971 // Modify image color: replace color
1972 void ImageColorReplace(Image *image, Color color, Color replace)
1973 {
1974     // Security check to avoid program crash
1975     if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
1976
1977     Color *pixels = LoadImageColors(*image);
1978
1979     for (int y = 0; y < image->height; y++)
1980     {
1981         for (int x = 0; x < image->width; x++)
1982         {
1983             if ((pixels[y*image->width + x].r == color.r) &&
1984                 (pixels[y*image->width + x].g == color.g) &&
1985                 (pixels[y*image->width + x].b == color.b) &&
1986                 (pixels[y*image->width + x].a == color.a))
1987             {
1988                 pixels[y*image->width + x].r = replace.r;
1989                 pixels[y*image->width + x].g = replace.g;
1990                 pixels[y*image->width + x].b = replace.b;
1991                 pixels[y*image->width + x].a = replace.a;
1992             }
1993         }
1994     }
1995
1996     int format = image->format;
1997     RL_FREE(image->data);
1998
1999     image->data = pixels;
2000     image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
2001
2002     ImageFormat(image, format);
2003 }
2004 #endif      // SUPPORT_IMAGE_MANIPULATION
2005
2006 // Load color data from image as a Color array (RGBA - 32bit)
2007 // NOTE: Memory allocated should be freed using UnloadImageColors();
2008 Color *LoadImageColors(Image image)
2009 {
2010     if ((image.width == 0) || (image.height == 0)) return NULL;
2011
2012     Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color));
2013
2014     if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
2015     else
2016     {
2017         if ((image.format == PIXELFORMAT_UNCOMPRESSED_R32) ||
2018             (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
2019             (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 32bit to 8bit per channel");
2020
2021         for (int i = 0, k = 0; i < image.width*image.height; i++)
2022         {
2023             switch (image.format)
2024             {
2025                 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
2026                 {
2027                     pixels[i].r = ((unsigned char *)image.data)[i];
2028                     pixels[i].g = ((unsigned char *)image.data)[i];
2029                     pixels[i].b = ((unsigned char *)image.data)[i];
2030                     pixels[i].a = 255;
2031
2032                 } break;
2033                 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
2034                 {
2035                     pixels[i].r = ((unsigned char *)image.data)[k];
2036                     pixels[i].g = ((unsigned char *)image.data)[k];
2037                     pixels[i].b = ((unsigned char *)image.data)[k];
2038                     pixels[i].a = ((unsigned char *)image.data)[k + 1];
2039
2040                     k += 2;
2041                 } break;
2042                 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
2043                 {
2044                     unsigned short pixel = ((unsigned short *)image.data)[i];
2045
2046                     pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
2047                     pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
2048                     pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
2049                     pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255);
2050
2051                 } break;
2052                 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
2053                 {
2054                     unsigned short pixel = ((unsigned short *)image.data)[i];
2055
2056                     pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
2057                     pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
2058                     pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
2059                     pixels[i].a = 255;
2060
2061                 } break;
2062                 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
2063                 {
2064                     unsigned short pixel = ((unsigned short *)image.data)[i];
2065
2066                     pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
2067                     pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
2068                     pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
2069                     pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
2070
2071                 } break;
2072                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
2073                 {
2074                     pixels[i].r = ((unsigned char *)image.data)[k];
2075                     pixels[i].g = ((unsigned char *)image.data)[k + 1];
2076                     pixels[i].b = ((unsigned char *)image.data)[k + 2];
2077                     pixels[i].a = ((unsigned char *)image.data)[k + 3];
2078
2079                     k += 4;
2080                 } break;
2081                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
2082                 {
2083                     pixels[i].r = (unsigned char)((unsigned char *)image.data)[k];
2084                     pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1];
2085                     pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2];
2086                     pixels[i].a = 255;
2087
2088                     k += 3;
2089                 } break;
2090                 case PIXELFORMAT_UNCOMPRESSED_R32:
2091                 {
2092                     pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
2093                     pixels[i].g = 0;
2094                     pixels[i].b = 0;
2095                     pixels[i].a = 255;
2096
2097                 } break;
2098                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
2099                 {
2100                     pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
2101                     pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
2102                     pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
2103                     pixels[i].a = 255;
2104
2105                     k += 3;
2106                 } break;
2107                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
2108                 {
2109                     pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
2110                     pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f);
2111                     pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f);
2112                     pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f);
2113
2114                     k += 4;
2115                 } break;
2116                 default: break;
2117             }
2118         }
2119     }
2120
2121     return pixels;
2122 }
2123
2124 // Load colors palette from image as a Color array (RGBA - 32bit)
2125 // NOTE: Memory allocated should be freed using UnloadImagePalette()
2126 Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount)
2127 {
2128     #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
2129
2130     int palCount = 0;
2131     Color *palette = NULL;
2132     Color *pixels = LoadImageColors(image);
2133
2134     if (pixels != NULL)
2135     {
2136         palette = (Color *)RL_MALLOC(maxPaletteSize*sizeof(Color));
2137
2138         for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK;   // Set all colors to BLANK
2139
2140         for (int i = 0; i < image.width*image.height; i++)
2141         {
2142             if (pixels[i].a > 0)
2143             {
2144                 bool colorInPalette = false;
2145
2146                 // Check if the color is already on palette
2147                 for (int j = 0; j < maxPaletteSize; j++)
2148                 {
2149                     if (COLOR_EQUAL(pixels[i], palette[j]))
2150                     {
2151                         colorInPalette = true;
2152                         break;
2153                     }
2154                 }
2155
2156                 // Store color if not on the palette
2157                 if (!colorInPalette)
2158                 {
2159                     palette[palCount] = pixels[i];      // Add pixels[i] to palette
2160                     palCount++;
2161
2162                     // We reached the limit of colors supported by palette
2163                     if (palCount >= maxPaletteSize)
2164                     {
2165                         i = image.width*image.height;   // Finish palette get
2166                         TRACELOG(LOG_WARNING, "IMAGE: Palette is greater than %i colors", maxPaletteSize);
2167                     }
2168                 }
2169             }
2170         }
2171
2172         UnloadImageColors(pixels);
2173     }
2174
2175     *colorsCount = palCount;
2176
2177     return palette;
2178 }
2179
2180 // Unload color data loaded with LoadImageColors()
2181 void UnloadImageColors(Color *colors)
2182 {
2183     RL_FREE(colors);
2184 }
2185
2186 // Unload colors palette loaded with LoadImagePalette()
2187 void UnloadImagePalette(Color *colors)
2188 {
2189     RL_FREE(colors);
2190 }
2191
2192 // Get pixel data from image as Vector4 array (float normalized)
2193 static Vector4 *LoadImageDataNormalized(Image image)
2194 {
2195     Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4));
2196
2197     if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
2198     else
2199     {
2200         for (int i = 0, k = 0; i < image.width*image.height; i++)
2201         {
2202             switch (image.format)
2203             {
2204                 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
2205                 {
2206                     pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f;
2207                     pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f;
2208                     pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f;
2209                     pixels[i].w = 1.0f;
2210
2211                 } break;
2212                 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
2213                 {
2214                     pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
2215                     pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f;
2216                     pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f;
2217                     pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f;
2218
2219                     k += 2;
2220                 } break;
2221                 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
2222                 {
2223                     unsigned short pixel = ((unsigned short *)image.data)[i];
2224
2225                     pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
2226                     pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
2227                     pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
2228                     pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
2229
2230                 } break;
2231                 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
2232                 {
2233                     unsigned short pixel = ((unsigned short *)image.data)[i];
2234
2235                     pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
2236                     pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63);
2237                     pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31);
2238                     pixels[i].w = 1.0f;
2239
2240                 } break;
2241                 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
2242                 {
2243                     unsigned short pixel = ((unsigned short *)image.data)[i];
2244
2245                     pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15);
2246                     pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15);
2247                     pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15);
2248                     pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15);
2249
2250                 } break;
2251                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
2252                 {
2253                     pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
2254                     pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
2255                     pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
2256                     pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f;
2257
2258                     k += 4;
2259                 } break;
2260                 case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
2261                 {
2262                     pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
2263                     pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
2264                     pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
2265                     pixels[i].w = 1.0f;
2266
2267                     k += 3;
2268                 } break;
2269                 case PIXELFORMAT_UNCOMPRESSED_R32:
2270                 {
2271                     pixels[i].x = ((float *)image.data)[k];
2272                     pixels[i].y = 0.0f;
2273                     pixels[i].z = 0.0f;
2274                     pixels[i].w = 1.0f;
2275
2276                 } break;
2277                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
2278                 {
2279                     pixels[i].x = ((float *)image.data)[k];
2280                     pixels[i].y = ((float *)image.data)[k + 1];
2281                     pixels[i].z = ((float *)image.data)[k + 2];
2282                     pixels[i].w = 1.0f;
2283
2284                     k += 3;
2285                 } break;
2286                 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
2287                 {
2288                     pixels[i].x = ((float *)image.data)[k];
2289                     pixels[i].y = ((float *)image.data)[k + 1];
2290                     pixels[i].z = ((float *)image.data)[k + 2];
2291                     pixels[i].w = ((float *)image.data)[k + 3];
2292
2293                     k += 4;
2294                 }
2295                 default: break;
2296             }
2297         }
2298     }
2299
2300     return pixels;
2301 }
2302
2303 // Get image alpha border rectangle
2304 // NOTE: Threshold is defined as a percentatge: 0.0f -> 1.0f
2305 Rectangle GetImageAlphaBorder(Image image, float threshold)
2306 {
2307     Rectangle crop = { 0 };
2308
2309     Color *pixels = LoadImageColors(image);
2310
2311     if (pixels != NULL)
2312     {
2313         int xMin = 65536;   // Define a big enough number
2314         int xMax = 0;
2315         int yMin = 65536;
2316         int yMax = 0;
2317
2318         for (int y = 0; y < image.height; y++)
2319         {
2320             for (int x = 0; x < image.width; x++)
2321             {
2322                 if (pixels[y*image.width + x].a > (unsigned char)(threshold*255.0f))
2323                 {
2324                     if (x < xMin) xMin = x;
2325                     if (x > xMax) xMax = x;
2326                     if (y < yMin) yMin = y;
2327                     if (y > yMax) yMax = y;
2328                 }
2329             }
2330         }
2331
2332         // Check for empty blank image
2333         if ((xMin != 65536) && (xMax != 65536))
2334         {
2335             crop = (Rectangle){ (float)xMin, (float)yMin, (float)((xMax + 1) - xMin), (float)((yMax + 1) - yMin) };
2336         }
2337
2338         UnloadImageColors(pixels);
2339     }
2340
2341     return crop;
2342 }
2343
2344 //------------------------------------------------------------------------------------
2345 // Image drawing functions
2346 //------------------------------------------------------------------------------------
2347 // Clear image background with given color
2348 void ImageClearBackground(Image *dst, Color color)
2349 {
2350     for (int i = 0; i < dst->width*dst->height; ++i) ImageDrawPixel(dst, i%dst->width, i/dst->width, color);
2351 }
2352
2353 // Draw pixel within an image
2354 // NOTE: Compressed image formats not supported
2355 void ImageDrawPixel(Image *dst, int x, int y, Color color)
2356 {
2357     // Security check to avoid program crash
2358     if ((dst->data == NULL) || (x < 0) || (x >= dst->width) || (y < 0) || (y >= dst->height)) return;
2359
2360     switch (dst->format)
2361     {
2362         case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
2363         {
2364             // NOTE: Calculate grayscale equivalent color
2365             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
2366             unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
2367
2368             ((unsigned char *)dst->data)[y*dst->width + x] = gray;
2369
2370         } break;
2371         case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
2372         {
2373             // NOTE: Calculate grayscale equivalent color
2374             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
2375             unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
2376
2377             ((unsigned char *)dst->data)[(y*dst->width + x)*2] = gray;
2378             ((unsigned char *)dst->data)[(y*dst->width + x)*2 + 1] = color.a;
2379
2380         } break;
2381         case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
2382         {
2383             // NOTE: Calculate R5G6B5 equivalent color
2384             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
2385
2386             unsigned char r = (unsigned char)(round(coln.x*31.0f));
2387             unsigned char g = (unsigned char)(round(coln.y*63.0f));
2388             unsigned char b = (unsigned char)(round(coln.z*31.0f));
2389
2390             ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
2391
2392         } break;
2393         case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
2394         {
2395             // NOTE: Calculate R5G5B5A1 equivalent color
2396             Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
2397
2398             unsigned char r = (unsigned char)(round(coln.x*31.0f));
2399             unsigned char g = (unsigned char)(round(coln.y*31.0f));
2400             unsigned char b = (unsigned char)(round(coln.z*31.0f));
2401             unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;;
2402
2403             ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
2404
2405         } break;
2406         case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
2407         {
2408             // NOTE: Calculate R5G5B5A1 equivalent color
2409             Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
2410
2411             unsigned char r = (unsigned char)(round(coln.x*15.0f));
2412             unsigned char g = (unsigned char)(round(coln.y*15.0f));
2413             unsigned char b = (unsigned char)(round(coln.z*15.0f));
2414             unsigned char a = (unsigned char)(round(coln.w*15.0f));
2415
2416             ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
2417
2418         } break;
2419         case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
2420         {
2421             ((unsigned char *)dst->data)[(y*dst->width + x)*3] = color.r;
2422             ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 1] = color.g;
2423             ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 2] = color.b;
2424
2425         } break;
2426         case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
2427         {
2428             ((unsigned char *)dst->data)[(y*dst->width + x)*4] = color.r;
2429             ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 1] = color.g;
2430             ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 2] = color.b;
2431             ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 3] = color.a;
2432
2433         } break;
2434         case PIXELFORMAT_UNCOMPRESSED_R32:
2435         {
2436             // NOTE: Calculate grayscale equivalent color (normalized to 32bit)
2437             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
2438
2439             ((float *)dst->data)[y*dst->width + x] = coln.x*0.299f + coln.y*0.587f + coln.z*0.114f;
2440
2441         } break;
2442         case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
2443         {
2444             // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit)
2445             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
2446
2447             ((float *)dst->data)[(y*dst->width + x)*3] = coln.x;
2448             ((float *)dst->data)[(y*dst->width + x)*3 + 1] = coln.y;
2449             ((float *)dst->data)[(y*dst->width + x)*3 + 2] = coln.z;
2450         } break;
2451         case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
2452         {
2453             // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit)
2454             Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
2455
2456             ((float *)dst->data)[(y*dst->width + x)*4] = coln.x;
2457             ((float *)dst->data)[(y*dst->width + x)*4 + 1] = coln.y;
2458             ((float *)dst->data)[(y*dst->width + x)*4 + 2] = coln.z;
2459             ((float *)dst->data)[(y*dst->width + x)*4 + 3] = coln.w;
2460
2461         } break;
2462         default: break;
2463     }
2464 }
2465
2466 // Draw pixel within an image (Vector version)
2467 void ImageDrawPixelV(Image *dst, Vector2 position, Color color)
2468 {
2469     ImageDrawPixel(dst, (int)position.x, (int)position.y, color);
2470 }
2471
2472 // Draw line within an image
2473 void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color)
2474 {
2475     int m = 2*(endPosY - startPosY);
2476     int slopeError = m - (endPosX - startPosX);
2477
2478     for (int x = startPosX, y = startPosY; x <= endPosX; x++)
2479     {
2480         ImageDrawPixel(dst, x, y, color);
2481         slopeError += m;
2482
2483         if (slopeError >= 0)
2484         {
2485             y++;
2486             slopeError -= 2*(endPosX - startPosX);
2487         }
2488     }
2489 }
2490
2491 // Draw line within an image (Vector version)
2492 void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color)
2493 {
2494     ImageDrawLine(dst, (int)start.x, (int)start.y, (int)end.x, (int)end.y, color);
2495 }
2496
2497 // Draw circle within an image
2498 void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color)
2499 {
2500     int x = 0, y = radius;
2501     int decesionParameter = 3 - 2*radius;
2502
2503     while (y >= x)
2504     {
2505         ImageDrawPixel(dst, centerX + x, centerY + y, color);
2506         ImageDrawPixel(dst, centerX - x, centerY + y, color);
2507         ImageDrawPixel(dst, centerX + x, centerY - y, color);
2508         ImageDrawPixel(dst, centerX - x, centerY - y, color);
2509         ImageDrawPixel(dst, centerX + y, centerY + x, color);
2510         ImageDrawPixel(dst, centerX - y, centerY + x, color);
2511         ImageDrawPixel(dst, centerX + y, centerY - x, color);
2512         ImageDrawPixel(dst, centerX - y, centerY - x, color);
2513         x++;
2514
2515         if (decesionParameter > 0)
2516         {
2517             y--;
2518             decesionParameter = decesionParameter + 4*(x - y) + 10;
2519         }
2520         else decesionParameter = decesionParameter + 4*x + 6;
2521     }
2522 }
2523
2524 // Draw circle within an image (Vector version)
2525 void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color)
2526 {
2527     ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color);
2528 }
2529
2530 // Draw rectangle within an image
2531 void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color)
2532 {
2533     ImageDrawRectangleRec(dst, (Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color);
2534 }
2535
2536 // Draw rectangle within an image (Vector version)
2537 void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color)
2538 {
2539     ImageDrawRectangle(dst, (int)position.x, (int)position.y, (int)size.x, (int)size.y, color);
2540 }
2541
2542 // Draw rectangle within an image
2543 void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
2544 {
2545     // Security check to avoid program crash
2546     if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
2547
2548     int sy = (int)rec.y;
2549     int ey = sy + (int)rec.height;
2550
2551     int sx = (int)rec.x;
2552     int ex = sx + (int)rec.width;
2553
2554     for (int y = sy; y < ey; y++)
2555     {
2556         for (int x = sx; x < ex; x++)
2557         {
2558             ImageDrawPixel(dst, x, y, color);
2559         }
2560     }
2561 }
2562
2563 // Draw rectangle lines within an image
2564 void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
2565 {
2566     ImageDrawRectangle(dst, (int)rec.x, (int)rec.y, (int)rec.width, thick, color);
2567     ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
2568     ImageDrawRectangle(dst, (int)(rec.x + rec.width - thick), (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
2569     ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color);
2570 }
2571
2572 // Draw an image (source) within an image (destination)
2573 // NOTE: Color tint is applied to source image
2574 void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint)
2575 {
2576     // Security check to avoid program crash
2577     if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) ||
2578         (src.data == NULL) || (src.width == 0) || (src.height == 0)) return;
2579
2580     if (dst->mipmaps > 1) TRACELOG(LOG_WARNING, "Image drawing only applied to base mipmap level");
2581     if (dst->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image drawing not supported for compressed formats");
2582     else
2583     {
2584         Image srcMod = { 0 };       // Source copy (in case it was required)
2585         Image *srcPtr = &src;       // Pointer to source image
2586         bool useSrcMod = false;     // Track source copy required
2587
2588         // Source rectangle out-of-bounds security checks
2589         if (srcRec.x < 0) { srcRec.width += srcRec.x; srcRec.x = 0; }
2590         if (srcRec.y < 0) { srcRec.height += srcRec.y; srcRec.y = 0; }
2591         if ((srcRec.x + srcRec.width) > src.width) srcRec.width = src.width - srcRec.x;
2592         if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y;
2593
2594         // Check if source rectangle needs to be resized to destination rectangle
2595         // In that case, we make a copy of source and we apply all required transform
2596         if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height))
2597         {
2598             srcMod = ImageFromImage(src, srcRec);   // Create image from another image
2599             ImageResize(&srcMod, (int)dstRec.width, (int)dstRec.height);   // Resize to destination rectangle
2600             srcRec = (Rectangle){ 0, 0, (float)srcMod.width, (float)srcMod.height };
2601
2602             srcPtr = &srcMod;
2603             useSrcMod = true;
2604         }
2605
2606         // Destination rectangle out-of-bounds security checks
2607         if (dstRec.x < 0)
2608         {
2609             srcRec.x = -dstRec.x;
2610             srcRec.width += dstRec.x;
2611             dstRec.x = 0;
2612         }
2613         else if ((dstRec.x + srcRec.width) > dst->width) srcRec.width = dst->width - dstRec.x;
2614
2615         if (dstRec.y < 0)
2616         {
2617             srcRec.y = -dstRec.y;
2618             srcRec.height += dstRec.y;
2619             dstRec.y = 0;
2620         }
2621         else if ((dstRec.y + srcRec.height) > dst->height) srcRec.height = dst->height - dstRec.y;
2622
2623         if (dst->width < srcRec.width) srcRec.width = (float)dst->width;
2624         if (dst->height < srcRec.height) srcRec.height = (float)dst->height;
2625
2626         // This blitting method is quite fast! The process followed is:
2627         // for every pixel -> [get_src_format/get_dst_format -> blend -> format_to_dst]
2628         // Some optimization ideas:
2629         //    [x] Avoid creating source copy if not required (no resize required)
2630         //    [x] Optimize ImageResize() for pixel format (alternative: ImageResizeNN())
2631         //    [x] Optimize ColorAlphaBlend() to avoid processing (alpha = 0) and (alpha = 1)
2632         //    [x] Optimize ColorAlphaBlend() for faster operations (maybe avoiding divs?)
2633         //    [x] Consider fast path: no alpha blending required cases (src has no alpha)
2634         //    [x] Consider fast path: same src/dst format with no alpha -> direct line copy
2635         //    [-] GetPixelColor(): Return Vector4 instead of Color, easier for ColorAlphaBlend()
2636
2637         Color colSrc, colDst, blend;
2638         bool blendRequired = true;
2639
2640         // Fast path: Avoid blend if source has no alpha to blend
2641         if ((tint.a == 255) && ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5))) blendRequired = false;
2642
2643         int strideDst = GetPixelDataSize(dst->width, 1, dst->format);
2644         int bytesPerPixelDst = strideDst/(dst->width);
2645
2646         int strideSrc = GetPixelDataSize(srcPtr->width, 1, srcPtr->format);
2647         int bytesPerPixelSrc = strideSrc/(srcPtr->width);
2648
2649         unsigned char *pSrcBase = (unsigned char *)srcPtr->data + ((int)srcRec.y*srcPtr->width + (int)srcRec.x)*bytesPerPixelSrc;
2650         unsigned char *pDstBase = (unsigned char *)dst->data + ((int)dstRec.y*dst->width + (int)dstRec.x)*bytesPerPixelDst;
2651
2652         for (int y = 0; y < (int)srcRec.height; y++)
2653         {
2654             unsigned char *pSrc = pSrcBase;
2655             unsigned char *pDst = pDstBase;
2656
2657             // Fast path: Avoid moving pixel by pixel if no blend required and same format
2658             if (!blendRequired && (srcPtr->format == dst->format)) memcpy(pDst, pSrc, (int)(srcRec.width)*bytesPerPixelSrc);
2659             else
2660             {
2661                 for (int x = 0; x < (int)srcRec.width; x++)
2662                 {
2663                     colSrc = GetPixelColor(pSrc, srcPtr->format);
2664                     colDst = GetPixelColor(pDst, dst->format);
2665
2666                     // Fast path: Avoid blend if source has no alpha to blend
2667                     if (blendRequired) blend = ColorAlphaBlend(colDst, colSrc, tint);
2668                     else blend = colSrc;
2669
2670                     SetPixelColor(pDst, blend, dst->format);
2671
2672                     pDst += bytesPerPixelDst;
2673                     pSrc += bytesPerPixelSrc;
2674                 }
2675             }
2676
2677             pSrcBase += strideSrc;
2678             pDstBase += strideDst;
2679         }
2680
2681         if (useSrcMod) UnloadImage(srcMod);     // Unload source modified image
2682     }
2683 }
2684
2685 // Draw text (default font) within an image (destination)
2686 void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
2687 {
2688     Vector2 position = { (float)posX, (float)posY };
2689
2690     // NOTE: For default font, sapcing is set to desired font size / default font size (10)
2691     ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color);
2692 }
2693
2694 // Draw text (custom sprite font) within an image (destination)
2695 void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
2696 {
2697     Image imText = ImageTextEx(font, text, fontSize, spacing, tint);
2698
2699     Rectangle srcRec = { 0.0f, 0.0f, (float)imText.width, (float)imText.height };
2700     Rectangle dstRec = { position.x, position.y, (float)imText.width, (float)imText.height };
2701
2702     ImageDraw(dst, imText, srcRec, dstRec, WHITE);
2703
2704     UnloadImage(imText);
2705 }
2706
2707 //------------------------------------------------------------------------------------
2708 // Texture loading functions
2709 //------------------------------------------------------------------------------------
2710 // Load texture from file into GPU memory (VRAM)
2711 Texture2D LoadTexture(const char *fileName)
2712 {
2713     Texture2D texture = { 0 };
2714
2715     Image image = LoadImage(fileName);
2716
2717     if (image.data != NULL)
2718     {
2719         texture = LoadTextureFromImage(image);
2720         UnloadImage(image);
2721     }
2722
2723     return texture;
2724 }
2725
2726 // Load a texture from image data
2727 // NOTE: image is not unloaded, it must be done manually
2728 Texture2D LoadTextureFromImage(Image image)
2729 {
2730     Texture2D texture = { 0 };
2731
2732     if ((image.data != NULL) && (image.width != 0) && (image.height != 0))
2733     {
2734         texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
2735     }
2736     else TRACELOG(LOG_WARNING, "IMAGE: Data is not valid to load texture");
2737
2738     texture.width = image.width;
2739     texture.height = image.height;
2740     texture.mipmaps = image.mipmaps;
2741     texture.format = image.format;
2742
2743     return texture;
2744 }
2745
2746 // Load cubemap from image, multiple image cubemap layouts supported
2747 TextureCubemap LoadTextureCubemap(Image image, int layout)
2748 {
2749     TextureCubemap cubemap = { 0 };
2750
2751     if (layout == CUBEMAP_LAYOUT_AUTO_DETECT)      // Try to automatically guess layout type
2752     {
2753         // Check image width/height to determine the type of cubemap provided
2754         if (image.width > image.height)
2755         {
2756             if ((image.width/6) == image.height) { layout = CUBEMAP_LAYOUT_LINE_HORIZONTAL; cubemap.width = image.width/6; }
2757             else if ((image.width/4) == (image.height/3)) { layout = CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
2758             else if (image.width >= (int)((float)image.height*1.85f)) { layout = CUBEMAP_LAYOUT_PANORAMA; cubemap.width = image.width/4; }
2759         }
2760         else if (image.height > image.width)
2761         {
2762             if ((image.height/6) == image.width) { layout = CUBEMAP_LAYOUT_LINE_VERTICAL; cubemap.width = image.height/6; }
2763             else if ((image.width/3) == (image.height/4)) { layout = CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
2764         }
2765
2766         cubemap.height = cubemap.width;
2767     }
2768
2769     if (layout != CUBEMAP_LAYOUT_AUTO_DETECT)
2770     {
2771         int size = cubemap.width;
2772
2773         Image faces = { 0 };                // Vertical column image
2774         Rectangle faceRecs[6] = { 0 };      // Face source rectangles
2775         for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, (float)size, (float)size };
2776
2777         if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
2778         {
2779             faces = image;
2780             for (int i = 0; i < 6; i++) faceRecs[i].y = (float)size*i;
2781         }
2782         else if (layout == CUBEMAP_LAYOUT_PANORAMA)
2783         {
2784             // TODO: Convert panorama image to square faces...
2785             // Ref: https://github.com/denivip/panorama/blob/master/panorama.cpp
2786         }
2787         else
2788         {
2789             if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = (float)size*i;
2790             else if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR)
2791             {
2792                 faceRecs[0].x = (float)size; faceRecs[0].y = (float)size;
2793                 faceRecs[1].x = (float)size; faceRecs[1].y = (float)size*3;
2794                 faceRecs[2].x = (float)size; faceRecs[2].y = 0;
2795                 faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
2796                 faceRecs[4].x = 0; faceRecs[4].y = (float)size;
2797                 faceRecs[5].x = (float)size*2; faceRecs[5].y = (float)size;
2798             }
2799             else if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE)
2800             {
2801                 faceRecs[0].x = (float)size*2; faceRecs[0].y = (float)size;
2802                 faceRecs[1].x = 0; faceRecs[1].y = (float)size;
2803                 faceRecs[2].x = (float)size; faceRecs[2].y = 0;
2804                 faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
2805                 faceRecs[4].x = (float)size; faceRecs[4].y = (float)size;
2806                 faceRecs[5].x = (float)size*3; faceRecs[5].y = (float)size;
2807             }
2808
2809             // Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
2810             faces = GenImageColor(size, size*6, MAGENTA);
2811             ImageFormat(&faces, image.format);
2812
2813             // TODO: Image formating does not work with compressed textures!
2814         }
2815
2816         for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
2817
2818         cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
2819         if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
2820
2821         UnloadImage(faces);
2822     }
2823     else TRACELOG(LOG_WARNING, "IMAGE: Failed to detect cubemap image layout");
2824
2825     return cubemap;
2826 }
2827
2828 // Load texture for rendering (framebuffer)
2829 // NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
2830 RenderTexture2D LoadRenderTexture(int width, int height)
2831 {
2832     RenderTexture2D target = { 0 };
2833
2834     target.id = rlLoadFramebuffer(width, height);   // Load an empty framebuffer
2835
2836     if (target.id > 0)
2837     {
2838         rlEnableFramebuffer(target.id);
2839
2840         // Create color texture (default to RGBA)
2841         target.texture.id = rlLoadTexture(NULL, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
2842         target.texture.width = width;
2843         target.texture.height = height;
2844         target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
2845         target.texture.mipmaps = 1;
2846
2847         // Create depth renderbuffer/texture
2848         target.depth.id = rlLoadTextureDepth(width, height, true);
2849         target.depth.width = width;
2850         target.depth.height = height;
2851         target.depth.format = 19;       //DEPTH_COMPONENT_24BIT?
2852         target.depth.mipmaps = 1;
2853
2854         // Attach color texture and depth renderbuffer/texture to FBO
2855         rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
2856         rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
2857
2858         // Check if fbo is complete with attachments (valid)
2859         if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
2860
2861         rlDisableFramebuffer();
2862     }
2863     else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
2864
2865     return target;
2866 }
2867
2868 // Unload texture from GPU memory (VRAM)
2869 void UnloadTexture(Texture2D texture)
2870 {
2871     if (texture.id > 0)
2872     {
2873         rlUnloadTexture(texture.id);
2874
2875         TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded texture data from VRAM (GPU)", texture.id);
2876     }
2877 }
2878
2879 // Unload render texture from GPU memory (VRAM)
2880 void UnloadRenderTexture(RenderTexture2D target)
2881 {
2882     if (target.id > 0)
2883     {
2884         // Color texture attached to FBO is deleted
2885         rlUnloadTexture(target.texture.id);
2886
2887         // NOTE: Depth texture/renderbuffer is automatically
2888         // queried and deleted before deleting framebuffer
2889         rlUnloadFramebuffer(target.id);
2890     }
2891 }
2892
2893 // Update GPU texture with new data
2894 // NOTE: pixels data must match texture.format
2895 void UpdateTexture(Texture2D texture, const void *pixels)
2896 {
2897     rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
2898 }
2899
2900 // Update GPU texture rectangle with new data
2901 // NOTE: pixels data must match texture.format
2902 void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
2903 {
2904     rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
2905 }
2906
2907 // Get pixel data from GPU texture and return an Image
2908 // NOTE: Compressed texture formats not supported
2909 Image GetTextureData(Texture2D texture)
2910 {
2911     Image image = { 0 };
2912
2913     if (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
2914     {
2915         image.data = rlReadTexturePixels(texture);
2916
2917         if (image.data != NULL)
2918         {
2919             image.width = texture.width;
2920             image.height = texture.height;
2921             image.format = texture.format;
2922             image.mipmaps = 1;
2923
2924 #if defined(GRAPHICS_API_OPENGL_ES2)
2925             // NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA,
2926             // coming from FBO color buffer attachment, but it seems
2927             // original texture format is retrieved on RPI...
2928             image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
2929 #endif
2930             TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id);
2931         }
2932         else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id);
2933     }
2934     else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id);
2935
2936     return image;
2937 }
2938
2939 // Get pixel data from GPU frontbuffer and return an Image (screenshot)
2940 Image GetScreenData(void)
2941 {
2942     Image image = { 0 };
2943
2944     image.width = GetScreenWidth();
2945     image.height = GetScreenHeight();
2946     image.mipmaps = 1;
2947     image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
2948     image.data = rlReadScreenPixels(image.width, image.height);
2949
2950     return image;
2951 }
2952
2953 //------------------------------------------------------------------------------------
2954 // Texture configuration functions
2955 //------------------------------------------------------------------------------------
2956 // Generate GPU mipmaps for a texture
2957 void GenTextureMipmaps(Texture2D *texture)
2958 {
2959     // NOTE: NPOT textures support check inside function
2960     // On WebGL (OpenGL ES 2.0) NPOT textures support is limited
2961     rlGenerateMipmaps(texture);
2962 }
2963
2964 // Set texture scaling filter mode
2965 void SetTextureFilter(Texture2D texture, int filter)
2966 {
2967     switch (filter)
2968     {
2969         case TEXTURE_FILTER_POINT:
2970         {
2971             if (texture.mipmaps > 1)
2972             {
2973                 // RL_TEXTURE_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
2974                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_NEAREST);
2975
2976                 // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
2977                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
2978             }
2979             else
2980             {
2981                 // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
2982                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_NEAREST);
2983                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
2984             }
2985         } break;
2986         case TEXTURE_FILTER_BILINEAR:
2987         {
2988             if (texture.mipmaps > 1)
2989             {
2990                 // RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
2991                 // Alternative: RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
2992                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST);
2993
2994                 // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
2995                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
2996             }
2997             else
2998             {
2999                 // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
3000                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
3001                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
3002             }
3003         } break;
3004         case TEXTURE_FILTER_TRILINEAR:
3005         {
3006             if (texture.mipmaps > 1)
3007             {
3008                 // RL_TEXTURE_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
3009                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR);
3010
3011                 // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
3012                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
3013             }
3014             else
3015             {
3016                 TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
3017
3018                 // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
3019                 rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
3020                 rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
3021             }
3022         } break;
3023         case TEXTURE_FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 4); break;
3024         case TEXTURE_FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 8); break;
3025         case TEXTURE_FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 16); break;
3026         default: break;
3027     }
3028 }
3029
3030 // Set texture wrapping mode
3031 void SetTextureWrap(Texture2D texture, int wrap)
3032 {
3033     switch (wrap)
3034     {
3035         case TEXTURE_WRAP_REPEAT:
3036         {
3037             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT);
3038             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT);
3039         } break;
3040         case TEXTURE_WRAP_CLAMP:
3041         {
3042             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_CLAMP);
3043             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_CLAMP);
3044         } break;
3045         case TEXTURE_WRAP_MIRROR_REPEAT:
3046         {
3047             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_REPEAT);
3048             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_REPEAT);
3049         } break;
3050         case TEXTURE_WRAP_MIRROR_CLAMP:
3051         {
3052             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_CLAMP);
3053             rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_CLAMP);
3054         } break;
3055         default: break;
3056     }
3057 }
3058
3059 //------------------------------------------------------------------------------------
3060 // Texture drawing functions
3061 //------------------------------------------------------------------------------------
3062 // Draw a Texture2D
3063 void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
3064 {
3065     DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY }, 0.0f, 1.0f, tint);
3066 }
3067
3068 // Draw a Texture2D with position defined as Vector2
3069 void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
3070 {
3071     DrawTextureEx(texture, position, 0, 1.0f, tint);
3072 }
3073
3074 // Draw a Texture2D with extended parameters
3075 void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
3076 {
3077     Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
3078     Rectangle dest = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale };
3079     Vector2 origin = { 0.0f, 0.0f };
3080
3081     DrawTexturePro(texture, source, dest, origin, rotation, tint);
3082 }
3083
3084 // Draw a part of a texture (defined by a rectangle)
3085 void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint)
3086 {
3087     Rectangle dest = { position.x, position.y, fabsf(source.width), fabsf(source.height) };
3088     Vector2 origin = { 0.0f, 0.0f };
3089
3090     DrawTexturePro(texture, source, dest, origin, 0.0f, tint);
3091 }
3092
3093 // Draw texture quad with tiling and offset parameters
3094 // NOTE: Tiling and offset should be provided considering normalized texture values [0..1]
3095 // i.e tiling = { 1.0f, 1.0f } refers to all texture, offset = { 0.5f, 0.5f } moves texture origin to center
3096 void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint)
3097 {
3098     Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height };
3099     Vector2 origin = { 0.0f, 0.0f };
3100
3101     DrawTexturePro(texture, source, quad, origin, 0.0f, tint);
3102 }
3103
3104 // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest.
3105 // NOTE: For tilling a whole texture DrawTextureQuad() is better
3106 void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint)
3107 {
3108     if ((texture.id <= 0) || (scale <= 0.0f)) return;  // Wanna see a infinite loop?!...just delete this line!
3109
3110     int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale);
3111     if ((dest.width < tileWidth) && (dest.height < tileHeight))
3112     {
3113         // Can fit only one tile
3114         DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height},
3115                     (Rectangle){dest.x, dest.y, dest.width, dest.height}, origin, rotation, tint);
3116     }
3117     else if (dest.width <= tileWidth)
3118     {
3119         // Tiled vertically (one column)
3120         int dy = 0;
3121         for (;dy+tileHeight < dest.height; dy += tileHeight)
3122         {
3123             DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, source.height}, (Rectangle){dest.x, dest.y + dy, dest.width, (float)tileHeight}, origin, rotation, tint);
3124         }
3125
3126         // Fit last tile
3127         if (dy < dest.height)
3128         {
3129             DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
3130                         (Rectangle){dest.x, dest.y + dy, dest.width, dest.height - dy}, origin, rotation, tint);
3131         }
3132     }
3133     else if (dest.height <= tileHeight)
3134     {
3135         // Tiled horizontally (one row)
3136         int dx = 0;
3137         for (;dx+tileWidth < dest.width; dx += tileWidth)
3138         {
3139             DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)dest.height/tileHeight)*source.height}, (Rectangle){dest.x + dx, dest.y, (float)tileWidth, dest.height}, origin, rotation, tint);
3140         }
3141
3142         // Fit last tile
3143         if (dx < dest.width)
3144         {
3145             DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height},
3146                         (Rectangle){dest.x + dx, dest.y, dest.width - dx, dest.height}, origin, rotation, tint);
3147         }
3148     }
3149     else
3150     {
3151         // Tiled both horizontally and vertically (rows and columns)
3152         int dx = 0;
3153         for (;dx+tileWidth < dest.width; dx += tileWidth)
3154         {
3155             int dy = 0;
3156             for (;dy+tileHeight < dest.height; dy += tileHeight)
3157             {
3158                 DrawTexturePro(texture, source, (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, (float)tileHeight}, origin, rotation, tint);
3159             }
3160
3161             if (dy < dest.height)
3162             {
3163                 DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
3164                     (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, dest.height - dy}, origin, rotation, tint);
3165             }
3166         }
3167
3168         // Fit last column of tiles
3169         if (dx < dest.width)
3170         {
3171             int dy = 0;
3172             for (;dy+tileHeight < dest.height; dy += tileHeight)
3173             {
3174                 DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, source.height},
3175                         (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, (float)tileHeight}, origin, rotation, tint);
3176             }
3177
3178             // Draw final tile in the bottom right corner
3179             if (dy < dest.height)
3180             {
3181                 DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
3182                     (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, dest.height - dy}, origin, rotation, tint);
3183             }
3184         }
3185     }
3186 }
3187
3188 // Draw a part of a texture (defined by a rectangle) with 'pro' parameters
3189 // NOTE: origin is relative to destination rectangle size
3190 void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint)
3191 {
3192     // Check if texture is valid
3193     if (texture.id > 0)
3194     {
3195         float width = (float)texture.width;
3196         float height = (float)texture.height;
3197
3198         bool flipX = false;
3199
3200         if (source.width < 0) { flipX = true; source.width *= -1; }
3201         if (source.height < 0) source.y -= source.height;
3202
3203         Vector2 topLeft = { 0 };
3204         Vector2 topRight = { 0 };
3205         Vector2 bottomLeft = { 0 };
3206         Vector2 bottomRight = { 0 };
3207
3208         // Only calculate rotation if needed
3209         if (rotation == 0.0f)
3210         {
3211             float x = dest.x - origin.x;
3212             float y = dest.y - origin.y;
3213             topLeft = (Vector2){ x, y };
3214             topRight = (Vector2){ x + dest.width, y };
3215             bottomLeft = (Vector2){ x, y + dest.height };
3216             bottomRight = (Vector2){ x + dest.width, y + dest.height };
3217         }
3218         else
3219         {
3220             float sinRotation = sinf(rotation*DEG2RAD);
3221             float cosRotation = cosf(rotation*DEG2RAD);
3222             float x = dest.x;
3223             float y = dest.y;
3224             float dx = -origin.x;
3225             float dy = -origin.y;
3226
3227             topLeft.x = x + dx*cosRotation - dy*sinRotation;
3228             topLeft.y = y + dx*sinRotation + dy*cosRotation;
3229
3230             topRight.x = x + (dx + dest.width)*cosRotation - dy*sinRotation;
3231             topRight.y = y + (dx + dest.width)*sinRotation + dy*cosRotation;
3232
3233             bottomLeft.x = x + dx*cosRotation - (dy + dest.height)*sinRotation;
3234             bottomLeft.y = y + dx*sinRotation + (dy + dest.height)*cosRotation;
3235
3236             bottomRight.x = x + (dx + dest.width)*cosRotation - (dy + dest.height)*sinRotation;
3237             bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation;
3238         }
3239
3240         rlCheckRenderBatchLimit(4);     // Make sure there is enough free space on the batch buffer
3241
3242         rlSetTexture(texture.id);
3243         rlBegin(RL_QUADS);
3244
3245             rlColor4ub(tint.r, tint.g, tint.b, tint.a);
3246             rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
3247
3248             // Top-left corner for texture and quad
3249             if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
3250             else rlTexCoord2f(source.x/width, source.y/height);
3251             rlVertex2f(topLeft.x, topLeft.y);
3252
3253             // Bottom-left corner for texture and quad
3254             if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
3255             else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
3256             rlVertex2f(bottomLeft.x, bottomLeft.y);
3257
3258             // Bottom-right corner for texture and quad
3259             if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
3260             else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
3261             rlVertex2f(bottomRight.x, bottomRight.y);
3262
3263             // Top-right corner for texture and quad
3264             if (flipX) rlTexCoord2f(source.x/width, source.y/height);
3265             else rlTexCoord2f((source.x + source.width)/width, source.y/height);
3266             rlVertex2f(topRight.x, topRight.y);
3267
3268         rlEnd();
3269         rlSetTexture(0);
3270
3271         // NOTE: Vertex position can be transformed using matrices
3272         // but the process is way more costly than just calculating
3273         // the vertex positions manually, like done above.
3274         // I leave here the old implementation for educational pourposes,
3275         // just in case someone wants to do some performance test
3276         /*
3277         rlSetTexture(texture.id);
3278         rlPushMatrix();
3279             rlTranslatef(dest.x, dest.y, 0.0f);
3280             if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
3281             rlTranslatef(-origin.x, -origin.y, 0.0f);
3282
3283             rlBegin(RL_QUADS);
3284                 rlColor4ub(tint.r, tint.g, tint.b, tint.a);
3285                 rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
3286
3287                 // Bottom-left corner for texture and quad
3288                 if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
3289                 else rlTexCoord2f(source.x/width, source.y/height);
3290                 rlVertex2f(0.0f, 0.0f);
3291
3292                 // Bottom-right corner for texture and quad
3293                 if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
3294                 else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
3295                 rlVertex2f(0.0f, dest.height);
3296
3297                 // Top-right corner for texture and quad
3298                 if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
3299                 else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
3300                 rlVertex2f(dest.width, dest.height);
3301
3302                 // Top-left corner for texture and quad
3303                 if (flipX) rlTexCoord2f(source.x/width, source.y/height);
3304                 else rlTexCoord2f((source.x + source.width)/width, source.y/height);
3305                 rlVertex2f(dest.width, 0.0f);
3306             rlEnd();
3307         rlPopMatrix();
3308         rlSetTexture(0);
3309         */
3310     }
3311 }
3312
3313 // Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info
3314 void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint)
3315 {
3316     if (texture.id > 0)
3317     {
3318         float width = (float)texture.width;
3319         float height = (float)texture.height;
3320
3321         float patchWidth = (dest.width <= 0.0f)? 0.0f : dest.width;
3322         float patchHeight = (dest.height <= 0.0f)? 0.0f : dest.height;
3323
3324         if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width;
3325         if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height;
3326         if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL) patchHeight = nPatchInfo.source.height;
3327         if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL) patchWidth = nPatchInfo.source.width;
3328
3329         bool drawCenter = true;
3330         bool drawMiddle = true;
3331         float leftBorder = (float)nPatchInfo.left;
3332         float topBorder = (float)nPatchInfo.top;
3333         float rightBorder = (float)nPatchInfo.right;
3334         float bottomBorder = (float)nPatchInfo.bottom;
3335
3336         // adjust the lateral (left and right) border widths in case patchWidth < texture.width
3337         if (patchWidth <= (leftBorder + rightBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_VERTICAL)
3338         {
3339             drawCenter = false;
3340             leftBorder = (leftBorder/(leftBorder + rightBorder))*patchWidth;
3341             rightBorder = patchWidth - leftBorder;
3342         }
3343         // adjust the lateral (top and bottom) border heights in case patchHeight < texture.height
3344         if (patchHeight <= (topBorder + bottomBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_HORIZONTAL)
3345         {
3346             drawMiddle = false;
3347             topBorder = (topBorder/(topBorder + bottomBorder))*patchHeight;
3348             bottomBorder = patchHeight - topBorder;
3349         }
3350
3351         Vector2 vertA, vertB, vertC, vertD;
3352         vertA.x = 0.0f;                             // outer left
3353         vertA.y = 0.0f;                             // outer top
3354         vertB.x = leftBorder;                       // inner left
3355         vertB.y = topBorder;                        // inner top
3356         vertC.x = patchWidth  - rightBorder;        // inner right
3357         vertC.y = patchHeight - bottomBorder;       // inner bottom
3358         vertD.x = patchWidth;                       // outer right
3359         vertD.y = patchHeight;                      // outer bottom
3360
3361         Vector2 coordA, coordB, coordC, coordD;
3362         coordA.x = nPatchInfo.source.x/width;
3363         coordA.y = nPatchInfo.source.y/height;
3364         coordB.x = (nPatchInfo.source.x + leftBorder)/width;
3365         coordB.y = (nPatchInfo.source.y + topBorder)/height;
3366         coordC.x = (nPatchInfo.source.x + nPatchInfo.source.width  - rightBorder)/width;
3367         coordC.y = (nPatchInfo.source.y + nPatchInfo.source.height - bottomBorder)/height;
3368         coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width;
3369         coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height;
3370
3371         rlSetTexture(texture.id);
3372
3373         rlPushMatrix();
3374             rlTranslatef(dest.x, dest.y, 0.0f);
3375             rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
3376             rlTranslatef(-origin.x, -origin.y, 0.0f);
3377
3378             rlBegin(RL_QUADS);
3379                 rlColor4ub(tint.r, tint.g, tint.b, tint.a);
3380                 rlNormal3f(0.0f, 0.0f, 1.0f);               // Normal vector pointing towards viewer
3381
3382                 if (nPatchInfo.layout == NPATCH_NINE_PATCH)
3383                 {
3384                     // ------------------------------------------------------------
3385                     // TOP-LEFT QUAD
3386                     rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
3387                     rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-right corner for texture and quad
3388                     rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
3389                     rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
3390                     if (drawCenter)
3391                     {
3392                         // TOP-CENTER QUAD
3393                         rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-left corner for texture and quad
3394                         rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-right corner for texture and quad
3395                         rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
3396                         rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
3397                     }
3398                     // TOP-RIGHT QUAD
3399                     rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-left corner for texture and quad
3400                     rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
3401                     rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
3402                     rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
3403                     if (drawMiddle)
3404                     {
3405                         // ------------------------------------------------------------
3406                         // MIDDLE-LEFT QUAD
3407                         rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
3408                         rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-right corner for texture and quad
3409                         rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-right corner for texture and quad
3410                         rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
3411                         if (drawCenter)
3412                         {
3413                             // MIDDLE-CENTER QUAD
3414                             rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-left corner for texture and quad
3415                             rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-right corner for texture and quad
3416                             rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-right corner for texture and quad
3417                             rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-left corner for texture and quad
3418                         }
3419
3420                         // MIDDLE-RIGHT QUAD
3421                         rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-left corner for texture and quad
3422                         rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
3423                         rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
3424                         rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-left corner for texture and quad
3425                     }
3426
3427                     // ------------------------------------------------------------
3428                     // BOTTOM-LEFT QUAD
3429                     rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
3430                     rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
3431                     rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-right corner for texture and quad
3432                     rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
3433                     if (drawCenter)
3434                     {
3435                         // BOTTOM-CENTER QUAD
3436                         rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
3437                         rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
3438                         rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-right corner for texture and quad
3439                         rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-left corner for texture and quad
3440                     }
3441
3442                     // BOTTOM-RIGHT QUAD
3443                     rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
3444                     rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
3445                     rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
3446                     rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-left corner for texture and quad
3447                 }
3448                 else if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL)
3449                 {
3450                     // TOP QUAD
3451                     // -----------------------------------------------------------
3452                     // Texture coords                 Vertices
3453                     rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
3454                     rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
3455                     rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
3456                     rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
3457                     if (drawCenter)
3458                     {
3459                         // MIDDLE QUAD
3460                         // -----------------------------------------------------------
3461                         // Texture coords                 Vertices
3462                         rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
3463                         rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
3464                         rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
3465                         rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
3466                     }
3467                     // BOTTOM QUAD
3468                     // -----------------------------------------------------------
3469                     // Texture coords                 Vertices
3470                     rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
3471                     rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
3472                     rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
3473                     rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
3474                 }
3475                 else if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL)
3476                 {
3477                     // LEFT QUAD
3478                     // -----------------------------------------------------------
3479                     // Texture coords                 Vertices
3480                     rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
3481                     rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
3482                     rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
3483                     rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
3484                     if (drawCenter)
3485                     {
3486                         // CENTER QUAD
3487                         // -----------------------------------------------------------
3488                         // Texture coords                 Vertices
3489                         rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
3490                         rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
3491                         rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
3492                         rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
3493                     }
3494                     // RIGHT QUAD
3495                     // -----------------------------------------------------------
3496                     // Texture coords                 Vertices
3497                     rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
3498                     rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
3499                     rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
3500                     rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
3501                 }
3502             rlEnd();
3503         rlPopMatrix();
3504
3505         rlSetTexture(0);
3506     }
3507 }
3508
3509 // Draw textured polygon, defined by vertex and texturecoordinates
3510 // NOTE: Polygon center must have straight line path to all points
3511 // without crossing perimeter, points must be in anticlockwise order
3512 void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointsCount, Color tint)
3513 {
3514     rlCheckRenderBatchLimit((pointsCount - 1)*4);
3515
3516     rlSetTexture(texture.id);
3517
3518     // Texturing is only supported on QUADs
3519     rlBegin(RL_QUADS);
3520
3521         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
3522
3523         for (int i = 0; i < pointsCount - 1; i++)
3524         {
3525             rlTexCoord2f(0.5f, 0.5f);
3526             rlVertex2f(center.x, center.y);
3527
3528             rlTexCoord2f(texcoords[i].x, texcoords[i].y);
3529             rlVertex2f(points[i].x + center.x, points[i].y + center.y);
3530
3531             rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y);
3532             rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y);
3533
3534             rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y);
3535             rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y);
3536         }
3537     rlEnd();
3538
3539     rlSetTexture(0);
3540 }
3541
3542 // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
3543 Color Fade(Color color, float alpha)
3544 {
3545     if (alpha < 0.0f) alpha = 0.0f;
3546     else if (alpha > 1.0f) alpha = 1.0f;
3547
3548     return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
3549 }
3550
3551 // Returns hexadecimal value for a Color
3552 int ColorToInt(Color color)
3553 {
3554     return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
3555 }
3556
3557 // Returns color normalized as float [0..1]
3558 Vector4 ColorNormalize(Color color)
3559 {
3560     Vector4 result;
3561
3562     result.x = (float)color.r/255.0f;
3563     result.y = (float)color.g/255.0f;
3564     result.z = (float)color.b/255.0f;
3565     result.w = (float)color.a/255.0f;
3566
3567     return result;
3568 }
3569
3570 // Returns color from normalized values [0..1]
3571 Color ColorFromNormalized(Vector4 normalized)
3572 {
3573     Color result;
3574
3575     result.r = (unsigned char)(normalized.x*255.0f);
3576     result.g = (unsigned char)(normalized.y*255.0f);
3577     result.b = (unsigned char)(normalized.z*255.0f);
3578     result.a = (unsigned char)(normalized.w*255.0f);
3579
3580     return result;
3581 }
3582
3583 // Returns HSV values for a Color
3584 // NOTE: Hue is returned as degrees [0..360]
3585 Vector3 ColorToHSV(Color color)
3586 {
3587     Vector3 hsv = { 0 };
3588     Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
3589     float min, max, delta;
3590
3591     min = rgb.x < rgb.y? rgb.x : rgb.y;
3592     min = min  < rgb.z? min  : rgb.z;
3593
3594     max = rgb.x > rgb.y? rgb.x : rgb.y;
3595     max = max  > rgb.z? max  : rgb.z;
3596
3597     hsv.z = max;            // Value
3598     delta = max - min;
3599
3600     if (delta < 0.00001f)
3601     {
3602         hsv.y = 0.0f;
3603         hsv.x = 0.0f;       // Undefined, maybe NAN?
3604         return hsv;
3605     }
3606
3607     if (max > 0.0f)
3608     {
3609         // NOTE: If max is 0, this divide would cause a crash
3610         hsv.y = (delta/max);    // Saturation
3611     }
3612     else
3613     {
3614         // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
3615         hsv.y = 0.0f;
3616         hsv.x = NAN;        // Undefined
3617         return hsv;
3618     }
3619
3620     // NOTE: Comparing float values could not work properly
3621     if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta;    // Between yellow & magenta
3622     else
3623     {
3624         if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta;  // Between cyan & yellow
3625         else hsv.x = 4.0f + (rgb.x - rgb.y)/delta;      // Between magenta & cyan
3626     }
3627
3628     hsv.x *= 60.0f;     // Convert to degrees
3629
3630     if (hsv.x < 0.0f) hsv.x += 360.0f;
3631
3632     return hsv;
3633 }
3634
3635 // Returns a Color from HSV values
3636 // Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion
3637 // NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors
3638 // Hue is provided in degrees: [0..360]
3639 // Saturation/Value are provided normalized: [0.0f..1.0f]
3640 Color ColorFromHSV(float hue, float saturation, float value)
3641 {
3642     Color color = { 0, 0, 0, 255 };
3643
3644     // Red channel
3645     float k = fmodf((5.0f + hue/60.0f), 6);
3646     float t = 4.0f - k;
3647     k = (t < k)? t : k;
3648     k = (k < 1)? k : 1;
3649     k = (k > 0)? k : 0;
3650     color.r = (unsigned char)((value - value*saturation*k)*255.0f);
3651
3652     // Green channel
3653     k = fmodf((3.0f + hue/60.0f), 6);
3654     t = 4.0f - k;
3655     k = (t < k)? t : k;
3656     k = (k < 1)? k : 1;
3657     k = (k > 0)? k : 0;
3658     color.g = (unsigned char)((value - value*saturation*k)*255.0f);
3659
3660     // Blue channel
3661     k = fmodf((1.0f + hue/60.0f), 6);
3662     t = 4.0f - k;
3663     k = (t < k)? t : k;
3664     k = (k < 1)? k : 1;
3665     k = (k > 0)? k : 0;
3666     color.b = (unsigned char)((value - value*saturation*k)*255.0f);
3667
3668     return color;
3669 }
3670
3671 // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
3672 Color ColorAlpha(Color color, float alpha)
3673 {
3674     if (alpha < 0.0f) alpha = 0.0f;
3675     else if (alpha > 1.0f) alpha = 1.0f;
3676
3677     return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
3678 }
3679
3680 // Returns src alpha-blended into dst color with tint
3681 Color ColorAlphaBlend(Color dst, Color src, Color tint)
3682 {
3683     Color out = WHITE;
3684
3685     // Apply color tint to source color
3686     src.r = (unsigned char)(((unsigned int)src.r*(unsigned int)tint.r) >> 8);
3687     src.g = (unsigned char)(((unsigned int)src.g*(unsigned int)tint.g) >> 8);
3688     src.b = (unsigned char)(((unsigned int)src.b*(unsigned int)tint.b) >> 8);
3689     src.a = (unsigned char)(((unsigned int)src.a*(unsigned int)tint.a) >> 8);
3690
3691 //#define COLORALPHABLEND_FLOAT
3692 #define COLORALPHABLEND_INTEGERS
3693 #if defined(COLORALPHABLEND_INTEGERS)
3694     if (src.a == 0) out = dst;
3695     else if (src.a == 255) out = src;
3696     else
3697     {
3698         unsigned int alpha = (unsigned int)src.a + 1;     // We are shifting by 8 (dividing by 256), so we need to take that excess into account
3699         out.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8);
3700
3701         if (out.a > 0)
3702         {
3703             out.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
3704             out.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
3705             out.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
3706         }
3707     }
3708 #endif
3709 #if defined(COLORALPHABLEND_FLOAT)
3710     if (src.a == 0) out = dst;
3711     else if (src.a == 255) out = src;
3712     else
3713     {
3714         Vector4 fdst = ColorNormalize(dst);
3715         Vector4 fsrc = ColorNormalize(src);
3716         Vector4 ftint = ColorNormalize(tint);
3717         Vector4 fout = { 0 };
3718
3719         fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w);
3720
3721         if (fout.w > 0.0f)
3722         {
3723             fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w;
3724             fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w;
3725             fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
3726         }
3727
3728         out = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) };
3729     }
3730 #endif
3731
3732     return out;
3733 }
3734
3735 // Returns a Color struct from hexadecimal value
3736 Color GetColor(int hexValue)
3737 {
3738     Color color;
3739
3740     color.r = (unsigned char)(hexValue >> 24) & 0xFF;
3741     color.g = (unsigned char)(hexValue >> 16) & 0xFF;
3742     color.b = (unsigned char)(hexValue >> 8) & 0xFF;
3743     color.a = (unsigned char)hexValue & 0xFF;
3744
3745     return color;
3746 }
3747
3748 // Get color from a pixel from certain format
3749 Color GetPixelColor(void *srcPtr, int format)
3750 {
3751     Color col = { 0 };
3752
3753     switch (format)
3754     {
3755         case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], 255 }; break;
3756         case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1] }; break;
3757         case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
3758         {
3759             col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
3760             col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 5) & 0b0000000000111111)*255/63);
3761             col.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31);
3762             col.a = 255;
3763
3764         } break;
3765         case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
3766         {
3767             col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
3768             col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 6) & 0b0000000000011111)*255/31);
3769             col.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31);
3770             col.a = (((unsigned short *)srcPtr)[0] & 0b0000000000000001)? 255 : 0;
3771
3772         } break;
3773         case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
3774         {
3775             col.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 12)*255/15);
3776             col.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 8) & 0b0000000000001111)*255/15);
3777             col.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 4) & 0b0000000000001111)*255/15);
3778             col.a = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000001111)*255/15);
3779
3780         } break;
3781         case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], ((unsigned char *)srcPtr)[3] }; break;
3782         case PIXELFORMAT_UNCOMPRESSED_R8G8B8: col = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], 255 }; break;
3783         // TODO: case PIXELFORMAT_UNCOMPRESSED_R32: break;
3784         // TODO: case PIXELFORMAT_UNCOMPRESSED_R32G32B32: break;
3785         // TODO: case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: break;
3786         default: break;
3787     }
3788
3789     return col;
3790 }
3791
3792 // Set pixel color formatted into destination pointer
3793 void SetPixelColor(void *dstPtr, Color color, int format)
3794 {
3795     switch (format)
3796     {
3797         case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
3798         {
3799             // NOTE: Calculate grayscale equivalent color
3800             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
3801             unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
3802
3803             ((unsigned char *)dstPtr)[0] = gray;
3804
3805         } break;
3806         case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
3807         {
3808             // NOTE: Calculate grayscale equivalent color
3809             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
3810             unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
3811
3812             ((unsigned char *)dstPtr)[0] = gray;
3813             ((unsigned char *)dstPtr)[1] = color.a;
3814
3815         } break;
3816         case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
3817         {
3818             // NOTE: Calculate R5G6B5 equivalent color
3819             Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
3820
3821             unsigned char r = (unsigned char)(round(coln.x*31.0f));
3822             unsigned char g = (unsigned char)(round(coln.y*63.0f));
3823             unsigned char b = (unsigned char)(round(coln.z*31.0f));
3824
3825             ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
3826
3827         } break;
3828         case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
3829         {
3830             // NOTE: Calculate R5G5B5A1 equivalent color
3831             Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
3832
3833             unsigned char r = (unsigned char)(round(coln.x*31.0f));
3834             unsigned char g = (unsigned char)(round(coln.y*31.0f));
3835             unsigned char b = (unsigned char)(round(coln.z*31.0f));
3836             unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;;
3837
3838             ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
3839
3840         } break;
3841         case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
3842         {
3843             // NOTE: Calculate R5G5B5A1 equivalent color
3844             Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
3845
3846             unsigned char r = (unsigned char)(round(coln.x*15.0f));
3847             unsigned char g = (unsigned char)(round(coln.y*15.0f));
3848             unsigned char b = (unsigned char)(round(coln.z*15.0f));
3849             unsigned char a = (unsigned char)(round(coln.w*15.0f));
3850
3851             ((unsigned short *)dstPtr)[0] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
3852
3853         } break;
3854         case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
3855         {
3856             ((unsigned char *)dstPtr)[0] = color.r;
3857             ((unsigned char *)dstPtr)[1] = color.g;
3858             ((unsigned char *)dstPtr)[2] = color.b;
3859
3860         } break;
3861         case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
3862         {
3863             ((unsigned char *)dstPtr)[0] = color.r;
3864             ((unsigned char *)dstPtr)[1] = color.g;
3865             ((unsigned char *)dstPtr)[2] = color.b;
3866             ((unsigned char *)dstPtr)[3] = color.a;
3867
3868         } break;
3869         default: break;
3870     }
3871 }
3872
3873 // Get pixel data size in bytes for certain format
3874 // NOTE: Size can be requested for Image or Texture data
3875 int GetPixelDataSize(int width, int height, int format)
3876 {
3877     int dataSize = 0;       // Size in bytes
3878     int bpp = 0;            // Bits per pixel
3879
3880     switch (format)
3881     {
3882         case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
3883         case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
3884         case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
3885         case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
3886         case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
3887         case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
3888         case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
3889         case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
3890         case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
3891         case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
3892         case PIXELFORMAT_COMPRESSED_DXT1_RGB:
3893         case PIXELFORMAT_COMPRESSED_DXT1_RGBA:
3894         case PIXELFORMAT_COMPRESSED_ETC1_RGB:
3895         case PIXELFORMAT_COMPRESSED_ETC2_RGB:
3896         case PIXELFORMAT_COMPRESSED_PVRT_RGB:
3897         case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
3898         case PIXELFORMAT_COMPRESSED_DXT3_RGBA:
3899         case PIXELFORMAT_COMPRESSED_DXT5_RGBA:
3900         case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
3901         case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
3902         case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
3903         default: break;
3904     }
3905
3906     dataSize = width*height*bpp/8;  // Total data size in bytes
3907
3908     // Most compressed formats works on 4x4 blocks,
3909     // if texture is smaller, minimum dataSize is 8 or 16
3910     if ((width < 4) && (height < 4))
3911     {
3912         if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
3913         else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
3914     }
3915
3916     return dataSize;
3917 }
3918
3919 //----------------------------------------------------------------------------------
3920 // Module specific Functions Definition
3921 //----------------------------------------------------------------------------------
3922 #if defined(SUPPORT_FILEFORMAT_DDS)
3923 // Loading DDS image data (compressed or uncompressed)
3924 static Image LoadDDS(const unsigned char *fileData, unsigned int fileSize)
3925 {
3926     unsigned char *fileDataPtr = (unsigned char *)fileData;
3927
3928     // Required extension:
3929     // GL_EXT_texture_compression_s3tc
3930
3931     // Supported tokens (defined by extensions)
3932     // GL_COMPRESSED_RGB_S3TC_DXT1_EXT      0x83F0
3933     // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT     0x83F1
3934     // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT     0x83F2
3935     // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT     0x83F3
3936
3937     #define FOURCC_DXT1 0x31545844  // Equivalent to "DXT1" in ASCII
3938     #define FOURCC_DXT3 0x33545844  // Equivalent to "DXT3" in ASCII
3939     #define FOURCC_DXT5 0x35545844  // Equivalent to "DXT5" in ASCII
3940
3941     // DDS Pixel Format
3942     typedef struct {
3943         unsigned int size;
3944         unsigned int flags;
3945         unsigned int fourCC;
3946         unsigned int rgbBitCount;
3947         unsigned int rBitMask;
3948         unsigned int gBitMask;
3949         unsigned int bBitMask;
3950         unsigned int aBitMask;
3951     } DDSPixelFormat;
3952
3953     // DDS Header (124 bytes)
3954     typedef struct {
3955         unsigned int size;
3956         unsigned int flags;
3957         unsigned int height;
3958         unsigned int width;
3959         unsigned int pitchOrLinearSize;
3960         unsigned int depth;
3961         unsigned int mipmapCount;
3962         unsigned int reserved1[11];
3963         DDSPixelFormat ddspf;
3964         unsigned int caps;
3965         unsigned int caps2;
3966         unsigned int caps3;
3967         unsigned int caps4;
3968         unsigned int reserved2;
3969     } DDSHeader;
3970
3971     Image image = { 0 };
3972
3973     if (fileDataPtr != NULL)
3974     {
3975         // Verify the type of file
3976         unsigned char *ddsHeaderId = fileDataPtr;
3977         fileDataPtr += 4;
3978
3979         if ((ddsHeaderId[0] != 'D') || (ddsHeaderId[1] != 'D') || (ddsHeaderId[2] != 'S') || (ddsHeaderId[3] != ' '))
3980         {
3981             TRACELOG(LOG_WARNING, "IMAGE: DDS file data not valid");
3982         }
3983         else
3984         {
3985             DDSHeader *ddsHeader = (DDSHeader *)fileDataPtr;
3986
3987             TRACELOGD("IMAGE: DDS file data info:");
3988             TRACELOGD("    > Header size:        %i", sizeof(DDSHeader));
3989             TRACELOGD("    > Pixel format size:  %i", ddsHeader->ddspf.size);
3990             TRACELOGD("    > Pixel format flags: 0x%x", ddsHeader->ddspf.flags);
3991             TRACELOGD("    > File format:        0x%x", ddsHeader->ddspf.fourCC);
3992             TRACELOGD("    > File bit count:     0x%x", ddsHeader->ddspf.rgbBitCount);
3993
3994             fileDataPtr += sizeof(DDSHeader);   // Skip header
3995
3996             image.width = ddsHeader->width;
3997             image.height = ddsHeader->height;
3998
3999             if (ddsHeader->mipmapCount == 0) image.mipmaps = 1;      // Parameter not used
4000             else image.mipmaps = ddsHeader->mipmapCount;
4001
4002             if (ddsHeader->ddspf.rgbBitCount == 16)     // 16bit mode, no compressed
4003             {
4004                 if (ddsHeader->ddspf.flags == 0x40)         // no alpha channel
4005                 {
4006                     int dataSize = image.width*image.height*sizeof(unsigned short);
4007                     image.data = (unsigned short *)RL_MALLOC(dataSize);
4008
4009                     memcpy(image.data, fileDataPtr, dataSize);
4010
4011                     image.format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
4012                 }
4013                 else if (ddsHeader->ddspf.flags == 0x41)        // with alpha channel
4014                 {
4015                     if (ddsHeader->ddspf.aBitMask == 0x8000)    // 1bit alpha
4016                     {
4017                         int dataSize = image.width*image.height*sizeof(unsigned short);
4018                         image.data = (unsigned short *)RL_MALLOC(dataSize);
4019
4020                         memcpy(image.data, fileDataPtr, dataSize);
4021
4022                         unsigned char alpha = 0;
4023
4024                         // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1
4025                         for (int i = 0; i < image.width*image.height; i++)
4026                         {
4027                             alpha = ((unsigned short *)image.data)[i] >> 15;
4028                             ((unsigned short *)image.data)[i] = ((unsigned short *)image.data)[i] << 1;
4029                             ((unsigned short *)image.data)[i] += alpha;
4030                         }
4031
4032                         image.format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
4033                     }
4034                     else if (ddsHeader->ddspf.aBitMask == 0xf000)   // 4bit alpha
4035                     {
4036                         int dataSize = image.width*image.height*sizeof(unsigned short);
4037                         image.data = (unsigned short *)RL_MALLOC(dataSize);
4038
4039                         memcpy(image.data, fileDataPtr, dataSize);
4040
4041                         unsigned char alpha = 0;
4042
4043                         // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4
4044                         for (int i = 0; i < image.width*image.height; i++)
4045                         {
4046                             alpha = ((unsigned short *)image.data)[i] >> 12;
4047                             ((unsigned short *)image.data)[i] = ((unsigned short *)image.data)[i] << 4;
4048                             ((unsigned short *)image.data)[i] += alpha;
4049                         }
4050
4051                         image.format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
4052                     }
4053                 }
4054             }
4055             else if (ddsHeader->ddspf.flags == 0x40 && ddsHeader->ddspf.rgbBitCount == 24)   // DDS_RGB, no compressed
4056             {
4057                 int dataSize = image.width*image.height*3*sizeof(unsigned char);
4058                 image.data = (unsigned short *)RL_MALLOC(dataSize);
4059
4060                 memcpy(image.data, fileDataPtr, dataSize);
4061
4062                 image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
4063             }
4064             else if (ddsHeader->ddspf.flags == 0x41 && ddsHeader->ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
4065             {
4066                 int dataSize = image.width*image.height*4*sizeof(unsigned char);
4067                 image.data = (unsigned short *)RL_MALLOC(dataSize);
4068
4069                 memcpy(image.data, fileDataPtr, dataSize);
4070
4071                 unsigned char blue = 0;
4072
4073                 // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment)
4074                 // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA
4075                 // So, we must realign B8G8R8A8 to R8G8B8A8
4076                 for (int i = 0; i < image.width*image.height*4; i += 4)
4077                 {
4078                     blue = ((unsigned char *)image.data)[i];
4079                     ((unsigned char *)image.data)[i] = ((unsigned char *)image.data)[i + 2];
4080                     ((unsigned char *)image.data)[i + 2] = blue;
4081                 }
4082
4083                 image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
4084             }
4085             else if (((ddsHeader->ddspf.flags == 0x04) || (ddsHeader->ddspf.flags == 0x05)) && (ddsHeader->ddspf.fourCC > 0)) // Compressed
4086             {
4087                 int dataSize = 0;
4088
4089                 // Calculate data size, including all mipmaps
4090                 if (ddsHeader->mipmapCount > 1) dataSize = ddsHeader->pitchOrLinearSize*2;
4091                 else dataSize = ddsHeader->pitchOrLinearSize;
4092
4093                 image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
4094
4095                 memcpy(image.data, fileDataPtr, dataSize);
4096
4097                 switch (ddsHeader->ddspf.fourCC)
4098                 {
4099                     case FOURCC_DXT1:
4100                     {
4101                         if (ddsHeader->ddspf.flags == 0x04) image.format = PIXELFORMAT_COMPRESSED_DXT1_RGB;
4102                         else image.format = PIXELFORMAT_COMPRESSED_DXT1_RGBA;
4103                     } break;
4104                     case FOURCC_DXT3: image.format = PIXELFORMAT_COMPRESSED_DXT3_RGBA; break;
4105                     case FOURCC_DXT5: image.format = PIXELFORMAT_COMPRESSED_DXT5_RGBA; break;
4106                     default: break;
4107                 }
4108             }
4109         }
4110     }
4111
4112     return image;
4113 }
4114 #endif
4115
4116 #if defined(SUPPORT_FILEFORMAT_PKM)
4117 // Loading PKM image data (ETC1/ETC2 compression)
4118 // NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
4119 // PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
4120 static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize)
4121 {
4122     unsigned char *fileDataPtr = (unsigned char *)fileData;
4123
4124     // Required extensions:
4125     // GL_OES_compressed_ETC1_RGB8_texture  (ETC1) (OpenGL ES 2.0)
4126     // GL_ARB_ES3_compatibility  (ETC2/EAC) (OpenGL ES 3.0)
4127
4128     // Supported tokens (defined by extensions)
4129     // GL_ETC1_RGB8_OES                 0x8D64
4130     // GL_COMPRESSED_RGB8_ETC2          0x9274
4131     // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
4132
4133     // PKM file (ETC1) Header (16 bytes)
4134     typedef struct {
4135         char id[4];                 // "PKM "
4136         char version[2];            // "10" or "20"
4137         unsigned short format;      // Data format (big-endian) (Check list below)
4138         unsigned short width;       // Texture width (big-endian) (origWidth rounded to multiple of 4)
4139         unsigned short height;      // Texture height (big-endian) (origHeight rounded to multiple of 4)
4140         unsigned short origWidth;   // Original width (big-endian)
4141         unsigned short origHeight;  // Original height (big-endian)
4142     } PKMHeader;
4143
4144     // Formats list
4145     // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
4146     // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R
4147
4148     // NOTE: The extended width and height are the widths rounded up to a multiple of 4.
4149     // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels)
4150
4151     Image image = { 0 };
4152
4153     if (fileDataPtr != NULL)
4154     {
4155         PKMHeader *pkmHeader = (PKMHeader *)fileDataPtr;
4156
4157         if ((pkmHeader->id[0] != 'P') || (pkmHeader->id[1] != 'K') || (pkmHeader->id[2] != 'M') || (pkmHeader->id[3] != ' '))
4158         {
4159             TRACELOG(LOG_WARNING, "IMAGE: PKM file data not valid");
4160         }
4161         else
4162         {
4163             fileDataPtr += sizeof(PKMHeader);   // Skip header
4164
4165             // NOTE: format, width and height come as big-endian, data must be swapped to little-endian
4166             pkmHeader->format = ((pkmHeader->format & 0x00FF) << 8) | ((pkmHeader->format & 0xFF00) >> 8);
4167             pkmHeader->width = ((pkmHeader->width & 0x00FF) << 8) | ((pkmHeader->width & 0xFF00) >> 8);
4168             pkmHeader->height = ((pkmHeader->height & 0x00FF) << 8) | ((pkmHeader->height & 0xFF00) >> 8);
4169
4170             TRACELOGD("IMAGE: PKM file data info:");
4171             TRACELOGD("    > Image width:  %i", pkmHeader->width);
4172             TRACELOGD("    > Image height: %i", pkmHeader->height);
4173             TRACELOGD("    > Image format: %i", pkmHeader->format);
4174
4175             image.width = pkmHeader->width;
4176             image.height = pkmHeader->height;
4177             image.mipmaps = 1;
4178
4179             int bpp = 4;
4180             if (pkmHeader->format == 3) bpp = 8;
4181
4182             int dataSize = image.width*image.height*bpp/8;  // Total data size in bytes
4183
4184             image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
4185
4186             memcpy(image.data, fileDataPtr, dataSize);
4187
4188             if (pkmHeader->format == 0) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
4189             else if (pkmHeader->format == 1) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
4190             else if (pkmHeader->format == 3) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
4191         }
4192     }
4193
4194     return image;
4195 }
4196 #endif
4197
4198 #if defined(SUPPORT_FILEFORMAT_KTX)
4199 // Load KTX compressed image data (ETC1/ETC2 compression)
4200 static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize)
4201 {
4202     unsigned char *fileDataPtr = (unsigned char *)fileData;
4203
4204     // Required extensions:
4205     // GL_OES_compressed_ETC1_RGB8_texture  (ETC1)
4206     // GL_ARB_ES3_compatibility  (ETC2/EAC)
4207
4208     // Supported tokens (defined by extensions)
4209     // GL_ETC1_RGB8_OES                 0x8D64
4210     // GL_COMPRESSED_RGB8_ETC2          0x9274
4211     // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
4212
4213     // KTX file Header (64 bytes)
4214     // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
4215     // v2.0 - http://github.khronos.org/KTX-Specification/
4216
4217     // TODO: Support KTX 2.2 specs!
4218
4219     typedef struct {
4220         char id[12];                        // Identifier: "«KTX 11»\r\n\x1A\n"
4221         unsigned int endianness;            // Little endian: 0x01 0x02 0x03 0x04
4222         unsigned int glType;                // For compressed textures, glType must equal 0
4223         unsigned int glTypeSize;            // For compressed texture data, usually 1
4224         unsigned int glFormat;              // For compressed textures is 0
4225         unsigned int glInternalFormat;      // Compressed internal format
4226         unsigned int glBaseInternalFormat;  // Same as glFormat (RGB, RGBA, ALPHA...)
4227         unsigned int width;                 // Texture image width in pixels
4228         unsigned int height;                // Texture image height in pixels
4229         unsigned int depth;                 // For 2D textures is 0
4230         unsigned int elements;              // Number of array elements, usually 0
4231         unsigned int faces;                 // Cubemap faces, for no-cubemap = 1
4232         unsigned int mipmapLevels;          // Non-mipmapped textures = 1
4233         unsigned int keyValueDataSize;      // Used to encode any arbitrary data...
4234     } KTXHeader;
4235
4236     // NOTE: Before start of every mipmap data block, we have: unsigned int dataSize
4237
4238     Image image = { 0 };
4239
4240     if (fileDataPtr != NULL)
4241     {
4242         KTXHeader *ktxHeader = (KTXHeader *)fileDataPtr;
4243
4244         if ((ktxHeader->id[1] != 'K') || (ktxHeader->id[2] != 'T') || (ktxHeader->id[3] != 'X') ||
4245             (ktxHeader->id[4] != ' ') || (ktxHeader->id[5] != '1') || (ktxHeader->id[6] != '1'))
4246         {
4247             TRACELOG(LOG_WARNING, "IMAGE: KTX file data not valid");
4248         }
4249         else
4250         {
4251             fileDataPtr += sizeof(KTXHeader);           // Move file data pointer
4252
4253             image.width = ktxHeader->width;
4254             image.height = ktxHeader->height;
4255             image.mipmaps = ktxHeader->mipmapLevels;
4256
4257             TRACELOGD("IMAGE: KTX file data info:");
4258             TRACELOGD("    > Image width:  %i", ktxHeader->width);
4259             TRACELOGD("    > Image height: %i", ktxHeader->height);
4260             TRACELOGD("    > Image format: 0x%x", ktxHeader->glInternalFormat);
4261
4262             fileDataPtr += ktxHeader->keyValueDataSize; // Skip value data size
4263
4264             int dataSize = ((int *)fileDataPtr)[0];
4265             fileDataPtr += sizeof(int);
4266
4267             image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
4268
4269             memcpy(image.data, fileDataPtr, dataSize);
4270
4271             if (ktxHeader->glInternalFormat == 0x8D64) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
4272             else if (ktxHeader->glInternalFormat == 0x9274) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
4273             else if (ktxHeader->glInternalFormat == 0x9278) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
4274         }
4275     }
4276
4277     return image;
4278 }
4279
4280 // Save image data as KTX file
4281 // NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
4282 static int SaveKTX(Image image, const char *fileName)
4283 {
4284     // KTX file Header (64 bytes)
4285     // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
4286     // v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation
4287     typedef struct {
4288         char id[12];                        // Identifier: "«KTX 11»\r\n\x1A\n"             // KTX 2.0: "«KTX 22»\r\n\x1A\n"
4289         unsigned int endianness;            // Little endian: 0x01 0x02 0x03 0x04
4290         unsigned int glType;                // For compressed textures, glType must equal 0
4291         unsigned int glTypeSize;            // For compressed texture data, usually 1
4292         unsigned int glFormat;              // For compressed textures is 0
4293         unsigned int glInternalFormat;      // Compressed internal format
4294         unsigned int glBaseInternalFormat;  // Same as glFormat (RGB, RGBA, ALPHA...)       // KTX 2.0: UInt32 vkFormat
4295         unsigned int width;                 // Texture image width in pixels
4296         unsigned int height;                // Texture image height in pixels
4297         unsigned int depth;                 // For 2D textures is 0
4298         unsigned int elements;              // Number of array elements, usually 0
4299         unsigned int faces;                 // Cubemap faces, for no-cubemap = 1
4300         unsigned int mipmapLevels;          // Non-mipmapped textures = 1
4301         unsigned int keyValueDataSize;      // Used to encode any arbitrary data...         // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0
4302                                                                                             // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)...
4303         // KTX 2.0 defines additional header elements...
4304     } KTXHeader;
4305
4306     // Calculate file dataSize required
4307     int dataSize = sizeof(KTXHeader);
4308
4309     for (int i = 0, width = image.width, height = image.height; i < image.mipmaps; i++)
4310     {
4311         dataSize += GetPixelDataSize(width, height, image.format);
4312         width /= 2; height /= 2;
4313     }
4314
4315     unsigned char *fileData = RL_CALLOC(dataSize, 1);
4316     unsigned char *fileDataPtr = fileData;
4317
4318     KTXHeader ktxHeader = { 0 };
4319
4320     // KTX identifier (v1.1)
4321     //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
4322     //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
4323
4324     const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
4325
4326     // Get the image header
4327     memcpy(ktxHeader.id, ktxIdentifier, 12);  // KTX 1.1 signature
4328     ktxHeader.endianness = 0;
4329     ktxHeader.glType = 0;                     // Obtained from image.format
4330     ktxHeader.glTypeSize = 1;
4331     ktxHeader.glFormat = 0;                   // Obtained from image.format
4332     ktxHeader.glInternalFormat = 0;           // Obtained from image.format
4333     ktxHeader.glBaseInternalFormat = 0;
4334     ktxHeader.width = image.width;
4335     ktxHeader.height = image.height;
4336     ktxHeader.depth = 0;
4337     ktxHeader.elements = 0;
4338     ktxHeader.faces = 1;
4339     ktxHeader.mipmapLevels = image.mipmaps;   // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
4340     ktxHeader.keyValueDataSize = 0;           // No extra data after the header
4341
4342     rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType);   // rlgl module function
4343     ktxHeader.glBaseInternalFormat = ktxHeader.glFormat;    // KTX 1.1 only
4344
4345     // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
4346
4347     if (ktxHeader.glFormat == -1) TRACELOG(LOG_WARNING, "IMAGE: GL format not supported for KTX export (%i)", ktxHeader.glFormat);
4348     else
4349     {
4350         memcpy(fileDataPtr, &ktxHeader, sizeof(KTXHeader));
4351         fileDataPtr += sizeof(KTXHeader);
4352
4353         int width = image.width;
4354         int height = image.height;
4355         int dataOffset = 0;
4356
4357         // Save all mipmaps data
4358         for (int i = 0; i < image.mipmaps; i++)
4359         {
4360             unsigned int dataSize = GetPixelDataSize(width, height, image.format);
4361
4362             memcpy(fileDataPtr, &dataSize, sizeof(unsigned int));
4363             memcpy(fileDataPtr + 4, (unsigned char *)image.data + dataOffset, dataSize);
4364
4365             width /= 2;
4366             height /= 2;
4367             dataOffset += dataSize;
4368             fileDataPtr += (4 + dataSize);
4369         }
4370     }
4371
4372     int success = SaveFileData(fileName, fileData, dataSize);
4373
4374     RL_FREE(fileData);    // Free file data buffer
4375
4376     // If all data has been written correctly to file, success = 1
4377     return success;
4378 }
4379 #endif
4380
4381 #if defined(SUPPORT_FILEFORMAT_PVR)
4382 // Loading PVR image data (uncompressed or PVRT compression)
4383 // NOTE: PVR v2 not supported, use PVR v3 instead
4384 static Image LoadPVR(const unsigned char *fileData, unsigned int fileSize)
4385 {
4386     unsigned char *fileDataPtr = (unsigned char *)fileData;
4387
4388     // Required extension:
4389     // GL_IMG_texture_compression_pvrtc
4390
4391     // Supported tokens (defined by extensions)
4392     // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG       0x8C00
4393     // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG      0x8C02
4394
4395 #if 0   // Not used...
4396     // PVR file v2 Header (52 bytes)
4397     typedef struct {
4398         unsigned int headerLength;
4399         unsigned int height;
4400         unsigned int width;
4401         unsigned int numMipmaps;
4402         unsigned int flags;
4403         unsigned int dataLength;
4404         unsigned int bpp;
4405         unsigned int bitmaskRed;
4406         unsigned int bitmaskGreen;
4407         unsigned int bitmaskBlue;
4408         unsigned int bitmaskAlpha;
4409         unsigned int pvrTag;
4410         unsigned int numSurfs;
4411     } PVRHeaderV2;
4412 #endif
4413
4414     // PVR file v3 Header (52 bytes)
4415     // NOTE: After it could be metadata (15 bytes?)
4416     typedef struct {
4417         char id[4];
4418         unsigned int flags;
4419         unsigned char channels[4];      // pixelFormat high part
4420         unsigned char channelDepth[4];  // pixelFormat low part
4421         unsigned int colourSpace;
4422         unsigned int channelType;
4423         unsigned int height;
4424         unsigned int width;
4425         unsigned int depth;
4426         unsigned int numSurfaces;
4427         unsigned int numFaces;
4428         unsigned int numMipmaps;
4429         unsigned int metaDataSize;
4430     } PVRHeaderV3;
4431
4432 #if 0   // Not used...
4433     // Metadata (usually 15 bytes)
4434     typedef struct {
4435         unsigned int devFOURCC;
4436         unsigned int key;
4437         unsigned int dataSize;      // Not used?
4438         unsigned char *data;        // Not used?
4439     } PVRMetadata;
4440 #endif
4441
4442     Image image = { 0 };
4443
4444     if (fileDataPtr != NULL)
4445     {
4446         // Check PVR image version
4447         unsigned char pvrVersion = fileDataPtr[0];
4448
4449         // Load different PVR data formats
4450         if (pvrVersion == 0x50)
4451         {
4452             PVRHeaderV3 *pvrHeader = (PVRHeaderV3 *)fileDataPtr;
4453
4454             if ((pvrHeader->id[0] != 'P') || (pvrHeader->id[1] != 'V') || (pvrHeader->id[2] != 'R') || (pvrHeader->id[3] != 3))
4455             {
4456                 TRACELOG(LOG_WARNING, "IMAGE: PVR file data not valid");
4457             }
4458             else
4459             {
4460                 fileDataPtr += sizeof(PVRHeaderV3);   // Skip header
4461
4462                 image.width = pvrHeader->width;
4463                 image.height = pvrHeader->height;
4464                 image.mipmaps = pvrHeader->numMipmaps;
4465
4466                 // Check data format
4467                 if (((pvrHeader->channels[0] == 'l') && (pvrHeader->channels[1] == 0)) && (pvrHeader->channelDepth[0] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
4468                 else if (((pvrHeader->channels[0] == 'l') && (pvrHeader->channels[1] == 'a')) && ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8))) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
4469                 else if ((pvrHeader->channels[0] == 'r') && (pvrHeader->channels[1] == 'g') && (pvrHeader->channels[2] == 'b'))
4470                 {
4471                     if (pvrHeader->channels[3] == 'a')
4472                     {
4473                         if ((pvrHeader->channelDepth[0] == 5) && (pvrHeader->channelDepth[1] == 5) && (pvrHeader->channelDepth[2] == 5) && (pvrHeader->channelDepth[3] == 1)) image.format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
4474                         else if ((pvrHeader->channelDepth[0] == 4) && (pvrHeader->channelDepth[1] == 4) && (pvrHeader->channelDepth[2] == 4) && (pvrHeader->channelDepth[3] == 4)) image.format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
4475                         else if ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8) && (pvrHeader->channelDepth[2] == 8) && (pvrHeader->channelDepth[3] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
4476                     }
4477                     else if (pvrHeader->channels[3] == 0)
4478                     {
4479                         if ((pvrHeader->channelDepth[0] == 5) && (pvrHeader->channelDepth[1] == 6) && (pvrHeader->channelDepth[2] == 5)) image.format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
4480                         else if ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8) && (pvrHeader->channelDepth[2] == 8)) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
4481                     }
4482                 }
4483                 else if (pvrHeader->channels[0] == 2) image.format = PIXELFORMAT_COMPRESSED_PVRT_RGB;
4484                 else if (pvrHeader->channels[0] == 3) image.format = PIXELFORMAT_COMPRESSED_PVRT_RGBA;
4485
4486                 fileDataPtr += pvrHeader->metaDataSize;    // Skip meta data header
4487
4488                 // Calculate data size (depends on format)
4489                 int bpp = 0;
4490                 switch (image.format)
4491                 {
4492                     case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
4493                     case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
4494                     case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
4495                     case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
4496                     case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
4497                     case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
4498                     case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
4499                     case PIXELFORMAT_COMPRESSED_PVRT_RGB:
4500                     case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
4501                     default: break;
4502                 }
4503
4504                 int dataSize = image.width*image.height*bpp/8;  // Total data size in bytes
4505                 image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
4506
4507                 memcpy(image.data, fileDataPtr, dataSize);
4508             }
4509         }
4510         else if (pvrVersion == 52) TRACELOG(LOG_INFO, "IMAGE: PVRv2 format not supported, update your files to PVRv3");
4511     }
4512
4513     return image;
4514 }
4515 #endif
4516
4517 #if defined(SUPPORT_FILEFORMAT_ASTC)
4518 // Load ASTC compressed image data (ASTC compression)
4519 static Image LoadASTC(const unsigned char *fileData, unsigned int fileSize)
4520 {
4521     unsigned char *fileDataPtr = (unsigned char *)fileData;
4522
4523     // Required extensions:
4524     // GL_KHR_texture_compression_astc_hdr
4525     // GL_KHR_texture_compression_astc_ldr
4526
4527     // Supported tokens (defined by extensions)
4528     // GL_COMPRESSED_RGBA_ASTC_4x4_KHR      0x93b0
4529     // GL_COMPRESSED_RGBA_ASTC_8x8_KHR      0x93b7
4530
4531     // ASTC file Header (16 bytes)
4532     typedef struct {
4533         unsigned char id[4];        // Signature: 0x13 0xAB 0xA1 0x5C
4534         unsigned char blockX;       // Block X dimensions
4535         unsigned char blockY;       // Block Y dimensions
4536         unsigned char blockZ;       // Block Z dimensions (1 for 2D images)
4537         unsigned char width[3];     // Image width in pixels (24bit value)
4538         unsigned char height[3];    // Image height in pixels (24bit value)
4539         unsigned char length[3];    // Image Z-size (1 for 2D images)
4540     } ASTCHeader;
4541
4542     Image image = { 0 };
4543
4544     if (fileDataPtr != NULL)
4545     {
4546         ASTCHeader *astcHeader = (ASTCHeader *)fileDataPtr;
4547
4548         if ((astcHeader->id[3] != 0x5c) || (astcHeader->id[2] != 0xa1) || (astcHeader->id[1] != 0xab) || (astcHeader->id[0] != 0x13))
4549         {
4550             TRACELOG(LOG_WARNING, "IMAGE: ASTC file data not valid");
4551         }
4552         else
4553         {
4554             fileDataPtr += sizeof(ASTCHeader);   // Skip header
4555
4556             // NOTE: Assuming Little Endian (could it be wrong?)
4557             image.width = 0x00000000 | ((int)astcHeader->width[2] << 16) | ((int)astcHeader->width[1] << 8) | ((int)astcHeader->width[0]);
4558             image.height = 0x00000000 | ((int)astcHeader->height[2] << 16) | ((int)astcHeader->height[1] << 8) | ((int)astcHeader->height[0]);
4559
4560             TRACELOGD("IMAGE: ASTC file data info:");
4561             TRACELOGD("    > Image width:  %i", image.width);
4562             TRACELOGD("    > Image height: %i", image.height);
4563             TRACELOGD("    > Image blocks: %ix%i", astcHeader->blockX, astcHeader->blockY);
4564
4565             image.mipmaps = 1;      // NOTE: ASTC format only contains one mipmap level
4566
4567             // NOTE: Each block is always stored in 128bit so we can calculate the bpp
4568             int bpp = 128/(astcHeader->blockX*astcHeader->blockY);
4569
4570             // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
4571             if ((bpp == 8) || (bpp == 2))
4572             {
4573                 int dataSize = image.width*image.height*bpp/8;  // Data size in bytes
4574
4575                 image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
4576
4577                 memcpy(image.data, fileDataPtr, dataSize);
4578
4579                 if (bpp == 8) image.format = PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA;
4580                 else if (bpp == 2) image.format = PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA;
4581             }
4582             else TRACELOG(LOG_WARNING, "IMAGE: ASTC block size configuration not supported");
4583         }
4584     }
4585
4586     return image;
4587 }
4588 #endif