/*
* 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 <http://www.gnu.org/licenses/>.
*/
#define _USE_MATH_DEFINES
#include "frei0r.hpp"
#include <cairo.h>
#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);