diff --git a/examples/Makefile b/examples/Makefile index cc9ef2395..c2ea35bf4 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -453,6 +453,7 @@ TEXTURES = \ textures/textures_image_generation \ textures/textures_image_loading \ textures/textures_image_processing \ + textures/textures_image_rotate \ textures/textures_image_text \ textures/textures_to_image \ textures/textures_raw_data \ diff --git a/examples/textures/textures_image_rotate.c b/examples/textures/textures_image_rotate.c new file mode 100644 index 000000000..bcff14297 --- /dev/null +++ b/examples/textures/textures_image_rotate.c @@ -0,0 +1,79 @@ +/******************************************************************************************* +* +* raylib [textures] example - Image Rotation +* +* Example originally created with raylib 1.0, last time updated with raylib 1.0 +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#define NUM_TEXTURES 3 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing"); + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) + Image image45 = LoadImage("resources/raylib_logo.png"); + Image image90 = LoadImage("resources/raylib_logo.png"); + Image imageNeg90 = LoadImage("resources/raylib_logo.png"); + + ImageRotate(&image45, 45); + ImageRotate(&image90, 90); + ImageRotate(&imageNeg90, -90); + + Texture2D textures[NUM_TEXTURES] = { 0 }; + + textures[0] = LoadTextureFromImage(image45); + textures[1] = LoadTextureFromImage(image90); + textures[2] = LoadTextureFromImage(imageNeg90); + + int currentTexture = 0; + //--------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) || IsKeyPressed(KEY_RIGHT)) + { + currentTexture = (currentTexture + 1)%NUM_TEXTURES; // Cycle between the textures + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawTexture(textures[currentTexture], screenWidth/2 - textures[currentTexture].width/2, screenHeight/2 - textures[currentTexture].height/2, WHITE); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + for (int i = 0; i < NUM_TEXTURES; i++) UnloadTexture(textures[i]); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/textures/textures_image_rotate.png b/examples/textures/textures_image_rotate.png new file mode 100644 index 000000000..64bbc54e4 Binary files /dev/null and b/examples/textures/textures_image_rotate.png differ diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 85b3e3e4c..ced109eaf 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1685,6 +1685,10 @@ + + + + diff --git a/projects/Geany/raylib.c.tags b/projects/Geany/raylib.c.tags index 4cc6d4605..79a192a14 100644 --- a/projects/Geany/raylib.c.tags +++ b/projects/Geany/raylib.c.tags @@ -202,6 +202,7 @@ ImageDrawText|void|(Image *dst, Vector2 position, const char *text, int fontSize ImageDrawTextEx|void|(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color);| ImageFlipVertical|void|(Image *image);| ImageFlipHorizontal|void|(Image *image);| +ImageRotate|void|(Image *image, int degrees);| ImageRotateCW|void|(Image *image);| ImageRotateCCW|void|(Image *image);| ImageColorTint|void|(Image *image, Color color);| diff --git a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml index 7e173a936..883183cef 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml +++ b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml @@ -1570,6 +1570,12 @@ + + + + + + diff --git a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h index f20f065e3..c32cdb26e 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h +++ b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h @@ -346,6 +346,7 @@ RLAPI void ImageMipmaps(Image *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 void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageRotate(Image *image, int degrees); // Rotate image by input angle in degrees (-359 to 359) 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 diff --git a/src/raylib.h b/src/raylib.h index 703e70c21..b2b825831 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1268,6 +1268,7 @@ RLAPI void ImageMipmaps(Image *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 void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageRotate(Image *image, int degrees); // Rotate image by input angle in degrees (-359 to 359) 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 diff --git a/src/rtextures.c b/src/rtextures.c index eeeebba82..1134357bf 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -2118,6 +2118,65 @@ void ImageFlipHorizontal(Image *image) } } +// Rotate image in degrees +void ImageRotate(Image *image, int degrees) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); + if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); + else + { + double rad = degrees * PI / 180.0; + double sin_rad = sin(rad); + double cos_rad = cos(rad); + + int new_width = abs(image->width * cos_rad) + abs(image->height * sin_rad); + int new_height = abs(image->height * cos_rad) + abs(image->width * sin_rad); + + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *rotatedData = (unsigned char *)RL_CALLOC(new_width * new_height, bytesPerPixel); + + for (int y = 0; y < new_height; y++) + { + for (int x = 0; x < new_width; x++) + { + double oldX = ((x - new_width / 2.0) * cos_rad + (y - new_height / 2.0) * sin_rad) + image->width / 2.0; + double oldY = ((y - new_height / 2.0) * cos_rad - (x - new_width / 2.0) * sin_rad) + image->height / 2.0; + + if (oldX >= 0 && oldX < image->width && oldY >= 0 && oldY < image->height) + { + int x1 = (int)floor(oldX); + int y1 = (int)floor(oldY); + int x2 = MIN(x1 + 1, image->width - 1); + int y2 = MIN(y1 + 1, image->height - 1); + + double px = oldX - x1; + double py = oldY - y1; + + for (int i = 0; i < bytesPerPixel; i++) + { + double f1 = ((unsigned char *)image->data)[(y1 * image->width + x1) * bytesPerPixel + i]; + double f2 = ((unsigned char *)image->data)[(y1 * image->width + x2) * bytesPerPixel + i]; + double f3 = ((unsigned char *)image->data)[(y2 * image->width + x1) * bytesPerPixel + i]; + double f4 = ((unsigned char *)image->data)[(y2 * image->width + x2) * bytesPerPixel + i]; + + double val = f1 * (1 - px) * (1 - py) + f2 * px * (1 - py) + f3 * (1 - px) * py + f4 * px * py; + + rotatedData[(y * new_width + x) * bytesPerPixel + i] = (unsigned char)val; + } + } + } + } + + RL_FREE(image->data); + image->data = rotatedData; + image->width = new_width; + image->height = new_height; + } +} + // Rotate image clockwise 90deg void ImageRotateCW(Image *image) {