Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shakeoscillate effect #197

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ doc/html
/out/
/.vs/
CMakeSettings.json
.vscode
2 changes: 2 additions & 0 deletions src/filter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions src/filter/mirr0r/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
136 changes: 136 additions & 0 deletions src/filter/mirr0r/mirr0r.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2024 Johann JEG ([email protected])
*
* 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 <http://www.gnu.org/licenses/>.
*/

#include "frei0r.hpp"
#include <cairo.h>
#define _USE_MATH_DEFINES
#include <cmath>

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

Check warning on line 136 in src/filter/mirr0r/mirr0r.cpp

View workflow job for this annotation

GitHub Actions / 🚨 C lint

[cpplint] reported by reviewdog 🐶 Could not find a newline character at the end of the file. [whitespace/ending_newline] [5] Raw Output: src/filter/mirr0r/mirr0r.cpp:136: Could not find a newline character at the end of the file. [whitespace/ending_newline] [5]
15 changes: 15 additions & 0 deletions src/filter/shakeoscillate/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
195 changes: 195 additions & 0 deletions src/filter/shakeoscillate/shakeoscillate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2024 Johann JEG ([email protected])
*
* 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 <http://www.gnu.org/licenses/>.
*/

#include "frei0r.hpp"
#include <cairo.h>
#define _USE_MATH_DEFINES
#include <math.h>

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