From 8f4fa5006b5fd4dc25fec3ed5dcbbecd832dd345 Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 22 May 2018 12:09:12 +0200 Subject: Added a note --- src/textures.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 3a1934b9..c4ef31cf 100644 --- a/src/textures.c +++ b/src/textures.c @@ -567,8 +567,10 @@ void ExportImage(const char *fileName, Image image) { // NOTE: Getting Color array as RGBA unsigned char values unsigned char *imgData = (unsigned char *)GetImageData(image); + + // NOTE: SavePNG() not supported by some platforms: PLATFORM_WEB, PLATFORM_ANDROID SavePNG(fileName, imgData, image.width, image.height, 4); - // FIXME ^ this fails on PLATFORM_WEB, what should we do? + free(imgData); } -- cgit v1.2.3 From dbff40944a72df4b5435520fc09f3fb68e3cebdf Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 28 May 2018 00:48:07 +0200 Subject: Corrected issue with floats on TCC It seems TCC was not casting correctly int values to float in some specific situations --- examples/textures/textures_rectangle.c | 4 ++-- src/textures.c | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src/textures.c') diff --git a/examples/textures/textures_rectangle.c b/examples/textures/textures_rectangle.c index c90db8ac..e1247746 100644 --- a/examples/textures/textures_rectangle.c +++ b/examples/textures/textures_rectangle.c @@ -27,7 +27,7 @@ int main() Texture2D scarfy = LoadTexture("resources/scarfy.png"); // Texture loading Vector2 position = { 350.0f, 280.0f }; - Rectangle frameRec = { 0, 0, scarfy.width/6, scarfy.height }; + Rectangle frameRec = { 0.0f, 0.0f, (float)scarfy.width/6, (float)scarfy.height }; int currentFrame = 0; int framesCounter = 0; @@ -50,7 +50,7 @@ int main() if (currentFrame > 5) currentFrame = 0; - frameRec.x = currentFrame*scarfy.width/6; + frameRec.x = (float)currentFrame*(float)scarfy.width/6; } if (IsKeyPressed(KEY_RIGHT)) framesSpeed++; diff --git a/src/textures.c b/src/textures.c index c4ef31cf..bbdeca90 100644 --- a/src/textures.c +++ b/src/textures.c @@ -2022,9 +2022,9 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint) // Draw a Texture2D with extended parameters void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) { - Rectangle sourceRec = { 0, 0, texture.width, texture.height }; - Rectangle destRec = { position.x, position.y, texture.width*scale, texture.height*scale }; - Vector2 origin = { 0, 0 }; + Rectangle sourceRec = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; + Rectangle destRec = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale }; + Vector2 origin = { 0.0f, 0.0f }; DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); } @@ -2032,8 +2032,8 @@ 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 = { position.x, position.y, sourceRec.width, fabsf(sourceRec.height) }; - Vector2 origin = { 0, 0 }; + Rectangle destRec = { position.x, position.y, sourceRec.width, fabs(sourceRec.height) }; + Vector2 origin = { 0.0f, 0.0f }; DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint); } @@ -2045,6 +2045,9 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V // Check if texture is valid if (texture.id > 0) { + float width = (float)texture.width; + float height = (float)texture.height; + if (sourceRec.width < 0) sourceRec.x -= sourceRec.width; if (sourceRec.height < 0) sourceRec.y -= sourceRec.height; @@ -2060,19 +2063,19 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer // Bottom-left corner for texture and quad - rlTexCoord2f(sourceRec.x/texture.width, sourceRec.y/texture.height); + rlTexCoord2f(sourceRec.x/width, sourceRec.y/height); rlVertex2f(0.0f, 0.0f); // Bottom-right corner for texture and quad - rlTexCoord2f(sourceRec.x/texture.width, (sourceRec.y + sourceRec.height)/texture.height); + rlTexCoord2f(sourceRec.x/width, (sourceRec.y + sourceRec.height)/height); rlVertex2f(0.0f, destRec.height); // Top-right corner for texture and quad - rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, (sourceRec.y + sourceRec.height)/texture.height); + rlTexCoord2f((sourceRec.x + sourceRec.width)/width, (sourceRec.y + sourceRec.height)/height); rlVertex2f(destRec.width, destRec.height); // Top-left corner for texture and quad - rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, sourceRec.y/texture.height); + rlTexCoord2f((sourceRec.x + sourceRec.width)/width, sourceRec.y/height); rlVertex2f(destRec.width, 0.0f); rlEnd(); rlPopMatrix(); -- cgit v1.2.3 From 8f4b53384cd5eb1d877e6cad79fc57c984674d25 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 29 May 2018 09:09:40 +0200 Subject: Replaced tabs by spaces --- 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 bbdeca90..df1fe368 100644 --- a/src/textures.c +++ b/src/textures.c @@ -819,7 +819,7 @@ void ImageFormat(Image *image, int newFormat) if (image->mipmaps > 1) { image->mipmaps = 1; - assert(image->data != NULL); + assert(image->data != NULL); ImageMipmaps(image); } } -- cgit v1.2.3 From 129c890a28b50c2ce3820e3745f8c89c8833f02c Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 30 May 2018 00:06:23 +0200 Subject: Removed assert() Not used in raylib this mechanism --- src/textures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index df1fe368..0aac923f 100644 --- a/src/textures.c +++ b/src/textures.c @@ -814,13 +814,13 @@ void ImageFormat(Image *image, int newFormat) free(pixels); pixels = NULL; + // In case original image had mipmaps, generate mipmaps for formated image // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost if (image->mipmaps > 1) { image->mipmaps = 1; - assert(image->data != NULL); - ImageMipmaps(image); + if (image->data != NULL) ImageMipmaps(image); } } else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted"); -- cgit v1.2.3 From 2536bea379387e525e3107ee07355292ee87a566 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 1 Jun 2018 00:53:40 +0200 Subject: Added: ImageResizeCanvas() -WIP- Added note idea on ImageFormat() for future redesign (to support 16bit-32bit pixel-formats) --- src/raylib.h | 5 +++-- src/textures.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/textures.c') diff --git a/src/raylib.h b/src/raylib.h index e83650e6..2659d70d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -912,8 +912,9 @@ RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) -RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (bilinear filtering) +RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int anchor, Color color); // Resize canvas, using anchor point and color filling RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) diff --git a/src/textures.c b/src/textures.c index 0aac923f..239b7cf5 100644 --- a/src/textures.c +++ b/src/textures.c @@ -664,6 +664,7 @@ void ImageFormat(Image *image, int newFormat) if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB)) { Color *pixels = GetImageData(*image); + //Vector4 *pixels = GetImageDataNormalized(*image); // TODO: Support 8->32bit channels free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... image->data = NULL; @@ -1066,6 +1067,20 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) free(pixels); } +// Resize canvas, using anchor point and color filling +void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int anchor, Color color) +{ + Image imTemp = GenImageColor(newWidth, newHeight, color); + Rectangle rec = { 0, 0, image->width, image->height }; + + // TODO: consider anchor properly + + ImageDraw(&imTemp, *image, rec, rec); + ImageFormat(&imTemp, image->format); + UnloadImage(*image); + *image = imTemp; +} + // Generate all mipmap levels for a provided image // NOTE 1: Supports POT and NPOT images // NOTE 2: image.data is scaled to include mipmap levels -- cgit v1.2.3 From afc41817521fd86799ce96b049cce7c581a1f108 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 2 Jun 2018 12:47:05 +0200 Subject: Work on ImageResizeCanvas() --- src/textures.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 9 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 239b7cf5..c4e77458 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1067,18 +1067,58 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) free(pixels); } -// Resize canvas, using anchor point and color filling -void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int anchor, Color color) +// Resize canvas and fill with color +// NOTE: Resize offset is relative to the top-left corner of the original image +void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, int offsetY, Color color) { Image imTemp = GenImageColor(newWidth, newHeight, color); - Rectangle rec = { 0, 0, image->width, image->height }; + Rectangle srcRec = { 0, 0, image->width, image->height }; + Rectangle dstRec = { offsetX, offsetY, srcRec.width, srcRec.height }; - // TODO: consider anchor properly - - ImageDraw(&imTemp, *image, rec, rec); - ImageFormat(&imTemp, image->format); - UnloadImage(*image); - *image = imTemp; + if ((newWidth > image->width) && (newHeight > image->height)) + { + // Consider anchor properly + /* + switch (anchor) + { + case 0: break; // TOP-LEFT corner --> dstRec = srcRec + case 1: dstRec.x = (newWidth - image->width)/2; break; // TOP side + case 2: dstRec.x = newWidth - image->width; break; // TOP-RIGHT corner + case 3: dstRec.y = (newHeight - image->height)/2; break; // LEFT side + case 4: // CENTER + { + dstRec.x = (newWidth - image->width)/2; + dstRec.y = (newHeight - image->height)/2; + } break; + case 5: // RIGHT side + { + dstRec.x = newWidth - image->width; + dstRec.y = (newHeight - image->height)/2; + } break; + case 6: dstRec.y = newHeight - image->height; break; // BOTTOM-LEFT corner + case 7: // BOTTOM side + { + dstRec.x = (newWidth - image->width)/2; + dstRec.y = newHeight - image->height; + } break; + case 8: // BOTTOM-RIGHT side + { + dstRec.x = newWidth - image->width; + dstRec.y = newHeight - image->height; + } break; + default: break; + } + */ + ImageDraw(&imTemp, *image, srcRec, dstRec); + ImageFormat(&imTemp, image->format); + UnloadImage(*image); + *image = imTemp; + } + else + { + // TODO: ImageCrop(), define proper cropping rectangle + } + } // Generate all mipmap levels for a provided image -- cgit v1.2.3 From b1b4a11bdb450c415ae54eded7f868af19a7fb5d Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 2 Jun 2018 13:05:23 +0200 Subject: Corrected issue with function definition --- release/include/raylib.h | 5 +++-- release/libs/win32/tcc/libraylib.a | Bin 1463102 -> 1463584 bytes src/raylib.h | 2 +- src/textures.c | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/textures.c') diff --git a/release/include/raylib.h b/release/include/raylib.h index e83650e6..dad08ba2 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -912,8 +912,9 @@ RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) -RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (bilinear filtering) +RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) diff --git a/release/libs/win32/tcc/libraylib.a b/release/libs/win32/tcc/libraylib.a index 94114ac0..0d1d4549 100644 Binary files a/release/libs/win32/tcc/libraylib.a and b/release/libs/win32/tcc/libraylib.a differ diff --git a/src/raylib.h b/src/raylib.h index 2659d70d..dad08ba2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -914,7 +914,7 @@ RLAPI void ImageAlphaPremultiply(Image *image); RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (bilinear filtering) RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) -RLAPI void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int anchor, Color color); // Resize canvas, using anchor point and color filling +RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) diff --git a/src/textures.c b/src/textures.c index c4e77458..3a62ac14 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1118,7 +1118,6 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in { // TODO: ImageCrop(), define proper cropping rectangle } - } // Generate all mipmap levels for a provided image -- cgit v1.2.3 From 0e6458cfee398e572340db461ef6beb85253a4c5 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 3 Jun 2018 21:05:01 +0200 Subject: Added ImageRotate*() functions --- release/include/raylib.h | 2 ++ release/libs/win32/tcc/libraylib.a | Bin 1463584 -> 1465002 bytes src/raylib.h | 2 ++ src/textures.c | 56 +++++++++++++++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 2 deletions(-) (limited to 'src/textures.c') diff --git a/release/include/raylib.h b/release/include/raylib.h index a3fa1311..86ad5408 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -925,6 +925,8 @@ RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fon RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg +RLAPI void ImageRotateCCW(Image *image); // Rotate image counter-clockwise 90deg RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint RLAPI void ImageColorInvert(Image *image); // Modify image color: invert RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale diff --git a/release/libs/win32/tcc/libraylib.a b/release/libs/win32/tcc/libraylib.a index 0d1d4549..1aa76249 100644 Binary files a/release/libs/win32/tcc/libraylib.a and b/release/libs/win32/tcc/libraylib.a differ diff --git a/src/raylib.h b/src/raylib.h index a3fa1311..86ad5408 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -925,6 +925,8 @@ RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fon RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg +RLAPI void ImageRotateCCW(Image *image); // Rotate image counter-clockwise 90deg RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint RLAPI void ImageColorInvert(Image *image); // Modify image color: invert RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale diff --git a/src/textures.c b/src/textures.c index 3a62ac14..0b9f907e 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1539,7 +1539,7 @@ void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, void ImageFlipVertical(Image *image) { Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); + Color *dstPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -1563,7 +1563,7 @@ void ImageFlipVertical(Image *image) void ImageFlipHorizontal(Image *image) { Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); + Color *dstPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); for (int y = 0; y < image->height; y++) { @@ -1583,6 +1583,58 @@ void ImageFlipHorizontal(Image *image) image->data = processed.data; } +// Rotate image clockwise 90deg +void ImageRotateCW(Image *image) +{ + Color *srcPixels = GetImageData(*image); + Color *rotPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + rotPixels[x*image->height + (image->height - y - 1)] = srcPixels[y*image->width + x]; + } + } + + Image processed = LoadImageEx(rotPixels, image->height, image->width); + ImageFormat(&processed, image->format); + UnloadImage(*image); + + free(srcPixels); + free(rotPixels); + + image->data = processed.data; + image->width = processed.width; + image->height = processed.height; +} + +// Rotate image counter-clockwise 90deg +void ImageRotateCCW(Image *image) +{ + Color *srcPixels = GetImageData(*image); + Color *rotPixels = (Color *)malloc(image->width*image->height*sizeof(Color)); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + rotPixels[x*image->height + y] = srcPixels[y*image->width + (image->width - x - 1)]; + } + } + + Image processed = LoadImageEx(rotPixels, image->height, image->width); + ImageFormat(&processed, image->format); + UnloadImage(*image); + + free(srcPixels); + free(rotPixels); + + image->data = processed.data; + image->width = processed.width; + image->height = processed.height; +} + // Modify image color: tint void ImageColorTint(Image *image, Color color) { -- cgit v1.2.3 From 817ae075050b348e42223a567e7deaff42b6bb24 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 6 Jun 2018 00:43:52 +0200 Subject: Some comments cleaning ImageDraw() code tweak --- src/textures.c | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 0b9f907e..c7bd7648 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1075,40 +1075,10 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in Rectangle srcRec = { 0, 0, image->width, image->height }; Rectangle dstRec = { offsetX, offsetY, srcRec.width, srcRec.height }; + // TODO: Review different scaling situations + if ((newWidth > image->width) && (newHeight > image->height)) { - // Consider anchor properly - /* - switch (anchor) - { - case 0: break; // TOP-LEFT corner --> dstRec = srcRec - case 1: dstRec.x = (newWidth - image->width)/2; break; // TOP side - case 2: dstRec.x = newWidth - image->width; break; // TOP-RIGHT corner - case 3: dstRec.y = (newHeight - image->height)/2; break; // LEFT side - case 4: // CENTER - { - dstRec.x = (newWidth - image->width)/2; - dstRec.y = (newHeight - image->height)/2; - } break; - case 5: // RIGHT side - { - dstRec.x = newWidth - image->width; - dstRec.y = (newHeight - image->height)/2; - } break; - case 6: dstRec.y = newHeight - image->height; break; // BOTTOM-LEFT corner - case 7: // BOTTOM side - { - dstRec.x = (newWidth - image->width)/2; - dstRec.y = newHeight - image->height; - } break; - case 8: // BOTTOM-RIGHT side - { - dstRec.x = newWidth - image->width; - dstRec.y = newHeight - image->height; - } break; - default: break; - } - */ ImageDraw(&imTemp, *image, srcRec, dstRec); ImageFormat(&imTemp, image->format); UnloadImage(*image); @@ -1325,7 +1295,6 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) { srcRec.height = src.height - srcRec.y; TraceLog(LOG_WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height); - cropRequired = true; } Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it @@ -1337,10 +1306,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) if (dstRec.y < 0) dstRec.y = 0; // 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); - } + if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) ImageResize(&srcCopy, dstRec.width, dstRec.height); if ((dstRec.x + dstRec.width) > dst->width) { -- cgit v1.2.3 From b48d225a43c2a08bf1e37b1f66ec09cf0795371c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 10 Jun 2018 19:29:01 +0200 Subject: Propose new function: GenImageFont() --- src/textures.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index c7bd7648..789da14c 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1979,6 +1979,15 @@ Image GenImageCellular(int width, int height, int tileSize) return image; } + +// Generate image: font atlas. Requires TTF as input file. +// NOTE: Generated atlas packs characters in order and rectangles are defined with magenta borders (?) +Image GenImageFont(const char *fileName, int fontSize, int charsCount, int *fontChars, CharInfo *chars) +{ + CharInfo *chars; // Characters info (if required) + + // TODO. +} #endif // SUPPORT_IMAGE_GENERATION // Generate GPU mipmaps for a texture -- cgit v1.2.3 From 7d0e09ff4c7687853c6946466d38b0bb685b0088 Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 12 Jun 2018 12:05:28 +0200 Subject: Corrected bug --- src/textures.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 789da14c..fe408481 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1982,10 +1982,9 @@ Image GenImageCellular(int width, int height, int tileSize) // Generate image: font atlas. Requires TTF as input file. // NOTE: Generated atlas packs characters in order and rectangles are defined with magenta borders (?) +// NOTE: Characters info data should be allocated by user for charsCount Image GenImageFont(const char *fileName, int fontSize, int charsCount, int *fontChars, CharInfo *chars) { - CharInfo *chars; // Characters info (if required) - // TODO. } #endif // SUPPORT_IMAGE_GENERATION -- cgit v1.2.3 From 59fd2614916249ad5a229f032cb92f34692ca29b Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 12 Jun 2018 13:13:09 +0200 Subject: Added function: GetImageDataNormalized() Reviewed: GetImageData() Reviewed: ImageFormat() --- release/include/raylib.h | 1 + src/raylib.h | 1 + src/textures.c | 199 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 169 insertions(+), 32 deletions(-) (limited to 'src/textures.c') diff --git a/release/include/raylib.h b/release/include/raylib.h index 86ad5408..e0cfaa6d 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -899,6 +899,7 @@ RLAPI void UnloadImage(Image image); RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array +RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized) RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data diff --git a/src/raylib.h b/src/raylib.h index 86ad5408..e0cfaa6d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -899,6 +899,7 @@ RLAPI void UnloadImage(Image image); RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array +RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized) RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data diff --git a/src/textures.c b/src/textures.c index fe408481..5c2196e2 100644 --- a/src/textures.c +++ b/src/textures.c @@ -405,7 +405,6 @@ void UnloadRenderTexture(RenderTexture2D target) } // Get pixel data from image in the form of Color struct array -// TODO: Support float pixel data retrieval Color *GetImageData(Image image) { Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); @@ -479,6 +478,34 @@ Color *GetImageData(Image image) k += 3; } break; + case UNCOMPRESSED_R32: + { + TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel"); break; + + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = 0; + pixels[i].b = 0; + pixels[i].a = 255; + + } break; + case UNCOMPRESSED_R32G32B32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f); + pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f); + pixels[i].a = 255; + + k += 3; + } + case UNCOMPRESSED_R32G32B32A32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f); + + k += 4; + } default: TraceLog(LOG_WARNING, "Format not supported for pixel data retrieval"); break; } } @@ -486,6 +513,113 @@ Color *GetImageData(Image image) return pixels; } +// Get pixel data from image as Vector4 array (float normalized) +Vector4 *GetImageDataNormalized(Image image) +{ + Vector4 *pixels = (Vector4 *)malloc(image.width*image.height*sizeof(Vector4)); + + for (int i = 0, k = 0; i < image.width*image.height; i++) + { + switch (image.format) + { + case UNCOMPRESSED_GRAYSCALE: + { + pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].w = 1.0f; + + } break; + case UNCOMPRESSED_GRAY_ALPHA: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f; + + k += 2; + } break; + case UNCOMPRESSED_R5G5B5A1: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); + pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); + pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; + + } break; + case UNCOMPRESSED_R5G6B5: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); + pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31); + pixels[i].w = 1.0f; + + } break; + case UNCOMPRESSED_R4G4B4A4: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); + pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); + pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); + pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15); + + } break; + case UNCOMPRESSED_R8G8B8A8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f; + + k += 4; + } break; + case UNCOMPRESSED_R8G8B8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = 1.0f; + + k += 3; + } break; + case UNCOMPRESSED_R32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = 0.0f; + pixels[i].z = 0.0f; + pixels[i].w = 1.0f; + + } break; + case UNCOMPRESSED_R32G32B32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = 1.0f; + + k += 3; + } + case UNCOMPRESSED_R32G32B32A32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = ((float *)image.data)[k + 3]; + + k += 4; + } + default: TraceLog(LOG_WARNING, "Format not supported for pixel data retrieval"); break; + } + } + + return pixels; +} + // Get pixel data size in bytes (image or texture) // NOTE: Size depends on pixel format int GetPixelDataSize(int width, int height, int format) @@ -663,8 +797,7 @@ void ImageFormat(Image *image, int newFormat) { if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB)) { - Color *pixels = GetImageData(*image); - //Vector4 *pixels = GetImageDataNormalized(*image); // TODO: Support 8->32bit channels + Vector4 *pixels = GetImageDataNormalized(*image); // Supports 8 to 32 bit per channel free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... image->data = NULL; @@ -680,7 +813,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[i].r*0.299f + (float)pixels[i].g*0.587f + (float)pixels[i].b*0.114f); + ((unsigned char *)image->data)[i] = (unsigned char)((pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)*255.0f); } } break; @@ -690,8 +823,8 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0; i < image->width*image->height*2; i += 2, k++) { - ((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; + ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f); + ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f); } } break; @@ -705,9 +838,9 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0; i < image->width*image->height; i++) { - r = (unsigned char)(round((float)pixels[i].r*31.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*63.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*31.0f/255)); + r = (unsigned char)(round(pixels[i].x*31.0f)); + g = (unsigned char)(round(pixels[i].y*63.0f)); + b = (unsigned char)(round(pixels[i].z*31.0f)); ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; } @@ -719,9 +852,9 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) { - ((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] = (unsigned char)(pixels[k].x*255.0f); + ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f); + ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f); } } break; case UNCOMPRESSED_R5G5B5A1: @@ -737,10 +870,10 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0; i < image->width*image->height; i++) { - r = (unsigned char)(round((float)pixels[i].r*31.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*31.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*31.0f/255)); - a = (pixels[i].a > ALPHA_THRESHOLD) ? 1 : 0; + r = (unsigned char)(round(pixels[i].x*31.0f)); + g = (unsigned char)(round(pixels[i].y*31.0f)); + b = (unsigned char)(round(pixels[i].z*31.0f)); + a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f)) ? 1 : 0; ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; } @@ -757,10 +890,10 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0; i < image->width*image->height; i++) { - r = (unsigned char)(round((float)pixels[i].r*15.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*15.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*15.0f/255)); - a = (unsigned char)(round((float)pixels[i].a*15.0f/255)); + r = (unsigned char)(round(pixels[i].x*15.0f)); + g = (unsigned char)(round(pixels[i].y*15.0f)); + b = (unsigned char)(round(pixels[i].z*15.0f)); + a = (unsigned char)(round(pixels[i].w*15.0f)); ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; } @@ -772,19 +905,21 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) { - ((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; + ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f); + ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f); + ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f); + ((unsigned char *)image->data)[i + 3] = (unsigned char)(pixels[k].w*255.0f); } } break; case UNCOMPRESSED_R32: { + // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit + image->data = (float *)malloc(image->width*image->height*sizeof(float)); for (int i = 0; i < image->width*image->height; i++) { - ((float *)image->data)[i] = (float)((float)pixels[i].r*0.299f/255.0f + (float)pixels[i].g*0.587f/255.0f + (float)pixels[i].b*0.114f/255.0f); + ((float *)image->data)[i] = (float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f); } } break; case UNCOMPRESSED_R32G32B32: @@ -793,9 +928,9 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) { - ((float *)image->data)[i] = (float)pixels[k].r/255.0f; - ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; - ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; + ((float *)image->data)[i] = pixels[k].x; + ((float *)image->data)[i + 1] = pixels[k].y; + ((float *)image->data)[i + 2] = pixels[k].z; } } break; case UNCOMPRESSED_R32G32B32A32: @@ -804,10 +939,10 @@ void ImageFormat(Image *image, int newFormat) for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) { - ((float *)image->data)[i] = (float)pixels[k].r/255.0f; - ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; - ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; - ((float *)image->data)[i + 3] = (float)pixels[k].a/255.0f; + ((float *)image->data)[i] = pixels[k].x; + ((float *)image->data)[i + 1] = pixels[k].y; + ((float *)image->data)[i + 2] = pixels[k].z; + ((float *)image->data)[i + 3] = pixels[k].w; } } break; default: break; -- cgit v1.2.3 From 64804f30e6c57f1259b8a8ca0400e56e436de069 Mon Sep 17 00:00:00 2001 From: Ray San Date: Tue, 12 Jun 2018 13:27:41 +0200 Subject: Comment review --- src/textures.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 5c2196e2..0ea60ad9 100644 --- a/src/textures.c +++ b/src/textures.c @@ -780,8 +780,7 @@ void ImageToPOT(Image *image, Color fillColor) int format = image->format; // Store image data format to reconvert later - // TODO: Image width and height changes... do we want to store new values or keep the old ones? - // NOTE: Issues when using image.width and image.height for sprite animations... + // NOTE: Image size changes, new width and height *image = LoadImageEx(pixelsPOT, potWidth, potHeight); free(pixelsPOT); // Free POT pixels data -- cgit v1.2.3 From 372e4a1139f8ac4b5e1220771447f1220104b112 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 12 Jun 2018 16:30:03 +0200 Subject: Reviewed some functions - GetImageData() - GetImageDataNormalized() --- src/textures.c | 360 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 187 insertions(+), 173 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 0ea60ad9..eeaf7ffd 100644 --- a/src/textures.c +++ b/src/textures.c @@ -409,104 +409,110 @@ Color *GetImageData(Image image) { Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); - for (int i = 0, k = 0; i < image.width*image.height; i++) + if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats"); + else { - switch (image.format) + if ((image.format == UNCOMPRESSED_R32) || + (image.format == UNCOMPRESSED_R32G32B32) || + (image.format == UNCOMPRESSED_R32G32B32A32)) TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel"); + + for (int i = 0, k = 0; i < image.width*image.height; i++) { - case UNCOMPRESSED_GRAYSCALE: + switch (image.format) { - pixels[i].r = ((unsigned char *)image.data)[i]; - pixels[i].g = ((unsigned char *)image.data)[i]; - pixels[i].b = ((unsigned char *)image.data)[i]; - pixels[i].a = 255; + case UNCOMPRESSED_GRAYSCALE: + { + pixels[i].r = ((unsigned char *)image.data)[i]; + pixels[i].g = ((unsigned char *)image.data)[i]; + pixels[i].b = ((unsigned char *)image.data)[i]; + pixels[i].a = 255; - } break; - case UNCOMPRESSED_GRAY_ALPHA: - { - pixels[i].r = ((unsigned char *)image.data)[k]; - pixels[i].g = ((unsigned char *)image.data)[k]; - pixels[i].b = ((unsigned char *)image.data)[k]; - pixels[i].a = ((unsigned char *)image.data)[k + 1]; - - k += 2; - } break; - case UNCOMPRESSED_R5G5B5A1: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + } break; + case UNCOMPRESSED_GRAY_ALPHA: + { + pixels[i].r = ((unsigned char *)image.data)[k]; + pixels[i].g = ((unsigned char *)image.data)[k]; + pixels[i].b = ((unsigned char *)image.data)[k]; + pixels[i].a = ((unsigned char *)image.data)[k + 1]; - pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); - pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); - pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); + k += 2; + } break; + case UNCOMPRESSED_R5G5B5A1: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R5G6B5: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); + pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); + pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); - pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); - pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); - pixels[i].a = 255; + } break; + case UNCOMPRESSED_R5G6B5: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); + pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); + pixels[i].a = 255; - pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); - pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); - pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); + } break; + case UNCOMPRESSED_R4G4B4A4: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R8G8B8A8: - { - pixels[i].r = ((unsigned char *)image.data)[k]; - pixels[i].g = ((unsigned char *)image.data)[k + 1]; - pixels[i].b = ((unsigned char *)image.data)[k + 2]; - pixels[i].a = ((unsigned char *)image.data)[k + 3]; - - k += 4; - } break; - case UNCOMPRESSED_R8G8B8: - { - pixels[i].r = (unsigned char)((unsigned char *)image.data)[k]; - pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1]; - pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2]; - pixels[i].a = 255; - - k += 3; - } break; - case UNCOMPRESSED_R32: - { - TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel"); break; - - pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].g = 0; - pixels[i].b = 0; - pixels[i].a = 255; - - } break; - case UNCOMPRESSED_R32G32B32: - { - pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f); - pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f); - pixels[i].a = 255; - - k += 3; - } - case UNCOMPRESSED_R32G32B32A32: - { - pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f); - pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f); - - k += 4; + pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); + pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); + pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); + + } break; + case UNCOMPRESSED_R8G8B8A8: + { + pixels[i].r = ((unsigned char *)image.data)[k]; + pixels[i].g = ((unsigned char *)image.data)[k + 1]; + pixels[i].b = ((unsigned char *)image.data)[k + 2]; + pixels[i].a = ((unsigned char *)image.data)[k + 3]; + + k += 4; + } break; + case UNCOMPRESSED_R8G8B8: + { + pixels[i].r = (unsigned char)((unsigned char *)image.data)[k]; + pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1]; + pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2]; + pixels[i].a = 255; + + k += 3; + } break; + case UNCOMPRESSED_R32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = 0; + pixels[i].b = 0; + pixels[i].a = 255; + + } break; + case UNCOMPRESSED_R32G32B32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f); + pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f); + pixels[i].a = 255; + + k += 3; + } + case UNCOMPRESSED_R32G32B32A32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f); + + k += 4; + } + default: break; } - default: TraceLog(LOG_WARNING, "Format not supported for pixel data retrieval"); break; } } @@ -518,102 +524,106 @@ Vector4 *GetImageDataNormalized(Image image) { Vector4 *pixels = (Vector4 *)malloc(image.width*image.height*sizeof(Vector4)); - for (int i = 0, k = 0; i < image.width*image.height; i++) + if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats"); + else { - switch (image.format) + for (int i = 0, k = 0; i < image.width*image.height; i++) { - case UNCOMPRESSED_GRAYSCALE: + switch (image.format) { - pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f; - pixels[i].w = 1.0f; + case UNCOMPRESSED_GRAYSCALE: + { + pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f; + pixels[i].w = 1.0f; - } break; - case UNCOMPRESSED_GRAY_ALPHA: - { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f; - - k += 2; - } break; - case UNCOMPRESSED_R5G5B5A1: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + } break; + case UNCOMPRESSED_GRAY_ALPHA: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f; - pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); - pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); - pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; + k += 2; + } break; + case UNCOMPRESSED_R5G5B5A1: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R5G6B5: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); + pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); + pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; - pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); - pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); - pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31); - pixels[i].w = 1.0f; + } break; + case UNCOMPRESSED_R5G6B5: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; + pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); + pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63); + pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31); + pixels[i].w = 1.0f; - pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); - pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); - pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); - pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15); + } break; + case UNCOMPRESSED_R4G4B4A4: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; - } break; - case UNCOMPRESSED_R8G8B8A8: - { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; - pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f; - - k += 4; - } break; - case UNCOMPRESSED_R8G8B8: - { - pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; - pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; - pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; - pixels[i].w = 1.0f; - - k += 3; - } break; - case UNCOMPRESSED_R32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = 0.0f; - pixels[i].z = 0.0f; - pixels[i].w = 1.0f; - - } break; - case UNCOMPRESSED_R32G32B32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = ((float *)image.data)[k + 1]; - pixels[i].z = ((float *)image.data)[k + 2]; - pixels[i].w = 1.0f; - - k += 3; - } - case UNCOMPRESSED_R32G32B32A32: - { - pixels[i].x = ((float *)image.data)[k]; - pixels[i].y = ((float *)image.data)[k + 1]; - pixels[i].z = ((float *)image.data)[k + 2]; - pixels[i].w = ((float *)image.data)[k + 3]; - - k += 4; + pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15); + pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15); + pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15); + pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15); + + } break; + case UNCOMPRESSED_R8G8B8A8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f; + + k += 4; + } break; + case UNCOMPRESSED_R8G8B8: + { + pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f; + pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f; + pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f; + pixels[i].w = 1.0f; + + k += 3; + } break; + case UNCOMPRESSED_R32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = 0.0f; + pixels[i].z = 0.0f; + pixels[i].w = 1.0f; + + } break; + case UNCOMPRESSED_R32G32B32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = 1.0f; + + k += 3; + } + case UNCOMPRESSED_R32G32B32A32: + { + pixels[i].x = ((float *)image.data)[k]; + pixels[i].y = ((float *)image.data)[k + 1]; + pixels[i].z = ((float *)image.data)[k + 2]; + pixels[i].w = ((float *)image.data)[k + 3]; + + k += 4; + } + default: break; } - default: TraceLog(LOG_WARNING, "Format not supported for pixel data retrieval"); break; } } @@ -792,7 +802,7 @@ void ImageToPOT(Image *image, Color fillColor) // Convert image data to desired format void ImageFormat(Image *image, int newFormat) { - if (image->format != newFormat) + if ((newFormat != 0) && (image->format != newFormat)) { if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB)) { @@ -2119,7 +2129,11 @@ Image GenImageCellular(int width, int height, int tileSize) // NOTE: Characters info data should be allocated by user for charsCount Image GenImageFont(const char *fileName, int fontSize, int charsCount, int *fontChars, CharInfo *chars) { + Image image = { 0 }; + // TODO. + + return image; } #endif // SUPPORT_IMAGE_GENERATION -- cgit v1.2.3 From 75ba5aca551d2b16fa75ba31e616b009ac5dde6a Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 20 Jun 2018 00:52:14 +0200 Subject: Improved font generation and SDF Added: data to CharInfo struct Added: LoadFontData() Added: GenImageFontAtlas() Removed: LoadFontEx() Removed: LoadTTF() [internal] Some code tweaks --- release/include/raylib.h | 27 +-- release/libs/win32/mingw32/libraylib.a | Bin 1103438 -> 1116752 bytes src/raylib.h | 27 +-- src/text.c | 356 ++++++++++++++++++++------------- src/textures.c | 4 +- 5 files changed, 243 insertions(+), 171 deletions(-) (limited to 'src/textures.c') diff --git a/release/include/raylib.h b/release/include/raylib.h index e0cfaa6d..49434d52 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -389,6 +389,7 @@ typedef struct CharInfo { int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X + unsigned char *data; // Character pixel data (grayscale) } CharInfo; // Font type, includes texture and charSet array data @@ -955,29 +956,29 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters - //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ // Font loading/unloading functions -RLAPI Font GetDefaultFont(void); // Get the default Font -RLAPI Font LoadFont(const char *fileName); // Load Font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load Font from file with extended parameters -RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) +RLAPI Font GetDefaultFont(void); // Get the default Font +RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) +RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf); // Load font data for further use +RLAPI Image GenImageFontAtlas(CharInfo *chars, int fontSize, int charsCount, int packing); // Generate image font atlas using chars info +RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Shows current FPS -RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using Font and additional parameters +RLAPI void DrawFPS(int posX, int posY); // Shows current FPS +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters // Text misc. functions -RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string -RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on sprite font //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/release/libs/win32/mingw32/libraylib.a b/release/libs/win32/mingw32/libraylib.a index 2701869a..3425c71a 100644 Binary files a/release/libs/win32/mingw32/libraylib.a and b/release/libs/win32/mingw32/libraylib.a differ diff --git a/src/raylib.h b/src/raylib.h index e0cfaa6d..49434d52 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -389,6 +389,7 @@ typedef struct CharInfo { int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X + unsigned char *data; // Character pixel data (grayscale) } CharInfo; // Font type, includes texture and charSet array data @@ -955,29 +956,29 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters - //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ // Font loading/unloading functions -RLAPI Font GetDefaultFont(void); // Get the default Font -RLAPI Font LoadFont(const char *fileName); // Load Font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load Font from file with extended parameters -RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) +RLAPI Font GetDefaultFont(void); // Get the default Font +RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) +RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf); // Load font data for further use +RLAPI Image GenImageFontAtlas(CharInfo *chars, int fontSize, int charsCount, int packing); // Generate image font atlas using chars info +RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Shows current FPS -RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using Font and additional parameters +RLAPI void DrawFPS(int posX, int posY); // Shows current FPS +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters // Text misc. functions -RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string -RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on sprite font //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/src/text.c b/src/text.c index 9755ff8b..3c3ff751 100644 --- a/src/text.c +++ b/src/text.c @@ -47,16 +47,14 @@ #include "utils.h" // Required for: fopen() Android mapping #if defined(SUPPORT_FILEFORMAT_TTF) - // Following libs are used on LoadTTF() - #define STBTT_STATIC // Define stb_truetype functions static to this module + #define STB_RECT_PACK_IMPLEMENTATION + #include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging + + #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION - #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() + #include "external/stb_truetype.h" // Required for: ttf font data reading #endif -// Rectangle packing functions (not used at the moment) -//#define STB_RECT_PACK_IMPLEMENTATION -//#include "stb_rect_pack.h" - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -89,7 +87,7 @@ static Font LoadImageFont(Image image, Color key, int firstChar); // Load a Imag static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) #endif #if defined(SUPPORT_FILEFORMAT_TTF) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data +//static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data #endif #if defined(SUPPORT_DEFAULT_FONT) @@ -276,68 +274,244 @@ Font LoadFont(const char *fileName) // Default hardcoded values for ttf file loading #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs - #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont + #define DEFAULT_FIRST_CHAR 32 // Expected first char for image sprite font - Font spriteFont = { 0 }; + Font font = { 0 }; #if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); + if (IsFileExtension(fileName, ".ttf")) + { + font.baseSize = DEFAULT_TTF_FONTSIZE; + font.charsCount = DEFAULT_TTF_NUMCHARS; + font.chars = LoadFontData(fileName, font.baseSize, NULL, font.charsCount, false); + Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 0); + font.texture = LoadTextureFromImage(atlas); + UnloadImage(atlas); + } else #endif #if defined(SUPPORT_FILEFORMAT_FNT) - if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); + if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName); else #endif { Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); + if (image.data != NULL) font = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); UnloadImage(image); } - if (spriteFont.texture.id == 0) + if (font.texture.id == 0) { TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName); - spriteFont = GetDefaultFont(); + font = GetDefaultFont(); } - else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) + else SetTextureFilter(font.texture, FILTER_POINT); // By default we set point filter (best performance) - return spriteFont; + return font; } -// Load Font from TTF font file with generation parameters -// NOTE: You can pass an array with desired characters, those characters should be available in the font -// if array is NULL, default char set is selected 32..126 -Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) +// Load font data for further use +// NOTE: Requires TTF font and can generate SDF data +CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf) { - Font spriteFont = { 0 }; - int totalChars = 95; // Default charset [32..126] - bool fontCharsLoaded = false; + // NOTE: Using some SDF generation default values, + // trades off precision with ability to handle *smaller* sizes + #define SDF_CHAR_PADDING 4 + #define SDF_ON_EDGE_VALUE 128 + #define SDF_PIXEL_DIST_SCALE 64.0f + + CharInfo *chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); + + // Load font data (including pixel data) from TTF file + // NOTE: Loaded information should be enough to generate font image atlas, + // using any packaging method + FILE *fontFile = fopen(fileName, "rb"); // Load font file + + fseek(fontFile, 0, SEEK_END); + long size = ftell(fontFile); // Get file size + fseek(fontFile, 0, SEEK_SET); // Reset file pointer + + unsigned char *fontBuffer = (unsigned char *)malloc(size); + + fread(fontBuffer, size, 1, fontFile); + fclose(fontFile); + + // Init font for data reading + stbtt_fontinfo fontInfo; + if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!"); -#if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) + // Calculate font scale factor + float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); + + // Calculate font basic metrics + // NOTE: ascent is equivalent to font baseline + int ascent, descent, lineGap; + stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); + ascent *= scaleFactor; + descent *= scaleFactor; + + // Fill fontChars in case not provided externally + // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) + int genFontChars = false; + if (fontChars == NULL) genFontChars = true; + if (genFontChars) + { + fontChars = (int *)malloc(charsCount*sizeof(int)); + for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; + } + + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) + { + int chw = 0, chh = 0; // Character width and height (on generation) + int ch = fontChars[i]; // Character value to get info for + chars[i].value = ch; + + // Render a unicode codepoint to a bitmap + // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap + // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be + // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide + + if (!sdf) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + + chars[i].rec.width = (float)chw; + chars[i].rec.height = (float)chh; + chars[i].offsetY += ascent; + + // Get bounding box for character (may be offset to account for chars that dip above or below the line) + int chX1, chY1, chX2, chY2; + stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); + + TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); + TraceLog(LOG_DEBUG, "Character offsetY: %i", ascent + chY1); + + stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); + chars[i].advanceX *= scaleFactor; + } + + free(fontBuffer); + if (genFontChars) free(fontChars); + + return chars; +} + +// Generate image font atlas using chars info +// NOTE: Packing method: 0-Default, 1-Skyline +Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int packing) +{ + Image atlas = { 0 }; + + int padding = 10; + + // Calculate atlas texture size based on fontSize + // NOTE: Font texture size is predicted (being as much conservative as possible) + // Predictive method consist of supposing same number of chars by line-column (sqrtf) + // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... + //float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); + //int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT + + // TODO: TEXTURE SIZE NOT GOOD ENOUGH! -> Calculate chars area -> guess texture size? + float requiredArea = 0; + for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].rec.width + 2*padding)*(chars[i].rec.height + 2*padding)); + float guessSize = sqrtf(requiredArea)*1.25f; + int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT + + atlas.width = textureSize; // Atlas bitmap width + atlas.height = textureSize; // Atlas bitmap height + atlas.data = (unsigned char *)calloc(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) + atlas.format = UNCOMPRESSED_GRAYSCALE; + atlas.mipmaps = 1; + + if (packing == 0) // Use basic packing algorythm { - if (charsCount != 0) totalChars = charsCount; + int offsetX = padding; + int offsetY = padding; - if (fontChars == NULL) + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) { - fontChars = (int *)malloc(totalChars*sizeof(int)); - for (int i = 0; i < totalChars; i++) fontChars[i] = i + 32; // Default first character: SPACE[32] - fontCharsLoaded = true; + // Copy pixel data from fc.data to atlas + for (int y = 0; y < (int)chars[i].rec.height; y++) + { + for (int x = 0; x < (int)chars[i].rec.width; x++) + { + ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = chars[i].data[y*(int)chars[i].rec.width + x]; + } + } + + chars[i].rec.x = offsetX; + chars[i].rec.y = offsetY; + + // Move atlas position X for next character drawing + offsetX += ((int)chars[i].advanceX + 2*padding); + + if (offsetX >= (atlas.width - (int)chars[i].rec.width - padding)) + { + offsetX = padding; + offsetY += (fontSize + 2*padding); + + if (offsetY > (atlas.height - fontSize - padding)) break; + } } + } + else if (packing == 1) // Use Skyline rect packing algorythm + { + stbrp_context *context = (stbrp_context *)malloc(sizeof(*context)); + stbrp_node *nodes = (stbrp_node *)malloc(charsCount*sizeof(*nodes)); + + stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); + stbrp_rect *rects = (stbrp_rect *)malloc(charsCount*sizeof(stbrp_rect)); - spriteFont = LoadTTF(fileName, fontSize, totalChars, fontChars); + // Fill rectangles for packaging + for (int i = 0; i < charsCount; i++) + { + rects[i].id = i; + rects[i].w = (int)chars[i].rec.width + 2*padding; + rects[i].h = (int)chars[i].rec.height + 2*padding; + } + + // Package rectangles into atlas + stbrp_pack_rects(context, rects, charsCount); - if (fontCharsLoaded) free(fontChars); + for (int i = 0; i < charsCount; i++) + { + chars[i].rec.x = rects[i].x + padding; + chars[i].rec.y = rects[i].y + padding; + + if (rects[i].was_packed) + { + // Copy pixel data from fc.data to atlas + for (int y = 0; y < (int)chars[i].rec.height; y++) + { + for (int x = 0; x < (int)chars[i].rec.width; x++) + { + ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = chars[i].data[y*(int)chars[i].rec.width + x]; + } + } + } + else TraceLog(LOG_WARNING, "Character could not be packed: %i", i); + } + + free(nodes); + free(context); } -#endif + + // Convert image data from GRAYSCALE to GRAY_ALPHA + //ImageAlphaMask(&atlas, atlas); // WARNING: Not working in this case, requires manual operation + unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - if (spriteFont.texture.id == 0) + for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) { - TraceLog(LOG_WARNING, "[%s] Font could not be generated, using default font", fileName); - spriteFont = GetDefaultFont(); + dataGrayAlpha[k] = 255; + dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i]; } - return spriteFont; + free(atlas.data); + atlas.data = dataGrayAlpha; + atlas.format = UNCOMPRESSED_GRAY_ALPHA; + + return atlas; } // Unload Font from GPU memory (VRAM) @@ -811,108 +985,4 @@ static Font LoadBMFont(const char *fileName) return font; } -#endif - -#if defined(SUPPORT_FILEFORMAT_TTF) -// Generate a sprite font from TTF file data (font size required) -// TODO: Review texture packing method and generation (use oversampling) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) -{ - #define MAX_TTF_SIZE 16 // Maximum ttf file size in MB - - // NOTE: Font texture size is predicted (being as much conservative as possible) - // Predictive method consist of supposing same number of chars by line-column (sqrtf) - // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... - - // Calculate next power-of-two value - float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); - int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT - - TraceLog(LOG_INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); - - unsigned char *ttfBuffer = (unsigned char *)malloc(MAX_TTF_SIZE*1024*1024); - unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); - - Font font = { 0 }; - - FILE *ttfFile = fopen(fileName, "rb"); - - if (ttfFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); - return font; - } - - // NOTE: We try reading up to 16 MB of elements of 1 byte - fread(ttfBuffer, 1, MAX_TTF_SIZE*1024*1024, ttfFile); - - // Find font baseline (vertical origin of the font) - // NOTE: This value is required because y-offset depends on it! - stbtt_fontinfo fontInfo; - int ascent, baseline; - float scale; - - stbtt_InitFont(&fontInfo, ttfBuffer, 0); - scale = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); - stbtt_GetFontVMetrics(&fontInfo, &ascent, 0, 0); - baseline = (int)(ascent*scale); - - if (fontChars[0] != 32) TraceLog(LOG_WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); - - // NOTE: Using stb_truetype crappy packing method, no guarantee the font fits the image... - // TODO: Replace this function by a proper packing method and support random chars order, - // we already receive a list (fontChars) with the ordered expected characters - int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData); - - //if (result > 0) TraceLog(LOG_INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); - if (result < 0) TraceLog(LOG_WARNING, "TTF spritefont loading: Not all the characters fit in the font"); - - free(ttfBuffer); - - // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - - for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) - { - dataGrayAlpha[k] = 0xff; - dataGrayAlpha[k + 1] = dataBitmap[i]; - } - - free(dataBitmap); - - // Sprite font generation from TTF extracted data - Image image; - image.width = textureSize; - image.height = textureSize; - image.mipmaps = 1; - image.format = UNCOMPRESSED_GRAY_ALPHA; - image.data = dataGrayAlpha; - font.texture = LoadTextureFromImage(image); // Load image into texture - UnloadImage(image); // Unloads image data (dataGrayAlpha) - - - // Fill font characters info data - font.baseSize = fontSize; - font.charsCount = charsCount; - font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo)); - - for (int i = 0; i < font.charsCount; i++) - { - font.chars[i].value = fontChars[i]; - - font.chars[i].rec.x = (int)charData[i].x0; - font.chars[i].rec.y = (int)charData[i].y0; - font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0; - font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; - - font.chars[i].offsetX = charData[i].xoff; - font.chars[i].offsetY = baseline + charData[i].yoff; - font.chars[i].advanceX = (int)charData[i].xadvance; - } - - free(charData); - - return font; -} -#endif +#endif \ No newline at end of file diff --git a/src/textures.c b/src/textures.c index eeaf7ffd..29316a7a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -828,9 +828,9 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_GRAY_ALPHA: { - image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); + 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, k++) + for (int i = 0; i < image->width*image->height*2; i += 2, k++) { ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f); ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f); -- cgit v1.2.3 From 276974de05f4ab01feae89b633dcfafa720a9bf2 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 Jul 2018 16:39:04 +0200 Subject: Removed function prototype This function was added in text module as GenImageFontAtlas() --- src/textures.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/textures.c') diff --git a/src/textures.c b/src/textures.c index 29316a7a..81bbbf3c 100644 --- a/src/textures.c +++ b/src/textures.c @@ -2123,18 +2123,6 @@ Image GenImageCellular(int width, int height, int tileSize) return image; } - -// Generate image: font atlas. Requires TTF as input file. -// NOTE: Generated atlas packs characters in order and rectangles are defined with magenta borders (?) -// NOTE: Characters info data should be allocated by user for charsCount -Image GenImageFont(const char *fileName, int fontSize, int charsCount, int *fontChars, CharInfo *chars) -{ - Image image = { 0 }; - - // TODO. - - return image; -} #endif // SUPPORT_IMAGE_GENERATION // Generate GPU mipmaps for a texture -- cgit v1.2.3 From 74fd0e7ca4faaa428c248a9ae714e2e7371e6ed4 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 3 Jul 2018 00:57:58 +0200 Subject: Added function: ImageColorReplace() --- release/include/raylib.h | 1 + release/libs/win32/mingw32/libraylib.a | Bin 1118066 -> 1118620 bytes src/raylib.h | 1 + src/textures.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+) (limited to 'src/textures.c') diff --git a/release/include/raylib.h b/release/include/raylib.h index 96bf2443..43000318 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -937,6 +937,7 @@ RLAPI void ImageColorInvert(Image *image); RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) +RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color // Image generation functions RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color diff --git a/release/libs/win32/mingw32/libraylib.a b/release/libs/win32/mingw32/libraylib.a index 675b11ea..e5a6a9bc 100644 Binary files a/release/libs/win32/mingw32/libraylib.a and b/release/libs/win32/mingw32/libraylib.a differ diff --git a/src/raylib.h b/src/raylib.h index 96bf2443..43000318 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -937,6 +937,7 @@ RLAPI void ImageColorInvert(Image *image); RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) +RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color // Image generation functions RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color diff --git a/src/textures.c b/src/textures.c index 81bbbf3c..f2dc7ca3 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1901,6 +1901,36 @@ void ImageColorBrightness(Image *image, int brightness) image->data = processed.data; } + +// Modify image color: replace color +void ImageColorReplace(Image *image, Color color, Color replace) +{ + Color *pixels = GetImageData(*image); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + if ((pixels[y*image->width + x].r == color.r) && + (pixels[y*image->width + x].g == color.g) && + (pixels[y*image->width + x].b == color.b) && + (pixels[y*image->width + x].a == color.a)) + { + pixels[y*image->width + x].r = replace.r; + pixels[y*image->width + x].g = replace.g; + pixels[y*image->width + x].b = replace.b; + pixels[y*image->width + x].a = replace.a; + } + } + } + + Image processed = LoadImageEx(pixels, image->width, image->height); + ImageFormat(&processed, image->format); + UnloadImage(*image); + free(pixels); + + image->data = processed.data; +} #endif // SUPPORT_IMAGE_MANIPULATION #if defined(SUPPORT_IMAGE_GENERATION) -- cgit v1.2.3