From c708f01d59e44f1092708d9476f89baa31da315a Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Sun, 18 Aug 2024 15:24:08 -0400 Subject: [PATCH 1/7] mirr0r filter added --- src/filter/CMakeLists.txt | 1 + src/filter/mirr0r/CMakeLists.txt | 15 ++++ src/filter/mirr0r/mirr0r.cpp | 143 +++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100755 src/filter/mirr0r/CMakeLists.txt create mode 100755 src/filter/mirr0r/mirr0r.cpp diff --git a/src/filter/CMakeLists.txt b/src/filter/CMakeLists.txt index 0c228521..8ede934c 100644 --- a/src/filter/CMakeLists.txt +++ b/src/filter/CMakeLists.txt @@ -12,6 +12,7 @@ endif (${OpenCV_FOUND}) if (${Cairo_FOUND}) add_subdirectory (cairoimagegrid) add_subdirectory (cairogradient) + add_subdirectory (mirr0r) endif (${Cairo_FOUND}) add_subdirectory (3dflippo) diff --git a/src/filter/mirr0r/CMakeLists.txt b/src/filter/mirr0r/CMakeLists.txt new file mode 100755 index 00000000..7a811bde --- /dev/null +++ b/src/filter/mirr0r/CMakeLists.txt @@ -0,0 +1,15 @@ +set (SOURCES mirr0r.cpp) +set (TARGET mirr0r) + +include_directories(${Cairo_INCLUDE_DIR}) +set(LIBS ${LIBS} ${Cairo_LIBRARY}) + +if (MSVC) + set (SOURCES ${SOURCES} ${FREI0R_DEF}) +endif (MSVC) + +add_library (${TARGET} MODULE ${SOURCES}) + +set_target_properties (${TARGET} PROPERTIES PREFIX "") +target_link_libraries(mirr0r ${LIBS}) +install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR}) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp new file mode 100755 index 00000000..d687d057 --- /dev/null +++ b/src/filter/mirr0r/mirr0r.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2024 Johann JEG (johannjeg1057@gmail.com) + * + * This file is a Frei0r plugin. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "frei0r.hpp" +#include +#include +#include +#include + +#define PI 3.14159265358979323846 + +#ifdef __cplusplus +extern "C"{ +#endif + +#define register + +#include "frei0r/cairo.h" + +#undef register + +#ifdef __cplusplus +} +#endif + +class Mirr0r : public frei0r::filter { + +private: + unsigned int width; + unsigned int height; + double x_offset; + double y_offset; + double zoom; + double rotation; + +public: + + Mirr0r(unsigned int width, unsigned int height){ + register_param(this->x_offset, "x_offset", "Horizontal offset for image positioning."); + register_param(this->y_offset, "y_offset", "Vertical offset for image positioning."); + register_param(this->zoom, "zoom", "Zoom level for image scaling."); + register_param(this->rotation, "rotation", "Rotation angle in degrees."); + + this->width = width; + this->height = height; + this->x_offset = 0.5; + this->y_offset = 0.5; + this->zoom = 0.5; + this->rotation = 0.5; + } + + ~Mirr0r(){ + + } + + virtual void update(double time, uint32_t* out, const uint32_t* in){ + const unsigned char* src = (unsigned char*)in; + unsigned char* dst = (unsigned char*)out; + + int w = this->width; + int h = this->height; + + if (w <= 0 || h <= 0) { + return; + } + + // Zoom limit range from -0.9 to 2.0 + float zoom = 1.0f + CLAMP(this->zoom, -0.9, 2.0); + + int x_offset_px = (int)(this->x_offset * w); + int y_offset_px = (int)(this->y_offset * h); + + // Calculate the center of the destination image + float center_x = (float)w / 2.0f; + float center_y = (float)h / 2.0f; + + // Convert the rotation to radians + float angle = (float)(this->rotation * PI / 180.0f); + float cos_angle = cosf(angle); + float sin_angle = sinf(angle); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + // Convert the destination coordinates to source coordinates with zoom + float src_x = (x - center_x) / zoom + center_x; + float src_y = (y - center_y) / zoom + center_y; + + // Apply the rotation + float rotated_x = cos_angle * (src_x - center_x) - sin_angle * (src_y - center_y) + center_x; + float rotated_y = sin_angle * (src_x - center_x) + cos_angle * (src_y - center_y) + center_y; + + // Apply the offset + rotated_x += x_offset_px; + rotated_y += y_offset_px; + + int src_x_int = (int)rotated_x % (w * 2); + int src_y_int = (int)rotated_y % (h * 2); + + // Reflect the image if coordinates are out of bounds + // If less than the bound + if (src_x_int < 0) { + src_x_int = 0 - src_x_int - 1; + } + if (src_y_int < 0) { + src_y_int = 0 - src_y_int - 1; + } + // If greater than the bounds + if (src_x_int >= w) { + src_x_int = w - (src_x_int - w) - 1; + } + if (src_y_int >= h) { + src_y_int = h - (src_y_int - h) - 1; + } + + // Copy the pixel from the source image to the destination buffer + ((uint32_t*)dst)[y * w + x] = ((const uint32_t*)src)[src_y_int * w + src_x_int]; + } + } + } +}; + +frei0r::construct plugin( + "Mirr0r", + "Repeats and flips the input image when it goes out of bounds, allowing for adjustable offset, zoom and rotation. A versatile tool for creative video effects.", + "Johann JEG", + 1, 0, + F0R_COLOR_MODEL_RGBA8888); From a359faeffc5468bca10183dd7fff4e2b36d9f95b Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Mon, 19 Aug 2024 05:04:50 -0400 Subject: [PATCH 2/7] removed redundant and unused includes --- .gitignore | 1 + src/filter/CMakeLists.txt | 2 +- src/filter/mirr0r/CMakeLists.txt | 3 --- src/filter/mirr0r/mirr0r.cpp | 23 +++-------------------- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index de08b02d..3a4e0e22 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ doc/html /out/ /.vs/ CMakeSettings.json +.vscode diff --git a/src/filter/CMakeLists.txt b/src/filter/CMakeLists.txt index 8ede934c..9775a6fe 100644 --- a/src/filter/CMakeLists.txt +++ b/src/filter/CMakeLists.txt @@ -12,7 +12,6 @@ endif (${OpenCV_FOUND}) if (${Cairo_FOUND}) add_subdirectory (cairoimagegrid) add_subdirectory (cairogradient) - add_subdirectory (mirr0r) endif (${Cairo_FOUND}) add_subdirectory (3dflippo) @@ -66,6 +65,7 @@ add_subdirectory (luminance) add_subdirectory (mask0mate) add_subdirectory (medians) add_subdirectory (measure) +add_subdirectory (mirr0r) add_subdirectory (ndvi) add_subdirectory (nervous) add_subdirectory (normaliz0r) diff --git a/src/filter/mirr0r/CMakeLists.txt b/src/filter/mirr0r/CMakeLists.txt index 7a811bde..0430c7ef 100755 --- a/src/filter/mirr0r/CMakeLists.txt +++ b/src/filter/mirr0r/CMakeLists.txt @@ -1,9 +1,6 @@ set (SOURCES mirr0r.cpp) set (TARGET mirr0r) -include_directories(${Cairo_INCLUDE_DIR}) -set(LIBS ${LIBS} ${Cairo_LIBRARY}) - if (MSVC) set (SOURCES ${SOURCES} ${FREI0R_DEF}) endif (MSVC) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp index d687d057..54463619 100755 --- a/src/filter/mirr0r/mirr0r.cpp +++ b/src/filter/mirr0r/mirr0r.cpp @@ -18,26 +18,9 @@ */ #include "frei0r.hpp" -#include -#include +#include "frei0r/math.h" +#define _USE_MATH_DEFINES #include -#include - -#define PI 3.14159265358979323846 - -#ifdef __cplusplus -extern "C"{ -#endif - -#define register - -#include "frei0r/cairo.h" - -#undef register - -#ifdef __cplusplus -} -#endif class Mirr0r : public frei0r::filter { @@ -91,7 +74,7 @@ class Mirr0r : public frei0r::filter { float center_y = (float)h / 2.0f; // Convert the rotation to radians - float angle = (float)(this->rotation * PI / 180.0f); + float angle = (float)(this->rotation * M_PI / 180.0f); float cos_angle = cosf(angle); float sin_angle = sinf(angle); From db1dfc43db1ce0c47060b80381bcb0b5562beead Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Thu, 22 Aug 2024 05:07:48 -0400 Subject: [PATCH 3/7] Using Cairo graphics library --- src/filter/CMakeLists.txt | 2 +- src/filter/mirr0r/CMakeLists.txt | 3 + src/filter/mirr0r/mirr0r.cpp | 117 +++++++++++++++---------------- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/filter/CMakeLists.txt b/src/filter/CMakeLists.txt index 9775a6fe..8ede934c 100644 --- a/src/filter/CMakeLists.txt +++ b/src/filter/CMakeLists.txt @@ -12,6 +12,7 @@ endif (${OpenCV_FOUND}) if (${Cairo_FOUND}) add_subdirectory (cairoimagegrid) add_subdirectory (cairogradient) + add_subdirectory (mirr0r) endif (${Cairo_FOUND}) add_subdirectory (3dflippo) @@ -65,7 +66,6 @@ add_subdirectory (luminance) add_subdirectory (mask0mate) add_subdirectory (medians) add_subdirectory (measure) -add_subdirectory (mirr0r) add_subdirectory (ndvi) add_subdirectory (nervous) add_subdirectory (normaliz0r) diff --git a/src/filter/mirr0r/CMakeLists.txt b/src/filter/mirr0r/CMakeLists.txt index 0430c7ef..7a811bde 100755 --- a/src/filter/mirr0r/CMakeLists.txt +++ b/src/filter/mirr0r/CMakeLists.txt @@ -1,6 +1,9 @@ set (SOURCES mirr0r.cpp) set (TARGET mirr0r) +include_directories(${Cairo_INCLUDE_DIR}) +set(LIBS ${LIBS} ${Cairo_LIBRARY}) + if (MSVC) set (SOURCES ${SOURCES} ${FREI0R_DEF}) endif (MSVC) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp index 54463619..4e41ff52 100755 --- a/src/filter/mirr0r/mirr0r.cpp +++ b/src/filter/mirr0r/mirr0r.cpp @@ -19,8 +19,9 @@ #include "frei0r.hpp" #include "frei0r/math.h" +#include #define _USE_MATH_DEFINES -#include +#include class Mirr0r : public frei0r::filter { @@ -52,69 +53,66 @@ class Mirr0r : public frei0r::filter { } - virtual void update(double time, uint32_t* out, const uint32_t* in){ - const unsigned char* src = (unsigned char*)in; - unsigned char* dst = (unsigned char*)out; - + virtual void update(double time, uint32_t* out, const uint32_t* in) { + int w = this->width; int h = this->height; - if (w <= 0 || h <= 0) { - return; - } - - // Zoom limit range from -0.9 to 2.0 - float zoom = 1.0f + CLAMP(this->zoom, -0.9, 2.0); - - int x_offset_px = (int)(this->x_offset * w); - int y_offset_px = (int)(this->y_offset * h); - - // Calculate the center of the destination image + // Calculate the stride for the image surface based on width and format + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); + + // Create a Cairo surface for the destination image + cairo_surface_t* dest_image = cairo_image_surface_create_for_data((unsigned char*)out, + CAIRO_FORMAT_ARGB32, + w, + h, + stride); + + // Create a Cairo drawing context for the destination surface + cairo_t *cr = cairo_create(dest_image); + + // Create a Cairo surface for the source image + cairo_surface_t *image = cairo_image_surface_create_for_data((unsigned char*)in, + CAIRO_FORMAT_ARGB32, + w, + h, + stride); + // Create a pattern from the source image surface + cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); + // Set the pattern extend mode to reflect (mirror) when the pattern is out of bounds + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + + // Initialize the transformation matrix + cairo_matrix_t matrix; + cairo_matrix_init_identity(&matrix); + + // Calculate the center coordinates of the destination image float center_x = (float)w / 2.0f; float center_y = (float)h / 2.0f; - - // Convert the rotation to radians - float angle = (float)(this->rotation * M_PI / 180.0f); - float cos_angle = cosf(angle); - float sin_angle = sinf(angle); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - // Convert the destination coordinates to source coordinates with zoom - float src_x = (x - center_x) / zoom + center_x; - float src_y = (y - center_y) / zoom + center_y; - - // Apply the rotation - float rotated_x = cos_angle * (src_x - center_x) - sin_angle * (src_y - center_y) + center_x; - float rotated_y = sin_angle * (src_x - center_x) + cos_angle * (src_y - center_y) + center_y; - - // Apply the offset - rotated_x += x_offset_px; - rotated_y += y_offset_px; - - int src_x_int = (int)rotated_x % (w * 2); - int src_y_int = (int)rotated_y % (h * 2); - - // Reflect the image if coordinates are out of bounds - // If less than the bound - if (src_x_int < 0) { - src_x_int = 0 - src_x_int - 1; - } - if (src_y_int < 0) { - src_y_int = 0 - src_y_int - 1; - } - // If greater than the bounds - if (src_x_int >= w) { - src_x_int = w - (src_x_int - w) - 1; - } - if (src_y_int >= h) { - src_y_int = h - (src_y_int - h) - 1; - } - - // Copy the pixel from the source image to the destination buffer - ((uint32_t*)dst)[y * w + x] = ((const uint32_t*)src)[src_y_int * w + src_x_int]; - } - } + + float scale_factor = 1.0f - CLAMP(this->zoom, -0.99, 0.99); + + // Apply transformations + cairo_matrix_translate(&matrix, center_x - (this->x_offset) * w, center_y - (this->y_offset) * h); + cairo_matrix_scale(&matrix, scale_factor, scale_factor); + cairo_matrix_rotate(&matrix, this->rotation * M_PI / 180.0); + cairo_matrix_translate(&matrix, -center_x, -center_y); + + // Set the transformation matrix for the pattern + cairo_pattern_set_matrix(pattern, &matrix); + // Set the source pattern to be used for drawing + cairo_set_source(cr, pattern); + + // Draw a rectangle covering the entire image area + cairo_rectangle(cr, 0, 0, w, h); + // Fill the rectangle with the source pattern + cairo_fill(cr); + + // Clean up resources + cairo_pattern_destroy (pattern); + cairo_surface_destroy (image); + cairo_surface_destroy (dest_image); + cairo_destroy (cr); } }; @@ -124,3 +122,4 @@ frei0r::construct plugin( "Johann JEG", 1, 0, F0R_COLOR_MODEL_RGBA8888); + \ No newline at end of file From 185b53724871aec4aea869d8c0920db2ccf8f90b Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Thu, 22 Aug 2024 23:44:29 -0400 Subject: [PATCH 4/7] fixed parameters range --- src/filter/mirr0r/mirr0r.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp index 4e41ff52..abad27e9 100755 --- a/src/filter/mirr0r/mirr0r.cpp +++ b/src/filter/mirr0r/mirr0r.cpp @@ -43,10 +43,10 @@ class Mirr0r : public frei0r::filter { this->width = width; this->height = height; - this->x_offset = 0.5; - this->y_offset = 0.5; + this->x_offset = 0.0; + this->y_offset = 0.0; this->zoom = 0.5; - this->rotation = 0.5; + this->rotation = 0.0; } ~Mirr0r(){ @@ -90,12 +90,12 @@ class Mirr0r : public frei0r::filter { float center_x = (float)w / 2.0f; float center_y = (float)h / 2.0f; - float scale_factor = 1.0f - CLAMP(this->zoom, -0.99, 0.99); - + float scale_factor = 1.5f - this->zoom; + // Apply transformations cairo_matrix_translate(&matrix, center_x - (this->x_offset) * w, center_y - (this->y_offset) * h); cairo_matrix_scale(&matrix, scale_factor, scale_factor); - cairo_matrix_rotate(&matrix, this->rotation * M_PI / 180.0); + cairo_matrix_rotate(&matrix, this->rotation * M_PI); cairo_matrix_translate(&matrix, -center_x, -center_y); // Set the transformation matrix for the pattern From 53e5f25c34977e5f2cad40bb20d735bb077657d4 Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Fri, 23 Aug 2024 05:04:19 -0400 Subject: [PATCH 5/7] Clear the screen before drawing, to avoid problems with image sources with transparency. --- src/filter/mirr0r/mirr0r.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp index abad27e9..555bb1b7 100755 --- a/src/filter/mirr0r/mirr0r.cpp +++ b/src/filter/mirr0r/mirr0r.cpp @@ -53,6 +53,14 @@ class Mirr0r : public frei0r::filter { } + void clearScreen(cairo_t* cr, int width, int height) { + cairo_save (cr); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_restore (cr); + } + virtual void update(double time, uint32_t* out, const uint32_t* in) { int w = this->width; @@ -71,6 +79,9 @@ class Mirr0r : public frei0r::filter { // Create a Cairo drawing context for the destination surface cairo_t *cr = cairo_create(dest_image); + // Clear the screen + clearScreen(cr, w, h); + // Create a Cairo surface for the source image cairo_surface_t *image = cairo_image_surface_create_for_data((unsigned char*)in, CAIRO_FORMAT_ARGB32, From df67d905a057c10753d427edd7458c92ab947b48 Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:22:04 -0400 Subject: [PATCH 6/7] Remove unused import --- src/filter/mirr0r/mirr0r.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filter/mirr0r/mirr0r.cpp b/src/filter/mirr0r/mirr0r.cpp index 555bb1b7..a6113db1 100755 --- a/src/filter/mirr0r/mirr0r.cpp +++ b/src/filter/mirr0r/mirr0r.cpp @@ -18,7 +18,6 @@ */ #include "frei0r.hpp" -#include "frei0r/math.h" #include #define _USE_MATH_DEFINES #include @@ -26,6 +25,7 @@ class Mirr0r : public frei0r::filter { private: + unsigned int width; unsigned int height; double x_offset; From b1f53681e1efffae805864c6c60a7b074f6427d2 Mon Sep 17 00:00:00 2001 From: JohannJEG <125712359+JohannJEG@users.noreply.github.com> Date: Sun, 25 Aug 2024 07:54:30 -0400 Subject: [PATCH 7/7] Added new filter effect shakeoscillate --- src/filter/CMakeLists.txt | 1 + src/filter/shakeoscillate/CMakeLists.txt | 15 ++ src/filter/shakeoscillate/shakeoscillate.cpp | 195 +++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100755 src/filter/shakeoscillate/CMakeLists.txt create mode 100755 src/filter/shakeoscillate/shakeoscillate.cpp diff --git a/src/filter/CMakeLists.txt b/src/filter/CMakeLists.txt index 8ede934c..030679bb 100644 --- a/src/filter/CMakeLists.txt +++ b/src/filter/CMakeLists.txt @@ -13,6 +13,7 @@ if (${Cairo_FOUND}) add_subdirectory (cairoimagegrid) add_subdirectory (cairogradient) add_subdirectory (mirr0r) + add_subdirectory (shakeoscillate) endif (${Cairo_FOUND}) add_subdirectory (3dflippo) diff --git a/src/filter/shakeoscillate/CMakeLists.txt b/src/filter/shakeoscillate/CMakeLists.txt new file mode 100755 index 00000000..573a78af --- /dev/null +++ b/src/filter/shakeoscillate/CMakeLists.txt @@ -0,0 +1,15 @@ +set (SOURCES shakeoscillate.cpp) +set (TARGET shakeoscillate) + +include_directories(${Cairo_INCLUDE_DIR}) +set(LIBS ${LIBS} ${Cairo_LIBRARY}) + +if (MSVC) + set (SOURCES ${SOURCES} ${FREI0R_DEF}) +endif (MSVC) + +add_library (${TARGET} MODULE ${SOURCES}) + +set_target_properties (${TARGET} PROPERTIES PREFIX "") +target_link_libraries(shakeoscillate ${LIBS}) +install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR}) diff --git a/src/filter/shakeoscillate/shakeoscillate.cpp b/src/filter/shakeoscillate/shakeoscillate.cpp new file mode 100755 index 00000000..88913eec --- /dev/null +++ b/src/filter/shakeoscillate/shakeoscillate.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2024 Johann JEG (johannjeg1057@gmail.com) + * + * This file is a Frei0r plugin. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "frei0r.hpp" +#include +#define _USE_MATH_DEFINES +#include + +class ShakeOscillate : public frei0r::filter { + +private: + + unsigned int width; + unsigned int height; + double movement_amount_x; + double movement_speed_x; + double movement_amount_y; + double movement_speed_y; + double rotation_amount; + double rotation_speed; + double scale; + double phase; + bool mirrored; + + const float MOVEMENT_AMOUNT_MULTIPLIER = 0.3f; + const float ROTATION_AMOUNT_MULTIPLIER = 0.2f; + const float SPEED_MULTIPLIER = 10.0f; + +public: + + ShakeOscillate(unsigned int width, unsigned int height) { + register_param(this->movement_amount_x, "movement_amount_x", "Amount of the X movement."); + register_param(this->movement_speed_x, "movement_speed_x", "X Movement Speed."); + register_param(this->movement_amount_y, "movement_amount_y", "Amount of the Y movement."); + register_param(this->movement_speed_y, "movement_speed_y", "Y Movement Speed."); + register_param(this->rotation_amount, "rotation_amount", "Rotation amount."); + register_param(this->rotation_speed, "rotation_speed", "Rotation Speed."); + register_param(this->scale, "scale", "Scale level."); + register_param(this->phase, "phase", "The phase of the sin and cos functions of this effect."); + register_param(this->mirrored, "mirrored", "On/Off Image Mirror Extend"); + + this->width = width; + this->height = height; + this->movement_amount_x = 0.5; // Movement amount off is 0.5 + this->movement_speed_x = 0.2; + this->movement_amount_y = 0.5; // Movement amount off is 0.5 + this->movement_speed_y = 0.1; + this->rotation_amount = 0.5; // Rotation amount off is 0.5 + this->rotation_speed = 0.2; + this->scale = 0.5; // Original image size is 0.5 + this->phase = 0.0; + this->mirrored = true; + } + + ~ShakeOscillate() { + + } + + void clearScreen(cairo_t* cr, int width, int height) { + cairo_save (cr); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_restore (cr); + } + + void oscillate(cairo_matrix_t* matrix, double time) { + float x = 0.0f; + float y = 0.0f; + + // Operations for the translation amount do not depend on the screen size + float movement_range_x = MOVEMENT_AMOUNT_MULTIPLIER * this->height; + float movement_range_y = MOVEMENT_AMOUNT_MULTIPLIER * this->width; + + // Translate X + if(this->movement_amount_x != 0.5){ + float movement_x = (this->movement_amount_x - 0.5f) * 2.0f; + float movement_speed_value_x = this->movement_speed_x * SPEED_MULTIPLIER * time; + x = movement_x * movement_range_x * std::sin(movement_speed_value_x + this->phase); + } + + // Translate Y + if(this->movement_amount_y != 0.5){ + float movement_y = (this->movement_amount_y - 0.5f) * 2.0f; + float movement_speed_value_y = this->movement_speed_y * SPEED_MULTIPLIER * time; + y = movement_y * movement_range_y * std::cos(movement_speed_value_y + this->phase); + } + + // Translate by adding the half screen coordinates to scale and rotate from center + float center_x = this->width / 2.0f; + float center_y = this->height / 2.0f; + cairo_matrix_translate(matrix, center_x + x, center_y + y); + + // Scale + if(this->scale != 0.5){ + float scale_factor = 1.5f - this->scale; + cairo_matrix_scale(matrix, scale_factor, scale_factor); + } + + // Rotation + if(this->rotation_amount != 0.5){ + float rotation_speed_value = (this->rotation_speed * SPEED_MULTIPLIER * time) + this->phase; + float rotation = ((this->rotation_amount - 0.5f) * ROTATION_AMOUNT_MULTIPLIER) * std::sin(rotation_speed_value) * M_PI; + cairo_matrix_rotate(matrix, rotation); + } + + // Restore translate coordinates + cairo_matrix_translate(matrix, -center_x, -center_y); + } + + virtual void update(double time, uint32_t* out, const uint32_t* in) { + int w = this->width; + int h = this->height; + + // Calculate the stride for the image surface based on width and format + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); + + // Create a Cairo surface for the destination image + cairo_surface_t* dest_image = cairo_image_surface_create_for_data((unsigned char*)out, + CAIRO_FORMAT_ARGB32, + w, + h, + stride); + + // Create a Cairo drawing context for the destination surface + cairo_t *cr = cairo_create(dest_image); + + // Clear the screen + clearScreen(cr, w, h); + + // Create a Cairo surface for the source image + cairo_surface_t *image = cairo_image_surface_create_for_data((unsigned char*)in, + CAIRO_FORMAT_ARGB32, + w, + h, + stride); + + // Create a pattern from the source image surface + cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); + + if(this->mirrored){ + // Set the pattern extend mode to reflect (mirror) when the pattern is out of bounds + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + } else { + // Set the pattern extend mode to none (mirroring does not apply) + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + } + + // Initialize the transformation matrix + cairo_matrix_t matrix; + cairo_matrix_init_identity(&matrix); + + // Call the function that applies the movement + oscillate(&matrix, time); + + // Set the transformation matrix for the pattern + cairo_pattern_set_matrix(pattern, &matrix); + // Set the source pattern to be used for drawing + cairo_set_source(cr, pattern); + + // Draw a rectangle covering the entire image area + cairo_rectangle(cr, 0, 0, w, h); + // Fill the rectangle with the source pattern + cairo_fill(cr); + + // Clean up resources + cairo_pattern_destroy (pattern); + cairo_surface_destroy (image); + cairo_surface_destroy (dest_image); + cairo_destroy (cr); + } +}; + +frei0r::construct plugin( + "ShakeOscillate", + "Animate the input image with adjustable parameters such as amount, speed, rotation, scale and option to mirror the image if it goes outside the screen bounds.", + "Johann JEG", + 1, 0, + F0R_COLOR_MODEL_RGBA8888);