summaryrefslogtreecommitdiffhomepage
path: root/src/textures.c
diff options
context:
space:
mode:
authorvictorfisac <[email protected]>2017-03-06 09:40:04 +0100
committervictorfisac <[email protected]>2017-03-06 09:40:04 +0100
commit9261c3b8dc03d093bff5246a18ad9310ae8eaeb3 (patch)
treeaf87165723ac563ee1a7e1c605c7a4df821d74ea /src/textures.c
parente8630c78d069a1cba50b1a78108663ebc19e5b9b (diff)
parentb734802743f2089c8d649b27aea48ab71fa653b3 (diff)
downloadraylib-9261c3b8dc03d093bff5246a18ad9310ae8eaeb3.tar.gz
raylib-9261c3b8dc03d093bff5246a18ad9310ae8eaeb3.zip
Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
Diffstat (limited to 'src/textures.c')
-rw-r--r--src/textures.c782
1 files changed, 358 insertions, 424 deletions
diff --git a/src/textures.c b/src/textures.c
index af59d035..7db3bf56 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -1,16 +1,35 @@
/**********************************************************************************************
*
-* raylib.textures
+* raylib.textures - Basic functions to load and draw Textures (2d)
*
-* Basic functions to load and draw Textures (2d)
+* CONFIGURATION:
*
-* External libs:
+* #define SUPPORT_STB_IMAGE / INCLUDE_STB_IMAGE
+*
+* #define SUPPORT_FILEFORMAT_BMP / SUPPORT_LOAD_BMP
+* #define SUPPORT_FILEFORMAT_PNG / SUPPORT_LOAD_PNG
+* #define SUPPORT_FILEFORMAT_TGA
+* #define SUPPORT_FILEFORMAT_JPG / ENABLE_LOAD_JPG
+* #define SUPPORT_FILEFORMAT_GIF
+* #define SUPPORT_FILEFORMAT_HDR
+* #define SUPPORT_FILEFORMAT_DDS / ENABLE_LOAD_DDS
+* #define SUPPORT_FILEFORMAT_PKM
+* #define SUPPORT_FILEFORMAT_KTX
+* #define SUPPORT_FILEFORMAT_PVR
+* #define SUPPORT_FILEFORMAT_ASTC
+* Selected desired fileformats to be supported for loading. Some of those formats are
+* supported by default, to remove support, just comment unrequired #define in this module
+*
+* #define SUPPORT_IMAGE_RESIZE / INCLUDE_STB_IMAGE_RESIZE
+* #define SUPPORT_IMAGE_MANIPULATION
+*
+* DEPENDENCIES:
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
* NOTE: stb_image has been slightly modified to support Android platform.
* stb_image_resize - Multiple image resize algorythms
*
-* Module Configuration Flags:
-* ...
+*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -37,11 +56,10 @@
#include <string.h> // Required for: strcmp(), strrchr(), strncmp()
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
- // Required: rlglLoadTexture() rlDeleteTextures(),
- // rlglGenerateMipmaps(), some funcs for DrawTexturePro()
+ // Required for: rlglLoadTexture() rlDeleteTextures(),
+ // rlglGenerateMipmaps(), some funcs for DrawTexturePro()
-#include "utils.h" // rRES data decompression utility function
- // NOTE: Includes Android fopen function map
+#include "utils.h" // Required for: fopen() Android mapping, TraceLog()
// Support only desired texture formats, by default: JPEG, PNG, BMP, TGA
//#define STBI_NO_JPEG // Image format .jpg and .jpeg
@@ -94,7 +112,7 @@ static Image LoadASTC(const char *fileName); // Load ASTC file
// Module Functions Definition
//----------------------------------------------------------------------------------
-// Load an image into CPU memory (RAM)
+// Load image from file into CPU memory (RAM)
Image LoadImage(const char *fileName)
{
Image image;
@@ -142,17 +160,25 @@ Image LoadImage(const char *fileName)
else if (strcmp(GetExtension(fileName),"ktx") == 0) image = LoadKTX(fileName);
else if (strcmp(GetExtension(fileName),"pvr") == 0) image = LoadPVR(fileName);
else if (strcmp(GetExtension(fileName),"astc") == 0) image = LoadASTC(fileName);
-
- if (image.data != NULL)
+ else if (strcmp(GetExtension(fileName),"rres") == 0)
{
- TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
+ RRES rres = LoadResource(fileName, 0);
+
+ // NOTE: Parameters for RRES_TYPE_IMAGE are: width, height, format, mipmaps
+
+ if (rres[0].type == RRES_TYPE_IMAGE) image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3);
+ else TraceLog(WARNING, "[%s] Resource file does not contain image data", fileName);
+
+ UnloadResource(rres);
}
- else TraceLog(WARNING, "[%s] Image could not be loaded, file not recognized", fileName);
+
+ if (image.data != NULL) TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
+ else TraceLog(WARNING, "[%s] Image could not be loaded", fileName);
return image;
}
-// Load image data from Color array data (RGBA - 32bit)
+// Load image from Color array data (RGBA - 32bit)
// NOTE: Creates a copy of pixels data array
Image LoadImageEx(Color *pixels, int width, int height)
{
@@ -179,7 +205,24 @@ Image LoadImageEx(Color *pixels, int width, int height)
return image;
}
-// Load an image from RAW file
+// Load image from raw data with parameters
+// NOTE: This functions makes a copy of provided data
+Image LoadImagePro(void *data, int width, int height, int format)
+{
+ Image srcImage = { 0 };
+
+ srcImage.data = data;
+ srcImage.width = width;
+ srcImage.height = height;
+ srcImage.mipmaps = 1;
+ srcImage.format = format;
+
+ Image dstImage = ImageCopy(srcImage);
+
+ return dstImage;
+}
+
+// Load an image from RAW file data
Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize)
{
Image image;
@@ -214,134 +257,32 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
default: TraceLog(WARNING, "Image format not suported"); break;
}
- fread(image.data, size, 1, rawFile);
-
- // TODO: Check if data have been read
+ // NOTE: fread() returns num read elements instead of bytes,
+ // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
+ int bytes = fread(image.data, 1, size, rawFile);
- image.width = width;
- image.height = height;
- image.mipmaps = 0;
- image.format = format;
-
- fclose(rawFile);
- }
-
- return image;
-}
-
-// Load an image from rRES file (raylib Resource)
-// TODO: Review function to support multiple color modes
-Image LoadImageFromRES(const char *rresName, int resId)
-{
- Image image = { 0 };
- bool found = false;
-
- char id[4]; // rRES file identifier
- unsigned char version; // rRES file version and subversion
- char useless; // rRES header reserved data
- short numRes;
-
- ResInfoHeader infoHeader;
-
- FILE *rresFile = fopen(rresName, "rb");
-
- if (rresFile == NULL)
- {
- TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
- }
- else
- {
- // Read rres file (basic file check - id)
- fread(&id[0], sizeof(char), 1, rresFile);
- fread(&id[1], sizeof(char), 1, rresFile);
- fread(&id[2], sizeof(char), 1, rresFile);
- fread(&id[3], sizeof(char), 1, rresFile);
- fread(&version, sizeof(char), 1, rresFile);
- fread(&useless, sizeof(char), 1, rresFile);
-
- if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
+ // Check if data has been read successfully
+ if (bytes < size)
{
- TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
+ TraceLog(WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName);
+
+ if (image.data != NULL) free(image.data);
}
else
{
- // Read number of resources embedded
- fread(&numRes, sizeof(short), 1, rresFile);
-
- for (int i = 0; i < numRes; i++)
- {
- fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
-
- if (infoHeader.id == resId)
- {
- found = true;
-
- // Check data is of valid IMAGE type
- if (infoHeader.type == 0) // IMAGE data type
- {
- // TODO: Check data compression type
- // NOTE: We suppose compression type 2 (DEFLATE - default)
-
- short imgWidth, imgHeight;
- char colorFormat, mipmaps;
-
- fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
- fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
- fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
- fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
-
- image.width = (int)imgWidth;
- image.height = (int)imgHeight;
-
- unsigned char *compData = malloc(infoHeader.size);
-
- fread(compData, infoHeader.size, 1, rresFile);
-
- unsigned char *imgData = DecompressData(compData, infoHeader.size, infoHeader.srcSize);
-
- // TODO: Review color mode
- //image.data = (unsigned char *)malloc(sizeof(unsigned char)*imgWidth*imgHeight*4);
- image.data = imgData;
-
- //free(imgData);
-
- free(compData);
-
- TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height);
- }
- else
- {
- TraceLog(WARNING, "[%s] Required resource do not seem to be a valid IMAGE resource", rresName);
- }
- }
- else
- {
- // Depending on type, skip the right amount of parameters
- switch (infoHeader.type)
- {
- case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
- case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
- case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
- case 3: break; // TEXT: No parameters
- case 4: break; // RAW: No parameters
- default: break;
- }
-
- // Jump DATA to read next infoHeader
- fseek(rresFile, infoHeader.size, SEEK_CUR);
- }
- }
+ image.width = width;
+ image.height = height;
+ image.mipmaps = 0;
+ image.format = format;
}
- fclose(rresFile);
+ fclose(rawFile);
}
- if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
-
return image;
}
-// Load an image as texture into GPU memory
+// Load texture from file into GPU memory (VRAM)
Texture2D LoadTexture(const char *fileName)
{
Texture2D texture;
@@ -362,33 +303,6 @@ Texture2D LoadTexture(const char *fileName)
return texture;
}
-// Load a texture from raw data into GPU memory
-Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat)
-{
- Texture2D texture;
-
- texture.width = width;
- texture.height = height;
- texture.mipmaps = 1;
- texture.format = textureFormat;
-
- texture.id = rlglLoadTexture(data, width, height, textureFormat, 1);
-
- return texture;
-}
-
-// Load an image as texture from rRES file (raylib Resource)
-Texture2D LoadTextureFromRES(const char *rresName, int resId)
-{
- Texture2D texture;
-
- Image image = LoadImageFromRES(rresName, resId);
- texture = LoadTextureFromImage(image);
- UnloadImage(image);
-
- return texture;
-}
-
// Load a texture from image data
// NOTE: image is not unloaded, it must be done manually
Texture2D LoadTextureFromImage(Image image)
@@ -412,7 +326,7 @@ Texture2D LoadTextureFromImage(Image image)
return texture;
}
-// Load a texture to be used for rendering
+// Load texture for rendering (framebuffer)
RenderTexture2D LoadRenderTexture(int width, int height)
{
RenderTexture2D target = rlglLoadRenderTexture(width, height);
@@ -429,7 +343,7 @@ void UnloadImage(Image image)
//TraceLog(INFO, "Unloaded image data");
}
-// Unload texture from GPU memory
+// Unload texture from GPU memory (VRAM)
void UnloadTexture(Texture2D texture)
{
if (texture.id != 0)
@@ -440,102 +354,12 @@ void UnloadTexture(Texture2D texture)
}
}
-// Unload render texture from GPU memory
+// Unload render texture from GPU memory (VRAM)
void UnloadRenderTexture(RenderTexture2D target)
{
if (target.id != 0) rlDeleteRenderTextures(target);
}
-// Set texture scaling filter mode
-void SetTextureFilter(Texture2D texture, int filterMode)
-{
- switch (filterMode)
- {
- case FILTER_POINT:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST);
-
- // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
- }
- else
- {
- // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
- }
- } break;
- case FILTER_BILINEAR:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
- // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- else
- {
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- } break;
- case FILTER_TRILINEAR:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- else
- {
- TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- } break;
- case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break;
- case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break;
- case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break;
- default: break;
- }
-}
-
-// Set texture wrapping mode
-void SetTextureWrap(Texture2D texture, int wrapMode)
-{
- switch (wrapMode)
- {
- case WRAP_REPEAT:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT);
- } break;
- case WRAP_CLAMP:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP);
- } break;
- case WRAP_MIRROR:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR);
- } break;
- default: break;
- }
-}
-
// Get pixel data from image in the form of Color struct array
Color *GetImageData(Image image)
{
@@ -654,6 +478,13 @@ Image GetTextureData(Texture2D texture)
return image;
}
+// Update GPU texture with new data
+// NOTE: pixels data must match texture.format
+void UpdateTexture(Texture2D texture, const void *pixels)
+{
+ rlglUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels);
+}
+
// Convert image data to desired format
void ImageFormat(Image *image, int newFormat)
{
@@ -805,12 +636,12 @@ void ImageAlphaMask(Image *image, Image alphaMask)
// Force mask to be Grayscale
Image mask = ImageCopy(alphaMask);
if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE);
-
+
// In case image is only grayscale, we just add alpha channel
if (image->format == UNCOMPRESSED_GRAYSCALE)
{
ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA);
-
+
// Apply alpha mask to alpha channel
for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
{
@@ -872,11 +703,11 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
- Color oldpixel = WHITE;
- Color newpixel = WHITE;
+ Color oldPixel = WHITE;
+ Color newPixel = WHITE;
- int error_r, error_g, error_b;
- unsigned short pixel_r, pixel_g, pixel_b, pixel_a; // Used for 16bit pixel composition
+ int rError, gError, bError;
+ unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -884,57 +715,57 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
for (int x = 0; x < image->width; x++)
{
- oldpixel = pixels[y*image->width + x];
+ oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
- newpixel.r = oldpixel.r>>(8 - rBpp); // R bits
- newpixel.g = oldpixel.g>>(8 - gBpp); // G bits
- newpixel.b = oldpixel.b>>(8 - bBpp); // B bits
- newpixel.a = oldpixel.a>>(8 - aBpp); // A bits (not used on dithering)
+ newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
+ newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
+ newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
+ newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
- error_r = (int)oldpixel.r - (int)(newpixel.r<<(8 - rBpp));
- error_g = (int)oldpixel.g - (int)(newpixel.g<<(8 - gBpp));
- error_b = (int)oldpixel.b - (int)(newpixel.b<<(8 - bBpp));
+ rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
+ gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
+ bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
- pixels[y*image->width + x] = newpixel;
+ pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
- pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)error_r*7.0f/16), 0xff);
- pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)error_g*7.0f/16), 0xff);
- pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)error_b*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
- pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)error_r*3.0f/16), 0xff);
- pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)error_g*3.0f/16), 0xff);
- pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)error_b*3.0f/16), 0xff);
+ 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);
+ 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);
+ 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);
}
if (y < (image->height - 1))
{
- pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)error_r*5.0f/16), 0xff);
- pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)error_g*5.0f/16), 0xff);
- pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)error_b*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
- pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)error_r*1.0f/16), 0xff);
- pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)error_g*1.0f/16), 0xff);
- pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)error_b*1.0f/16), 0xff);
+ 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);
+ 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);
+ 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);
}
- pixel_r = (unsigned short)newpixel.r;
- pixel_g = (unsigned short)newpixel.g;
- pixel_b = (unsigned short)newpixel.b;
- pixel_a = (unsigned short)newpixel.a;
+ rPixel = (unsigned short)newPixel.r;
+ gPixel = (unsigned short)newPixel.g;
+ bPixel = (unsigned short)newPixel.b;
+ aPixel = (unsigned short)newPixel.a;
- ((unsigned short *)image->data)[y*image->width + x] = (pixel_r<<(gBpp + bBpp + aBpp)) | (pixel_g<<(bBpp + aBpp)) | (pixel_b<<aBpp) | pixel_a;
+ ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
@@ -948,9 +779,10 @@ void ImageToPOT(Image *image, Color fillColor)
{
Color *pixels = GetImageData(*image); // Get pixels data
- // Just add the required amount of pixels at the right and bottom sides of image...
- int potWidth = GetNextPOT(image->width);
- int potHeight = GetNextPOT(image->height);
+ // Calculate next power-of-two values
+ // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
+ int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
+ int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
// Check if POT texture generation is required (if texture is not already POT)
if ((potWidth != image->width) || (potHeight != image->height))
@@ -991,24 +823,37 @@ Image ImageCopy(Image image)
{
Image newImage;
- int size = image.width*image.height;
+ int byteSize = image.width*image.height;
switch (image.format)
{
- case UNCOMPRESSED_GRAYSCALE: newImage.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha)
- case UNCOMPRESSED_GRAY_ALPHA: newImage.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels)
- case UNCOMPRESSED_R5G6B5: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp
- case UNCOMPRESSED_R8G8B8: newImage.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp
- case UNCOMPRESSED_R5G5B5A1: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (1 bit alpha)
- case UNCOMPRESSED_R4G4B4A4: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (4 bit alpha)
- case UNCOMPRESSED_R8G8B8A8: newImage.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp
- default: TraceLog(WARNING, "Image format not suported for copy"); break;
+ case UNCOMPRESSED_GRAYSCALE: break; // 8 bpp (1 byte)
+ case UNCOMPRESSED_GRAY_ALPHA: // 16 bpp
+ case UNCOMPRESSED_R5G6B5: // 16 bpp
+ case UNCOMPRESSED_R5G5B5A1: // 16 bpp
+ case UNCOMPRESSED_R4G4B4A4: byteSize *= 2; break; // 16 bpp (2 bytes)
+ case UNCOMPRESSED_R8G8B8: byteSize *= 3; break; // 24 bpp (3 bytes)
+ case UNCOMPRESSED_R8G8B8A8: byteSize *= 4; break; // 32 bpp (4 bytes)
+ case COMPRESSED_DXT3_RGBA:
+ case COMPRESSED_DXT5_RGBA:
+ case COMPRESSED_ETC2_EAC_RGBA:
+ case COMPRESSED_ASTC_4x4_RGBA: break; // 8 bpp (1 byte)
+ case COMPRESSED_DXT1_RGB:
+ case COMPRESSED_DXT1_RGBA:
+ case COMPRESSED_ETC1_RGB:
+ case COMPRESSED_ETC2_RGB:
+ case COMPRESSED_PVRT_RGB:
+ case COMPRESSED_PVRT_RGBA: byteSize /= 2; break; // 4 bpp
+ case COMPRESSED_ASTC_8x8_RGBA: byteSize /= 4; break;// 2 bpp
+ default: TraceLog(WARNING, "Image format not recognized"); break;
}
+ newImage.data = malloc(byteSize);
+
if (newImage.data != NULL)
{
// NOTE: Size must be provided in bytes
- memcpy(newImage.data, image.data, size);
+ memcpy(newImage.data, image.data, byteSize);
newImage.width = image.width;
newImage.height = image.height;
@@ -1100,18 +945,18 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color));
// EDIT: added +1 to account for an early rounding problem
- int x_ratio = (int)((image->width<<16)/newWidth) + 1;
- int y_ratio = (int)((image->height<<16)/newHeight) + 1;
+ int xRatio = (int)((image->width << 16)/newWidth) + 1;
+ int yRatio = (int)((image->height << 16)/newHeight) + 1;
int x2, y2;
- for (int i = 0; i < newHeight; i++)
+ for (int y = 0; y < newHeight; y++)
{
- for (int j = 0; j < newWidth; j++)
+ for (int x = 0; x < newWidth; x++)
{
- x2 = ((j*x_ratio) >> 16);
- y2 = ((i*y_ratio) >> 16);
+ x2 = ((x*xRatio) >> 16);
+ y2 = ((y*yRatio) >> 16);
- output[(i*newWidth) + j] = pixels[(y2*image->width) + x2] ;
+ output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
}
}
@@ -1131,7 +976,7 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
{
bool cropRequired = false;
-
+
// Security checks to avoid size and rectangle issues (out of bounds)
// Check that srcRec is inside src image
if (srcRec.x < 0) srcRec.x = 0;
@@ -1149,15 +994,15 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
TraceLog(WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height);
cropRequired = true;
}
-
+
Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it
ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle
-
+
// Check that dstRec is inside dst image
// TODO: Allow negative position within destination with cropping
if (dstRec.x < 0) dstRec.x = 0;
if (dstRec.y < 0) dstRec.y = 0;
-
+
// Scale source image in case destination rec size is different than source rec size
if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height))
{
@@ -1177,24 +1022,24 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
TraceLog(WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height);
cropRequired = true;
}
-
+
if (cropRequired)
{
// Crop destination rectangle if out of bounds
Rectangle crop = { 0, 0, dstRec.width, dstRec.height };
ImageCrop(&srcCopy, crop);
}
-
+
// Get image data as Color pixels array to work with it
Color *dstPixels = GetImageData(*dst);
Color *srcPixels = GetImageData(srcCopy);
UnloadImage(srcCopy); // Source copy not required any more...
-
+
Color srcCol, dstCol;
// Blit pixels, copy source image into destination
- // TODO: Probably out-of-bounds blitting could be considering here instead of so much cropping...
+ // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping...
for (int j = dstRec.y; j < (dstRec.y + dstRec.height); j++)
{
for (int i = dstRec.x; i < (dstRec.x + dstRec.width); i++)
@@ -1202,13 +1047,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
// Alpha blending implementation
dstCol = dstPixels[j*dst->width + i];
srcCol = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)];
-
+
dstCol.r = ((srcCol.a*(srcCol.r - dstCol.r)) >> 8) + dstCol.r;
dstCol.g = ((srcCol.a*(srcCol.g - dstCol.g)) >> 8) + dstCol.g;
dstCol.b = ((srcCol.a*(srcCol.b - dstCol.b)) >> 8) + dstCol.b;
-
+
dstPixels[j*dst->width + i] = dstCol;
-
+
// TODO: Support other blending options
}
}
@@ -1240,7 +1085,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
int length = strlen(text);
int posX = 0;
- Vector2 imSize = MeasureTextEx(font, text, font.size, spacing);
+ Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing);
// NOTE: GetTextureData() not available in OpenGL ES
Image imFont = GetTextureData(font.texture);
@@ -1256,7 +1101,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
for (int i = 0; i < length; i++)
{
- Rectangle letterRec = font.charRecs[(int)text[i] - 32];
+ Rectangle letterRec = font.chars[(int)text[i] - 32].rec;
for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++)
{
@@ -1516,14 +1361,15 @@ void ImageColorBrightness(Image *image, int brightness)
}
// Generate GPU mipmaps for a texture
-void GenTextureMipmaps(Texture2D texture)
+void GenTextureMipmaps(Texture2D *texture)
{
#if PLATFORM_WEB
- int potWidth = GetNextPOT(texture.width);
- int potHeight = GetNextPOT(texture.height);
+ // Calculate next power-of-two values
+ int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2)));
+ int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2)));
// Check if texture is POT
- if ((potWidth != texture.width) || (potHeight != texture.height))
+ if ((potWidth != texture->width) || (potHeight != texture->height))
{
TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures");
}
@@ -1533,11 +1379,94 @@ void GenTextureMipmaps(Texture2D texture)
#endif
}
-// Update GPU texture with new data
-// NOTE: pixels data must match texture.format
-void UpdateTexture(Texture2D texture, void *pixels)
+// Set texture scaling filter mode
+void SetTextureFilter(Texture2D texture, int filterMode)
{
- rlglUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels);
+ switch (filterMode)
+ {
+ case FILTER_POINT:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST);
+
+ // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+ }
+ else
+ {
+ // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+ }
+ } break;
+ case FILTER_BILINEAR:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
+ // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ else
+ {
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ } break;
+ case FILTER_TRILINEAR:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ else
+ {
+ TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ } break;
+ case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break;
+ case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break;
+ case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break;
+ default: break;
+ }
+}
+
+// Set texture wrapping mode
+void SetTextureWrap(Texture2D texture, int wrapMode)
+{
+ switch (wrapMode)
+ {
+ case WRAP_REPEAT:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT);
+ } break;
+ case WRAP_CLAMP:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP);
+ } break;
+ case WRAP_MIRROR:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR);
+ } break;
+ default: break;
+ }
}
// Draw a Texture2D
@@ -1584,7 +1513,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
rlEnableTexture(texture.id);
rlPushMatrix();
- rlTranslatef(destRec.x, destRec.y, 0);
+ rlTranslatef((float)destRec.x, (float)destRec.y, 0);
rlRotatef(rotation, 0, 0, 1);
rlTranslatef(-origin.x, -origin.y, 0);
@@ -1598,15 +1527,15 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
// Bottom-right corner for texture and quad
rlTexCoord2f((float)sourceRec.x/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height);
- rlVertex2f(0.0f, destRec.height);
+ rlVertex2f(0.0f, (float)destRec.height);
// Top-right corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height);
- rlVertex2f(destRec.width, destRec.height);
+ rlVertex2f((float)destRec.width, (float)destRec.height);
// Top-left corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)sourceRec.y/texture.height);
- rlVertex2f(destRec.width, 0.0f);
+ rlVertex2f((float)destRec.width, 0.0f);
rlEnd();
rlPopMatrix();
@@ -1644,7 +1573,7 @@ static Image LoadDDS(const char *fileName)
unsigned int gBitMask;
unsigned int bBitMask;
unsigned int aBitMask;
- } ddsPixelFormat;
+ } DDSPixelFormat;
// DDS Header (124 bytes)
typedef struct {
@@ -1656,13 +1585,13 @@ static Image LoadDDS(const char *fileName)
unsigned int depth;
unsigned int mipmapCount;
unsigned int reserved1[11];
- ddsPixelFormat ddspf;
+ DDSPixelFormat ddspf;
unsigned int caps;
unsigned int caps2;
unsigned int caps3;
unsigned int caps4;
unsigned int reserved2;
- } ddsHeader;
+ } DDSHeader;
Image image;
@@ -1683,7 +1612,7 @@ static Image LoadDDS(const char *fileName)
// Verify the type of file
char filecode[4];
- fread(filecode, 1, 4, ddsFile);
+ fread(filecode, 4, 1, ddsFile);
if (strncmp(filecode, "DDS ", 4) != 0)
{
@@ -1691,33 +1620,33 @@ static Image LoadDDS(const char *fileName)
}
else
{
- ddsHeader header;
+ DDSHeader ddsHeader;
// Get the image header
- fread(&header, sizeof(ddsHeader), 1, ddsFile);
+ fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
- TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
- TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
- TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
- TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC);
- TraceLog(DEBUG, "[%s] DDS file bit count: 0x%x", fileName, header.ddspf.rgbBitCount);
+ TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(DDSHeader));
+ TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, ddsHeader.ddspf.size);
+ TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
+ TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
+ TraceLog(DEBUG, "[%s] DDS file bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = 1; // Default value, could be changed (header.mipmapCount)
+ image.width = ddsHeader.width;
+ image.height = ddsHeader.height;
+ image.mipmaps = 1; // Default value, could be changed (ddsHeader.mipmapCount)
- if (header.ddspf.rgbBitCount == 16) // 16bit mode, no compressed
+ if (ddsHeader.ddspf.rgbBitCount == 16) // 16bit mode, no compressed
{
- if (header.ddspf.flags == 0x40) // no alpha channel
+ if (ddsHeader.ddspf.flags == 0x40) // no alpha channel
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
image.format = UNCOMPRESSED_R5G6B5;
}
- else if (header.ddspf.flags == 0x41) // with alpha channel
+ else if (ddsHeader.ddspf.flags == 0x41) // with alpha channel
{
- if (header.ddspf.aBitMask == 0x8000) // 1bit alpha
+ if (ddsHeader.ddspf.aBitMask == 0x8000) // 1bit alpha
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
@@ -1734,7 +1663,7 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R5G5B5A1;
}
- else if (header.ddspf.aBitMask == 0xf000) // 4bit alpha
+ else if (ddsHeader.ddspf.aBitMask == 0xf000) // 4bit alpha
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
@@ -1753,7 +1682,7 @@ static Image LoadDDS(const char *fileName)
}
}
}
- if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
+ if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
{
// NOTE: not sure if this case exists...
image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char));
@@ -1761,7 +1690,7 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R8G8B8;
}
- else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
+ else if (ddsHeader.ddspf.flags == 0x41 && ddsHeader.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
{
image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char));
fread(image.data, image.width*image.height*4, 1, ddsFile);
@@ -1780,27 +1709,27 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R8G8B8A8;
}
- else if (((header.ddspf.flags == 0x04) || (header.ddspf.flags == 0x05)) && (header.ddspf.fourCC > 0)) // Compressed
+ else if (((ddsHeader.ddspf.flags == 0x04) || (ddsHeader.ddspf.flags == 0x05)) && (ddsHeader.ddspf.fourCC > 0)) // Compressed
{
- int bufsize;
+ int size; // DDS image data size
// Calculate data size, including all mipmaps
- if (header.mipmapCount > 1) bufsize = header.pitchOrLinearSize*2;
- else bufsize = header.pitchOrLinearSize;
+ if (ddsHeader.mipmapCount > 1) size = ddsHeader.pitchOrLinearSize*2;
+ else size = ddsHeader.pitchOrLinearSize;
- TraceLog(DEBUG, "Pitch or linear size: %i", header.pitchOrLinearSize);
+ TraceLog(DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize);
- image.data = (unsigned char*)malloc(bufsize*sizeof(unsigned char));
+ image.data = (unsigned char*)malloc(size*sizeof(unsigned char));
- fread(image.data, 1, bufsize, ddsFile);
+ fread(image.data, size, 1, ddsFile);
- image.mipmaps = header.mipmapCount;
+ image.mipmaps = ddsHeader.mipmapCount;
- switch (header.ddspf.fourCC)
+ switch (ddsHeader.ddspf.fourCC)
{
case FOURCC_DXT1:
{
- if (header.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
+ if (ddsHeader.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
else image.format = COMPRESSED_DXT1_RGBA;
} break;
case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break;
@@ -1839,7 +1768,7 @@ static Image LoadPKM(const char *fileName)
unsigned short height; // Texture height (big-endian) (origHeight rounded to multiple of 4)
unsigned short origWidth; // Original width (big-endian)
unsigned short origHeight; // Original height (big-endian)
- } pkmHeader;
+ } PKMHeader;
// Formats list
// version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
@@ -1864,42 +1793,42 @@ static Image LoadPKM(const char *fileName)
}
else
{
- pkmHeader header;
+ PKMHeader pkmHeader;
// Get the image header
- fread(&header, sizeof(pkmHeader), 1, pkmFile);
+ fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
- if (strncmp(header.id, "PKM ", 4) != 0)
+ if (strncmp(pkmHeader.id, "PKM ", 4) != 0)
{
TraceLog(WARNING, "[%s] PKM file does not seem to be a valid image", fileName);
}
else
{
// NOTE: format, width and height come as big-endian, data must be swapped to little-endian
- header.format = ((header.format & 0x00FF) << 8) | ((header.format & 0xFF00) >> 8);
- header.width = ((header.width & 0x00FF) << 8) | ((header.width & 0xFF00) >> 8);
- header.height = ((header.height & 0x00FF) << 8) | ((header.height & 0xFF00) >> 8);
+ pkmHeader.format = ((pkmHeader.format & 0x00FF) << 8) | ((pkmHeader.format & 0xFF00) >> 8);
+ pkmHeader.width = ((pkmHeader.width & 0x00FF) << 8) | ((pkmHeader.width & 0xFF00) >> 8);
+ pkmHeader.height = ((pkmHeader.height & 0x00FF) << 8) | ((pkmHeader.height & 0xFF00) >> 8);
- TraceLog(DEBUG, "PKM (ETC) image width: %i", header.width);
- TraceLog(DEBUG, "PKM (ETC) image height: %i", header.height);
- TraceLog(DEBUG, "PKM (ETC) image format: %i", header.format);
+ TraceLog(DEBUG, "PKM (ETC) image width: %i", pkmHeader.width);
+ TraceLog(DEBUG, "PKM (ETC) image height: %i", pkmHeader.height);
+ TraceLog(DEBUG, "PKM (ETC) image format: %i", pkmHeader.format);
- image.width = header.width;
- image.height = header.height;
+ image.width = pkmHeader.width;
+ image.height = pkmHeader.height;
image.mipmaps = 1;
int bpp = 4;
- if (header.format == 3) bpp = 8;
+ if (pkmHeader.format == 3) bpp = 8;
int size = image.width*image.height*bpp/8; // Total data size in bytes
image.data = (unsigned char*)malloc(size*sizeof(unsigned char));
- fread(image.data, 1, size, pkmFile);
+ fread(image.data, size, 1, pkmFile);
- if (header.format == 0) image.format = COMPRESSED_ETC1_RGB;
- else if (header.format == 1) image.format = COMPRESSED_ETC2_RGB;
- else if (header.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA;
+ if (pkmHeader.format == 0) image.format = COMPRESSED_ETC1_RGB;
+ else if (pkmHeader.format == 1) image.format = COMPRESSED_ETC2_RGB;
+ else if (pkmHeader.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA;
}
fclose(pkmFile); // Close file pointer
@@ -1937,7 +1866,7 @@ static Image LoadKTX(const char *fileName)
unsigned int faces; // Cubemap faces, for no-cubemap = 1
unsigned int mipmapLevels; // Non-mipmapped textures = 1
unsigned int keyValueDataSize; // Used to encode any arbitrary data...
- } ktxHeader;
+ } KTXHeader;
// NOTE: Before start of every mipmap data block, we have: unsigned int dataSize
@@ -1956,31 +1885,31 @@ static Image LoadKTX(const char *fileName)
}
else
{
- ktxHeader header;
+ KTXHeader ktxHeader;
// Get the image header
- fread(&header, sizeof(ktxHeader), 1, ktxFile);
+ fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
- if ((header.id[1] != 'K') || (header.id[2] != 'T') || (header.id[3] != 'X') ||
- (header.id[4] != ' ') || (header.id[5] != '1') || (header.id[6] != '1'))
+ if ((ktxHeader.id[1] != 'K') || (ktxHeader.id[2] != 'T') || (ktxHeader.id[3] != 'X') ||
+ (ktxHeader.id[4] != ' ') || (ktxHeader.id[5] != '1') || (ktxHeader.id[6] != '1'))
{
TraceLog(WARNING, "[%s] KTX file does not seem to be a valid file", fileName);
}
else
{
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = header.mipmapLevels;
+ image.width = ktxHeader.width;
+ image.height = ktxHeader.height;
+ image.mipmaps = ktxHeader.mipmapLevels;
- TraceLog(DEBUG, "KTX (ETC) image width: %i", header.width);
- TraceLog(DEBUG, "KTX (ETC) image height: %i", header.height);
- TraceLog(DEBUG, "KTX (ETC) image format: 0x%x", header.glInternalFormat);
+ TraceLog(DEBUG, "KTX (ETC) image width: %i", ktxHeader.width);
+ TraceLog(DEBUG, "KTX (ETC) image height: %i", ktxHeader.height);
+ TraceLog(DEBUG, "KTX (ETC) image format: 0x%x", ktxHeader.glInternalFormat);
unsigned char unused;
- if (header.keyValueDataSize > 0)
+ if (ktxHeader.keyValueDataSize > 0)
{
- for (int i = 0; i < header.keyValueDataSize; i++) fread(&unused, 1, 1, ktxFile);
+ for (int i = 0; i < ktxHeader.keyValueDataSize; i++) fread(&unused, sizeof(unsigned char), 1, ktxFile);
}
int dataSize;
@@ -1988,11 +1917,11 @@ static Image LoadKTX(const char *fileName)
image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char));
- fread(image.data, 1, dataSize, ktxFile);
+ fread(image.data, dataSize, 1, ktxFile);
- if (header.glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB;
- else if (header.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
- else if (header.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA;
+ if (ktxHeader.glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB;
+ else if (ktxHeader.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
+ else if (ktxHeader.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA;
}
fclose(ktxFile); // Close file pointer
@@ -2028,7 +1957,7 @@ static Image LoadPVR(const char *fileName)
unsigned int bitmaskAlpha;
unsigned int pvrTag;
unsigned int numSurfs;
- } pvrHeaderV2;
+ } PVRHeaderV2;
#endif
// PVR file v3 Header (52 bytes)
@@ -2047,7 +1976,7 @@ static Image LoadPVR(const char *fileName)
unsigned int numFaces;
unsigned int numMipmaps;
unsigned int metaDataSize;
- } pvrHeaderV3;
+ } PVRHeaderV3;
#if 0 // Not used...
// Metadata (usually 15 bytes)
@@ -2056,7 +1985,7 @@ static Image LoadPVR(const char *fileName)
unsigned int key;
unsigned int dataSize; // Not used?
unsigned char *data; // Not used?
- } pvrMetadata;
+ } PVRMetadata;
#endif
Image image;
@@ -2083,44 +2012,49 @@ static Image LoadPVR(const char *fileName)
// Load different PVR data formats
if (pvrVersion == 0x50)
{
- pvrHeaderV3 header;
+ PVRHeaderV3 pvrHeader;
// Get PVR image header
- fread(&header, sizeof(pvrHeaderV3), 1, pvrFile);
+ fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
- if ((header.id[0] != 'P') || (header.id[1] != 'V') || (header.id[2] != 'R') || (header.id[3] != 3))
+ if ((pvrHeader.id[0] != 'P') || (pvrHeader.id[1] != 'V') || (pvrHeader.id[2] != 'R') || (pvrHeader.id[3] != 3))
{
TraceLog(WARNING, "[%s] PVR file does not seem to be a valid image", fileName);
}
else
{
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = header.numMipmaps;
+ image.width = pvrHeader.width;
+ image.height = pvrHeader.height;
+ image.mipmaps = pvrHeader.numMipmaps;
// Check data format
- if (((header.channels[0] == 'l') && (header.channels[1] == 0)) && (header.channelDepth[0] == 8)) image.format = UNCOMPRESSED_GRAYSCALE;
- else if (((header.channels[0] == 'l') && (header.channels[1] == 'a')) && ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8))) image.format = UNCOMPRESSED_GRAY_ALPHA;
- else if ((header.channels[0] == 'r') && (header.channels[1] == 'g') && (header.channels[2] == 'b'))
+ if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 0)) && (pvrHeader.channelDepth[0] == 8))
+ image.format = UNCOMPRESSED_GRAYSCALE;
+ else if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8)))
+ image.format = UNCOMPRESSED_GRAY_ALPHA;
+ else if ((pvrHeader.channels[0] == 'r') && (pvrHeader.channels[1] == 'g') && (pvrHeader.channels[2] == 'b'))
{
- if (header.channels[3] == 'a')
+ if (pvrHeader.channels[3] == 'a')
{
- if ((header.channelDepth[0] == 5) && (header.channelDepth[1] == 5) && (header.channelDepth[2] == 5) && (header.channelDepth[3] == 1)) image.format = UNCOMPRESSED_R5G5B5A1;
- else if ((header.channelDepth[0] == 4) && (header.channelDepth[1] == 4) && (header.channelDepth[2] == 4) && (header.channelDepth[3] == 4)) image.format = UNCOMPRESSED_R4G4B4A4;
- else if ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8) && (header.channelDepth[2] == 8) && (header.channelDepth[3] == 8)) image.format = UNCOMPRESSED_R8G8B8A8;
+ if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 5) && (pvrHeader.channelDepth[2] == 5) && (pvrHeader.channelDepth[3] == 1))
+ image.format = UNCOMPRESSED_R5G5B5A1;
+ else if ((pvrHeader.channelDepth[0] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4))
+ image.format = UNCOMPRESSED_R4G4B4A4;
+ else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8) && (pvrHeader.channelDepth[3] == 8))
+ image.format = UNCOMPRESSED_R8G8B8A8;
}
- else if (header.channels[3] == 0)
+ else if (pvrHeader.channels[3] == 0)
{
- if ((header.channelDepth[0] == 5) && (header.channelDepth[1] == 6) && (header.channelDepth[2] == 5)) image.format = UNCOMPRESSED_R5G6B5;
- else if ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8) && (header.channelDepth[2] == 8)) image.format = UNCOMPRESSED_R8G8B8;
+ if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 6) && (pvrHeader.channelDepth[2] == 5)) image.format = UNCOMPRESSED_R5G6B5;
+ else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8)) image.format = UNCOMPRESSED_R8G8B8;
}
}
- else if (header.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB;
- else if (header.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
+ else if (pvrHeader.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB;
+ else if (pvrHeader.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
// Skip meta data header
unsigned char unused = 0;
- for (int i = 0; i < header.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
+ for (int i = 0; i < pvrHeader.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
// Calculate data size (depends on format)
int bpp = 0;
@@ -2174,7 +2108,7 @@ static Image LoadASTC(const char *fileName)
unsigned char width[3]; // Image width in pixels (24bit value)
unsigned char height[3]; // Image height in pixels (24bit value)
unsigned char lenght[3]; // Image Z-size (1 for 2D images)
- } astcHeader;
+ } ASTCHeader;
Image image;
@@ -2192,30 +2126,30 @@ static Image LoadASTC(const char *fileName)
}
else
{
- astcHeader header;
+ ASTCHeader astcHeader;
// Get ASTC image header
- fread(&header, sizeof(astcHeader), 1, astcFile);
+ fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);
- if ((header.id[3] != 0x5c) || (header.id[2] != 0xa1) || (header.id[1] != 0xab) || (header.id[0] != 0x13))
+ if ((astcHeader.id[3] != 0x5c) || (astcHeader.id[2] != 0xa1) || (astcHeader.id[1] != 0xab) || (astcHeader.id[0] != 0x13))
{
TraceLog(WARNING, "[%s] ASTC file does not seem to be a valid image", fileName);
}
else
{
// NOTE: Assuming Little Endian (could it be wrong?)
- image.width = 0x00000000 | ((int)header.width[2] << 16) | ((int)header.width[1] << 8) | ((int)header.width[0]);
- image.height = 0x00000000 | ((int)header.height[2] << 16) | ((int)header.height[1] << 8) | ((int)header.height[0]);
+ image.width = 0x00000000 | ((int)astcHeader.width[2] << 16) | ((int)astcHeader.width[1] << 8) | ((int)astcHeader.width[0]);
+ image.height = 0x00000000 | ((int)astcHeader.height[2] << 16) | ((int)astcHeader.height[1] << 8) | ((int)astcHeader.height[0]);
// NOTE: ASTC format only contains one mipmap level
image.mipmaps = 1;
TraceLog(DEBUG, "ASTC image width: %i", image.width);
TraceLog(DEBUG, "ASTC image height: %i", image.height);
- TraceLog(DEBUG, "ASTC image blocks: %ix%i", header.blockX, header.blockY);
+ TraceLog(DEBUG, "ASTC image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
// NOTE: Each block is always stored in 128bit so we can calculate the bpp
- int bpp = 128/(header.blockX*header.blockY);
+ int bpp = 128/(astcHeader.blockX*astcHeader.blockY);
// NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
if ((bpp == 8) || (bpp == 2))