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);