|
|
@ -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 |
|
|
|