mirror of
https://github.com/dyne/frei0r.git
synced 2025-12-05 14:19:59 +01:00
Compare commits
9 Commits
40a50bec63
...
f081aa64d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f081aa64d4 | ||
|
|
542c4bc0a9 | ||
|
|
ce386ca806 | ||
|
|
7a044cba04 | ||
|
|
27af2abfb4 | ||
|
|
3a720e4270 | ||
|
|
b0a990ed18 | ||
|
|
33aaa39ac7 | ||
|
|
69d0711057 |
11
BUILD.md
11
BUILD.md
@@ -10,6 +10,10 @@ The presence of optional libraries on the system will trigger compilation of ext
|
||||
|
||||
+ [Cairo](http://cairographics.org) required for cairo- filters and mixers
|
||||
|
||||
## Optional build flags
|
||||
|
||||
+ `-DWITHOUT_FACERECOGNITION=ON` - Disable face recognition plugins (facedetect and facebl0r) to avoid protobuf conflicts with applications like MLT
|
||||
|
||||
It is recommended to use a separate `build` sub-folder.
|
||||
|
||||
```
|
||||
@@ -18,6 +22,13 @@ cd build && cmake ../
|
||||
make
|
||||
```
|
||||
|
||||
To disable face recognition plugins (recommended when using with MLT):
|
||||
```
|
||||
mkdir -p build
|
||||
cd build && cmake -DWITHOUT_FACERECOGNITION=ON ../
|
||||
make
|
||||
```
|
||||
|
||||
Also ninja and nmake are supported through cmake:
|
||||
```
|
||||
cmake -G 'Ninja' ../
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
cmake_minimum_required (VERSION 3.12...3.31)
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
project (frei0r)
|
||||
set (VERSION 1.8)
|
||||
set (VERSION 2.5.1)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
option (WITHOUT_OPENCV "Disable plugins dependent upon OpenCV" OFF)
|
||||
option (WITHOUT_FACERECOGNITION "Disable facedetect plugin to avoid protobuf conflicts" OFF)
|
||||
|
||||
if (NOT WITHOUT_OPENCV)
|
||||
find_package (OpenCV)
|
||||
endif ()
|
||||
|
||||
@@ -62,6 +62,14 @@
|
||||
*/
|
||||
void frei0r_cairo_set_operator(cairo_t *cr, char *op)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!cr || !op) {
|
||||
if (cr) {
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(strcmp(op, NORMAL) == 0)
|
||||
{
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
@@ -231,6 +239,11 @@ double frei0r_cairo_get_scale (double norm_scale)
|
||||
*/
|
||||
void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!rgba || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = rgba[3];
|
||||
@@ -255,6 +268,11 @@ void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
|
||||
*/
|
||||
void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!rgba || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = rgba[3];
|
||||
@@ -281,6 +299,11 @@ void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
|
||||
void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
|
||||
int pixels, int alpha)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!in || !out || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = in[3];
|
||||
|
||||
@@ -80,12 +80,13 @@ float AitNev3(int t, float xt[], float yt[], float x)
|
||||
{
|
||||
float p[10];
|
||||
int i,j,m;
|
||||
float zero = 0.0f; // MSVC doesn't allow division through a zero literal, but allows it through non-const variable set to zero
|
||||
|
||||
if ((x<xt[0])||(x>xt[t-1]))
|
||||
{
|
||||
// printf("\n\n x=%f je izven mej tabele!",x);
|
||||
return 1.0/zero;
|
||||
// Return a reasonable value instead of dividing by zero
|
||||
if (x<xt[0]) return yt[0];
|
||||
else return yt[t-1];
|
||||
}
|
||||
|
||||
//poisce, katere tocke bo uporabil
|
||||
@@ -98,7 +99,13 @@ float AitNev3(int t, float xt[], float yt[], float x)
|
||||
for (j=1;j<4;j++)
|
||||
for (i=(4-1);i>=j;i--)
|
||||
{
|
||||
p[i]=p[i]+(x-xt[i+m])/(xt[i+m]-xt[i-j+m])*(p[i]-p[i-1]);
|
||||
// Check for division by zero
|
||||
float denominator = xt[i+m]-xt[i-j+m];
|
||||
if (denominator == 0.0f) {
|
||||
// If denominator is zero, skip this iteration to avoid undefined behavior
|
||||
continue;
|
||||
}
|
||||
p[i]=p[i]+(x-xt[i+m])/denominator*(p[i]-p[i-1]);
|
||||
}
|
||||
return p[4-1];
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef struct {
|
||||
uint32_t size;
|
||||
} ScreenGeometry;
|
||||
|
||||
#define PIXELAT(x1,y1,s) ((s)+(x1)+ yprecal[y1])// (y1)*(geo->w)))
|
||||
#define PIXELAT(x1,y1,s,inst) ((s)+(x1)+ inst->yprecal[y1])// (y1)*(geo->w)))
|
||||
#define GMERROR(cc1,cc2) ((((RED(cc1)-RED(cc2))*(RED(cc1)-RED(cc2))) + \
|
||||
((GREEN(cc1)-GREEN(cc2)) *(GREEN(cc1)-GREEN(cc2))) + \
|
||||
((BLUE(cc1)-BLUE(cc2))*(BLUE(cc1)-BLUE(cc2)))))
|
||||
@@ -155,26 +155,26 @@ long Cartoon::GetMaxContrast(int32_t *src,int x,int y) {
|
||||
long error,max=0;
|
||||
|
||||
/* Assumes PrePixelModify has been run */
|
||||
c1 = *PIXELAT(x-m_diffspace,y,src);
|
||||
c2 = *PIXELAT(x+m_diffspace,y,src);
|
||||
c1 = *PIXELAT(x-m_diffspace,y,src,this);
|
||||
c2 = *PIXELAT(x+m_diffspace,y,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,16 +125,17 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
float b1 = inst->color.b * 255.0;
|
||||
float r2, g2, b2;
|
||||
int l;
|
||||
/* Scale factor to normalize distance to 0-255 range:
|
||||
0.705724361914764 ≈ 255.0 / sqrt(3 * 255^2) = 255.0 / (255.0 * sqrt(3)) */
|
||||
const float SCALE_FACTOR = 0.705724361914764;
|
||||
while (len--) {
|
||||
r2 = *src++;
|
||||
g2 = *src++;
|
||||
b2 = *src++;
|
||||
l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * 0.705724361914764 );
|
||||
/* Hint 0.35320727852735 == 255.0 / sqrt( (255)**2 + (255)**2 + (255)*2 )*/
|
||||
if ( r1 < 0 || r1 > 255 || g1 < 0 || g1 > 255 || b1 < 0 || b1 > 255 || r2 < 0 || r2 > 255 || g2 < 0 || g2 > 255 || b2 < 0 || b2 > 255 ) {
|
||||
printf ("%f %f %f\n", r2, g2, b2 );
|
||||
}
|
||||
l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * SCALE_FACTOR );
|
||||
|
||||
// Clamp result to valid range
|
||||
l = CLAMP(l, 0, 255);
|
||||
|
||||
*dst++ = (unsigned char) (l);
|
||||
*dst++ = (unsigned char) (l);
|
||||
|
||||
@@ -254,16 +254,21 @@ void interpolateGrid(grid_point_t* grid, unsigned int w, unsigned int h,
|
||||
step_line_u = (int32_t) ((u_right-u_left) >> GRID_SIZE_LOG);
|
||||
step_line_v = (int32_t) ((v_right-v_left) >> GRID_SIZE_LOG);
|
||||
|
||||
for(block_x=0; block_x < GRID_SIZE; ++block_x)
|
||||
{
|
||||
for(block_x=0; block_x < GRID_SIZE; ++block_x)
|
||||
{
|
||||
int uu = u_line_index >> 16;
|
||||
int vv = v_line_index >> 16;
|
||||
|
||||
u_line_index += step_line_u;
|
||||
v_line_index += step_line_v;
|
||||
|
||||
*pos++ = src[uu + vv * w];
|
||||
}
|
||||
|
||||
u_line_index += step_line_u;
|
||||
v_line_index += step_line_v;
|
||||
|
||||
// Bounds checking to prevent buffer overrun
|
||||
if (uu >= 0 && uu < (int)w && vv >= 0 && vv < (int)h) {
|
||||
*pos++ = src[uu + vv * w];
|
||||
} else {
|
||||
*pos++ = 0; // Black pixel for out-of-bounds access
|
||||
}
|
||||
}
|
||||
|
||||
start_col_uu += step_start_col_u;
|
||||
end_col_uu += step_end_col_u;
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
set (SOURCES facebl0r.cpp)
|
||||
set (TARGET facebl0r)
|
||||
# facebl0r filter - requires OpenCV (and protobuf)
|
||||
# This filter can cause conflicts with applications that also use protobuf
|
||||
# such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
|
||||
set (SOURCES facebl0r.cpp)
|
||||
set (TARGET facebl0r)
|
||||
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
endif()
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
set (SOURCES facedetect.cpp)
|
||||
set (TARGET facedetect)
|
||||
# facedetect filter - requires OpenCV (and protobuf)
|
||||
# This filter can cause conflicts with applications that also use protobuf
|
||||
# such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
|
||||
set (SOURCES facedetect.cpp)
|
||||
set (TARGET facedetect)
|
||||
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
endif()
|
||||
|
||||
@@ -45,7 +45,7 @@ struct glitch0r_state // helps to save time when allocating in a loop
|
||||
short int howToDistort1;
|
||||
short int howToDistort2;
|
||||
short int passThisLine;
|
||||
} g0r_state;
|
||||
};
|
||||
|
||||
typedef struct glitch0r_instance
|
||||
{
|
||||
@@ -58,6 +58,8 @@ typedef struct glitch0r_instance
|
||||
short int colorGlitchIntensity;
|
||||
short int doColorDistortion;
|
||||
short int glitchChance;
|
||||
|
||||
struct glitch0r_state state; // Instance-specific state
|
||||
} glitch0r_instance_t;
|
||||
|
||||
|
||||
@@ -68,17 +70,17 @@ inline static unsigned int rnd (unsigned int min, unsigned int max)
|
||||
|
||||
inline static void glitch0r_state_reset(glitch0r_instance_t *inst)
|
||||
{
|
||||
g0r_state.currentPos = 0;
|
||||
g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
g0r_state.blkShift = rnd(1, inst->maxBlockShift);
|
||||
g0r_state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
|
||||
inst->state.currentPos = 0;
|
||||
inst->state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
inst->state.blkShift = rnd(1, inst->maxBlockShift);
|
||||
inst->state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
{
|
||||
g0r_state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
|
||||
g0r_state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
|
||||
g0r_state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
|
||||
g0r_state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
|
||||
inst->state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
|
||||
inst->state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
|
||||
inst->state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
|
||||
inst->state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,49 +306,49 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
|
||||
uint32_t* dst = outframe;
|
||||
const uint32_t* src = inframe;
|
||||
uint32_t *pixel;
|
||||
uint32_t *pixel;
|
||||
|
||||
g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
inst->state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
|
||||
for (y = 0; y < inst->height; y++)
|
||||
{
|
||||
|
||||
if (g0r_state.currentPos > g0r_state.currentBlock)
|
||||
if (inst->state.currentPos > inst->state.currentBlock)
|
||||
{
|
||||
glitch0r_state_reset(inst);
|
||||
}
|
||||
else
|
||||
g0r_state.currentPos++;
|
||||
inst->state.currentPos++;
|
||||
|
||||
g0r_state.currentY = y*inst->width;
|
||||
pixel = dst + g0r_state.currentY;
|
||||
inst->state.currentY = y*inst->width;
|
||||
pixel = dst + inst->state.currentY;
|
||||
|
||||
if (g0r_state.passThisLine)
|
||||
if (inst->state.passThisLine)
|
||||
{
|
||||
memcpy((uint32_t *)(dst + g0r_state.currentY),
|
||||
(uint32_t *)(src + g0r_state.currentY),
|
||||
memcpy((uint32_t *)(dst + inst->state.currentY),
|
||||
(uint32_t *)(src + inst->state.currentY),
|
||||
(inst->width) * sizeof(uint32_t));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = g0r_state.blkShift; x < (inst->width); x++)
|
||||
for (x = inst->state.blkShift; x < (inst->width); x++)
|
||||
{
|
||||
*(pixel) = *(src + g0r_state.currentY + x);
|
||||
*(pixel) = *(src + inst->state.currentY + x);
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
glitch0r_pixel_dist0rt(pixel,
|
||||
g0r_state.distortionSeed1, g0r_state.howToDistort1);
|
||||
inst->state.distortionSeed1, inst->state.howToDistort1);
|
||||
|
||||
pixel++;
|
||||
}
|
||||
|
||||
for (x = 0; x < g0r_state.blkShift; x++)
|
||||
for (x = 0; x < inst->state.blkShift; x++)
|
||||
{
|
||||
*(pixel) = *(src + g0r_state.currentY + x);
|
||||
*(pixel) = *(src + inst->state.currentY + x);
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
glitch0r_pixel_dist0rt(pixel,
|
||||
g0r_state.distortionSeed2, g0r_state.howToDistort2);
|
||||
inst->state.distortionSeed2, inst->state.howToDistort2);
|
||||
|
||||
pixel++;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,9 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
levelsInput = CLAMP(levelsInput, 0.0, 48.0) + 2.0;
|
||||
int numLevels = (int)levelsInput;
|
||||
|
||||
// Prevent division by zero
|
||||
if (numLevels < 2) numLevels = 2;
|
||||
|
||||
// create levels table
|
||||
unsigned char levels[256];
|
||||
int i;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* It contains code from plug-ins/common/noise-rgb.c, see that for copyrights.
|
||||
*
|
||||
* rgbnoise.c
|
||||
* Copyright 2012 Janne Liljeblad
|
||||
* Copyright 2012 Janne Liljeblad
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
@@ -29,17 +29,17 @@
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
static int MY_MAX_RAND = 32767;// I assume RAND_MAX to be at least this big.
|
||||
static double gaussian_lookup[32767];
|
||||
static int TABLE_INITED = 0;
|
||||
static int next_gaussian_index = 0;
|
||||
static int last_in_range = 32766;
|
||||
#define MY_MAX_RAND 32767 // assume RAND_MAX to be at least this big.
|
||||
|
||||
typedef struct rgbnoise_instance
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double noise;
|
||||
double gaussian_lookup[MY_MAX_RAND];
|
||||
int table_inited;
|
||||
int next_gaussian_index;
|
||||
int last_in_range;
|
||||
} rgbnoise_instance_t;
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ void f0r_get_plugin_info(f0r_plugin_info_t* rgbnoiseInfo)
|
||||
rgbnoiseInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
rgbnoiseInfo->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
rgbnoiseInfo->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
rgbnoiseInfo->major_version = 0;
|
||||
rgbnoiseInfo->minor_version = 9;
|
||||
rgbnoiseInfo->num_params = 1;
|
||||
rgbnoiseInfo->major_version = 0;
|
||||
rgbnoiseInfo->minor_version = 9;
|
||||
rgbnoiseInfo->num_params = 1;
|
||||
rgbnoiseInfo->explanation = "Adds RGB noise to image.";
|
||||
}
|
||||
|
||||
@@ -74,9 +74,12 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
inst->noise = 0.2;
|
||||
inst->table_inited = 0;
|
||||
inst->next_gaussian_index = 0;
|
||||
inst->last_in_range = MY_MAX_RAND;
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ void f0r_destruct(f0r_instance_t instance)
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
@@ -99,9 +102,9 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
|
||||
void f0r_get_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
switch (param_index)
|
||||
switch (param_index)
|
||||
{
|
||||
case 0:
|
||||
*((double*)param) = inst->noise;
|
||||
@@ -133,7 +136,7 @@ static inline double gauss()
|
||||
return x;
|
||||
}
|
||||
|
||||
static void create_new_lookup_range()
|
||||
static void create_new_lookup_range(rgbnoise_instance_t* inst)
|
||||
{
|
||||
int first, last, tmp;
|
||||
first = rand() % (MY_MAX_RAND - 1);
|
||||
@@ -144,42 +147,33 @@ static void create_new_lookup_range()
|
||||
last = first;
|
||||
first = tmp;
|
||||
}
|
||||
next_gaussian_index = first;
|
||||
last_in_range = last;
|
||||
inst->next_gaussian_index = first;
|
||||
inst->last_in_range = last;
|
||||
}
|
||||
|
||||
static inline double next_gauss()
|
||||
static inline double next_gauss(rgbnoise_instance_t* inst)
|
||||
{
|
||||
next_gaussian_index++;
|
||||
if (next_gaussian_index >= last_in_range)
|
||||
inst->next_gaussian_index++;
|
||||
if (inst->next_gaussian_index >= inst->last_in_range)
|
||||
{
|
||||
create_new_lookup_range();
|
||||
create_new_lookup_range(inst);
|
||||
}
|
||||
return gaussian_lookup[next_gaussian_index];
|
||||
return inst->gaussian_lookup[inst->next_gaussian_index];
|
||||
}
|
||||
|
||||
static inline int addNoise(int sample, double noise)
|
||||
static inline int addNoise(rgbnoise_instance_t* inst, int sample, double noise)
|
||||
{
|
||||
int byteNoise = 0;
|
||||
int noiseSample = 0;
|
||||
|
||||
byteNoise = (int) (noise * next_gauss());
|
||||
byteNoise = (int) (noise * next_gauss(inst));
|
||||
noiseSample = sample + byteNoise;
|
||||
noiseSample = CLAMP(noiseSample, 0, 255);
|
||||
return noiseSample;
|
||||
}
|
||||
}
|
||||
|
||||
int f0r_init()
|
||||
{
|
||||
if (TABLE_INITED == 0)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MY_MAX_RAND; i++)
|
||||
{
|
||||
gaussian_lookup[i] = gauss() * 127.0;
|
||||
}
|
||||
TABLE_INITED = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -189,6 +183,19 @@ void rgb_noise(f0r_instance_t instance, double time,
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
|
||||
// Initialize the gaussian lookup table if not already done
|
||||
if (inst->table_inited == 0)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MY_MAX_RAND; i++)
|
||||
{
|
||||
inst->gaussian_lookup[i] = gauss() * 127.0;
|
||||
}
|
||||
inst->table_inited = 1;
|
||||
inst->next_gaussian_index = 0;
|
||||
inst->last_in_range = MY_MAX_RAND;
|
||||
}
|
||||
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
const unsigned char* src = (unsigned char*)inframe;
|
||||
|
||||
@@ -197,11 +204,11 @@ void rgb_noise(f0r_instance_t instance, double time,
|
||||
while (len--)
|
||||
{
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
@@ -213,4 +220,3 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
assert(instance);
|
||||
rgb_noise(instance, time, inframe, outframe);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* rgbsplit0r.c
|
||||
* Copyright (C) 2016 IDENT Software ~ http://identsoft.org
|
||||
* Inspired by the witch house and web culture
|
||||
*
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -111,7 +111,6 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
inst->width = width; inst->height = height;
|
||||
inst->shiftY = 0;
|
||||
inst->shiftX = 0;
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -120,7 +119,7 @@ void f0r_destruct(f0r_instance_t instance)
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
assert(instance);
|
||||
@@ -135,7 +134,10 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
double shiftY = *((double*)param) - 0.5;
|
||||
|
||||
// Convert to range from 0 to one eighth of height
|
||||
shiftY = ((inst->height / 8) * shiftY);
|
||||
if (inst->height > 0)
|
||||
shiftY = ((inst->height / 8) * shiftY);
|
||||
else
|
||||
shiftY = 0;
|
||||
|
||||
inst->shiftY = (unsigned int)shiftY;
|
||||
break;
|
||||
@@ -145,9 +147,12 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
{
|
||||
// scale to [-1/16..1/16]
|
||||
double shiftX = *((double*)param) - 0.5;
|
||||
|
||||
|
||||
// Convert to range from 0 to one eighth of width
|
||||
shiftX = ((inst->width / 8) * shiftX);
|
||||
if (inst->width > 0)
|
||||
shiftX = ((inst->width / 8) * shiftX);
|
||||
else
|
||||
shiftX = 0;
|
||||
|
||||
inst->shiftX = (unsigned int)shiftX;
|
||||
break;
|
||||
@@ -167,14 +172,20 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
case 0 : // vertical shift
|
||||
{
|
||||
// convert plugin's param to frei0r range
|
||||
*((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
|
||||
if (inst->height > 0)
|
||||
*((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
|
||||
else
|
||||
*((double*)param) = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
case 1 : // horizontal shift
|
||||
{
|
||||
// convert plugin's param to frei0r range
|
||||
*((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
|
||||
if (inst->width > 0)
|
||||
*((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
|
||||
else
|
||||
*((double*)param) = 0.5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -195,8 +206,8 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
uint32_t pxR = 0, pxG = 0, pxB = 0;
|
||||
|
||||
// First make a blue layer shifted back
|
||||
if (((x - inst->shiftX) < inst->width) &&
|
||||
((y - inst->shiftY) < inst->height))
|
||||
if (((int)x >= (int)inst->shiftX) &&
|
||||
((int)y >= (int)inst->shiftY))
|
||||
{
|
||||
rgbsplit0r_extract_color((uint32_t *)(src +
|
||||
(x - inst->shiftX) +
|
||||
@@ -221,4 +232,3 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
*(dst + x + (y*inst->width)) = (pxG | pxB | pxR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,16 @@ class sobel : public frei0r::filter
|
||||
public:
|
||||
sobel(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
}
|
||||
|
||||
virtual void update(double time,
|
||||
uint32_t* out,
|
||||
const uint32_t* in)
|
||||
{
|
||||
if (width == 0 || height == 0) return;
|
||||
|
||||
std::copy(in, in + width*height, out);
|
||||
for (unsigned int y=1; y<height-1; ++y)
|
||||
{
|
||||
@@ -46,9 +50,9 @@ public:
|
||||
unsigned char *p7 = (unsigned char *)&in[(y+1)*width+(x-1)];
|
||||
unsigned char *p8 = (unsigned char *)&in[(y+1)*width+x];
|
||||
unsigned char *p9 = (unsigned char *)&in[(y+1)*width+(x+1)];
|
||||
|
||||
|
||||
unsigned char *g = (unsigned char *)&out[y*width+x];
|
||||
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
g[i] = CLAMP0255(
|
||||
abs(p1[i] + p2[i]*2 + p3[i] - p7[i] - p8[i]*2 - p9[i]) +
|
||||
|
||||
@@ -22,8 +22,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
/* Check for SSE4.1 support */
|
||||
#if defined(__SSE4_1__)
|
||||
#include <smmintrin.h>
|
||||
#define USE_SSE4_1 1
|
||||
#else
|
||||
#define USE_SSE4_1 0
|
||||
#endif
|
||||
|
||||
/* Check for other SIMD instruction sets */
|
||||
#if defined(__AVX__) && defined(__AVX2__)
|
||||
#include <immintrin.h>
|
||||
#define USE_AVX2 1
|
||||
#else
|
||||
#define USE_AVX2 0
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
#define USE_NEON 1
|
||||
#else
|
||||
#define USE_NEON 0
|
||||
#endif
|
||||
|
||||
#include <frei0r.h>
|
||||
@@ -46,17 +65,17 @@ int f0r_init()
|
||||
void f0r_deinit()
|
||||
{ /* no initialization required */ }
|
||||
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* tint0r_instance_t)
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* info)
|
||||
{
|
||||
tint0r_instance_t->name = "Tint0r";
|
||||
tint0r_instance_t->author = "Maksim Golovkin & Cynthia";
|
||||
tint0r_instance_t->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
tint0r_instance_t->color_model = F0R_COLOR_MODEL_BGRA8888;
|
||||
tint0r_instance_t->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
tint0r_instance_t->major_version = 0;
|
||||
tint0r_instance_t->minor_version = 1;
|
||||
tint0r_instance_t->num_params = 3;
|
||||
tint0r_instance_t->explanation = "Tint a source image with specified colors";
|
||||
info->name = "Tint0r";
|
||||
info->author = "Maksim Golovkin & Cynthia";
|
||||
info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
info->color_model = F0R_COLOR_MODEL_BGRA8888;
|
||||
info->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
info->major_version = 0;
|
||||
info->minor_version = 1;
|
||||
info->num_params = 3;
|
||||
info->explanation = "Tint a source image with specified colors";
|
||||
}
|
||||
|
||||
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
@@ -143,70 +162,44 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __SSE4_1__
|
||||
static inline unsigned char map_color(double amount, double comp_amount, float color, float luma, float minColor, float maxColor)
|
||||
{
|
||||
double val = (comp_amount * color) + amount * (luma * (maxColor - minColor) + minColor);
|
||||
return (unsigned char)(255*CLAMP(val, 0, 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
const uint32_t* inframe, uint32_t* outframe)
|
||||
#if USE_SSE4_1
|
||||
static void tint_sse41(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
assert(instance);
|
||||
tint0r_instance_t* inst = (tint0r_instance_t*)instance;
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
size_t len = (inst->width * inst->height) / 4;
|
||||
|
||||
const __m128 weights = _mm_set_ps(0.0, 0.299, 0.587, 0.114),
|
||||
amount = _mm_set1_ps(inst->amount),
|
||||
const __m128 weights = _mm_set_ps(0.0, 0.114, 0.587, 0.299),
|
||||
sse_amount = _mm_set1_ps(amount),
|
||||
/* Pass the alpha channel */
|
||||
comp_amount = _mm_set_ps(1.0,
|
||||
1.0 - inst->amount,
|
||||
1.0 - inst->amount,
|
||||
1.0 - inst->amount);
|
||||
|
||||
f0r_param_color_t black = inst->blackColor,
|
||||
white = inst->whiteColor;
|
||||
1.0 - amount,
|
||||
1.0 - amount,
|
||||
1.0 - amount);
|
||||
|
||||
/* Zero the alpha component to exclude it from calculations. */
|
||||
const __m128 cmin = _mm_set_ps(0.0, black.r, black.g, black.b),
|
||||
cdelta = _mm_sub_ps(_mm_set_ps(0.0, white.r, white.g, white.b), cmin),
|
||||
tmp0 = _mm_mul_ps(cdelta, amount),
|
||||
tmp1 = _mm_mul_ps(_mm_mul_ps(amount, _mm_set1_ps(255.0)), cmin);
|
||||
const __m128 cmin = _mm_set_ps(0.0, blackColor.b, blackColor.g, blackColor.r),
|
||||
cdelta = _mm_sub_ps(_mm_set_ps(0.0, whiteColor.b, whiteColor.g, whiteColor.r), cmin),
|
||||
tmp0 = _mm_mul_ps(cdelta, sse_amount),
|
||||
tmp1 = _mm_mul_ps(_mm_mul_ps(sse_amount, _mm_set1_ps(255.0)), cmin);
|
||||
|
||||
__m128 p, p0, p1, p2, p3, luma;
|
||||
#else
|
||||
unsigned int len = inst->width * inst->height;
|
||||
double amount = inst->amount;
|
||||
double comp_amount = 1.0 - inst->amount;
|
||||
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
const unsigned char* src = (unsigned char*)inframe;
|
||||
float b, g, r;
|
||||
float luma;
|
||||
#endif
|
||||
|
||||
while (len--)
|
||||
// Process pixels in groups of 4
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
#ifdef __SSE4_1__
|
||||
/* Load four pixels at once. */
|
||||
p = _mm_loadu_si128((__m128i*)inframe);
|
||||
p = _mm_loadu_si128((__m128i*)(inframe + i * 4));
|
||||
|
||||
/* Extract four pixels into separate XMM registers and convert them to float. */
|
||||
p0 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(p));
|
||||
p1 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 4)));
|
||||
p2 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 8)));
|
||||
p3 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 12)));
|
||||
#else
|
||||
b = *src++ / 255.;
|
||||
g = *src++ / 255.;
|
||||
r = *src++ / 255.;
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
#define tint(v) \
|
||||
luma = _mm_dp_ps((v), weights, 0x7F); \
|
||||
v = _mm_add_ps(_mm_mul_ps(comp_amount, (v)), \
|
||||
@@ -219,19 +212,81 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
p = _mm_packus_epi16(_mm_packus_epi32(p0, p1),
|
||||
_mm_packus_epi32(p2, p3));
|
||||
|
||||
_mm_storeu_si128((__m128i*)outframe, p);
|
||||
_mm_storeu_si128((__m128i*)(outframe + i * 4), p);
|
||||
}
|
||||
}
|
||||
#elif USE_AVX2
|
||||
static void tint_avx2(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
// AVX2 implementation would go here
|
||||
// For now, fall back to scalar implementation
|
||||
// This is a placeholder for a future AVX2 implementation
|
||||
}
|
||||
#elif USE_NEON
|
||||
static void tint_neon(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
// NEON implementation would go here
|
||||
// For now, fall back to scalar implementation
|
||||
// This is a placeholder for a future NEON implementation
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stride of 128 bits; i.e. 16 bytes */
|
||||
inframe += 4;
|
||||
outframe += 4;
|
||||
#else
|
||||
luma = (b * .114 + g * .587 + r * .299);
|
||||
static void tint_scalar(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
double comp_amount = 1.0 - amount;
|
||||
|
||||
*dst++ = map_color(amount, comp_amount, b, luma, inst->blackColor.b, inst->whiteColor.b);
|
||||
*dst++ = map_color(amount, comp_amount, g, luma, inst->blackColor.g, inst->whiteColor.g);
|
||||
*dst++ = map_color(amount, comp_amount, r, luma, inst->blackColor.r, inst->whiteColor.r);
|
||||
*dst++ = *src++;
|
||||
#endif
|
||||
const unsigned char* src = (const unsigned char*)inframe;
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
|
||||
float b, g, r;
|
||||
float luma;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
b = src[0] / 255.0f;
|
||||
g = src[1] / 255.0f;
|
||||
r = src[2] / 255.0f;
|
||||
|
||||
luma = (b * 0.114f + g * 0.587f + r * 0.299f);
|
||||
|
||||
dst[0] = map_color(amount, comp_amount, b, luma, blackColor.b, whiteColor.b);
|
||||
dst[1] = map_color(amount, comp_amount, g, luma, blackColor.g, whiteColor.g);
|
||||
dst[2] = map_color(amount, comp_amount, r, luma, blackColor.r, whiteColor.r);
|
||||
dst[3] = src[3]; // Copy alpha
|
||||
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
assert(instance);
|
||||
tint0r_instance_t* inst = (tint0r_instance_t*)instance;
|
||||
size_t len = inst->width * inst->height;
|
||||
|
||||
#if USE_SSE4_1
|
||||
// Process in chunks of 4 pixels for SSE
|
||||
size_t sse_len = len / 4;
|
||||
size_t remainder = len % 4;
|
||||
|
||||
if (sse_len > 0) {
|
||||
tint_sse41(inframe, outframe, sse_len, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
}
|
||||
|
||||
// Handle remaining pixels with scalar implementation
|
||||
if (remainder > 0) {
|
||||
const uint32_t* remaining_in = inframe + (sse_len * 4);
|
||||
uint32_t* remaining_out = outframe + (sse_len * 4);
|
||||
tint_scalar(remaining_in, remaining_out, remainder, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
}
|
||||
#else
|
||||
// Use scalar implementation for all pixels
|
||||
tint_scalar(inframe, outframe, len, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Water filter
|
||||
*
|
||||
* (c) Copyright 2000-2007 Denis Rojo <jaromil@dyne.org>
|
||||
*
|
||||
* (c) Copyright 2000-2025 Denis Roio <jaromil@dyne.org>
|
||||
*
|
||||
* from an original idea of water algorithm by Federico 'Pix' Feroldi
|
||||
*
|
||||
* this code contains optimizations by Jason Hood and Scott Scriven
|
||||
@@ -10,7 +10,7 @@
|
||||
* ported to C++ and frei0r plugin API in 2007
|
||||
*
|
||||
* This source code is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Public License as published
|
||||
* modify it under the terms of the GNU Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
@@ -23,8 +23,6 @@
|
||||
* this source code; if not, write to:
|
||||
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* "$Id: water.c 193 2004-06-01 11:00:25Z jaromil $"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -81,8 +79,9 @@ public:
|
||||
surfer = 0;
|
||||
distort = 0;
|
||||
smooth = 0;
|
||||
position.x = 0;
|
||||
position.y = 0;
|
||||
position.x = 0.0;
|
||||
position.y = 0.0;
|
||||
//randomize_swirl = false;
|
||||
register_param(physics, "physics", "water density: from 0.0 to 1.0");
|
||||
register_param(swirl, "swirl", "swirling whirpool in the center");
|
||||
register_param(rain, "rain", "rain drops all over");
|
||||
@@ -120,11 +119,11 @@ public:
|
||||
|
||||
water_surfacesize = geo->size;
|
||||
calc_optimization = (height)*(width);
|
||||
|
||||
|
||||
xang = fastrand()%2048;
|
||||
yang = fastrand()%2048;
|
||||
swirlangle = fastrand()%2048;
|
||||
|
||||
|
||||
/* buffer allocation tango */
|
||||
if ( width*height > 0 ) {
|
||||
Height[0] = (uint32_t*)calloc(width*(height+1), sizeof(uint32_t));
|
||||
@@ -135,6 +134,9 @@ public:
|
||||
BkGdImage = (uint32_t*) malloc(geo->size);
|
||||
BkGdImagePost = (uint32_t*)malloc(geo->size);
|
||||
}
|
||||
|
||||
// Initialize surface to NULL
|
||||
surface = NULL;
|
||||
}
|
||||
|
||||
~Water() {
|
||||
@@ -152,7 +154,7 @@ public:
|
||||
memcpy(BkGdImage, in, width*height*sizeof(uint32_t));
|
||||
water_update(out);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
ScreenGeometry *geo;
|
||||
|
||||
@@ -162,11 +164,11 @@ private:
|
||||
uint32_t *BkGdImagePre;
|
||||
uint32_t *BkGdImage;
|
||||
uint32_t *BkGdImagePost;
|
||||
|
||||
|
||||
// uint32_t *buffer;
|
||||
|
||||
|
||||
void *surface;
|
||||
|
||||
|
||||
/* water effect variables */
|
||||
int Hpage;
|
||||
int xang, yang;
|
||||
@@ -174,39 +176,39 @@ private:
|
||||
int x, y, ox, oy;
|
||||
int done;
|
||||
int mode;
|
||||
|
||||
|
||||
/* precalculated to optimize a bit */
|
||||
int water_surfacesize;
|
||||
int calc_optimization;
|
||||
|
||||
|
||||
/* density: water density (step 1)
|
||||
pheight: splash height (step 40)
|
||||
radius: waterdrop radius (step 1) */
|
||||
int density, pheight, radius;
|
||||
int offset;
|
||||
|
||||
int offset;
|
||||
|
||||
int raincount;
|
||||
int blend;
|
||||
|
||||
void water_clear();
|
||||
void water_distort();
|
||||
void water_setphysics(double physics);
|
||||
void water_update(uint32_t* out);
|
||||
void water_update(uint32_t *out);
|
||||
void water_drop(int x, int y);
|
||||
void water_bigsplash(int x, int y);
|
||||
void water_surfer();
|
||||
void water_swirl();
|
||||
void water_3swirls();
|
||||
|
||||
void DrawWater(int page,uint32_t* out);
|
||||
|
||||
void DrawWater(int page, uint32_t* out);
|
||||
void CalcWater(int npage, int density);
|
||||
void CalcWaterBigFilter(int npage, int density);
|
||||
|
||||
|
||||
void SmoothWater(int npage);
|
||||
|
||||
|
||||
void HeightBlob(int x, int y, int radius, int height, int page);
|
||||
void HeightBox (int x, int y, int radius, int height, int page);
|
||||
|
||||
|
||||
void WarpBlob(int x, int y, int radius, int height, int page);
|
||||
void SineBlob(int x, int y, int radius, int height, int page);
|
||||
|
||||
@@ -215,7 +217,7 @@ private:
|
||||
int FSin(int angle) { return FSinTab[angle&FSINMAX]; }
|
||||
int FCos(int angle) { return FCosTab[angle&FSINMAX]; }
|
||||
void FCreateSines() {
|
||||
int i; double angle;
|
||||
int i; double angle;
|
||||
for(i=0; i<2048; i++) {
|
||||
angle = (float)i * (PI/1024.0);
|
||||
FSinTab[i] = (int)(sin(angle) * (float)0x10000);
|
||||
@@ -227,7 +229,7 @@ private:
|
||||
uint32_t randval;
|
||||
uint32_t fastrand() { return (randval=randval*1103515245+12345); };
|
||||
void fastsrand(uint32_t seed) { randval = seed; };
|
||||
|
||||
|
||||
/* integer optimized square root by jaromil */
|
||||
int isqrt(unsigned int x) {
|
||||
unsigned int m, y, b; m = 0x40000000;
|
||||
@@ -235,7 +237,7 @@ private:
|
||||
if(x>=b) { x=x-b; y=y|m; }
|
||||
m=m>>2; } return y;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
void Water::water_clear() {
|
||||
@@ -306,6 +308,7 @@ void Water::water_bigsplash(int x, int y) {
|
||||
}
|
||||
|
||||
void Water::water_surfer() {
|
||||
int x, y;
|
||||
x = (geo->w>>1)
|
||||
+ ((
|
||||
(
|
||||
@@ -322,7 +325,7 @@ void Water::water_surfer() {
|
||||
) >> 16);
|
||||
xang += 13;
|
||||
yang += 12;
|
||||
|
||||
|
||||
if(mode & 0x4000)
|
||||
{
|
||||
offset = (oy+y)/2*geo->w + ((ox+x)>>1); // QUAAA
|
||||
@@ -331,7 +334,7 @@ void Water::water_surfer() {
|
||||
Height[Hpage][offset - 1] =
|
||||
Height[Hpage][offset + geo->w] =
|
||||
Height[Hpage][offset - geo->w] = pheight >> 1;
|
||||
|
||||
|
||||
offset = y*geo->w + x;
|
||||
Height[Hpage][offset] = pheight<<1;
|
||||
Height[Hpage][offset + 1] =
|
||||
@@ -344,23 +347,24 @@ void Water::water_surfer() {
|
||||
SineBlob(((ox+x)>>1), ((oy+y)>>1), 3, -1200, Hpage);
|
||||
SineBlob(x, y, 4, -2000, Hpage);
|
||||
}
|
||||
|
||||
|
||||
ox = x;
|
||||
oy = y;
|
||||
oy = y;
|
||||
}
|
||||
|
||||
void Water::water_swirl() {
|
||||
int x, y;
|
||||
x = (geo->w>>1)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (25)
|
||||
) >> 16);
|
||||
|
||||
|
||||
y = (geo->h>>1)
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (25)
|
||||
) >> 16);
|
||||
x += position.x;
|
||||
y += position.y;
|
||||
x += (int)(position.x * geo->w);
|
||||
y += (int)(position.y * geo->h);
|
||||
|
||||
swirlangle += 50;
|
||||
if(mode & 0x4000)
|
||||
@@ -371,6 +375,7 @@ void Water::water_swirl() {
|
||||
|
||||
void Water::water_3swirls() {
|
||||
#define ANGLE 15
|
||||
int x, y;
|
||||
x = (95)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -382,7 +387,7 @@ void Water::water_3swirls() {
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
|
||||
x = (95)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -391,10 +396,10 @@ void Water::water_3swirls() {
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (ANGLE)
|
||||
) >> 16);
|
||||
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
|
||||
x = (345)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -403,7 +408,7 @@ void Water::water_3swirls() {
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (ANGLE)
|
||||
) >> 16);
|
||||
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
@@ -413,27 +418,27 @@ void Water::water_3swirls() {
|
||||
/* internal physics routines */
|
||||
void Water::DrawWater(int page,uint32_t* out) {
|
||||
int dx, dy;
|
||||
int x, y;
|
||||
uint32_t offset=geo->w + 1;
|
||||
uint32_t newoffset;
|
||||
int offset=geo->w + 1;
|
||||
int newoffset;
|
||||
int maxoffset = geo->w * geo->h;
|
||||
int *ptr = (int*)&Height[page][0];
|
||||
int maxoffset=geo->size/sizeof(uint32_t);
|
||||
|
||||
for (y = calc_optimization; offset < y; offset+=2) {
|
||||
for (x = offset+geo->w-2; offset < x; offset++) {
|
||||
|
||||
for (int y = calc_optimization; offset < y; offset += 2) {
|
||||
for (int x = offset+geo->w-2; offset < x; offset++) {
|
||||
dx = ptr[offset] - ptr[offset+1];
|
||||
dy = ptr[offset] - ptr[offset+geo->w];
|
||||
newoffset = offset + geo->w*(dy>>3) + (dx>>3);
|
||||
if(newoffset<maxoffset)
|
||||
if (newoffset < maxoffset) {
|
||||
out[offset] = BkGdImage[newoffset];
|
||||
}
|
||||
|
||||
offset++;
|
||||
|
||||
dx = ptr[offset] - ptr[offset+1];
|
||||
dy = ptr[offset] - ptr[offset+geo->w];
|
||||
newoffset = offset + geo->w*(dy>>3) + (dx>>3);
|
||||
if(newoffset<maxoffset)
|
||||
if (newoffset < maxoffset) {
|
||||
out[offset] = BkGdImage[newoffset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,10 +448,9 @@ void Water::CalcWater(int npage, int density) {
|
||||
int count = geo->w + 1;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for (y = calc_optimization; count < y; count += 2) {
|
||||
for (x = count+geo->w-2; count < x; count++) {
|
||||
for (int y = calc_optimization; count < y; count += 2) {
|
||||
for (int x = count+geo->w-2; count < x; count++) {
|
||||
/* eight pixels */
|
||||
newh = ((oldptr[count + geo->w]
|
||||
+ oldptr[count - geo->w]
|
||||
@@ -468,10 +472,9 @@ void Water::SmoothWater(int npage) {
|
||||
int count = geo->w + 1;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for(y=1; y<geo->h-1; y++) {
|
||||
for(x=1; x<geo->w-1; x++) {
|
||||
for(int y=1; y<geo->h-1; y++) {
|
||||
for(int x=1; x<geo->w-1; x++) {
|
||||
/* eight pixel */
|
||||
newh = ((oldptr[count + geo->w]
|
||||
+ oldptr[count - geo->w]
|
||||
@@ -483,8 +486,8 @@ void Water::SmoothWater(int npage) {
|
||||
+ oldptr[count + geo->w + 1]
|
||||
) >> 3 )
|
||||
+ newptr[count];
|
||||
|
||||
|
||||
|
||||
|
||||
newptr[count] = newh>>1;
|
||||
count++;
|
||||
}
|
||||
@@ -497,10 +500,9 @@ void Water::CalcWaterBigFilter(int npage, int density) {
|
||||
int count = (geo->w<<1) + 2;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for(y=2; y<geo->h-2; y++) {
|
||||
for(x=2; x<geo->w-2; x++) {
|
||||
|
||||
for(int y=2; y<geo->h-2; y++) {
|
||||
for(int x=2; x<geo->w-2; x++) {
|
||||
/* 25 pixels */
|
||||
newh = (
|
||||
(
|
||||
@@ -559,8 +561,13 @@ void Water::HeightBlob(int x, int y, int radius, int height, int page) {
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
cyq = cy*cy;
|
||||
for(cx = left; cx < right; cx++) {
|
||||
if(cx*cx + cyq < rquad)
|
||||
Height[page][geo->w*(cy+y) + (cx+x)] += height;
|
||||
if(cx*cx + cyq < rquad) {
|
||||
int index = geo->w*(cy+y) + (cx+x);
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,17 +579,21 @@ void Water::HeightBox (int x, int y, int radius, int height, int page) {
|
||||
|
||||
if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
|
||||
if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
|
||||
|
||||
|
||||
left=-radius; right = radius;
|
||||
top=-radius; bottom = radius;
|
||||
|
||||
|
||||
CLIP_EDGES
|
||||
|
||||
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
for(cx = left; cx < right; cx++) {
|
||||
Height[page][geo->w*(cy+y) + (cx+x)] = height;
|
||||
int index = geo->w*(cy+y) + (cx+x);
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Water::WarpBlob(int x, int y, int radius, int height, int page) {
|
||||
@@ -590,22 +601,25 @@ void Water::WarpBlob(int x, int y, int radius, int height, int page) {
|
||||
int left,top,right,bottom;
|
||||
int square;
|
||||
int radsquare = radius * radius;
|
||||
|
||||
|
||||
radsquare = (radius*radius);
|
||||
|
||||
|
||||
height = height>>5;
|
||||
|
||||
|
||||
left=-radius; right = radius;
|
||||
top=-radius; bottom = radius;
|
||||
|
||||
CLIP_EDGES
|
||||
|
||||
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
for(cx = left; cx < right; cx++) {
|
||||
square = cy*cy + cx*cx;
|
||||
if(square < radsquare) {
|
||||
Height[page][geo->w*(cy+y) + cx+x]
|
||||
+= (int)((radius-isqrt(square))*(float)(height));
|
||||
int index = geo->w*(cy+y) + cx+x;
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += (int)((radius-isqrt(square))*(float)(height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,7 +631,7 @@ void Water::SineBlob(int x, int y, int radius, int height, int page) {
|
||||
int square, dist;
|
||||
int radsquare = radius * radius;
|
||||
float length = (1024.0/(float)radius)*(1024.0/(float)radius);
|
||||
|
||||
|
||||
if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
|
||||
if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
|
||||
|
||||
@@ -632,8 +646,11 @@ void Water::SineBlob(int x, int y, int radius, int height, int page) {
|
||||
square = cy*cy + cx*cx;
|
||||
if(square < radsquare) {
|
||||
dist = (int)(isqrt(square*length));
|
||||
Height[page][geo->w*(cy+y) + cx+x]
|
||||
+= (int)((FCos(dist)+0xffff)*(height)) >> 19;
|
||||
int index = geo->w*(cy+y) + cx+x;
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += (int)((FCos(dist)+0xffff)*(height)) >> 19;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ class blend : public frei0r::mixer2
|
||||
public:
|
||||
blend(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->size = width * height;
|
||||
blend_factor = 0.5;
|
||||
register_param(blend_factor,"blend","blend factor");
|
||||
}
|
||||
@@ -45,6 +48,11 @@ public:
|
||||
const uint32_t* in1,
|
||||
const uint32_t* in2)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!out || !in1 || !in2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
|
||||
const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t*>(out);
|
||||
@@ -52,12 +60,17 @@ public:
|
||||
const uint8_t one_minus_bf = (255 - bf);
|
||||
uint32_t w = size;
|
||||
uint32_t b;
|
||||
|
||||
|
||||
// Validate size
|
||||
if (w == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (w--)
|
||||
{
|
||||
for (b = 0; b < NBYTES; b++)
|
||||
dst[b] = (src1[b] * one_minus_bf + src2[b] * bf) / 255;
|
||||
|
||||
|
||||
src1 += NBYTES;
|
||||
src2 += NBYTES;
|
||||
dst += NBYTES;
|
||||
|
||||
@@ -77,23 +77,42 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Validate inputs
|
||||
if (width == 0 || height == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
if (!inst) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
|
||||
inst->opacity = 1.0;
|
||||
|
||||
const char* blend_val = NORMAL;
|
||||
inst->blend_mode = (char*) malloc (strlen(blend_val) + 1 );
|
||||
strcpy (inst->blend_mode, blend_val);
|
||||
const char* blend_val = NORMAL;
|
||||
inst->blend_mode = (char*) malloc (strlen(blend_val) + 1);
|
||||
if (!inst->blend_mode) {
|
||||
free(inst);
|
||||
return NULL;
|
||||
}
|
||||
strcpy (inst->blend_mode, blend_val);
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
void f0r_destruct(f0r_instance_t instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*)instance;
|
||||
free(inst->blend_mode);
|
||||
if (inst->blend_mode) {
|
||||
free(inst->blend_mode);
|
||||
}
|
||||
free(instance);
|
||||
}
|
||||
|
||||
@@ -104,12 +123,22 @@ void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
char* sval;
|
||||
switch(param_index) {
|
||||
case 0:
|
||||
inst->opacity = *((double*)param);
|
||||
// Validate double parameter
|
||||
if (param) {
|
||||
inst->opacity = *((double*)param);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
sval = (*(char**)param);
|
||||
inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
|
||||
strcpy (inst->blend_mode, sval);
|
||||
// Validate string parameter
|
||||
if (param) {
|
||||
sval = (*(char**)param);
|
||||
if (sval) {
|
||||
inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
|
||||
if (inst->blend_mode) {
|
||||
strcpy (inst->blend_mode, sval);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -121,10 +150,16 @@ void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
|
||||
switch(param_index) {
|
||||
case 0:
|
||||
*((double*)param) = inst->opacity;
|
||||
if (param) {
|
||||
*((double*)param) = inst->opacity;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
*((f0r_param_string *)param) = inst->blend_mode;
|
||||
if (param && inst->blend_mode) {
|
||||
*((f0r_param_string *)param) = inst->blend_mode;
|
||||
} else if (param) {
|
||||
*((f0r_param_string *)param) = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -135,27 +170,53 @@ void draw_composite(cairo_blend_instance_t* inst, unsigned char* out, unsigned c
|
||||
int h = inst->height;
|
||||
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
|
||||
|
||||
// Validate inputs
|
||||
if (!inst || !out || !src || w <= 0 || h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_surface_t* out_image = cairo_image_surface_create_for_data (out,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
// Check if surface creation succeeded
|
||||
if (!out_image) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_t* cr = cairo_create (out_image);
|
||||
// Check if context creation succeeded
|
||||
if (!cr) {
|
||||
cairo_surface_destroy (out_image);
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_surface_t* src_image = cairo_image_surface_create_for_data ((unsigned char*)src,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
// Check if surface creation succeeded
|
||||
if (!src_image) {
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (out_image);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate blend mode string
|
||||
if (inst->blend_mode) {
|
||||
// Set source, blend mode and draw with current opacity
|
||||
frei0r_cairo_set_operator(cr, inst->blend_mode);
|
||||
}
|
||||
|
||||
// Set source, blen mode and draw with current opacity
|
||||
frei0r_cairo_set_operator(cr, inst->blend_mode);
|
||||
cairo_set_source_surface (cr, src_image, 0, 0);
|
||||
cairo_paint_with_alpha (cr, inst->opacity);
|
||||
|
||||
cairo_surface_destroy (out_image);
|
||||
// Clean up in proper order
|
||||
cairo_surface_destroy (src_image);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (out_image);
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
@@ -167,6 +228,11 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
void f0r_update2(f0r_instance_t instance, double time, const uint32_t* inframe1,
|
||||
const uint32_t* inframe2, const uint32_t* inframe3, uint32_t* outframe)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!instance || !inframe1 || !inframe2 || !outframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(instance);
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*) instance;
|
||||
|
||||
@@ -175,6 +241,11 @@ void f0r_update2(f0r_instance_t instance, double time, const uint32_t* inframe1,
|
||||
unsigned char* out = (unsigned char*)outframe;
|
||||
int pixels = inst->width * inst->height;
|
||||
|
||||
// Validate dimensions
|
||||
if (pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
frei0r_cairo_premultiply_rgba2 (dst, out, pixels, -1);
|
||||
frei0r_cairo_premultiply_rgba (src, pixels, -1);
|
||||
draw_composite (inst, out, src, time);
|
||||
|
||||
@@ -29,6 +29,9 @@ class overlay : public frei0r::mixer2
|
||||
public:
|
||||
overlay(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->size = width * height;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,22 +47,32 @@ public:
|
||||
const uint32_t* in1,
|
||||
const uint32_t* in2)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!out || !in1 || !in2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
|
||||
const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t*>(out);
|
||||
uint32_t sizeCounter = size;
|
||||
|
||||
|
||||
// Validate size
|
||||
if (sizeCounter == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t b, tmp, tmpM;
|
||||
|
||||
|
||||
while (sizeCounter--)
|
||||
{
|
||||
for (b = 0; b < ALPHA; b++)
|
||||
{
|
||||
dst[b] = INT_MULT(src1[b], src1[b] + INT_MULT(2 * src2[b], 255 - src1[b], tmpM), tmp);
|
||||
}
|
||||
|
||||
|
||||
dst[ALPHA] = MIN(src1[ALPHA], src2[ALPHA]);
|
||||
|
||||
|
||||
src1 += NBYTES;
|
||||
src2 += NBYTES;
|
||||
dst += NBYTES;
|
||||
|
||||
Reference in New Issue
Block a user