mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-25 10:22:33 -05:00
Improved mipmaps support and image loading
This commit is contained in:
378
src/textures.c
378
src/textures.c
@ -123,6 +123,32 @@ Image LoadImage(const char *fileName)
|
||||
return image;
|
||||
}
|
||||
|
||||
// Load image data from Color array data (RGBA - 32bit)
|
||||
Image LoadImageEx(Color *pixels, int width, int height)
|
||||
{
|
||||
Image image;
|
||||
image.data = NULL;
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.mipmaps = 1;
|
||||
image.format = UNCOMPRESSED_R8G8B8A8;
|
||||
|
||||
int k = 0;
|
||||
|
||||
image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image.width*image.height*4; i += 4)
|
||||
{
|
||||
((unsigned char *)image.data)[i] = pixels[k].r;
|
||||
((unsigned char *)image.data)[i + 1] = pixels[k].g;
|
||||
((unsigned char *)image.data)[i + 2] = pixels[k].b;
|
||||
((unsigned char *)image.data)[i + 3] = pixels[k].a;
|
||||
k++;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -243,12 +269,12 @@ Texture2D LoadTexture(const char *fileName)
|
||||
Image image = LoadImage(fileName);
|
||||
|
||||
#if defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
|
||||
ConvertToPOT(&image, BLANK);
|
||||
ImageConvertToPOT(&image, BLANK);
|
||||
#endif
|
||||
|
||||
if (image.data != NULL)
|
||||
{
|
||||
texture = LoadTextureFromImage(image, false);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
}
|
||||
else
|
||||
@ -261,7 +287,7 @@ Texture2D LoadTexture(const char *fileName)
|
||||
return texture;
|
||||
}
|
||||
|
||||
Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount, bool genMipmaps)
|
||||
Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount)
|
||||
{
|
||||
Texture2D texture;
|
||||
|
||||
@ -270,14 +296,14 @@ Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, in
|
||||
texture.mipmaps = mipmapCount;
|
||||
texture.format = textureFormat;
|
||||
|
||||
texture.id = rlglLoadTexture(data, width, height, textureFormat, mipmapCount, genMipmaps);
|
||||
texture.id = rlglLoadTexture(data, width, height, textureFormat, mipmapCount);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Load a texture from image data
|
||||
// NOTE: image is not unloaded, it must be done manually
|
||||
Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
|
||||
Texture2D LoadTextureFromImage(Image image)
|
||||
{
|
||||
Texture2D texture;
|
||||
|
||||
@ -288,7 +314,7 @@ Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
|
||||
texture.mipmaps = 0;
|
||||
texture.format = 0;
|
||||
|
||||
texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps, false);
|
||||
texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
|
||||
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
@ -304,7 +330,7 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
|
||||
Texture2D texture;
|
||||
|
||||
Image image = LoadImageFromRES(rresName, resId);
|
||||
texture = LoadTextureFromImage(image, false);
|
||||
texture = LoadTextureFromImage(image);
|
||||
UnloadImage(image);
|
||||
|
||||
return texture;
|
||||
@ -324,7 +350,7 @@ void UnloadTexture(Texture2D texture)
|
||||
|
||||
// Convert image to POT (power-of-two)
|
||||
// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5)
|
||||
void ConvertToPOT(Image *image, Color fillColor)
|
||||
void ImageConvertToPOT(Image *image, Color fillColor)
|
||||
{
|
||||
// TODO: Review for new image struct
|
||||
/*
|
||||
@ -447,144 +473,174 @@ Color *GetPixelData(Image image)
|
||||
return pixels;
|
||||
}
|
||||
|
||||
// Fill image data with pixels Color data (RGBA - 32bit)
|
||||
// NOTE: Data is transformed to desired format
|
||||
Image LoadImageFromData(Color *pixels, int width, int height, int format)
|
||||
// Get pixel data from GPU texture and return an Image
|
||||
Image GetTextureData(Texture2D texture)
|
||||
{
|
||||
Image image;
|
||||
image.data = NULL;
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.mipmaps = 1;
|
||||
image.format = format;
|
||||
|
||||
int k = 0;
|
||||
|
||||
switch (format)
|
||||
image.data = rlglReadTexturePixels(texture.id, texture.format);
|
||||
|
||||
if (image.data != NULL)
|
||||
{
|
||||
case UNCOMPRESSED_GRAYSCALE:
|
||||
{
|
||||
image.data = (unsigned char *)malloc(image.width*image.height*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image.width*image.height; i++)
|
||||
{
|
||||
((unsigned char *)image.data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_GRAY_ALPHA:
|
||||
{
|
||||
image.data = (unsigned char *)malloc(image.width*image.height*2*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image.width*image.height*2; i += 2)
|
||||
{
|
||||
((unsigned char *)image.data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
|
||||
((unsigned char *)image.data)[i + 1] = pixels[k].a;
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R5G6B5:
|
||||
{
|
||||
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
|
||||
for (int i = 0; i < image.width*image.height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*31/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*63/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*31/255));
|
||||
|
||||
((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R8G8B8:
|
||||
{
|
||||
image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image.width*image.height*3; i += 3)
|
||||
{
|
||||
((unsigned char *)image.data)[i] = pixels[k].r;
|
||||
((unsigned char *)image.data)[i + 1] = pixels[k].g;
|
||||
((unsigned char *)image.data)[i + 2] = pixels[k].b;
|
||||
k++;
|
||||
}
|
||||
} break;
|
||||
case UNCOMPRESSED_R5G5B5A1:
|
||||
{
|
||||
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a = 1;
|
||||
|
||||
for (int i = 0; i < image.width*image.height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*31/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*31/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*31/255));
|
||||
a = (pixels[k].a > 50) ? 1 : 0;
|
||||
|
||||
((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R4G4B4A4:
|
||||
{
|
||||
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a;
|
||||
|
||||
for (int i = 0; i < image.width*image.height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*15/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*15/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*15/255));
|
||||
a = (unsigned char)(round((float)pixels[k].a*15/255));
|
||||
|
||||
((unsigned short *)image.data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R8G8B8A8:
|
||||
{
|
||||
image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image.width*image.height*4; i += 4)
|
||||
{
|
||||
((unsigned char *)image.data)[i] = pixels[k].r;
|
||||
((unsigned char *)image.data)[i + 1] = pixels[k].g;
|
||||
((unsigned char *)image.data)[i + 2] = pixels[k].b;
|
||||
((unsigned char *)image.data)[i + 3] = pixels[k].a;
|
||||
k++;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
TraceLog(WARNING, "Format not recognized, image could not be loaded");
|
||||
|
||||
return image;
|
||||
} break;
|
||||
image.width = texture.width;
|
||||
image.height = texture.height;
|
||||
image.format = texture.format;
|
||||
image.mipmaps = 1;
|
||||
}
|
||||
|
||||
else TraceLog(WARNING, "Texture pixel data could not be obtained");
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// Convert image data to desired format
|
||||
void ImageConvertFormat(Image *image, int newFormat)
|
||||
{
|
||||
if ((image->format != newFormat) && (image->format < 8) && (newFormat < 8))
|
||||
{
|
||||
Color *pixels = GetPixelData(*image);
|
||||
|
||||
free(image->data);
|
||||
|
||||
image->format = newFormat;
|
||||
|
||||
int k = 0;
|
||||
|
||||
switch (image->format)
|
||||
{
|
||||
case UNCOMPRESSED_GRAYSCALE:
|
||||
{
|
||||
image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_GRAY_ALPHA:
|
||||
{
|
||||
image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image->width*image->height*2; i += 2)
|
||||
{
|
||||
((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f);
|
||||
((unsigned char *)image->data)[i + 1] = pixels[k].a;
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R5G6B5:
|
||||
{
|
||||
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*31/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*63/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*31/255));
|
||||
|
||||
((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R8G8B8:
|
||||
{
|
||||
image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image->width*image->height*3; i += 3)
|
||||
{
|
||||
((unsigned char *)image->data)[i] = pixels[k].r;
|
||||
((unsigned char *)image->data)[i + 1] = pixels[k].g;
|
||||
((unsigned char *)image->data)[i + 2] = pixels[k].b;
|
||||
k++;
|
||||
}
|
||||
} break;
|
||||
case UNCOMPRESSED_R5G5B5A1:
|
||||
{
|
||||
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a = 1;
|
||||
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*31/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*31/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*31/255));
|
||||
a = (pixels[k].a > 50) ? 1 : 0;
|
||||
|
||||
((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R4G4B4A4:
|
||||
{
|
||||
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
|
||||
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a;
|
||||
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
r = (unsigned char)(round((float)pixels[k].r*15/255));
|
||||
g = (unsigned char)(round((float)pixels[k].g*15/255));
|
||||
b = (unsigned char)(round((float)pixels[k].b*15/255));
|
||||
a = (unsigned char)(round((float)pixels[k].a*15/255));
|
||||
|
||||
((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a;
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case UNCOMPRESSED_R8G8B8A8:
|
||||
{
|
||||
image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char));
|
||||
|
||||
for (int i = 0; i < image->width*image->height*4; i += 4)
|
||||
{
|
||||
((unsigned char *)image->data)[i] = pixels[k].r;
|
||||
((unsigned char *)image->data)[i + 1] = pixels[k].g;
|
||||
((unsigned char *)image->data)[i + 2] = pixels[k].b;
|
||||
((unsigned char *)image->data)[i + 3] = pixels[k].a;
|
||||
k++;
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
free(pixels);
|
||||
}
|
||||
else TraceLog(WARNING, "Image data format is compressed, can not be converted");
|
||||
}
|
||||
|
||||
/*
|
||||
Image ImageCopy(Image image);
|
||||
void ImageCrop(Image *image, Rectangle crop);
|
||||
void ImageResize(Image *image, int newWidth, int newHeight);
|
||||
void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec);
|
||||
void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color);
|
||||
*/
|
||||
|
||||
// Generate GPU mipmaps for a texture
|
||||
void GenTextureMipmaps(Texture2D texture)
|
||||
{
|
||||
rlglGenerateMipmaps(texture.id);
|
||||
}
|
||||
|
||||
// Draw a Texture2D
|
||||
void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
|
||||
{
|
||||
@ -1224,6 +1280,8 @@ static Image LoadASTC(const char *fileName)
|
||||
// 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]);
|
||||
|
||||
// NOTE: ASTC format only contains one mipmap level
|
||||
image.mipmaps = 1;
|
||||
|
||||
TraceLog(DEBUG, "ASTC image width: %i", image.width);
|
||||
@ -1250,5 +1308,49 @@ static Image LoadASTC(const char *fileName)
|
||||
fclose(astcFile);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// Load RAW image file
|
||||
static Image LoadRAW(const char *fileName, int width, int height, int format, int headerSize)
|
||||
{
|
||||
Image image;
|
||||
|
||||
image.data = NULL;
|
||||
image.width = 0;
|
||||
image.height = 0;
|
||||
image.mipmaps = 0;
|
||||
image.format = 0;
|
||||
|
||||
FILE *rawFile = fopen(fileName, "rb");
|
||||
|
||||
if (rawFile == NULL)
|
||||
{
|
||||
TraceLog(WARNING, "[%s] RAW image file could not be opened", fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET);
|
||||
|
||||
int dataSize = 0;
|
||||
|
||||
// TODO: Calculate data size and allocate memory
|
||||
switch (format)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fread(image.data, dataSize, 1, rawFile);
|
||||
|
||||
// TODO: Check if data have been read
|
||||
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.mipmaps = 0;
|
||||
image.format = format;
|
||||
|
||||
fclose(rawFile);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
Reference in New Issue
Block a user