Replace file accesses by memory accesses
Several functions used to load external files have been reviewed to just load the full file with LoadFileData() and load data from memory from there. This way all file access functionality is centralized in utils module. Functions reviewed: LoadDDS(), LoadPKM(), LoadKTX(), LoadPVR(), LoadASTC(), SaveKTX()
This commit is contained in:
parent
a2955bc5b3
commit
0e56bc2929
1 changed files with 214 additions and 231 deletions
445
src/textures.c
445
src/textures.c
|
@ -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 (fileDataPtr != NULL)
|
||||||
|
|
||||||
if (ddsFile == NULL)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open DDS file", fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Verify the type of file
|
// Verify the type of file
|
||||||
char ddsHeaderId[4] = { 0 };
|
unsigned char *ddsHeaderId = fileDataPtr;
|
||||||
|
fileDataPtr += 4;
|
||||||
fread(ddsHeaderId, 4, 1, ddsFile);
|
|
||||||
|
|
||||||
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 };
|
DDSHeader *ddsHeader = (DDSHeader *)fileDataPtr;
|
||||||
|
|
||||||
// Get the image header
|
|
||||||
fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
|
|
||||||
|
|
||||||
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 size: %i", fileName, ddsHeader->ddspf.size);
|
||||||
TRACELOGD(" > Pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
|
TRACELOGD(" > Pixel format flags: 0x%x", fileName, ddsHeader->ddspf.flags);
|
||||||
TRACELOGD(" > File format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
|
TRACELOGD(" > File format: 0x%x", fileName, ddsHeader->ddspf.fourCC);
|
||||||
TRACELOGD(" > File bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
|
TRACELOGD(" > File bit count: 0x%x", fileName, ddsHeader->ddspf.rgbBitCount);
|
||||||
|
|
||||||
|
fileDataPtr += sizeof(DDSHeader); // Skip header
|
||||||
|
|
||||||
image.width = ddsHeader.width;
|
image.width = ddsHeader->width;
|
||||||
image.height = ddsHeader.height;
|
image.height = ddsHeader->height;
|
||||||
|
|
||||||
if (ddsHeader.mipmapCount == 0) image.mipmaps = 1; // Parameter not used
|
if (ddsHeader->mipmapCount == 0) image.mipmaps = 1; // Parameter not used
|
||||||
else image.mipmaps = ddsHeader.mipmapCount;
|
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));
|
int dataSize = image.width*image.height*sizeof(unsigned short);
|
||||||
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
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));
|
int dataSize = image.width*image.height*sizeof(unsigned short);
|
||||||
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
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));
|
int dataSize = image.width*image.height*sizeof(unsigned short);
|
||||||
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
|
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...
|
int dataSize = image.width*image.height*3*sizeof(unsigned char);
|
||||||
image.data = (unsigned char *)RL_MALLOC(image.width*image.height*3*sizeof(unsigned char));
|
image.data = (unsigned short *)RL_MALLOC(dataSize);
|
||||||
fread(image.data, image.width*image.height*3, 1, ddsFile);
|
|
||||||
|
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));
|
int dataSize = image.width*image.height*4*sizeof(unsigned char);
|
||||||
fread(image.data, image.width*image.height*4, 1, ddsFile);
|
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;
|
if (ddsHeader->mipmapCount > 1) dataSize = ddsHeader->pitchOrLinearSize*2;
|
||||||
else size = ddsHeader.pitchOrLinearSize;
|
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 (fileDataPtr != NULL)
|
||||||
|
|
||||||
if (pkmFile == NULL)
|
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open PKM file", fileName);
|
PKMHeader *pkmHeader = (PKMHeader *)fileDataPtr;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PKMHeader pkmHeader = { 0 };
|
|
||||||
|
|
||||||
// Get the image header
|
if ((pkmHeader->id[0] != 'P') || (pkmHeader->id[1] != 'K') || (pkmHeader->id[2] != 'M') || (pkmHeader->id[3] != ' '))
|
||||||
fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
|
|
||||||
|
|
||||||
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->format = ((pkmHeader->format & 0x00FF) << 8) | ((pkmHeader->format & 0xFF00) >> 8);
|
||||||
pkmHeader.width = ((pkmHeader.width & 0x00FF) << 8) | ((pkmHeader.width & 0xFF00) >> 8);
|
pkmHeader->width = ((pkmHeader->width & 0x00FF) << 8) | ((pkmHeader->width & 0xFF00) >> 8);
|
||||||
pkmHeader.height = ((pkmHeader.height & 0x00FF) << 8) | ((pkmHeader.height & 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 width: %i", pkmHeader->width);
|
||||||
TRACELOGD(" > Image height: %i", pkmHeader.height);
|
TRACELOGD(" > Image height: %i", pkmHeader->height);
|
||||||
TRACELOGD(" > Image format: %i", pkmHeader.format);
|
TRACELOGD(" > Image format: %i", pkmHeader->format);
|
||||||
|
|
||||||
image.width = pkmHeader.width;
|
image.width = pkmHeader->width;
|
||||||
image.height = pkmHeader.height;
|
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;
|
if (pkmHeader->format == 0) image.format = COMPRESSED_ETC1_RGB;
|
||||||
else if (pkmHeader.format == 1) image.format = COMPRESSED_ETC2_RGB;
|
else if (pkmHeader->format == 1) image.format = COMPRESSED_ETC2_RGB;
|
||||||
else if (pkmHeader.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA;
|
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 (fileDataPtr != NULL)
|
||||||
|
|
||||||
if (ktxFile == NULL)
|
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load KTX file", fileName);
|
KTXHeader *ktxHeader = (KTXHeader *)fileDataPtr;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KTXHeader ktxHeader = { 0 };
|
|
||||||
|
|
||||||
// Get the image header
|
if ((ktxHeader->id[1] != 'K') || (ktxHeader->id[2] != 'T') || (ktxHeader->id[3] != 'X') ||
|
||||||
fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
|
(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;
|
fileDataPtr += sizeof(KTXHeader); // Move file data pointer
|
||||||
image.height = ktxHeader.height;
|
|
||||||
image.mipmaps = ktxHeader.mipmapLevels;
|
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 width: %i", ktxHeader->width);
|
||||||
TRACELOGD(" > Image height: %i", ktxHeader.height);
|
TRACELOGD(" > Image height: %i", ktxHeader->height);
|
||||||
TRACELOGD(" > Image format: 0x%x", ktxHeader.glInternalFormat);
|
TRACELOGD(" > Image format: 0x%x", ktxHeader->glInternalFormat);
|
||||||
|
|
||||||
unsigned char unused;
|
fileDataPtr += ktxHeader->keyValueDataSize; // Skip value data size
|
||||||
|
|
||||||
if (ktxHeader.keyValueDataSize > 0)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < ktxHeader.keyValueDataSize; i++) fread(&unused, sizeof(unsigned char), 1U, ktxFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dataSize;
|
|
||||||
fread(&dataSize, sizeof(unsigned int), 1, ktxFile);
|
|
||||||
|
|
||||||
|
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;
|
if (ktxHeader->glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB;
|
||||||
else if (ktxHeader.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
|
else if (ktxHeader->glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
|
||||||
else if (ktxHeader.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA;
|
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
|
// Calculate file dataSize required
|
||||||
|
int dataSize = sizeof(KTXHeader);
|
||||||
FILE *ktxFile = fopen(fileName, "wb");
|
|
||||||
|
for (int i = 0, width = image.width, height = image.height; i < image.mipmaps; i++)
|
||||||
if (ktxFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open KTX file", fileName);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
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 };
|
|
||||||
|
|
||||||
const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
|
|
||||||
ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only
|
|
||||||
|
|
||||||
// NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
int width = image.width;
|
|
||||||
int height = image.height;
|
|
||||||
int dataOffset = 0;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
width /= 2;
|
|
||||||
height /= 2;
|
|
||||||
dataOffset += dataSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(ktxFile); // Close file pointer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char *fileData = RL_CALLOC(dataSize, 1);
|
||||||
|
unsigned char *fileDataPtr = fileData;
|
||||||
|
|
||||||
|
KTXHeader ktxHeader = { 0 };
|
||||||
|
|
||||||
|
// 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 };
|
||||||
|
|
||||||
|
const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
|
||||||
|
ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only
|
||||||
|
|
||||||
|
// NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (fileDataPtr != NULL)
|
||||||
|
|
||||||
if (pvrFile == NULL)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load PVR file", fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Check PVR image version
|
// Check PVR image version
|
||||||
unsigned char pvrVersion = 0;
|
unsigned char pvrVersion = fileDataPtr[0];
|
||||||
fread(&pvrVersion, sizeof(unsigned char), 1, pvrFile);
|
|
||||||
fseek(pvrFile, 0, SEEK_SET);
|
|
||||||
|
|
||||||
// Load different PVR data formats
|
// Load different PVR data formats
|
||||||
if (pvrVersion == 0x50)
|
if (pvrVersion == 0x50)
|
||||||
{
|
{
|
||||||
PVRHeaderV3 pvrHeader = { 0 };
|
PVRHeaderV3 *pvrHeader = (PVRHeaderV3 *)fileDataPtr;
|
||||||
|
|
||||||
// Get PVR image header
|
if ((pvrHeader->id[0] != 'P') || (pvrHeader->id[1] != 'V') || (pvrHeader->id[2] != 'R') || (pvrHeader->id[3] != 3))
|
||||||
fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
|
|
||||||
|
|
||||||
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;
|
fileDataPtr += sizeof(PVRHeaderV3); // Skip header
|
||||||
image.height = pvrHeader.height;
|
|
||||||
image.mipmaps = pvrHeader.numMipmaps;
|
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))
|
if (((pvrHeader->channels[0] == 'l') && (pvrHeader->channels[1] == 0)) && (pvrHeader->channelDepth[0] == 8)) image.format = UNCOMPRESSED_GRAYSCALE;
|
||||||
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] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8)))
|
else if ((pvrHeader->channels[0] == 'r') && (pvrHeader->channels[1] == 'g') && (pvrHeader->channels[2] == 'b'))
|
||||||
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))
|
if ((pvrHeader->channelDepth[0] == 5) && (pvrHeader->channelDepth[1] == 5) && (pvrHeader->channelDepth[2] == 5) && (pvrHeader->channelDepth[3] == 1)) image.format = UNCOMPRESSED_R5G5B5A1;
|
||||||
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] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4))
|
else if ((pvrHeader->channelDepth[0] == 8) && (pvrHeader->channelDepth[1] == 8) && (pvrHeader->channelDepth[2] == 8) && (pvrHeader->channelDepth[3] == 8)) image.format = UNCOMPRESSED_R8G8B8A8;
|
||||||
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;
|
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->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] == 2) image.format = COMPRESSED_PVRT_RGB;
|
||||||
else if (pvrHeader.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
|
else if (pvrHeader->channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
|
||||||
|
|
||||||
// Skip meta data header
|
fileDataPtr += pvrHeader->metaDataSize); // Skip meta data header
|
||||||
unsigned char unused = 0;
|
|
||||||
for (unsigned int i = 0; i < pvrHeader.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
|
|
||||||
|
|
||||||
// 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
|
memcpy(image.data, fileDataPtr, dataSize);
|
||||||
fread(image.data, dataSize, 1, pvrFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 (fileDataPtr != NULL)
|
||||||
|
|
||||||
if (astcFile == NULL)
|
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load ASTC file", fileName);
|
ASTCHeader *astcHeader = (ASTCHeader *)fileDataPtr;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASTCHeader astcHeader = { 0 };
|
|
||||||
|
|
||||||
// Get ASTC image header
|
if ((astcHeader->id[3] != 0x5c) || (astcHeader->id[2] != 0xa1) || (astcHeader->id[1] != 0xab) || (astcHeader->id[0] != 0x13))
|
||||||
fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);
|
|
||||||
|
|
||||||
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.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.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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue