|
@@ -3258,6 +3258,10 @@ static Image LoadAnimatedGIF(const char *fileName, int *frames, int **delays)
|
|
// Loading DDS image data (compressed or uncompressed)
|
|
// Loading DDS image data (compressed or uncompressed)
|
|
static Image LoadDDS(const char *fileName)
|
|
static Image LoadDDS(const char *fileName)
|
|
{
|
|
{
|
|
|
|
+ unsigned int fileSize = 0;
|
|
|
|
+ unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
+
|
|
// Required extension:
|
|
// Required extension:
|
|
// GL_EXT_texture_compression_s3tc
|
|
// GL_EXT_texture_compression_s3tc
|
|
|
|
|
|
@@ -3303,18 +3307,11 @@ static Image LoadDDS(const char *fileName)
|
|
|
|
|
|
Image image = { 0 };
|
|
Image image = { 0 };
|
|
|
|
|
|
- FILE *ddsFile = fopen(fileName, "rb");
|
|
|
|
-
|
|
|
|
- if (ddsFile == NULL)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open DDS file", fileName);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (fileDataPtr != NULL)
|
|
{
|
|
{
|
|
// Verify the type of file
|
|
// Verify the type of file
|
|
- char ddsHeaderId[4] = { 0 };
|
|
|
|
-
|
|
|
|
- fread(ddsHeaderId, 4, 1, ddsFile);
|
|
|
|
|
|
+ unsigned char *ddsHeaderId = fileDataPtr;
|
|
|
|
+ fileDataPtr += 4;
|
|
|
|
|
|
if ((ddsHeaderId[0] != 'D') || (ddsHeaderId[1] != 'D') || (ddsHeaderId[2] != 'S') || (ddsHeaderId[3] != ' '))
|
|
if ((ddsHeaderId[0] != 'D') || (ddsHeaderId[1] != 'D') || (ddsHeaderId[2] != 'S') || (ddsHeaderId[3] != ' '))
|
|
{
|
|
{
|
|
@@ -3322,39 +3319,42 @@ static Image LoadDDS(const char *fileName)
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- DDSHeader ddsHeader = { 0 };
|
|
|
|
-
|
|
|
|
- // Get the image header
|
|
|
|
- fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
|
|
|
|
|
|
+ DDSHeader *ddsHeader = (DDSHeader *)fileDataPtr;
|
|
|
|
|
|
TRACELOGD("IMAGE: [%s] DDS file info:", fileName);
|
|
TRACELOGD("IMAGE: [%s] DDS file info:", fileName);
|
|
TRACELOGD(" > Header size: %i", fileName, sizeof(DDSHeader));
|
|
TRACELOGD(" > Header size: %i", fileName, sizeof(DDSHeader));
|
|
- TRACELOGD(" > Pixel format size: %i", fileName, ddsHeader.ddspf.size);
|
|
|
|
- TRACELOGD(" > Pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
|
|
|
|
- TRACELOGD(" > File format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
|
|
|
|
- TRACELOGD(" > File bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
|
|
|
|
|
|
+ TRACELOGD(" > Pixel format size: %i", fileName, ddsHeader->ddspf.size);
|
|
|
|
+ TRACELOGD(" > Pixel format flags: 0x%x", fileName, ddsHeader->ddspf.flags);
|
|
|
|
+ TRACELOGD(" > File format: 0x%x", fileName, ddsHeader->ddspf.fourCC);
|
|
|
|
+ TRACELOGD(" > File bit count: 0x%x", fileName, ddsHeader->ddspf.rgbBitCount);
|
|
|
|
+
|
|
|
|
+ fileDataPtr += sizeof(DDSHeader); // Skip header
|
|
|
|
|
|
- image.width = ddsHeader.width;
|
|
|
|
- image.height = ddsHeader.height;
|
|
|
|
|
|
+ image.width = ddsHeader->width;
|
|
|
|
+ image.height = ddsHeader->height;
|
|
|
|
|
|
- if (ddsHeader.mipmapCount == 0) image.mipmaps = 1; // Parameter not used
|
|
|
|
- else image.mipmaps = ddsHeader.mipmapCount;
|
|
|
|
|
|
+ if (ddsHeader->mipmapCount == 0) image.mipmaps = 1; // Parameter not used
|
|
|
|
+ else image.mipmaps = ddsHeader->mipmapCount;
|
|
|
|
|
|
- if (ddsHeader.ddspf.rgbBitCount == 16) // 16bit mode, no compressed
|
|
|
|
|
|
+ if (ddsHeader->ddspf.rgbBitCount == 16) // 16bit mode, no compressed
|
|
{
|
|
{
|
|
- if (ddsHeader.ddspf.flags == 0x40) // no alpha channel
|
|
|
|
|
|
+ if (ddsHeader->ddspf.flags == 0x40) // no alpha channel
|
|
{
|
|
{
|
|
- image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short));
|
|
|
|
- fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
|
|
|
|
|
+ int dataSize = image.width*image.height*sizeof(unsigned short);
|
|
|
|
+ image.data = (unsigned short *)RL_MALLOC(dataSize);
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
image.format = UNCOMPRESSED_R5G6B5;
|
|
image.format = UNCOMPRESSED_R5G6B5;
|
|
}
|
|
}
|
|
- else if (ddsHeader.ddspf.flags == 0x41) // with alpha channel
|
|
|
|
|
|
+ else if (ddsHeader->ddspf.flags == 0x41) // with alpha channel
|
|
{
|
|
{
|
|
- if (ddsHeader.ddspf.aBitMask == 0x8000) // 1bit alpha
|
|
|
|
|
|
+ if (ddsHeader->ddspf.aBitMask == 0x8000) // 1bit alpha
|
|
{
|
|
{
|
|
- image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short));
|
|
|
|
- fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
|
|
|
|
|
+ int dataSize = image.width*image.height*sizeof(unsigned short);
|
|
|
|
+ image.data = (unsigned short *)RL_MALLOC(dataSize);
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
unsigned char alpha = 0;
|
|
unsigned char alpha = 0;
|
|
|
|
|
|
@@ -3368,10 +3368,12 @@ static Image LoadDDS(const char *fileName)
|
|
|
|
|
|
image.format = UNCOMPRESSED_R5G5B5A1;
|
|
image.format = UNCOMPRESSED_R5G5B5A1;
|
|
}
|
|
}
|
|
- else if (ddsHeader.ddspf.aBitMask == 0xf000) // 4bit alpha
|
|
|
|
|
|
+ else if (ddsHeader->ddspf.aBitMask == 0xf000) // 4bit alpha
|
|
{
|
|
{
|
|
- image.data = (unsigned short *)RL_MALLOC(image.width*image.height*sizeof(unsigned short));
|
|
|
|
- fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
|
|
|
|
|
+ int dataSize = image.width*image.height*sizeof(unsigned short);
|
|
|
|
+ image.data = (unsigned short *)RL_MALLOC(dataSize);
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
unsigned char alpha = 0;
|
|
unsigned char alpha = 0;
|
|
|
|
|
|
@@ -3387,18 +3389,21 @@ static Image LoadDDS(const char *fileName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- else if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
|
|
|
|
|
|
+ else if (ddsHeader->ddspf.flags == 0x40 && ddsHeader->ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
|
|
{
|
|
{
|
|
- // NOTE: not sure if this case exists...
|
|
|
|
- image.data = (unsigned char *)RL_MALLOC(image.width*image.height*3*sizeof(unsigned char));
|
|
|
|
- fread(image.data, image.width*image.height*3, 1, ddsFile);
|
|
|
|
|
|
+ int dataSize = image.width*image.height*3*sizeof(unsigned char);
|
|
|
|
+ image.data = (unsigned short *)RL_MALLOC(dataSize);
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
image.format = UNCOMPRESSED_R8G8B8;
|
|
image.format = UNCOMPRESSED_R8G8B8;
|
|
}
|
|
}
|
|
- else if (ddsHeader.ddspf.flags == 0x41 && ddsHeader.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 *)RL_MALLOC(image.width*image.height*4*sizeof(unsigned char));
|
|
|
|
- fread(image.data, image.width*image.height*4, 1, ddsFile);
|
|
|
|
|
|
+ int dataSize = image.width*image.height*4*sizeof(unsigned char);
|
|
|
|
+ image.data = (unsigned short *)RL_MALLOC(dataSize);
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
unsigned char blue = 0;
|
|
unsigned char blue = 0;
|
|
|
|
|
|
@@ -3414,23 +3419,23 @@ static Image LoadDDS(const char *fileName)
|
|
|
|
|
|
image.format = UNCOMPRESSED_R8G8B8A8;
|
|
image.format = UNCOMPRESSED_R8G8B8A8;
|
|
}
|
|
}
|
|
- else if (((ddsHeader.ddspf.flags == 0x04) || (ddsHeader.ddspf.flags == 0x05)) && (ddsHeader.ddspf.fourCC > 0)) // Compressed
|
|
|
|
|
|
+ else if (((ddsHeader->ddspf.flags == 0x04) || (ddsHeader->ddspf.flags == 0x05)) && (ddsHeader->ddspf.fourCC > 0)) // Compressed
|
|
{
|
|
{
|
|
- int size; // DDS image data size
|
|
|
|
|
|
+ int dataSize = 0;
|
|
|
|
|
|
// Calculate data size, including all mipmaps
|
|
// Calculate data size, including all mipmaps
|
|
- if (ddsHeader.mipmapCount > 1) size = ddsHeader.pitchOrLinearSize*2;
|
|
|
|
- else size = ddsHeader.pitchOrLinearSize;
|
|
|
|
|
|
+ if (ddsHeader->mipmapCount > 1) dataSize = ddsHeader->pitchOrLinearSize*2;
|
|
|
|
+ else dataSize = ddsHeader->pitchOrLinearSize;
|
|
|
|
|
|
- image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
|
|
|
|
|
|
+ image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
|
|
|
|
- fread(image.data, size, 1, ddsFile);
|
|
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
- switch (ddsHeader.ddspf.fourCC)
|
|
|
|
|
|
+ switch (ddsHeader->ddspf.fourCC)
|
|
{
|
|
{
|
|
case FOURCC_DXT1:
|
|
case FOURCC_DXT1:
|
|
{
|
|
{
|
|
- if (ddsHeader.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
|
|
|
|
|
|
+ if (ddsHeader->ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
|
|
else image.format = COMPRESSED_DXT1_RGBA;
|
|
else image.format = COMPRESSED_DXT1_RGBA;
|
|
} break;
|
|
} break;
|
|
case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break;
|
|
case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break;
|
|
@@ -3440,7 +3445,7 @@ static Image LoadDDS(const char *fileName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- fclose(ddsFile); // Close file pointer
|
|
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
}
|
|
}
|
|
|
|
|
|
return image;
|
|
return image;
|
|
@@ -3453,6 +3458,10 @@ static Image LoadDDS(const char *fileName)
|
|
// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
|
|
// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
|
|
static Image LoadPKM(const char *fileName)
|
|
static Image LoadPKM(const char *fileName)
|
|
{
|
|
{
|
|
|
|
+ unsigned int fileSize = 0;
|
|
|
|
+ unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
+
|
|
// Required extensions:
|
|
// Required extensions:
|
|
// GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0)
|
|
// GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0)
|
|
// GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0)
|
|
// GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0)
|
|
@@ -3482,54 +3491,47 @@ static Image LoadPKM(const char *fileName)
|
|
|
|
|
|
Image image = { 0 };
|
|
Image image = { 0 };
|
|
|
|
|
|
- FILE *pkmFile = fopen(fileName, "rb");
|
|
|
|
-
|
|
|
|
- if (pkmFile == NULL)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open PKM file", fileName);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (fileDataPtr != NULL)
|
|
{
|
|
{
|
|
- PKMHeader pkmHeader = { 0 };
|
|
|
|
-
|
|
|
|
- // Get the image header
|
|
|
|
- fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
|
|
|
|
|
|
+ PKMHeader *pkmHeader = (PKMHeader *)fileDataPtr;
|
|
|
|
|
|
- if ((pkmHeader.id[0] != 'P') || (pkmHeader.id[1] != 'K') || (pkmHeader.id[2] != 'M') || (pkmHeader.id[3] != ' '))
|
|
|
|
|
|
+ if ((pkmHeader->id[0] != 'P') || (pkmHeader->id[1] != 'K') || (pkmHeader->id[2] != 'M') || (pkmHeader->id[3] != ' '))
|
|
{
|
|
{
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] PKM file not a valid image", fileName);
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] PKM file not a valid image", fileName);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
|
|
+ fileDataPtr += sizeof(PKMHeader); // Skip header
|
|
|
|
+
|
|
// NOTE: format, width and height come as big-endian, data must be swapped to little-endian
|
|
// NOTE: format, width and height come as big-endian, data must be swapped to little-endian
|
|
- 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);
|
|
|
|
|
|
+ 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);
|
|
|
|
|
|
TRACELOGD("IMAGE: [%s] PKM file info:", fileName);
|
|
TRACELOGD("IMAGE: [%s] PKM file info:", fileName);
|
|
- TRACELOGD(" > Image width: %i", pkmHeader.width);
|
|
|
|
- TRACELOGD(" > Image height: %i", pkmHeader.height);
|
|
|
|
- TRACELOGD(" > Image format: %i", pkmHeader.format);
|
|
|
|
|
|
+ TRACELOGD(" > Image width: %i", pkmHeader->width);
|
|
|
|
+ TRACELOGD(" > Image height: %i", pkmHeader->height);
|
|
|
|
+ TRACELOGD(" > Image format: %i", pkmHeader->format);
|
|
|
|
|
|
- image.width = pkmHeader.width;
|
|
|
|
- image.height = pkmHeader.height;
|
|
|
|
|
|
+ image.width = pkmHeader->width;
|
|
|
|
+ image.height = pkmHeader->height;
|
|
image.mipmaps = 1;
|
|
image.mipmaps = 1;
|
|
|
|
|
|
int bpp = 4;
|
|
int bpp = 4;
|
|
- if (pkmHeader.format == 3) bpp = 8;
|
|
|
|
|
|
+ if (pkmHeader->format == 3) bpp = 8;
|
|
|
|
|
|
- int size = image.width*image.height*bpp/8; // Total data size in bytes
|
|
|
|
|
|
+ int dataSize = image.width*image.height*bpp/8; // Total data size in bytes
|
|
|
|
|
|
image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
|
|
image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
|
|
|
|
|
|
- fread(image.data, size, 1, pkmFile);
|
|
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ 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
|
|
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
}
|
|
}
|
|
|
|
|
|
return image;
|
|
return image;
|
|
@@ -3540,6 +3542,10 @@ static Image LoadPKM(const char *fileName)
|
|
// Load KTX compressed image data (ETC1/ETC2 compression)
|
|
// Load KTX compressed image data (ETC1/ETC2 compression)
|
|
static Image LoadKTX(const char *fileName)
|
|
static Image LoadKTX(const char *fileName)
|
|
{
|
|
{
|
|
|
|
+ unsigned int fileSize = 0;
|
|
|
|
+ unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
+
|
|
// Required extensions:
|
|
// Required extensions:
|
|
// GL_OES_compressed_ETC1_RGB8_texture (ETC1)
|
|
// GL_OES_compressed_ETC1_RGB8_texture (ETC1)
|
|
// GL_ARB_ES3_compatibility (ETC2/EAC)
|
|
// GL_ARB_ES3_compatibility (ETC2/EAC)
|
|
@@ -3576,55 +3582,43 @@ static Image LoadKTX(const char *fileName)
|
|
|
|
|
|
Image image = { 0 };
|
|
Image image = { 0 };
|
|
|
|
|
|
- FILE *ktxFile = fopen(fileName, "rb");
|
|
|
|
-
|
|
|
|
- if (ktxFile == NULL)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load KTX file", fileName);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (fileDataPtr != NULL)
|
|
{
|
|
{
|
|
- KTXHeader ktxHeader = { 0 };
|
|
|
|
|
|
+ KTXHeader *ktxHeader = (KTXHeader *)fileDataPtr;
|
|
|
|
|
|
- // Get the image header
|
|
|
|
- fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
|
|
|
|
-
|
|
|
|
- if ((ktxHeader.id[1] != 'K') || (ktxHeader.id[2] != 'T') || (ktxHeader.id[3] != 'X') ||
|
|
|
|
- (ktxHeader.id[4] != ' ') || (ktxHeader.id[5] != '1') || (ktxHeader.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(LOG_WARNING, "IMAGE: [%s] KTX file not a valid image", fileName);
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] KTX file not a valid image", fileName);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- image.width = ktxHeader.width;
|
|
|
|
- image.height = ktxHeader.height;
|
|
|
|
- image.mipmaps = ktxHeader.mipmapLevels;
|
|
|
|
|
|
+ fileDataPtr += sizeof(KTXHeader); // Move file data pointer
|
|
|
|
+
|
|
|
|
+ image.width = ktxHeader->width;
|
|
|
|
+ image.height = ktxHeader->height;
|
|
|
|
+ image.mipmaps = ktxHeader->mipmapLevels;
|
|
|
|
|
|
TRACELOGD("IMAGE: [%s] KTX file info:", fileName);
|
|
TRACELOGD("IMAGE: [%s] KTX file info:", fileName);
|
|
- TRACELOGD(" > Image width: %i", ktxHeader.width);
|
|
|
|
- TRACELOGD(" > Image height: %i", ktxHeader.height);
|
|
|
|
- TRACELOGD(" > Image format: 0x%x", ktxHeader.glInternalFormat);
|
|
|
|
-
|
|
|
|
- unsigned char unused;
|
|
|
|
-
|
|
|
|
- if (ktxHeader.keyValueDataSize > 0)
|
|
|
|
- {
|
|
|
|
- for (unsigned int i = 0; i < ktxHeader.keyValueDataSize; i++) fread(&unused, sizeof(unsigned char), 1U, ktxFile);
|
|
|
|
- }
|
|
|
|
|
|
+ TRACELOGD(" > Image width: %i", ktxHeader->width);
|
|
|
|
+ TRACELOGD(" > Image height: %i", ktxHeader->height);
|
|
|
|
+ TRACELOGD(" > Image format: 0x%x", ktxHeader->glInternalFormat);
|
|
|
|
|
|
- int dataSize;
|
|
|
|
- fread(&dataSize, sizeof(unsigned int), 1, ktxFile);
|
|
|
|
|
|
+ fileDataPtr += ktxHeader->keyValueDataSize; // Skip value data size
|
|
|
|
|
|
|
|
+ int dataSize = ((int *)fileDataPtr)[0];
|
|
|
|
+ fileDataPtr += sizeof(int);
|
|
|
|
+
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
|
|
|
|
- fread(image.data, dataSize, 1, ktxFile);
|
|
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ 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
|
|
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
}
|
|
}
|
|
|
|
|
|
return image;
|
|
return image;
|
|
@@ -3634,12 +3628,9 @@ static Image LoadKTX(const char *fileName)
|
|
// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
|
|
// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
|
|
static int SaveKTX(Image image, const char *fileName)
|
|
static int SaveKTX(Image image, const char *fileName)
|
|
{
|
|
{
|
|
- int success = 0;
|
|
|
|
-
|
|
|
|
// KTX file Header (64 bytes)
|
|
// KTX file Header (64 bytes)
|
|
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
|
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
|
// v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation
|
|
// v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation
|
|
-
|
|
|
|
typedef struct {
|
|
typedef struct {
|
|
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
|
|
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
|
|
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
|
|
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
|
|
@@ -3659,69 +3650,77 @@ static int SaveKTX(Image image, const char *fileName)
|
|
// KTX 2.0 defines additional header elements...
|
|
// KTX 2.0 defines additional header elements...
|
|
} KTXHeader;
|
|
} KTXHeader;
|
|
|
|
|
|
- // NOTE: Before start of every mipmap data block, we have: unsigned int dataSize
|
|
|
|
-
|
|
|
|
- FILE *ktxFile = fopen(fileName, "wb");
|
|
|
|
-
|
|
|
|
- if (ktxFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open KTX file", fileName);
|
|
|
|
- else
|
|
|
|
|
|
+ // Calculate file dataSize required
|
|
|
|
+ int dataSize = sizeof(KTXHeader);
|
|
|
|
+
|
|
|
|
+ for (int i = 0, width = image.width, height = image.height; i < image.mipmaps; i++)
|
|
{
|
|
{
|
|
- KTXHeader ktxHeader = { 0 };
|
|
|
|
|
|
+ dataSize += GetPixelDataSize(width, height, image.format);
|
|
|
|
+ width /= 2; height /= 2;
|
|
|
|
+ }
|
|
|
|
|
|
- // KTX identifier (v1.1)
|
|
|
|
- //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
|
|
|
|
- //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
|
|
|
|
|
|
+ unsigned char *fileData = RL_CALLOC(dataSize, 1);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
|
|
- const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
|
|
|
|
|
|
+ KTXHeader ktxHeader = { 0 };
|
|
|
|
|
|
- // Get the image header
|
|
|
|
- strncpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature
|
|
|
|
- ktxHeader.endianness = 0;
|
|
|
|
- ktxHeader.glType = 0; // Obtained from image.format
|
|
|
|
- ktxHeader.glTypeSize = 1;
|
|
|
|
- ktxHeader.glFormat = 0; // Obtained from image.format
|
|
|
|
- ktxHeader.glInternalFormat = 0; // Obtained from image.format
|
|
|
|
- ktxHeader.glBaseInternalFormat = 0;
|
|
|
|
- ktxHeader.width = image.width;
|
|
|
|
- ktxHeader.height = image.height;
|
|
|
|
- ktxHeader.depth = 0;
|
|
|
|
- ktxHeader.elements = 0;
|
|
|
|
- ktxHeader.faces = 1;
|
|
|
|
- ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
|
|
|
|
- ktxHeader.keyValueDataSize = 0; // No extra data after the header
|
|
|
|
|
|
+ // KTX identifier (v1.1)
|
|
|
|
+ //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
|
|
|
|
+ //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
|
|
|
|
|
|
- rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
|
|
|
|
- ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only
|
|
|
|
|
|
+ const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
|
|
|
|
|
|
- // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
|
|
|
|
|
|
+ // Get the image header
|
|
|
|
+ memcpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature
|
|
|
|
+ ktxHeader.endianness = 0;
|
|
|
|
+ ktxHeader.glType = 0; // Obtained from image.format
|
|
|
|
+ ktxHeader.glTypeSize = 1;
|
|
|
|
+ ktxHeader.glFormat = 0; // Obtained from image.format
|
|
|
|
+ ktxHeader.glInternalFormat = 0; // Obtained from image.format
|
|
|
|
+ ktxHeader.glBaseInternalFormat = 0;
|
|
|
|
+ ktxHeader.width = image.width;
|
|
|
|
+ ktxHeader.height = image.height;
|
|
|
|
+ ktxHeader.depth = 0;
|
|
|
|
+ ktxHeader.elements = 0;
|
|
|
|
+ ktxHeader.faces = 1;
|
|
|
|
+ ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
|
|
|
|
+ ktxHeader.keyValueDataSize = 0; // No extra data after the header
|
|
|
|
|
|
- if (ktxHeader.glFormat == -1) TRACELOG(LOG_WARNING, "IMAGE: GL format not supported for KTX export (%i)", ktxHeader.glFormat);
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- success = (int)fwrite(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
|
|
|
|
|
|
+ rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
|
|
|
|
+ ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only
|
|
|
|
|
|
- int width = image.width;
|
|
|
|
- int height = image.height;
|
|
|
|
- int dataOffset = 0;
|
|
|
|
|
|
+ // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
|
|
|
|
|
|
- // Save all mipmaps data
|
|
|
|
- for (int i = 0; i < image.mipmaps; i++)
|
|
|
|
- {
|
|
|
|
- unsigned int dataSize = GetPixelDataSize(width, height, image.format);
|
|
|
|
- success = (int)fwrite(&dataSize, sizeof(unsigned int), 1, ktxFile);
|
|
|
|
- success = (int)fwrite((unsigned char *)image.data + dataOffset, dataSize, 1, ktxFile);
|
|
|
|
|
|
+ if (ktxHeader.glFormat == -1) TRACELOG(LOG_WARNING, "IMAGE: GL format not supported for KTX export (%i)", ktxHeader.glFormat);
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ memcpy(fileDataPtr, &ktxHeader, sizeof(KTXHeader));
|
|
|
|
+ fileDataPtr += sizeof(KTXHeader);
|
|
|
|
+
|
|
|
|
+ int width = image.width;
|
|
|
|
+ int height = image.height;
|
|
|
|
+ int dataOffset = 0;
|
|
|
|
|
|
- width /= 2;
|
|
|
|
- height /= 2;
|
|
|
|
- dataOffset += dataSize;
|
|
|
|
- }
|
|
|
|
|
|
+ // Save all mipmaps data
|
|
|
|
+ for (int i = 0; i < image.mipmaps; i++)
|
|
|
|
+ {
|
|
|
|
+ unsigned int dataSize = GetPixelDataSize(width, height, image.format);
|
|
|
|
+
|
|
|
|
+ memcpy(fileDataPtr, &dataSize, sizeof(unsigned int));
|
|
|
|
+ memcpy(fileDataPtr + 4, (unsigned char *)image.data + dataOffset, dataSize);
|
|
|
|
+
|
|
|
|
+ width /= 2;
|
|
|
|
+ height /= 2;
|
|
|
|
+ dataOffset += dataSize;
|
|
|
|
+ fileDataPtr += (4 + dataSize);
|
|
}
|
|
}
|
|
-
|
|
|
|
- fclose(ktxFile); // Close file pointer
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ SaveFileData(fileName, fileData, dataSize);
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
|
|
+
|
|
// If all data has been written correctly to file, success = 1
|
|
// If all data has been written correctly to file, success = 1
|
|
- return success;
|
|
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -3730,6 +3729,10 @@ static int SaveKTX(Image image, const char *fileName)
|
|
// NOTE: PVR v2 not supported, use PVR v3 instead
|
|
// NOTE: PVR v2 not supported, use PVR v3 instead
|
|
static Image LoadPVR(const char *fileName)
|
|
static Image LoadPVR(const char *fileName)
|
|
{
|
|
{
|
|
|
|
+ unsigned int fileSize = 0;
|
|
|
|
+ unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
+
|
|
// Required extension:
|
|
// Required extension:
|
|
// GL_IMG_texture_compression_pvrtc
|
|
// GL_IMG_texture_compression_pvrtc
|
|
|
|
|
|
@@ -3786,69 +3789,52 @@ static Image LoadPVR(const char *fileName)
|
|
|
|
|
|
Image image = { 0 };
|
|
Image image = { 0 };
|
|
|
|
|
|
- FILE *pvrFile = fopen(fileName, "rb");
|
|
|
|
-
|
|
|
|
- if (pvrFile == NULL)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load PVR file", fileName);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (fileDataPtr != NULL)
|
|
{
|
|
{
|
|
// Check PVR image version
|
|
// Check PVR image version
|
|
- unsigned char pvrVersion = 0;
|
|
|
|
- fread(&pvrVersion, sizeof(unsigned char), 1, pvrFile);
|
|
|
|
- fseek(pvrFile, 0, SEEK_SET);
|
|
|
|
|
|
+ unsigned char pvrVersion = fileDataPtr[0];
|
|
|
|
|
|
// Load different PVR data formats
|
|
// Load different PVR data formats
|
|
if (pvrVersion == 0x50)
|
|
if (pvrVersion == 0x50)
|
|
{
|
|
{
|
|
- PVRHeaderV3 pvrHeader = { 0 };
|
|
|
|
-
|
|
|
|
- // Get PVR image header
|
|
|
|
- fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
|
|
|
|
|
|
+ PVRHeaderV3 *pvrHeader = (PVRHeaderV3 *)fileDataPtr;
|
|
|
|
|
|
- if ((pvrHeader.id[0] != 'P') || (pvrHeader.id[1] != 'V') || (pvrHeader.id[2] != 'R') || (pvrHeader.id[3] != 3))
|
|
|
|
|
|
+ if ((pvrHeader->id[0] != 'P') || (pvrHeader->id[1] != 'V') || (pvrHeader->id[2] != 'R') || (pvrHeader->id[3] != 3))
|
|
{
|
|
{
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] PVR file not a valid image", fileName);
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] PVR file not a valid image", fileName);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- image.width = pvrHeader.width;
|
|
|
|
- image.height = pvrHeader.height;
|
|
|
|
- image.mipmaps = pvrHeader.numMipmaps;
|
|
|
|
|
|
+ fileDataPtr += sizeof(PVRHeaderV3); // Skip header
|
|
|
|
+
|
|
|
|
+ image.width = pvrHeader->width;
|
|
|
|
+ image.height = pvrHeader->height;
|
|
|
|
+ image.mipmaps = pvrHeader->numMipmaps;
|
|
|
|
|
|
// Check data format
|
|
// Check data format
|
|
- 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 (((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 (pvrHeader.channels[3] == 'a')
|
|
|
|
|
|
+ if (pvrHeader->channels[3] == 'a')
|
|
{
|
|
{
|
|
- 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;
|
|
|
|
|
|
+ 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 (pvrHeader.channels[3] == 0)
|
|
|
|
|
|
+ else if (pvrHeader->channels[3] == 0)
|
|
{
|
|
{
|
|
- 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;
|
|
|
|
|
|
+ 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 (pvrHeader.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB;
|
|
|
|
- else if (pvrHeader.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 (unsigned int i = 0; i < pvrHeader.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
|
|
|
|
|
|
+ fileDataPtr += pvrHeader->metaDataSize); // Skip meta data header
|
|
|
|
|
|
// Calculate data size (depends on format)
|
|
// Calculate data size (depends on format)
|
|
int bpp = 0;
|
|
int bpp = 0;
|
|
-
|
|
|
|
switch (image.format)
|
|
switch (image.format)
|
|
{
|
|
{
|
|
case UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
|
|
case UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
|
|
@@ -3866,13 +3852,12 @@ static Image LoadPVR(const char *fileName)
|
|
int dataSize = image.width*image.height*bpp/8; // Total data size in bytes
|
|
int dataSize = image.width*image.height*bpp/8; // Total data size in bytes
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
|
|
|
|
- // Read data from file
|
|
|
|
- fread(image.data, dataSize, 1, pvrFile);
|
|
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pvrVersion == 52) TRACELOG(LOG_INFO, "IMAGE: [%s] PVRv2 format not supported, update your files to PVRv3", fileName);
|
|
else if (pvrVersion == 52) TRACELOG(LOG_INFO, "IMAGE: [%s] PVRv2 format not supported, update your files to PVRv3", fileName);
|
|
|
|
|
|
- fclose(pvrFile); // Close file pointer
|
|
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
}
|
|
}
|
|
|
|
|
|
return image;
|
|
return image;
|
|
@@ -3883,6 +3868,10 @@ static Image LoadPVR(const char *fileName)
|
|
// Load ASTC compressed image data (ASTC compression)
|
|
// Load ASTC compressed image data (ASTC compression)
|
|
static Image LoadASTC(const char *fileName)
|
|
static Image LoadASTC(const char *fileName)
|
|
{
|
|
{
|
|
|
|
+ unsigned int fileSize = 0;
|
|
|
|
+ unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
|
|
|
+ unsigned char *fileDataPtr = fileData;
|
|
|
|
+
|
|
// Required extensions:
|
|
// Required extensions:
|
|
// GL_KHR_texture_compression_astc_hdr
|
|
// GL_KHR_texture_compression_astc_hdr
|
|
// GL_KHR_texture_compression_astc_ldr
|
|
// GL_KHR_texture_compression_astc_ldr
|
|
@@ -3904,38 +3893,31 @@ static Image LoadASTC(const char *fileName)
|
|
|
|
|
|
Image image = { 0 };
|
|
Image image = { 0 };
|
|
|
|
|
|
- FILE *astcFile = fopen(fileName, "rb");
|
|
|
|
-
|
|
|
|
- if (astcFile == NULL)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load ASTC file", fileName);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (fileDataPtr != NULL)
|
|
{
|
|
{
|
|
- ASTCHeader astcHeader = { 0 };
|
|
|
|
|
|
+ ASTCHeader *astcHeader = (ASTCHeader *)fileDataPtr;
|
|
|
|
|
|
- // Get ASTC image header
|
|
|
|
- fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);
|
|
|
|
-
|
|
|
|
- if ((astcHeader.id[3] != 0x5c) || (astcHeader.id[2] != 0xa1) || (astcHeader.id[1] != 0xab) || (astcHeader.id[0] != 0x13))
|
|
|
|
|
|
+ if ((astcHeader->id[3] != 0x5c) || (astcHeader->id[2] != 0xa1) || (astcHeader->id[1] != 0xab) || (astcHeader->id[0] != 0x13))
|
|
{
|
|
{
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC file not a valid image", fileName);
|
|
TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC file not a valid image", fileName);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
|
|
+ fileDataPtr += sizeof(ASTCHeader); // Skip header
|
|
|
|
+
|
|
// NOTE: Assuming Little Endian (could it be wrong?)
|
|
// NOTE: Assuming Little Endian (could it be wrong?)
|
|
- 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]);
|
|
|
|
|
|
+ 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]);
|
|
|
|
|
|
TRACELOGD("IMAGE: [%s] ASTC file info:", fileName);
|
|
TRACELOGD("IMAGE: [%s] ASTC file info:", fileName);
|
|
TRACELOGD(" > Image width: %i", image.width);
|
|
TRACELOGD(" > Image width: %i", image.width);
|
|
TRACELOGD(" > Image height: %i", image.height);
|
|
TRACELOGD(" > Image height: %i", image.height);
|
|
- TRACELOGD(" > Image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
|
|
|
|
|
|
+ TRACELOGD(" > Image blocks: %ix%i", astcHeader->blockX, astcHeader->blockY);
|
|
|
|
|
|
image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level
|
|
image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level
|
|
|
|
|
|
// NOTE: Each block is always stored in 128bit so we can calculate the bpp
|
|
// NOTE: Each block is always stored in 128bit so we can calculate the bpp
|
|
- int bpp = 128/(astcHeader.blockX*astcHeader.blockY);
|
|
|
|
|
|
+ int bpp = 128/(astcHeader->blockX*astcHeader->blockY);
|
|
|
|
|
|
// NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
|
|
// NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
|
|
if ((bpp == 8) || (bpp == 2))
|
|
if ((bpp == 8) || (bpp == 2))
|
|
@@ -3943,7 +3925,8 @@ static Image LoadASTC(const char *fileName)
|
|
int dataSize = image.width*image.height*bpp/8; // Data size in bytes
|
|
int dataSize = image.width*image.height*bpp/8; // Data size in bytes
|
|
|
|
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
image.data = (unsigned char *)RL_MALLOC(dataSize*sizeof(unsigned char));
|
|
- fread(image.data, dataSize, 1, astcFile);
|
|
|
|
|
|
+
|
|
|
|
+ memcpy(image.data, fileDataPtr, dataSize);
|
|
|
|
|
|
if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA;
|
|
if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA;
|
|
else if (bpp == 2) image.format = COMPRESSED_ASTC_8x8_RGBA;
|
|
else if (bpp == 2) image.format = COMPRESSED_ASTC_8x8_RGBA;
|
|
@@ -3951,7 +3934,7 @@ static Image LoadASTC(const char *fileName)
|
|
else TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC block size configuration not supported", fileName);
|
|
else TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC block size configuration not supported", fileName);
|
|
}
|
|
}
|
|
|
|
|
|
- fclose(astcFile);
|
|
|
|
|
|
+ free(fileData); // Free file data buffer
|
|
}
|
|
}
|
|
|
|
|
|
return image;
|
|
return image;
|