diff options
| author | Ray <raysan5@gmail.com> | 2015-07-28 17:38:37 +0200 |
|---|---|---|
| committer | Ray <raysan5@gmail.com> | 2015-07-28 17:38:37 +0200 |
| commit | 8b3a82688e82922819d24494c08e24570c03bdc4 (patch) | |
| tree | 1df1379dfc4948477b664023d2ce0100d83d1783 /src/textures.c | |
| parent | a59433e7a3b22d5ded7505689fb44f1927194077 (diff) | |
| parent | 067b884f395b7b6d4c179cb3d58b0d17a02950ec (diff) | |
| download | raylib-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.c | 480 |
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 +} |
