diff --git a/.gitignore b/.gitignore
index de08b02..3a4e0e2 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 0c22852..030679b 100644
--- a/src/filter/CMakeLists.txt
+++ b/src/filter/CMakeLists.txt
@@ -12,6 +12,8 @@ endif (${OpenCV_FOUND})
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/mirr0r/CMakeLists.txt b/src/filter/mirr0r/CMakeLists.txt
new file mode 100755
index 0000000..7a811bd
--- /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 0000000..a6113db
--- /dev/null
+++ b/src/filter/mirr0r/mirr0r.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 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.0;
+ this->y_offset = 0.0;
+ this->zoom = 0.5;
+ this->rotation = 0.0;
+ }
+
+ ~Mirr0r(){
+
+ }
+
+ 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;
+ 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);
+ // 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;
+
+ 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);
+ 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);
+ }
+};
+
+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);
+
\ No newline at end of file
diff --git a/src/filter/shakeoscillate/CMakeLists.txt b/src/filter/shakeoscillate/CMakeLists.txt
new file mode 100755
index 0000000..573a78a
--- /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 0000000..88913ee
--- /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);