From 9bf411f5805e246c790beb0556a6912f6ca33452 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 6 Oct 2015 17:30:03 +0200 Subject: Added a bunch of image manipulation functions: Renamed functions (for coherence with new ones): - ImageConvertToPOT() -> ImageToPOT() - ImageConvertFormat() -> ImageFormat() New functions added (IN PROGRESS): - ImageCopy() - ImageCrop() - ImageResize() (Uses stb_image_resize.h) - ImageDraw() - ImageDrawText() - ImageDrawTextEx() - ImageFlipVertical() - ImageFlipHorizontal() - ImageColorInvert() - ImageColorGrayscale() - ImageColorContrast() - ImageColorBrightness() --- src/textures.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 243 insertions(+), 9 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 165d9358..96653ed3 100644 --- a/src/textures.c +++ b/src/textures.c @@ -42,6 +42,9 @@ #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" // Used to read image data (multiple formats support) +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "stb_image_resize.h" + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -322,7 +325,7 @@ Texture2D LoadTexture(const char *fileName) Image image = LoadImage(fileName); #if defined(PLATFORM_WEB) - ImageConvertToPOT(&image, BLANK); + ImageToPOT(&image, BLANK); #endif if (image.data != NULL) @@ -526,7 +529,7 @@ Image GetTextureData(Texture2D texture) } // Convert image data to desired format -void ImageConvertFormat(Image *image, int newFormat) +void ImageFormat(Image *image, int newFormat) { if (image->format != newFormat) { @@ -666,7 +669,7 @@ void ImageConvertFormat(Image *image, int newFormat) // Convert image to POT (power-of-two) // NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) -void ImageConvertToPOT(Image *image, Color fillColor) +void ImageToPOT(Image *image, Color fillColor) { Color *pixels = GetImageData(*image); // Get pixels data @@ -704,7 +707,7 @@ void ImageConvertToPOT(Image *image, Color fillColor) free(pixelsPOT); // Free POT pixels data - ImageConvertFormat(image, format); // Reconvert image to previous format + ImageFormat(image, format); // Reconvert image to previous format } } @@ -741,11 +744,242 @@ Image ImageCopy(Image image) 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) {} +// Crop an image to area defined by a rectangle +// NOTE: Security checks are performed in case rectangle goes out of bounds +void ImageCrop(Image *image, Rectangle crop) +{ + // Security checks to make sure cropping rectangle is inside margins + if ((crop.x + crop.width) > image->width) + { + crop.width = image->width - crop.x; + TraceLog(WARNING, "Crop rectangle width out of bounds, rescaled crop width: %i", crop.width); + } + + if ((crop.y + crop.height) > image->height) + { + crop.height = image->height - crop.y; + TraceLog(WARNING, "Crop rectangle height out of bounds, rescaled crop height: %i", crop.height); + } + + if ((crop.x < image->width) && (crop.y < image->height)) + { + // Start the cropping process + Color *pixels = GetImageData(*image); // Get data as Color pixels array + Color *cropPixels = (Color *)malloc(crop.width*crop.height*sizeof(Color)); + + for (int j = crop.y; j < (crop.y + crop.height); j++) + { + for (int i = crop.x; i < (crop.x + crop.width); i++) + { + cropPixels[(j - crop.y)*crop.width + (i - crop.x)] = pixels[j*image->width + i]; + } + } + + free(pixels); + + int format = image->format; + + UnloadImage(*image); + + *image = LoadImageEx(cropPixels, crop.width, crop.height); + + free(cropPixels); + + // Reformat 32bit RGBA image to original format + ImageFormat(image, format); + } + else + { + TraceLog(WARNING, "Image can not be cropped, crop rectangle out of bounds"); + } +} + +// Resize and image to new size +// NOTE: Uses stb default scaling filter +void ImageResize(Image *image, int newWidth, int newHeight) +{ + // Get data as Color pixels array to work with it + Color *pixels = GetImageData(*image); + Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color)); + + // NOTE: Color data is casted to (unsigned char *), there shouldn't been any problem... + stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4); + + int format = image->format; + + UnloadImage(*image); + + *image = LoadImageEx(output, newWidth, newHeight); + + free(output); + + // Reformat 32bit RGBA image to original format + ImageFormat(image, format); + + free(pixels); +} + +// Draw an image (source) within an image (destination) +void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) +{ + // Security checks to avoid size and rectangle issues (out of bounds) + // Check that srcRec is inside src image + if (srcRec.x < 0) srcRec.x = 0; + if (srcRec.y < 0) srcRec.y = 0; + + if ((srcRec.x + srcRec.width) > src.width) + { + srcRec.width = src.width - srcRec.x; + TraceLog(WARNING, "Source rectangle width out of bounds, rescaled width: %i", srcRec.width); + } + + if ((srcRec.y + srcRec.height) > src.height) + { + srcRec.height = src.height - srcRec.y; + TraceLog(WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height); + } + + // Check that dstRec is inside dst image + if (dstRec.x < 0) dstRec.x = 0; + if (dstRec.y < 0) dstRec.y = 0; + + if ((dstRec.x + dstRec.width) > dst->width) + { + dstRec.width = dst->width - dstRec.x; + TraceLog(WARNING, "Destination rectangle width out of bounds, rescaled width: %i", dstRec.width); + } + + if ((dstRec.y + dstRec.height) > dst->height) + { + dstRec.height = dst->height - dstRec.y; + TraceLog(WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height); + } + + // Get dstination image data as Color pixels array to work with it + Color *dstPixels = GetImageData(*dst); + + Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it + ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle + + // Scale source image in case destination rec size is different than source rec size + if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) + { + ImageResize(&srcCopy, dstRec.width, dstRec.height); + } + + // Get source image data as Color array + Color *srcPixels = GetImageData(srcCopy); + + UnloadImage(srcCopy); + + // Blit pixels, copy source image into destination + for (int j = dstRec.y; j < (dstRec.y + dstRec.height); j++) + { + for (int i = dstRec.x; i < (dstRec.x + dstRec.width); i++) + { + dstPixels[j*dst->width + i] = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)]; + } + } + + free(srcPixels); + + int format = dst->format; + + UnloadImage(*dst); + + *dst = LoadImageEx(dstPixels, dst->width, dst->height); + + free(dstPixels); + + ImageFormat(dst, format); +} + +// Draw a text within an image (destination) +// NOTE: Default font is used +void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color) +{ + ImageDrawTextEx(dst, GetDefaultFont(), text, position, size, color); +} + +// Draw a text within an image (destination) +// NOTE: Defined SpriteFont is used +void ImageDrawTextEx(Image *dst, SpriteFont font, const char *text, Vector2 position, int size, Color color) +{ + Image imFont = GetTextureData(font.texture); + + int posX = (int)position.x; + + Rectangle srcRec = { 0, 0, 0, font.size }; + Rectangle dstRec = { posX, (int)position.y, 0, font.size }; + int length = strlen(text); + + for (int i = 0; i < length; i++) + { + srcRec.x = font.charRecs[(int)text[i] - 32].x; + srcRec.y = font.charRecs[(int)text[i] - 32].y; + srcRec.width = font.charRecs[(int)text[i] - 32].width; + dstRec.width = font.charRecs[(int)text[i] - 32].width; + + printf("[%c] Source Rectangle: %i, %i, %i, %i\n", text[i], srcRec.x, srcRec.y, srcRec.width, srcRec.height); + printf("[%c] Destination Rectangle: %i, %i, %i, %i\n\n", text[i], dstRec.x, dstRec.y, dstRec.width, dstRec.height); + + ImageDraw(dst, imFont, srcRec, dstRec); + + dstRec.x += srcRec.width; + } + + UnloadImage(imFont); +} + +void ImageFlipVertical(Image *image) +{ + Image copy = ImageCopy(*image); + ImageFormat(©, UNCOMPRESSED_R8G8B8A8); + + Color *srcPixels = GetImageData(copy); // Get source image data as Color array + Color *dstPixels = GetImageData(copy); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + //dstPixels[y*image->width + x] = srcPixels[]; + } + } + + free(srcPixels); + free(dstPixels); + + ImageFormat(©, image->format); + + UnloadImage(*image); + image = © +} + +void ImageFlipHorizontal(Image *image) +{ + +} + +void ImageColorInvert(Image *image) +{ + +} + +void ImageColorGrayscale(Image *image) +{ + ImageFormat(image, UNCOMPRESSED_GRAYSCALE); +} + +void ImageColorContrast(Image *image, float contrast) +{ + +} + +void ImageColorBrightness(Image *image, int brightness) +{ + +} // Generate GPU mipmaps for a texture void GenTextureMipmaps(Texture2D texture) -- cgit v1.2.3 From 8c117cfb570874e726d6a24a4b85573e0c7b1669 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 24 Oct 2015 11:19:04 +0200 Subject: Reviewed NPOT messages and usage --- src/rlgl.c | 2 +- src/textures.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/textures.c') diff --git a/src/rlgl.c b/src/rlgl.c index d632a3ac..797833e6 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1028,7 +1028,7 @@ void rlglInit(void) else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported"); - else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures not supported"); + else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures support is limited (no-mipmaps, no-repeat"); #endif if (texCompDXTSupported) TraceLog(INFO, "[EXTENSION] DXT compressed textures supported"); diff --git a/src/textures.c b/src/textures.c index 96653ed3..6307702f 100644 --- a/src/textures.c +++ b/src/textures.c @@ -324,10 +324,6 @@ Texture2D LoadTexture(const char *fileName) Image image = LoadImage(fileName); -#if defined(PLATFORM_WEB) - ImageToPOT(&image, BLANK); -#endif - if (image.data != NULL) { texture = LoadTextureFromImage(image); @@ -984,7 +980,19 @@ void ImageColorBrightness(Image *image, int brightness) // Generate GPU mipmaps for a texture void GenTextureMipmaps(Texture2D texture) { +#if PLATFORM_WEB + int potWidth = GetNextPOT(image->width); + int potHeight = GetNextPOT(image->height); + + // Check if texture is POT + if ((potWidth != image->width) || (potHeight != image->height)) + { + TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures"); + } + else rlglGenerateMipmaps(texture.id); +#else rlglGenerateMipmaps(texture.id); +#endif } // Draw a Texture2D -- cgit v1.2.3 From afdf357fbee7f01535bddefb4e62cb1308ed55b5 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 25 Oct 2015 01:50:15 +0200 Subject: Added some image manipulation functions Added (or completed functions): Image ImageText(const char *text, int fontSize, Color color); Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint); void ImageFlipVertical(Image *image); void ImageFlipHorizontal(Image *image); void ImageColorTint(Image *image, Color color); void ImageColorInvert(Image *image); void ImageColorGrayscale(Image *image); void ImageColorContrast(Image *image, float contrast); void ImageColorBrightness(Image *image, int brightness); --- src/raylib.h | 21 ++--- src/text.c | 4 +- src/textures.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 232 insertions(+), 54 deletions(-) (limited to 'src/textures.c') diff --git a/src/raylib.h b/src/raylib.h index 74e6208f..9067c77d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -547,20 +547,21 @@ void UnloadImage(Image image); void UnloadTexture(Texture2D texture); // Unload texture from GPU memory Color *GetImageData(Image image); // Get pixel data from image as a Color struct array Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image -void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) -void ImageFormat(Image *image, int newFormat); // Convert image data to desired format +void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) +void ImageFormat(Image *image, int newFormat); // Convert image data to desired format Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image -void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color); // Draw text within an image -void ImageDrawTextEx(Image *dst, SpriteFont font, const char *text, Vector2 position, int size, Color color); -void ImageFlipVertical(Image *image); -void ImageFlipHorizontal(Image *image); -void ImageColorInvert(Image *image); -void ImageColorGrayscale(Image *image); -void ImageColorContrast(Image *image, float contrast); -void ImageColorBrightness(Image *image, int brightness); +Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) +Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) +void ImageFlipVertical(Image *image); // Flip image vertically +void ImageFlipHorizontal(Image *image); // Flip image horizontally +void ImageColorTint(Image *image, Color color); // Modify image color: tint +void ImageColorInvert(Image *image); // Modify image color: invert +void ImageColorGrayscale(Image *image); // Modify bimage color: grayscale +void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) +void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D diff --git a/src/text.c b/src/text.c index 381aa052..5e947187 100644 --- a/src/text.c +++ b/src/text.c @@ -279,9 +279,7 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color) Vector2 position = { (float)posX, (float)posY }; int defaultFontSize = 10; // Default Font chars height in pixel - if (fontSize < defaultFontSize) fontSize = defaultFontSize; - int spacing = fontSize / defaultFontSize; DrawTextEx(defaultFont, text, position, fontSize, spacing, color); @@ -380,7 +378,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int for (int i = 0; i < len; i++) { - textWidth += spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width; + if (text[i] != '\n') textWidth += spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width; } if (fontSize <= spriteFont.charRecs[0].height) scaleFactor = 1.0f; diff --git a/src/textures.c b/src/textures.c index 6307702f..66d2afc5 100644 --- a/src/textures.c +++ b/src/textures.c @@ -806,12 +806,9 @@ void ImageResize(Image *image, int newWidth, int newHeight) UnloadImage(*image); *image = LoadImageEx(output, newWidth, newHeight); - - free(output); - - // Reformat 32bit RGBA image to original format - ImageFormat(image, format); + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + free(output); free(pixels); } @@ -877,104 +874,286 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) } } - free(srcPixels); - - int format = dst->format; - - UnloadImage(*dst); + UnloadImage(*dst); // NOTE: Only dst->data is unloaded *dst = LoadImageEx(dstPixels, dst->width, dst->height); + ImageFormat(dst, dst->format); + free(srcPixels); free(dstPixels); - - ImageFormat(dst, format); } -// Draw a text within an image (destination) -// NOTE: Default font is used -void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color) +// Create an image from text (default font) +Image ImageText(const char *text, int fontSize, Color color) { - ImageDrawTextEx(dst, GetDefaultFont(), text, position, size, color); + int defaultFontSize = 10; // Default Font chars height in pixel + if (fontSize < defaultFontSize) fontSize = defaultFontSize; + int spacing = fontSize / defaultFontSize; + + Image imText = ImageTextEx(GetDefaultFont(), text, fontSize, spacing, color); + + return imText; } -// Draw a text within an image (destination) -// NOTE: Defined SpriteFont is used -void ImageDrawTextEx(Image *dst, SpriteFont font, const char *text, Vector2 position, int size, Color color) +// Create an image from text (custom sprite font) +Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint) { + int length = strlen(text); + int posX = 0; + + Vector2 imSize = MeasureTextEx(font, text, font.size, spacing); + + // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); - int posX = (int)position.x; + ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Required for color tint + ImageColorTint(&imFont, tint); // Apply color tint to font + + Color *fontPixels = GetImageData(imFont); - Rectangle srcRec = { 0, 0, 0, font.size }; - Rectangle dstRec = { posX, (int)position.y, 0, font.size }; - int length = strlen(text); + // Create image to store text + Color *pixels = (Color *)malloc(sizeof(Color)*(int)imSize.x*(int)imSize.y); for (int i = 0; i < length; i++) { - srcRec.x = font.charRecs[(int)text[i] - 32].x; - srcRec.y = font.charRecs[(int)text[i] - 32].y; - srcRec.width = font.charRecs[(int)text[i] - 32].width; - dstRec.width = font.charRecs[(int)text[i] - 32].width; - - printf("[%c] Source Rectangle: %i, %i, %i, %i\n", text[i], srcRec.x, srcRec.y, srcRec.width, srcRec.height); - printf("[%c] Destination Rectangle: %i, %i, %i, %i\n\n", text[i], dstRec.x, dstRec.y, dstRec.width, dstRec.height); + Rectangle letterRec = font.charRecs[(int)text[i] - 32]; - ImageDraw(dst, imFont, srcRec, dstRec); + for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++) + { + for (int x = posX; x < (posX + letterRec.width); x++) + { + pixels[(y - letterRec.y)*(int)imSize.x + x] = fontPixels[y*font.texture.width + (x - posX + letterRec.x)]; + } + } - dstRec.x += srcRec.width; + posX += letterRec.width + spacing; } UnloadImage(imFont); + + Image imText = LoadImageEx(pixels, (int)imSize.x, (int)imSize.y); + + // Scale image depending on text size + if (fontSize > (int)imSize.y) + { + float scaleFactor = (float)fontSize/imSize.y; + TraceLog(INFO, "Scalefactor: %f", scaleFactor); + + // TODO: Allow nearest-neighbor scaling algorithm + ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); + } + + free(pixels); + free(fontPixels); + + return imText; } +// Flip image vertically void ImageFlipVertical(Image *image) { - Image copy = ImageCopy(*image); - ImageFormat(©, UNCOMPRESSED_R8G8B8A8); - - Color *srcPixels = GetImageData(copy); // Get source image data as Color array - Color *dstPixels = GetImageData(copy); + Color *srcPixels = GetImageData(*image); + Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) { - //dstPixels[y*image->width + x] = srcPixels[]; + dstPixels[y*image->width + x] = srcPixels[(image->height - 1 - y)*image->width + x]; } } + Image processed = LoadImageEx(dstPixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(srcPixels); free(dstPixels); - ImageFormat(©, image->format); + image->data = processed.data; +} + +// Flip image horizontally +void ImageFlipHorizontal(Image *image) +{ + Color *srcPixels = GetImageData(*image); + Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + dstPixels[y*image->width + x] = srcPixels[y*image->width + (image->width - 1 - x)]; + } + } + + Image processed = LoadImageEx(dstPixels, image->width, image->height); + ImageFormat(&processed, image->format); UnloadImage(*image); - image = © + + free(srcPixels); + free(dstPixels); + + image->data = processed.data; } -void ImageFlipHorizontal(Image *image) +// Modify image color: tint +void ImageColorTint(Image *image, Color color) { + Color *pixels = GetImageData(*image); + + float cR = (float)color.r/255; + float cG = (float)color.g/255; + float cB = (float)color.b/255; + float cA = (float)color.a/255; + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + unsigned char r = 255*((float)pixels[y*image->width + x].r/255*cR); + unsigned char g = 255*((float)pixels[y*image->width + x].g/255*cG); + unsigned char b = 255*((float)pixels[y*image->width + x].b/255*cB); + unsigned char a = 255*((float)pixels[y*image->width + x].a/255*cA); + + pixels[y*image->width + x].r = r; + pixels[y*image->width + x].g = g; + pixels[y*image->width + x].b = b; + pixels[y*image->width + x].a = a; + } + } + + Image processed = LoadImageEx(pixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(pixels); + + TraceLog(INFO,"color tint applied"); + + image->data = processed.data; } +// Modify image color: invert void ImageColorInvert(Image *image) { + Color *pixels = GetImageData(*image); + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + pixels[y*image->width + x].r = 255 - pixels[y*image->width + x].r; + pixels[y*image->width + x].g = 255 - pixels[y*image->width + x].g; + pixels[y*image->width + x].b = 255 - pixels[y*image->width + x].b; + } + } + + Image processed = LoadImageEx(pixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(pixels); + + image->data = processed.data; } +// Modify image color: grayscale void ImageColorGrayscale(Image *image) { ImageFormat(image, UNCOMPRESSED_GRAYSCALE); } +// Modify image color: contrast +// NOTE: Contrast values between -100 and 100 void ImageColorContrast(Image *image, float contrast) { + if (contrast < -100) contrast = -100; + if (contrast > 100) contrast = 100; + + contrast = (100.0 + contrast)/100.0; + contrast *= contrast; + + Color *pixels = GetImageData(*image); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + float pR = (float)pixels[y*image->width + x].r/255.0; + pR -= 0.5; + pR *= contrast; + pR += 0.5; + pR *= 255; + if (pR < 0) pR = 0; + if (pR > 255) pR = 255; + + float pG = (float)pixels[y*image->width + x].g/255.0; + pG -= 0.5; + pG *= contrast; + pG += 0.5; + pG *= 255; + if (pG < 0) pG = 0; + if (pG > 255) pG = 255; + + float pB = (float)pixels[y*image->width + x].b/255.0; + pB -= 0.5; + pB *= contrast; + pB += 0.5; + pB *= 255; + if (pB < 0) pB = 0; + if (pB > 255) pB = 255; + + pixels[y*image->width + x].r = (unsigned char)pR; + pixels[y*image->width + x].g = (unsigned char)pG; + pixels[y*image->width + x].b = (unsigned char)pB; + } + } + + Image processed = LoadImageEx(pixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(pixels); + image->data = processed.data; } +// Modify image color: brightness +// NOTE: Brightness values between -255 and 255 void ImageColorBrightness(Image *image, int brightness) { + if (brightness < -255) brightness = -255; + if (brightness > 255) brightness = 255; + + Color *pixels = GetImageData(*image); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + int cR = pixels[y*image->width + x].r + brightness; + int cG = pixels[y*image->width + x].g + brightness; + int cB = pixels[y*image->width + x].b + brightness; + + if (cR < 0) cR = 1; + if (cR > 255) cR = 255; + + if (cG < 0) cG = 1; + if (cG > 255) cG = 255; + + if (cB < 0) cB = 1; + if (cB > 255) cB = 255; + + pixels[y*image->width + x].r = (unsigned char)cR; + pixels[y*image->width + x].g = (unsigned char)cG; + pixels[y*image->width + x].b = (unsigned char)cB; + } + } + + Image processed = LoadImageEx(pixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(pixels); + image->data = processed.data; } // Generate GPU mipmaps for a texture -- cgit v1.2.3 From fb4105cf8a6a26b0f00da1c71ad8c56c2aefd875 Mon Sep 17 00:00:00 2001 From: Ray San Date: Mon, 26 Oct 2015 11:50:28 +0100 Subject: Corrected bug on web --- src/textures.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 66d2afc5..29eed874 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1160,11 +1160,11 @@ void ImageColorBrightness(Image *image, int brightness) void GenTextureMipmaps(Texture2D texture) { #if PLATFORM_WEB - int potWidth = GetNextPOT(image->width); - int potHeight = GetNextPOT(image->height); + int potWidth = GetNextPOT(texture.width); + int potHeight = GetNextPOT(texture.height); // Check if texture is POT - if ((potWidth != image->width) || (potHeight != image->height)) + if ((potWidth != texture.width) || (potHeight != texture.height)) { TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures"); } -- cgit v1.2.3 From 67423ff64b3b1b8c52819c9d0afdf4408e3b410d Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 27 Oct 2015 19:24:14 +0100 Subject: Removed unneeded comment --- src/textures.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 29eed874..007547ca 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1028,8 +1028,6 @@ void ImageColorTint(Image *image, Color color) UnloadImage(*image); free(pixels); - TraceLog(INFO,"color tint applied"); - image->data = processed.data; } -- cgit v1.2.3 From 76024b5036f060a19a1a2eea49c401d6db81cda8 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 4 Nov 2015 18:33:46 +0100 Subject: Added some texture functionality (view details) LoadTextureEx() - Simplified parameters UpdateTexture() - Added, allows updating GPU texture data --- src/raylib.h | 3 ++- src/rlgl.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/rlgl.h | 3 ++- src/textures.c | 14 ++++++++++--- 4 files changed, 76 insertions(+), 10 deletions(-) (limited to 'src/textures.c') diff --git a/src/raylib.h b/src/raylib.h index 419989d0..0b07e523 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -579,7 +579,7 @@ Image LoadImageEx(Color *pixels, int width, int height); Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory -Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount); // Load a texture from raw data into GPU memory +Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) Texture2D LoadTextureFromImage(Image image); // Load a texture from image data void UnloadImage(Image image); // Unload image from CPU memory (RAM) @@ -602,6 +602,7 @@ void ImageColorGrayscale(Image *image); void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture +void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 diff --git a/src/rlgl.c b/src/rlgl.c index ebff0d53..0befad3f 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1880,6 +1880,38 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma return id; } +void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data) +{ + glBindTexture(GL_TEXTURE_2D, id); + +#if defined(GRAPHICS_API_OPENGL_33) + switch (format) + { + case UNCOMPRESSED_GRAYSCALE: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_GRAY_ALPHA: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_R5G6B5: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break; + case UNCOMPRESSED_R8G8B8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_R5G5B5A1: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; + case UNCOMPRESSED_R4G4B4A4: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; + case UNCOMPRESSED_R8G8B8A8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + default: TraceLog(WARNING, "Texture format updating not supported"); break; + } +#elif defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA + switch (format) + { + case UNCOMPRESSED_GRAYSCALE: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_GRAY_ALPHA: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_R5G6B5: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (unsigned short *)data); break; + case UNCOMPRESSED_R8G8B8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + case UNCOMPRESSED_R5G5B5A1: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, (unsigned short *)data); break; + case UNCOMPRESSED_R4G4B4A4: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, (unsigned short *)data); break; + case UNCOMPRESSED_R8G8B8A8: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)data); break; + default: TraceLog(WARNING, "Texture format updating not supported"); break; + } +#endif +} + // Generate mipmap data for selected texture void rlglGenerateMipmaps(unsigned int textureId) { @@ -2046,6 +2078,7 @@ unsigned char *rlglReadScreenPixels(int width, int height) // Read texture pixel data // NOTE: Retrieving pixel data from GPU (glGetTexImage()) not supported on OpenGL ES 2.0 +//void *rlglReadTexturePixels(Texture2D texture) // Required to know texture size! It could not be retrieved on OpenGL ES 2.0 void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) { void *pixels = NULL; @@ -2108,14 +2141,32 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) #endif #if defined(GRAPHICS_API_OPENGL_ES2) - // TODO: Look for some way to retrieve texture width and height from id + // TODO: Look for some way to retrieve texture width and height from id -> NO WAY AVAILABLE int width = 1024; int height = 1024; FBO fbo = rlglLoadFBO(width, height); - // NOTE: Altenatively we can bind texture to color fbo and glReadPixels() + // NOTE: Two possible Options: + // 1 - Bind texture to color fbo attachment and glReadPixels() + // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() + +#define GET_TEXTURE_FBO_OPTION_1 + +#if defined(GET_TEXTURE_FBO_OPTION_1) + glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); + + // Attach color texture and depth renderbuffer to FBO + // NOTE: texture must RGB + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); + + pixels = (unsigned char *)malloc(width*height*3*sizeof(unsigned char)); + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + +#elif defined(GET_TEXTURE_FBO_OPTION_2) // Render texture to fbo glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); glClearColor(0.0, 0.0, 0.0, 0.0); @@ -2131,8 +2182,12 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) //glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); - //Model quad = GenModelQuad(width, height); - //DrawModel(quad, (Vector3){ 0, 0, 0 }, 1.0f, WHITE); + Model quad; + //quad.mesh = GenMeshQuad(width, height); + quad.transform = MatrixIdentity(); + quad.shader = simpleShader; + + DrawModel(quad, (Vector3){ 0, 0, 0 }, 1.0f, WHITE); pixels = (unsigned char *)malloc(width*height*4*sizeof(unsigned char)); @@ -2140,7 +2195,8 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) // Bind framebuffer 0, which means render to back buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); - +#endif // GET_TEXTURE_FBO_OPTION + // Clean up temporal fbo rlglUnloadFBO(fbo); #endif diff --git a/src/rlgl.h b/src/rlgl.h index 272b245e..ce823d97 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -242,7 +242,8 @@ void rlglClose(void); // De-init rlgl void rlglDraw(void); // Draw VAO/VBO void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff) -unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load in GPU OpenGL texture +unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU +void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data void rlglGenerateMipmaps(unsigned int textureId); // Generate mipmap data for selected texture // NOTE: There is a set of shader related functions that are available to end user, diff --git a/src/textures.c b/src/textures.c index 007547ca..076ed935 100644 --- a/src/textures.c +++ b/src/textures.c @@ -338,16 +338,17 @@ Texture2D LoadTexture(const char *fileName) return texture; } -Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, int mipmapCount) +// Load a texture from raw data into GPU memory +Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat) { Texture2D texture; texture.width = width; texture.height = height; - texture.mipmaps = mipmapCount; + texture.mipmaps = 1; texture.format = textureFormat; - texture.id = rlglLoadTexture(data, width, height, textureFormat, mipmapCount); + texture.id = rlglLoadTexture(data, width, height, textureFormat, 1); return texture; } @@ -1172,6 +1173,13 @@ void GenTextureMipmaps(Texture2D texture) #endif } +// Update GPU texture with new data +// NOTE: pixels data must match texture.format +void UpdateTexture(Texture2D texture, void *pixels) +{ + rlglUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels); +} + // Draw a Texture2D void DrawTexture(Texture2D texture, int posX, int posY, Color tint) { -- cgit v1.2.3 From 88e1fd9530100311071352f71999cca08854a3a2 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 5 Nov 2015 12:32:47 +0100 Subject: Added texture retrieval support on OpenGL ES 2.0 Updated functions: Image GetTextureData(Texture2D texture); void *rlglReadTexturePixels(Texture2D texture); --- src/rlgl.c | 74 ++++++++++++++++++++++++++-------------------------------- src/rlgl.h | 6 ++--- src/textures.c | 15 ++++++------ 3 files changed, 44 insertions(+), 51 deletions(-) (limited to 'src/textures.c') diff --git a/src/rlgl.c b/src/rlgl.c index 6df49846..766a834d 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1029,7 +1029,7 @@ void rlglInit(void) else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported"); - else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures support is limited (no-mipmaps, no-repeat"); + else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures support is limited (no-mipmaps, no-repeat)"); #endif if (texCompDXTSupported) TraceLog(INFO, "[EXTENSION] DXT compressed textures supported"); @@ -2051,8 +2051,6 @@ Model rlglLoadModel(VertexData mesh) } // Read screen pixel data (color buffer) -// ISSUE: Non pre-multiplied alpha when reading from backbuffer! -// TODO: Multiply alpha unsigned char *rlglReadScreenPixels(int width, int height) { unsigned char *screenData = (unsigned char *)malloc(width*height*sizeof(unsigned char)*4); @@ -2082,28 +2080,30 @@ unsigned char *rlglReadScreenPixels(int width, int height) } // Read texture pixel data -// NOTE: Retrieving pixel data from GPU (glGetTexImage()) not supported on OpenGL ES 2.0 -//void *rlglReadTexturePixels(Texture2D texture) // Required to know texture size! It could not be retrieved on OpenGL ES 2.0 -void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) +// NOTE: glGetTexImage() is not available on OpenGL ES 2.0 +// Texture2D width and height are required on OpenGL ES 2.0. There is no way to get it from texture id. +void *rlglReadTexturePixels(Texture2D texture) { void *pixels = NULL; #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - int width, height; - - glBindTexture(GL_TEXTURE_2D, textureId); + glBindTexture(GL_TEXTURE_2D, texture.id); + // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0) + /* + int width, height, format; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); - //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); - //GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); + // Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE + */ int glFormat = 0, glType = 0; - unsigned int size = width*height; + unsigned int size = texture.width*texture.height; // NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1 - // Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3 and data must be swizzled + // Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3 switch (format) { @@ -2111,27 +2111,15 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break; // 8 bit per pixel (no alpha) case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_LUMINANCE_ALPHA; glType = GL_UNSIGNED_BYTE; break; // 16 bpp (2 channels) #elif defined(GRAPHICS_API_OPENGL_33) - case UNCOMPRESSED_GRAYSCALE: // 8 bit per pixel (no alpha) - { - pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; - - GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } break; - case UNCOMPRESSED_GRAY_ALPHA: // 16 bpp (2 channels) - { - pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE; - - GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } break; + case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE; break; #endif case UNCOMPRESSED_R5G6B5: pixels = (unsigned short *)malloc(size); glFormat = GL_RGB; glType = GL_UNSIGNED_SHORT_5_6_5; break; // 16 bpp case UNCOMPRESSED_R8G8B8: pixels = (unsigned char *)malloc(size*3); glFormat = GL_RGB; glType = GL_UNSIGNED_BYTE; break; // 24 bpp case UNCOMPRESSED_R5G5B5A1: pixels = (unsigned short *)malloc(size); glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_5_5_5_1; break; // 16 bpp (1 bit alpha) case UNCOMPRESSED_R4G4B4A4: pixels = (unsigned short *)malloc(size); glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_4_4_4_4; break; // 16 bpp (4 bit alpha) case UNCOMPRESSED_R8G8B8A8: pixels = (unsigned char *)malloc(size*4); glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; // 32 bpp - default: TraceLog(WARNING, "Texture format not suported"); break; + default: TraceLog(WARNING, "Texture data retrieval, format not suported"); break; } // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding. @@ -2146,34 +2134,36 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) #endif #if defined(GRAPHICS_API_OPENGL_ES2) - // TODO: Look for some way to retrieve texture width and height from id -> NO WAY AVAILABLE - int width = 1024; - int height = 1024; - - FBO fbo = rlglLoadFBO(width, height); + FBO fbo = rlglLoadFBO(texture.width, texture.height); // NOTE: Two possible Options: // 1 - Bind texture to color fbo attachment and glReadPixels() // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() -#define GET_TEXTURE_FBO_OPTION_1 +#define GET_TEXTURE_FBO_OPTION_1 // It works #if defined(GET_TEXTURE_FBO_OPTION_1) glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); + glBindTexture(GL_TEXTURE_2D, 0); - // Attach color texture and depth renderbuffer to FBO - // NOTE: texture must RGB - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); + // Attach our texture to FBO -> Texture must be RGB + // NOTE: Previoust attached texture is automatically detached + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0); - pixels = (unsigned char *)malloc(width*height*3*sizeof(unsigned char)); + pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char)); - glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + // NOTE: Despite FBO color texture is RGB, we read data as RGBA... reading as RGB doesn't work... o__O + glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Re-attach internal FBO color texture before deleting it + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.colorTextureId, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); #elif defined(GET_TEXTURE_FBO_OPTION_2) // Render texture to fbo glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); + glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepthf(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -2194,12 +2184,14 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format) DrawModel(quad, (Vector3){ 0, 0, 0 }, 1.0f, WHITE); - pixels = (unsigned char *)malloc(width*height*4*sizeof(unsigned char)); + pixels = (unsigned char *)malloc(texture.width*texture.height*3*sizeof(unsigned char)); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glReadPixels(0, 0, texture.width, texture.height, GL_RGB, GL_UNSIGNED_BYTE, pixels); // Bind framebuffer 0, which means render to back buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); + + UnloadModel(quad); #endif // GET_TEXTURE_FBO_OPTION // Clean up temporal fbo diff --git a/src/rlgl.h b/src/rlgl.h index ce823d97..0960fa83 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -255,10 +255,10 @@ void rlglDrawPostpro(void); // Draw with postprocessing shad Model rlglLoadModel(VertexData mesh); // Upload vertex data into GPU and provided VAO/VBO ids void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires); -Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates +Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates -unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) -void *rlglReadTexturePixels(unsigned int textureId, unsigned int format); // Read texture pixel data +unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) +void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) void PrintProjectionMatrix(void); // DEBUG: Print projection matrix diff --git a/src/textures.c b/src/textures.c index 076ed935..27046b61 100644 --- a/src/textures.c +++ b/src/textures.c @@ -502,26 +502,27 @@ Image GetTextureData(Texture2D texture) Image image; image.data = NULL; -#if defined(GRAPHICS_API_OPENGL_ES2) - TraceLog(WARNING, "Texture data retrieval not supported on OpenGL ES 2.0"); -#else if (texture.format < 8) { - image.data = rlglReadTexturePixels(texture.id, texture.format); + image.data = rlglReadTexturePixels(texture); if (image.data != NULL) { image.width = texture.width; image.height = texture.height; - image.format = texture.format; image.mipmaps = 1; - +#if defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: Data retrieved on OpenGL ES 2.0 comes as RGB (from framebuffer) + image.format = UNCOMPRESSED_R8G8B8A8; +#else + image.format = texture.format; +#endif TraceLog(INFO, "Texture pixel data obtained successfully"); } else TraceLog(WARNING, "Texture pixel data could not be obtained"); } else TraceLog(WARNING, "Compressed texture data could not be obtained"); -#endif + return image; } -- cgit v1.2.3 From 2bd72455080409f1d9ecc6c5576f58c1ff093c3f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 9 Dec 2015 20:22:42 +0100 Subject: DrawTextureRec() function review to allow flipped rectangle --- src/textures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 27046b61..f97812da 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1206,7 +1206,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc // Draw a part of a texture (defined by a rectangle) void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) { - Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height }; + Rectangle destRec = { (int)position.x, (int)position.y, abs(sourceRec.width), abs(sourceRec.height) }; Vector2 origin = { 0, 0 }; DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint); -- cgit v1.2.3 From 5dbb93dbb476c35d8f8aab24d9c3507640b171e8 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 30 Dec 2015 13:32:41 +0100 Subject: Added function: ImageDither() Corrected some code details --- src/raylib.h | 2 + src/textures.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 134 insertions(+), 29 deletions(-) (limited to 'src/textures.c') diff --git a/src/raylib.h b/src/raylib.h index 4eefa3ea..785ebebb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -654,6 +654,7 @@ Color *GetImageData(Image image); Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) void ImageFormat(Image *image, int newFormat); // Convert image data to desired format +void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) @@ -692,6 +693,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +const char *SubText(const char *text, int position, int length); // Get a piece of a text string //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/src/textures.c b/src/textures.c index f97812da..54cf2cc9 100644 --- a/src/textures.c +++ b/src/textures.c @@ -549,8 +549,7 @@ void ImageFormat(Image *image, int newFormat) 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++; + ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[i].r*0.299f + (float)pixels[i].g*0.587f + (float)pixels[i].b*0.114f); } } break; @@ -570,9 +569,9 @@ void ImageFormat(Image *image, int newFormat) { image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - unsigned char r; - unsigned char g; - unsigned char b; + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; for (int i = 0; i < image->width*image->height; i++) { @@ -581,8 +580,6 @@ void ImageFormat(Image *image, int newFormat) 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; @@ -600,45 +597,43 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_R5G5B5A1: { + #define ALPHA_THRESHOLD 50 + 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; + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + unsigned char a = 0; 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; + r = (unsigned char)(round((float)pixels[i].r*31/255)); + g = (unsigned char)(round((float)pixels[i].g*31/255)); + b = (unsigned char)(round((float)pixels[i].b*31/255)); + a = (pixels[i].a > ALPHA_THRESHOLD) ? 1 : 0; - ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1| (unsigned short)a; - - k++; + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; } - + } 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; + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + unsigned char a = 0; 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)); + r = (unsigned char)(round((float)pixels[i].r*15/255)); + g = (unsigned char)(round((float)pixels[i].g*15/255)); + b = (unsigned char)(round((float)pixels[i].b*15/255)); + a = (unsigned char)(round((float)pixels[i].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; @@ -664,6 +659,114 @@ void ImageFormat(Image *image, int newFormat) } } +// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +// NOTE: In case selected bpp do not represent an known 16bit format, +// dithered data is stored in the LSB part of the unsigned short +void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) +{ + if (image->format >= 8) + { + TraceLog(WARNING, "Compressed data formats can not be dithered"); + return; + } + + if ((rBpp+gBpp+bBpp+aBpp) > 16) + { + TraceLog(WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); + } + else + { + Color *pixels = GetImageData(*image); + + free(image->data); // free old image data + + if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) + { + TraceLog(WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); + } + + // Define new image format, check if desired bpp match internal known format + if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; + else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; + else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; + else + { + image->format = 0; + TraceLog(WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); + } + + // NOTE: We will store the dithered data as unsigned short (16bpp) + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); + + Color oldpixel = WHITE; + Color newpixel = WHITE; + + int error_r, error_g, error_b; + unsigned short pixel_r, pixel_g, pixel_b, pixel_a; // Used for 16bit pixel composition + + #define MIN(a,b) (((a)<(b))?(a):(b)) + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + oldpixel = pixels[y*image->width + x]; + + // TODO: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) + newpixel.r = oldpixel.r>>(8 - rBpp); // R bits + newpixel.g = oldpixel.g>>(8 - gBpp); // G bits + newpixel.b = oldpixel.b>>(8 - bBpp); // B bits + newpixel.a = oldpixel.a>>(8 - aBpp); // A bits (not used on dithering) + + // NOTE: Error must be computed between new and old pixel but using same number of bits! + // We want to know how much color precision we have lost... + error_r = (int)oldpixel.r - (int)(newpixel.r<<(8 - rBpp)); + error_g = (int)oldpixel.g - (int)(newpixel.g<<(8 - gBpp)); + error_b = (int)oldpixel.b - (int)(newpixel.b<<(8 - bBpp)); + + pixels[y*image->width + x] = newpixel; + + // NOTE: Some cases are out of the array and should be ignored + if (x < (image->width - 1)) + { + pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)error_r*7.0f/16), 0xff); + pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)error_g*7.0f/16), 0xff); + pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)error_b*7.0f/16), 0xff); + } + + if ((x > 0) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)error_r*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)error_g*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)error_b*3.0f/16), 0xff); + } + + if (y < (image->height - 1)) + { + pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)error_r*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)error_g*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)error_b*5.0f/16), 0xff); + } + + if ((x < (image->width - 1)) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)error_r*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)error_g*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)error_b*1.0f/16), 0xff); + } + + pixel_r = (unsigned short)newpixel.r; + pixel_g = (unsigned short)newpixel.g; + pixel_b = (unsigned short)newpixel.b; + pixel_a = (unsigned short)newpixel.a; + + ((unsigned short *)image->data)[y*image->width + x] = (pixel_r<<(gBpp + bBpp + aBpp)) | (pixel_g<<(bBpp + aBpp)) | (pixel_b< Date: Sat, 2 Jan 2016 10:41:37 +0100 Subject: Small code tweaks --- examples/models_billboard.c | 4 ++-- src/textures.c | 4 ++++ src/utils.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/textures.c') diff --git a/examples/models_billboard.c b/examples/models_billboard.c index 05d836ca..e5f6489f 100644 --- a/examples/models_billboard.c +++ b/examples/models_billboard.c @@ -48,11 +48,11 @@ int main() ClearBackground(RAYWHITE); Begin3dMode(camera); + + DrawGrid(10.0, 1.0); // Draw a grid DrawBillboard(camera, bill, billPosition, 2.0f, WHITE); - DrawGrid(10.0, 1.0); // Draw a grid - End3dMode(); DrawFPS(10, 10); diff --git a/src/textures.c b/src/textures.c index 54cf2cc9..30ffb945 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1749,6 +1749,7 @@ static Image LoadPVR(const char *fileName) // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#if 0 // Not used... // PVR file v2 Header (52 bytes) typedef struct { unsigned int headerLength; @@ -1765,6 +1766,7 @@ static Image LoadPVR(const char *fileName) unsigned int pvrTag; unsigned int numSurfs; } pvrHeaderV2; +#endif // PVR file v3 Header (52 bytes) // NOTE: After it could be metadata (15 bytes?) @@ -1784,6 +1786,7 @@ static Image LoadPVR(const char *fileName) unsigned int metaDataSize; } pvrHeaderV3; +#if 0 // Not used... // Metadata (usually 15 bytes) typedef struct { unsigned int devFOURCC; @@ -1791,6 +1794,7 @@ static Image LoadPVR(const char *fileName) unsigned int dataSize; // Not used? unsigned char *data; // Not used? } pvrMetadata; +#endif Image image; diff --git a/src/utils.c b/src/utils.c index aac461cd..974088f3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -267,7 +267,7 @@ void RecordMalloc(int mallocType, int mallocSize, const char *msg) const char *GetExtension(const char *fileName) { const char *dot = strrchr(fileName, '.'); - if(!dot || dot == fileName) return ""; + if (!dot || dot == fileName) return ""; return (dot + 1); } -- cgit v1.2.3 From 95da97fa744766fb46b912dcae504cd858fd2377 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 4 Jan 2016 15:09:44 +0100 Subject: Fixed bug: rlglGenerateMipmaps() --- src/rlgl.c | 33 ++++++++++++--------------------- src/rlgl.h | 2 +- src/textures.c | 4 ++-- 3 files changed, 15 insertions(+), 24 deletions(-) (limited to 'src/textures.c') diff --git a/src/rlgl.c b/src/rlgl.c index 8a0440e0..504381b2 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1921,40 +1921,31 @@ void rlglUpdateTexture(unsigned int id, int width, int height, int format, void } // Generate mipmap data for selected texture -void rlglGenerateMipmaps(unsigned int textureId) +void rlglGenerateMipmaps(Texture2D texture) { - glBindTexture(GL_TEXTURE_2D, textureId); + glBindTexture(GL_TEXTURE_2D, texture.id); // Check if texture is power-of-two (POT) bool texIsPOT = false; - // NOTE: In OpenGL ES 2.0 we have no way to retrieve texture size from id - -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - int width, height; - - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); - - if (((width > 0) && ((width & (width - 1)) == 0)) && ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true; -#endif + if (((texture.width > 0) && ((texture.width & (texture.width - 1)) == 0)) && + ((texture.height > 0) && ((texture.height & (texture.height - 1)) == 0))) texIsPOT = true; if ((texIsPOT) || (npotSupported)) { #if defined(GRAPHICS_API_OPENGL_11) // Compute required mipmaps - // TODO: rlglReadTexturePixels() needs Texture2D type parameter, not unsigned int parameter - void *data; // = rlglReadTexturePixels(textureId, UNCOMPRESSED_R8G8B8A8); // TODO: Detect internal format + void *data = rlglReadTexturePixels(texture); // NOTE: data size is reallocated to fit mipmaps data - int mipmapCount = GenerateMipmaps(data, width, height); + int mipmapCount = GenerateMipmaps(data, texture.width, texture.height); // TODO: Adjust mipmap size depending on texture format! - int size = width*height*4; + int size = texture.width*texture.height*4; int offset = size; - int mipWidth = width/2; - int mipHeight = height/2; + int mipWidth = texture.width/2; + int mipHeight = texture.height/2; // Load the mipmaps for (int level = 1; level < mipmapCount; level++) @@ -1968,17 +1959,17 @@ void rlglGenerateMipmaps(unsigned int textureId) mipHeight /= 2; } - TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", textureId); + TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture.id); #elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically - TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", textureId); + TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps (must be available) #endif } - else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", textureId); + else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", texture.id); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/rlgl.h b/src/rlgl.h index a7df043e..93b56bb2 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -246,7 +246,7 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Init unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data -void rlglGenerateMipmaps(unsigned int textureId); // Generate mipmap data for selected texture +void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture // NOTE: There is a set of shader related functions that are available to end user, // to avoid creating function wrappers through core module, they have been directly declared in raylib.h diff --git a/src/textures.c b/src/textures.c index 30ffb945..f03d2d9a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1271,9 +1271,9 @@ void GenTextureMipmaps(Texture2D texture) { TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures"); } - else rlglGenerateMipmaps(texture.id); + else rlglGenerateMipmaps(texture); #else - rlglGenerateMipmaps(texture.id); + rlglGenerateMipmaps(texture); #endif } -- cgit v1.2.3 From 823abf666e09e96ccbf5230c96f2d3a61ff60895 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 12 Feb 2016 12:22:56 +0100 Subject: Reviewed code TODOs --- src/audio.c | 2 +- src/camera.c | 2 +- src/core.c | 17 +++++++---------- src/models.c | 1 - src/rlgl.c | 10 +++------- src/text.c | 2 +- src/textures.c | 10 ++++++---- 7 files changed, 19 insertions(+), 25 deletions(-) (limited to 'src/textures.c') diff --git a/src/audio.c b/src/audio.c index e40fdd41..260f6778 100644 --- a/src/audio.c +++ b/src/audio.c @@ -280,9 +280,9 @@ Sound LoadSoundFromWave(Wave wave) } // Load sound to memory from rRES file (raylib Resource) +// TODO: Maybe rresName could be directly a char array with all the data? Sound LoadSoundFromRES(const char *rresName, int resId) { - // NOTE: rresName could be directly a char array with all the data!!! --> TODO Sound sound = { 0 }; #if defined(AUDIO_STANDALONE) diff --git a/src/camera.c b/src/camera.c index 6539da5f..517e4a2b 100644 --- a/src/camera.c +++ b/src/camera.c @@ -375,7 +375,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) } // Focus to center - // TODO: Move this function out of the module? + // TODO: Move this function out of this module? if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera position update diff --git a/src/core.c b/src/core.c index 05ec0c0a..413006e4 100644 --- a/src/core.c +++ b/src/core.c @@ -359,7 +359,7 @@ void InitWindow(int width, int height, struct android_app *state) if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(INFO, "PORTRAIT window orientation"); else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(INFO, "LANDSCAPE window orientation"); - // TODO: Review, it doesn't work... + // TODO: Automatic orientation doesn't seem to work if (width <= height) { AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_PORT); @@ -1246,7 +1246,7 @@ int GetTouchY(void) } // Returns touch position XY -// TODO: touch position should be scaled depending on display size and render size +// TODO: Touch position should be scaled depending on display size and render size Vector2 GetTouchPosition(int index) { Vector2 position = { -1.0f, -1.0f }; @@ -1257,7 +1257,7 @@ Vector2 GetTouchPosition(int index) if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { - // TODO: Seems to work ok but... review! + // TODO: Review touch position scaling for screenSize vs displaySize position.x = position.x*((float)screenWidth/(float)(displayWidth - renderOffsetX)) - renderOffsetX/2; position.y = position.y*((float)screenHeight/(float)(displayHeight - renderOffsetY)) - renderOffsetY/2; } @@ -1668,8 +1668,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i #endif else currentKeyState[key] = action; - // HACK for GuiTextBox, to deteck back key - // TODO: Review... + // TODO: Review (and remove) this HACK for GuiTextBox, to deteck back key if ((key == 259) && (action == GLFW_PRESS)) lastKeyPressed = 3; } @@ -1678,8 +1677,6 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int { currentMouseState[button] = action; - // TODO: Test mouse gestures - #define ENABLE_MOUSE_GESTURES #if defined(ENABLE_MOUSE_GESTURES) // Process mouse events as touches to be able to use mouse-gestures @@ -2046,7 +2043,7 @@ static bool GetKeyStatus(int key) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) - // TODO: Check virtual keyboard (?) + // TODO: Check for virtual keyboard return false; #elif defined(PLATFORM_RPI) // NOTE: Keys states are filled in PollInputEvents() @@ -2061,7 +2058,7 @@ static bool GetMouseButtonStatus(int button) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetMouseButton(window, button); #elif defined(PLATFORM_ANDROID) - // TODO: Check virtual keyboard (?) + // TODO: Check for virtual keyboard return false; #elif defined(PLATFORM_RPI) // NOTE: mouse buttons array is filled on PollInputEvents() @@ -2382,7 +2379,7 @@ static void RestoreKeyboard(void) // Init gamepad system static void InitGamepad(void) { - // TODO: Gamepad support + // TODO: Add Gamepad support if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); else TraceLog(INFO, "Gamepad device initialized successfully"); } diff --git a/src/models.c b/src/models.c index 94e61d84..8a36c279 100644 --- a/src/models.c +++ b/src/models.c @@ -704,7 +704,6 @@ Model LoadHeightmap(Image heightmap, Vector3 size) // TODO: Calculate normals in an efficient way nCounter += 18; // 6 vertex, 18 floats - trisCounter += 2; } } diff --git a/src/rlgl.c b/src/rlgl.c index 2ea06e1c..5f8a5ea1 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -171,7 +171,7 @@ typedef struct { typedef struct { GLuint textureId; int vertexCount; - // TODO: DrawState state -> Blending mode, shader + // TODO: Store draw state -> blending mode, shader } DrawCall; // pixel type (same as Color type) @@ -1475,11 +1475,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro // Calculate model-view-projection matrix (MVP) Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates - // NOTE: Drawing in OpenGL 3.3+, matrices are passed to shader - // TODO: Reduce number of matrices passed to shaders, use only matMVP - //glUniformMatrix4fv(model.material.shader.modelLoc, 1, false, MatrixToFloat(matModel)); - //glUniformMatrix4fv(model.material.shader.viewLoc, 1, false, MatrixToFloat(matView)); - + // Send combined model-view-projection matrix to shader glUniformMatrix4fv(model.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); // Apply color tinting to model @@ -1900,7 +1896,7 @@ void rlglGenerateMipmaps(Texture2D texture) int mipmapCount = GenerateMipmaps(data, texture.width, texture.height); // TODO: Adjust mipmap size depending on texture format! - int size = texture.width*texture.height*4; + int size = texture.width*texture.height*4; // RGBA 32bit only int offset = size; int mipWidth = texture.width/2; diff --git a/src/text.c b/src/text.c index 3755932d..e4c7bbf3 100644 --- a/src/text.c +++ b/src/text.c @@ -346,7 +346,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f for(int i = 0; i < length; i++) { - // TODO: Right now we are supposing characters follow a continous order and start at FONT_FIRST_CHAR, + // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR, // this sytem can be improved to support any characters order and init value... // An intermediate table could be created to link char values with predefined char position index in chars rectangle array diff --git a/src/textures.c b/src/textures.c index f03d2d9a..36819daf 100644 --- a/src/textures.c +++ b/src/textures.c @@ -712,7 +712,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { oldpixel = pixels[y*image->width + x]; - // TODO: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) + // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) newpixel.r = oldpixel.r>>(8 - rBpp); // R bits newpixel.g = oldpixel.g>>(8 - gBpp); // G bits newpixel.b = oldpixel.b>>(8 - bBpp); // B bits @@ -769,7 +769,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) } // Convert image to POT (power-of-two) -// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) +// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) void ImageToPOT(Image *image, Color fillColor) { Color *pixels = GetImageData(*image); // Get pixels data @@ -784,7 +784,7 @@ void ImageToPOT(Image *image, Color fillColor) Color *pixelsPOT = NULL; // Generate POT array from NPOT data - pixelsPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); + pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); for (int j = 0; j < potHeight; j++) { @@ -896,7 +896,9 @@ void ImageCrop(Image *image, Rectangle crop) } // Resize and image to new size -// NOTE: Uses stb default scaling filter +// NOTE: Uses stb default scaling filters (both bicubic): +// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) void ImageResize(Image *image, int newWidth, int newHeight) { // Get data as Color pixels array to work with it -- cgit v1.2.3