From 7e66903d5610ea5c72852d11b29c3f1a31a5aa00 Mon Sep 17 00:00:00 2001 From: Yuri Rubinsky Date: Thu, 14 Jul 2022 22:20:12 +0300 Subject: [PATCH] Implement `rotate_90/rotate_180` functions to `Image` --- core/io/image.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++ core/io/image.h | 3 ++ doc/classes/Image.xml | 13 ++++++ 3 files changed, 121 insertions(+) diff --git a/core/io/image.cpp b/core/io/image.cpp index 473d70bd7c4..45ca4d2af1e 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1339,6 +1339,108 @@ void Image::crop(int p_width, int p_height) { crop_from_point(0, 0, p_width, p_height); } +void Image::rotate_90(ClockDirection p_direction) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + int saved_width = height; + int saved_height = width; + + if (width != height) { + int n = MAX(width, height); + resize(n, n, INTERPOLATE_NEAREST); + } + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + // Flip. + + if (p_direction == CLOCKWISE) { + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(x, height - y - 1, pixel_size, w, dst); + + _put_pixelb(x, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } else { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width / 2; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, y, pixel_size, w, dst); + + _put_pixelb(width - x - 1, y, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + // Transpose. + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x < y) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(y, x, pixel_size, w, dst); + + _put_pixelb(y, x, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + } + + if (saved_width != saved_height) { + resize(saved_width, saved_height, INTERPOLATE_NEAREST); + } else if (used_mipmaps) { + generate_mipmaps(); + } +} + +void Image::rotate_180() { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + + _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + if (used_mipmaps) { + generate_mipmaps(); + } +} + void Image::flip_y() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); @@ -3217,6 +3319,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); + ClassDB::bind_method(D_METHOD("rotate_90", "direction"), &Image::rotate_90); + ClassDB::bind_method(D_METHOD("rotate_180"), &Image::rotate_180); + ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges); ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); diff --git a/core/io/image.h b/core/io/image.h index 6b323e5eb3f..74d84157820 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -254,6 +254,9 @@ public: void crop_from_point(int p_x, int p_y, int p_width, int p_height); void crop(int p_width, int p_height); + void rotate_90(ClockDirection p_direction); + void rotate_180(); + void flip_x(); void flip_y(); diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 31bd938c403..4735e63783d 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -378,6 +378,19 @@ Converts a standard RGBE (Red Green Blue Exponent) image to an sRGB image. + + + + Rotates the image by [code]180[/code] degrees. The width and height of the image must be greater than [code]1[/code]. + + + + + + + Rotates the image in the specified [code]direction[/code] by [code]90[/code] degrees. The width and height of the image must be greater than [code]1[/code]. If the width and height are not equal, the image will be resized. + +