aboutsummaryrefslogtreecommitdiff
path: root/src/textures.c
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2015-07-28 17:38:37 +0200
committerRay <raysan5@gmail.com>2015-07-28 17:38:37 +0200
commit8b3a82688e82922819d24494c08e24570c03bdc4 (patch)
tree1df1379dfc4948477b664023d2ce0100d83d1783 /src/textures.c
parenta59433e7a3b22d5ded7505689fb44f1927194077 (diff)
parent067b884f395b7b6d4c179cb3d58b0d17a02950ec (diff)
downloadraylib-8b3a82688e82922819d24494c08e24570c03bdc4.tar.gz
raylib-8b3a82688e82922819d24494c08e24570c03bdc4.zip
Merge pull request #24 from raysan5/develop
Integrate Develop branch
Diffstat (limited to 'src/textures.c')
-rw-r--r--src/textures.c480
1 files changed, 310 insertions, 170 deletions
diff --git a/src/textures.c b/src/textures.c
index e6c6cccb..b7ab1f7e 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -123,6 +123,82 @@ 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 RAW file
+Image LoadImageRaw(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);
+
+ unsigned int size = width*height;
+
+ switch (format)
+ {
+ case UNCOMPRESSED_GRAYSCALE: image.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha)
+ case UNCOMPRESSED_GRAY_ALPHA: image.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels)
+ case UNCOMPRESSED_R5G6B5: image.data = (unsigned short *)malloc(size); break; // 16 bpp
+ case UNCOMPRESSED_R8G8B8: image.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp
+ case UNCOMPRESSED_R5G5B5A1: image.data = (unsigned short *)malloc(size); break; // 16 bpp (1 bit alpha)
+ case UNCOMPRESSED_R4G4B4A4: image.data = (unsigned short *)malloc(size); break; // 16 bpp (4 bit alpha)
+ case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp
+ default: TraceLog(WARNING, "Image format not suported"); break;
+ }
+
+ fread(image.data, size, 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;
+}
+
// 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 +319,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 +337,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 +346,26 @@ 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 an image as texture from rRES file (raylib Resource)
+Texture2D LoadTextureFromRES(const char *rresName, int resId)
+{
+ Texture2D texture;
+
+ Image image = LoadImageFromRES(rresName, resId);
+ texture = LoadTextureFromImage(image);
+ UnloadImage(image);
+
+ return texture;
+}
+
// Load a texture from image data
// NOTE: image is not unloaded, it must be done manually
-Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
+Texture2D LoadTextureFromImage(Image image)
{
Texture2D texture;
@@ -288,7 +376,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;
@@ -298,18 +386,6 @@ Texture2D LoadTextureFromImage(Image image, bool genMipmaps)
return texture;
}
-// Load an image as texture from rRES file (raylib Resource)
-Texture2D LoadTextureFromRES(const char *rresName, int resId)
-{
- Texture2D texture;
-
- Image image = LoadImageFromRES(rresName, resId);
- texture = LoadTextureFromImage(image, false);
- UnloadImage(image);
-
- return texture;
-}
-
// Unload image from CPU memory (RAM)
void UnloadImage(Image image)
{
@@ -322,46 +398,8 @@ void UnloadTexture(Texture2D texture)
rlDeleteTextures(texture.id);
}
-// Convert image to POT (power-of-two)
-// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5)
-void ConvertToPOT(Image *image, Color fillColor)
-{
- // TODO: Review for new image struct
- /*
- // Just add the required amount of pixels at the right and bottom sides of image...
- int potWidth = GetNextPOT(image->width);
- int potHeight = GetNextPOT(image->height);
-
- // Check if POT texture generation is required (if texture is not already POT)
- if ((potWidth != image->width) || (potHeight != image->height))
- {
- Color *imgDataPixelPOT = NULL;
-
- // Generate POT array from NPOT data
- imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
-
- for (int j = 0; j < potHeight; j++)
- {
- for (int i = 0; i < potWidth; i++)
- {
- if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->data[j*image->width + i];
- else imgDataPixelPOT[j*potWidth + i] = fillColor;
- }
- }
-
- TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
-
- free(image->pixels);
-
- image->pixels = imgDataPixelPOT;
- image->width = potWidth;
- image->height = potHeight;
- }
- */
-}
-
// Get pixel data from image in the form of Color struct array
-Color *GetPixelData(Image image)
+Color *GetImageData(Image image)
{
Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color));
@@ -447,142 +485,242 @@ 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++;
- }
+ 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");
- } break;
- case UNCOMPRESSED_GRAY_ALPHA:
+ 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 = GetImageData(*image);
+
+ free(image->data);
+
+ image->format = newFormat;
+
+ int k = 0;
+
+ switch (image->format)
{
- 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)
+ case UNCOMPRESSED_GRAYSCALE:
{
- ((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++;
- }
+ 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++)
+ } break;
+ case UNCOMPRESSED_R5G6B5:
{
- 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));
+ image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
+
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
- ((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)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++;
- }
+ 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)
+ } break;
+ case UNCOMPRESSED_R8G8B8:
{
- ((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++)
+ 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:
{
- 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;
+ image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
- ((unsigned short *)image.data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a;
-
- k++;
- }
+ 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++)
+ } break;
+ case UNCOMPRESSED_R4G4B4A4:
{
- 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));
+ 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++;
+ }
- ((unsigned short *)image.data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a;
+ } 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");
+}
- k++;
- }
-
- } break;
- case UNCOMPRESSED_R8G8B8A8:
+
+// Convert image to POT (power-of-two)
+// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5)
+void ImageConvertToPOT(Image *image, Color fillColor)
+{
+ // TODO: Review for new image struct
+ /*
+ // Just add the required amount of pixels at the right and bottom sides of image...
+ int potWidth = GetNextPOT(image->width);
+ int potHeight = GetNextPOT(image->height);
+
+ // Check if POT texture generation is required (if texture is not already POT)
+ if ((potWidth != image->width) || (potHeight != image->height))
+ {
+ Color *imgDataPixelPOT = NULL;
+
+ // Generate POT array from NPOT data
+ imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
+
+ for (int j = 0; j < potHeight; j++)
{
- 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)
+ for (int i = 0; i < potWidth; i++)
{
- ((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++;
+ if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->data[j*image->width + i];
+ else imgDataPixelPOT[j*potWidth + i] = fillColor;
}
- } break;
- default:
- {
- TraceLog(WARNING, "Format not recognized, image could not be loaded");
-
- return image;
- } break;
+ }
+
+ TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
+
+ free(image->pixels);
+
+ image->pixels = imgDataPixelPOT;
+ image->width = potWidth;
+ image->height = potHeight;
}
+ */
+}
- return image;
+// Copy an image to a new image
+Image ImageCopy(Image image)
+{
+ Image newImage;
+
+ int size = image.width*image.height;
+
+ switch (image.format)
+ {
+ case UNCOMPRESSED_GRAYSCALE: newImage.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha)
+ case UNCOMPRESSED_GRAY_ALPHA: newImage.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels)
+ case UNCOMPRESSED_R5G6B5: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp
+ case UNCOMPRESSED_R8G8B8: newImage.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp
+ case UNCOMPRESSED_R5G5B5A1: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (1 bit alpha)
+ case UNCOMPRESSED_R4G4B4A4: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (4 bit alpha)
+ case UNCOMPRESSED_R8G8B8A8: newImage.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp
+ default: TraceLog(WARNING, "Image format not suported for copy"); break;
+ }
+
+ if (newImage.data != NULL)
+ {
+ // NOTE: Size must be provided in bytes
+ memcpy(newImage.data, image.data, size);
+
+ newImage.width = image.width;
+ newImage.height = image.height;
+ newImage.mipmaps = image.mipmaps;
+ newImage.format = image.format;
+ }
+
+ return newImage;
+}
+
+// TODO: Some useful functions to deal with images
+//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
@@ -1224,6 +1362,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);
@@ -1251,4 +1391,4 @@ static Image LoadASTC(const char *fileName)
}
return image;
-} \ No newline at end of file
+}