Codebase list frei0r / 8ef685c
New upstream version 2.5.1 IOhannes m zmölnig (Debian/GNU) 6 months ago
27 changed file(s) with 871 addition(s) and 321 deletion(s). Raw diff Collapse all Expand all
99
1010 + [Cairo](http://cairographics.org) required for cairo- filters and mixers
1111
12 ## Optional build flags
13
14 + `-DWITHOUT_FACERECOGNITION=ON` - Disable face recognition plugins (facedetect and facebl0r) to avoid protobuf conflicts with applications like MLT
15
1216 It is recommended to use a separate `build` sub-folder.
1317
1418 ```
1519 mkdir -p build
1620 cd build && cmake ../
21 make
22 ```
23
24 To disable face recognition plugins (recommended when using with MLT):
25 ```
26 mkdir -p build
27 cd build && cmake -DWITHOUT_FACERECOGNITION=ON ../
1728 make
1829 ```
1930
0 cmake_minimum_required (VERSION 3.12...3.31)
0 cmake_minimum_required (VERSION 3.12)
11
22 list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
33
44 project (frei0r)
5 set (VERSION 1.8)
5 set (VERSION 2.5.1)
66
77 include(GNUInstallDirs)
88
99 option (WITHOUT_OPENCV "Disable plugins dependent upon OpenCV" OFF)
10 option (WITHOUT_FACERECOGNITION "Disable facedetect plugin to avoid protobuf conflicts" OFF)
11
1012 if (NOT WITHOUT_OPENCV)
1113 find_package (OpenCV)
1214 endif ()
5151 ## https://github.com/dyne/frei0r/releases
5252
5353 Frei0r sourcecode is released under the terms of the GNU General Public License and, eventually other compatible Free Software licenses.
54
55 ## Packaging
56
57 [![Packaging status](https://repology.org/badge/vertical-allrepos/frei0r.svg?columns=3)](https://repology.org/project/frei0r/versions)
5458
5559 ## Build dependencies
5660
6161 */
6262 void frei0r_cairo_set_operator(cairo_t *cr, char *op)
6363 {
64 // Validate inputs
65 if (!cr || !op) {
66 if (cr) {
67 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
68 }
69 return;
70 }
71
6472 if(strcmp(op, NORMAL) == 0)
6573 {
6674 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
230238 */
231239 void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
232240 {
241 // Validate inputs
242 if (!rgba || pixels <= 0) {
243 return;
244 }
245
233246 int i = pixels + 1;
234247 while ( --i ) {
235248 register unsigned char a = rgba[3];
254267 */
255268 void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
256269 {
270 // Validate inputs
271 if (!rgba || pixels <= 0) {
272 return;
273 }
274
257275 int i = pixels + 1;
258276 while ( --i ) {
259277 register unsigned char a = rgba[3];
280298 void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
281299 int pixels, int alpha)
282300 {
301 // Validate inputs
302 if (!in || !out || pixels <= 0) {
303 return;
304 }
305
283306 int i = pixels + 1;
284307 while ( --i ) {
285308 register unsigned char a = in[3];
1717 add_subdirectory (3dflippo)
1818 add_subdirectory (aech0r)
1919 add_subdirectory (alpha0ps)
20 add_subdirectory (autothresh0ld)
2021 add_subdirectory (balanc0r)
2122 add_subdirectory (baltan)
2223 add_subdirectory (bluescreen0r)
0 set (SOURCES autothresh0ld.c)
1 set (TARGET autothresh0ld)
2
3 if (MSVC)
4 set (SOURCES ${SOURCES} ${FREI0R_DEF})
5 endif (MSVC)
6
7 add_library (${TARGET} MODULE ${SOURCES})
8
9 # No «lib» prefix (name.so instead of libname.so)
10 set_target_properties (${TARGET} PROPERTIES PREFIX "")
0 /**
1 * (c) Copyright 2025 Cynthia <cynthia2048@proton.me>
2 *
3 * This is based on Otsu's algorithm to segment an image into foreground
4 * or background based on the shape of the histogram. Instead of doing a
5 * hard threshold, we use the threshold obtained from Otsu's algorithm
6 * as the base for a sigmoidal transfer with a high slope; this produces
7 * a more eye-soothing threshold effect as seen in ImageMagick.
8 *
9 * This has the added benefit that, whereas the sigmoidal filter's base
10 * requires manual tuning, here it is determined algorithmically and thus
11 * can adapt on a frame-to-frame basis.
12 *
13 * This file is a Frei0r plugin.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <math.h>
33
34 #include "frei0r.h"
35 #include "frei0r/math.h"
36
37 #include "variance.h"
38
39 typedef struct {
40 unsigned int width, height;
41 float slope;
42
43 uint8_t lut[256][256];
44 uint8_t *lumaframe;
45 } s0ft0tsu_t;
46
47 static void gen_sigmoid_lut (uint8_t lut[256][256], float slope)
48 {
49 float k = expf(slope) / 255.0;
50
51 for (int j = 0; j < 256; ++j)
52 for (int i = 0; i < 256; ++i)
53 lut[j][i] = CLAMP (255.0 / (1.0 + expf(-k * (i - j))), 0, 255);
54 }
55
56 int f0r_init()
57 {
58 return 0;
59 }
60
61 void f0r_deinit() {}
62
63 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
64 {
65 s0ft0tsu_t* s = calloc(1, sizeof(s0ft0tsu_t));
66
67 s->width = width;
68 s->height = height;
69 s->slope = 4.0;
70 s->lumaframe = malloc(s->width * s->height);
71
72 gen_sigmoid_lut(s->lut, s->slope);
73
74 return s;
75 }
76
77 void f0r_get_plugin_info(f0r_plugin_info_t* info)
78 {
79 info->name = "autothreshold";
80 info->author = "Cynthia";
81 info->explanation = "Automatically threshold moving pictures";
82 info->major_version = 0;
83 info->minor_version = 1;
84 info->frei0r_version = FREI0R_MAJOR_VERSION;
85 info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
86 info->color_model = F0R_COLOR_MODEL_RGBA8888;
87 info->num_params = 1;
88 }
89
90 void f0r_get_param_info(f0r_param_info_t *info, int index)
91 {
92 switch (index)
93 {
94 case 0:
95 info->name = "Slope";
96 info->explanation = "Slope of sigmoidal transfer";
97 info->type = F0R_PARAM_DOUBLE;
98 break;
99 }
100 }
101
102 void f0r_get_param_value(f0r_instance_t inst, f0r_param_t param, int index)
103 {
104 s0ft0tsu_t* s = inst;
105
106 switch (index)
107 {
108 case 0:
109 *(double*)param = s->slope / 7.0;
110 break;
111 }
112 }
113
114 void f0r_set_param_value(f0r_instance_t inst, f0r_param_t param, int index)
115 {
116 s0ft0tsu_t* s = inst;
117
118 switch (index)
119 {
120 case 0:
121 s->slope = *(double*)param * 7.0;
122
123 gen_sigmoid_lut(s->lut, s->slope);
124 break;
125 }
126 }
127
128 void f0r_update(f0r_instance_t inst, double time,
129 const uint32_t* inframe, uint32_t* outframe)
130 {
131 s0ft0tsu_t *s = inst;
132
133 uint8_t *src = (uint8_t*)inframe;
134 uint8_t *dst = s->lumaframe;
135 uint8_t r, g, b, luma;
136 size_t len = s->width * s->height;
137
138 // Normalised histogram (L = 256)
139 float hist[256] = {0};
140
141 for (int i = 0; i < len; ++i)
142 {
143 r = *src++;
144 g = *src++;
145 b = *src++;
146 src++; // Ignore alpha
147
148 luma = CLAMP(0.299 * r + 0.587 * g + 0.114 * b, 0, 255);
149 *dst++ = luma;
150
151 ++hist[luma]; // Add to histogram
152 }
153
154 // Normalise histogram; becomes a probability distribution
155 for (int i = 0; i < 256; ++i)
156 hist[i] /= len;
157
158 uint8_t thresh = 0.0;
159 float max_var = 0.0; // Maximum inter-class variance.
160
161 for (int i = 1; i < 256; ++i)
162 {
163 float var = find_variance(hist, i);
164 if (var > max_var)
165 {
166 thresh = i;
167 max_var = var;
168 }
169 }
170
171 src = (uint8_t*)s->lumaframe; // Replenish
172 dst = (uint8_t*)outframe;
173
174 for (int i = 0; i < len; ++i)
175 {
176 // Select the appropriate transfer
177 uint8_t* lut = s->lut[thresh];
178
179 luma = lut[*src++];
180
181 *dst++ = luma;
182 *dst++ = luma;
183 *dst++ = luma;
184 *dst++ = 0xFF; // TODO Copy alpha
185 }
186 }
187
188 void f0r_destruct(f0r_instance_t s)
189 {
190 free(s);
191 }
0 #ifdef __SSE2__
1 #include <emmintrin.h>
2 #endif
3
4 static float find_variance(float *hist, int thresh)
5 {
6 float w_0 = 0.0, mu_0 = 0.0, w_1 = 0.0, mu_1 = 0.0;
7
8 for (int i = 0; i < thresh; ++i)
9 {
10 w_0 += hist[i];
11 mu_0 += i * hist[i];
12 }
13 for (int i = thresh; i < 256; ++i)
14 {
15 w_1 += hist[i];
16 mu_1 += i * hist[i];
17 }
18
19 float mu_diff = (mu_0/w_0 - mu_1/w_1);
20 return w_0*w_1*mu_diff*mu_diff;
21 }
22
23 #ifdef __SSE2__
24 static float _sse1_hadd_ps(__m128 v)
25 {
26 // Based on a StackOverflow answer.
27 __m128 shuf = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 3, 0, 1));
28 __m128 sums = _mm_add_ps(v, shuf);
29 shuf = _mm_movehl_ps(shuf, sums);
30 sums = _mm_add_ss(sums, shuf);
31 return _mm_cvtss_f32(sums);
32 }
33
34 static float find_variance_sse2(float *hist, int thresh)
35 {
36 __m128 vw_0 = _mm_setzero_ps(), vmu_0 = _mm_setzero_ps(),
37 vw_1 = _mm_setzero_ps(), vmu_1 = _mm_setzero_ps();
38 __m128 vcnt = _mm_set_ps(0, 1, 2, 3);
39
40 int thresh_low = (thresh / 4 + 0) * 4,
41 thresh_up = (thresh / 4 + 1) * 4;
42
43 for (int i = 0; i < thresh_low; i+=4)
44 {
45 __m128 vhist = _mm_castsi128_ps(_mm_loadu_si128((void*)&hist[i]));
46
47 vw_0 = _mm_add_ps(vhist, vw_0);
48 vmu_0 = _mm_add_ps(_mm_mul_ps(vcnt, vhist), vw_0);
49 vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
50 }
51
52 // This is skipped, and handled as an edge case by non-SSE code.
53 vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
54
55 for (int i = thresh_up; i < 256; i+=4)
56 {
57 __m128 vhist = _mm_castsi128_ps(_mm_loadu_si128((void*)&hist[i]));
58
59 vw_1 = _mm_add_ps(vhist, vw_1);
60 vmu_1 = _mm_add_ps(_mm_mul_ps(vcnt, vhist), vw_1);
61 vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
62 }
63
64 float w_0 = _sse1_hadd_ps(vw_0), mu_0 = _sse1_hadd_ps(vmu_0),
65 w_1 = _sse1_hadd_ps(vw_1), mu_1 = _sse1_hadd_ps(vmu_1);
66
67 // This edge case is here, because thresh may not be a multiple of 4.
68 for (int i = thresh_low; i < thresh; ++i)
69 {
70 w_0 += hist[i];
71 mu_0 += i * hist[i];
72 }
73
74 for (int i = thresh; i < thresh_up; ++i)
75 {
76 w_1 += hist[i];
77 mu_1 += i * hist[i];
78 }
79
80 float mu_diff = (mu_0/w_0 - mu_1/w_1);
81 return w_0*w_1*mu_diff*mu_diff;
82 }
83 #endif
8282 *outpixel= (*pixel & 0x00FFFFFF); // copy all except alpha
8383
8484 uint32_t d = distance(*pixel); // get distance
85 unsigned char a = 255; // default alpha
85 unsigned char a = (*pixel >> 24); // default alpha
8686 if (d < distInt) {
8787 a = 0;
8888 if (d > distInt2) {
9999 };
100100
101101
102 frei0r::construct<bluescreen0r> plugin("bluescreen0r", "Color to alpha (blit SRCALPHA)", "Hedde Bosman",0,4,F0R_COLOR_MODEL_RGBA8888);
103
102 frei0r::construct<bluescreen0r> plugin("bluescreen0r",
103 "Color to alpha (blit SRCALPHA)",
104 "Hedde Bosman",
105 0, 5,
106 F0R_COLOR_MODEL_RGBA8888);
7979 {
8080 float p[10];
8181 int i,j,m;
82 float zero = 0.0f; // MSVC doesn't allow division through a zero literal, but allows it through non-const variable set to zero
8382
8483 if ((x<xt[0])||(x>xt[t-1]))
8584 {
8685 // printf("\n\n x=%f je izven mej tabele!",x);
87 return 1.0/zero;
86 // Return a reasonable value instead of dividing by zero
87 if (x<xt[0]) return yt[0];
88 else return yt[t-1];
8889 }
8990
9091 //poisce, katere tocke bo uporabil
9798 for (j=1;j<4;j++)
9899 for (i=(4-1);i>=j;i--)
99100 {
100 p[i]=p[i]+(x-xt[i+m])/(xt[i+m]-xt[i-j+m])*(p[i]-p[i-1]);
101 // Check for division by zero
102 float denominator = xt[i+m]-xt[i-j+m];
103 if (denominator == 0.0f) {
104 // If denominator is zero, skip this iteration to avoid undefined behavior
105 continue;
106 }
107 p[i]=p[i]+(x-xt[i+m])/denominator*(p[i]-p[i-1]);
101108 }
102109 return p[4-1];
103110 }
4545 uint32_t size;
4646 } ScreenGeometry;
4747
48 #define PIXELAT(x1,y1,s) ((s)+(x1)+ yprecal[y1])// (y1)*(geo->w)))
48 #define PIXELAT(x1,y1,s,inst) ((s)+(x1)+ inst->yprecal[y1])// (y1)*(geo->w)))
4949 #define GMERROR(cc1,cc2) ((((RED(cc1)-RED(cc2))*(RED(cc1)-RED(cc2))) + \
5050 ((GREEN(cc1)-GREEN(cc2)) *(GREEN(cc1)-GREEN(cc2))) + \
5151 ((BLUE(cc1)-BLUE(cc2))*(BLUE(cc1)-BLUE(cc2)))))
154154 long error,max=0;
155155
156156 /* Assumes PrePixelModify has been run */
157 c1 = *PIXELAT(x-m_diffspace,y,src);
158 c2 = *PIXELAT(x+m_diffspace,y,src);
157 c1 = *PIXELAT(x-m_diffspace,y,src,this);
158 c2 = *PIXELAT(x+m_diffspace,y,src,this);
159159 error = GMERROR(c1,c2);
160160 if (error>max) max = error;
161
162 c1 = *PIXELAT(x,y-m_diffspace,src);
163 c2 = *PIXELAT(x,y+m_diffspace,src);
161
162 c1 = *PIXELAT(x,y-m_diffspace,src,this);
163 c2 = *PIXELAT(x,y+m_diffspace,src,this);
164164 error = GMERROR(c1,c2);
165165 if (error>max) max = error;
166
167 c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src);
168 c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src);
166
167 c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src,this);
168 c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src,this);
169169 error = GMERROR(c1,c2);
170170 if (error>max) max = error;
171
172 c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src);
173 c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src);
171
172 c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src,this);
173 c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src,this);
174174 error = GMERROR(c1,c2);
175175 if (error>max) max = error;
176
176
177177 return(max);
178178 }
179179
124124 float b1 = inst->color.b * 255.0;
125125 float r2, g2, b2;
126126 int l;
127 /* Scale factor to normalize distance to 0-255 range:
128 0.705724361914764 ≈ 255.0 / sqrt(3 * 255^2) = 255.0 / (255.0 * sqrt(3)) */
129 const float SCALE_FACTOR = 0.705724361914764;
127130 while (len--) {
128131 r2 = *src++;
129132 g2 = *src++;
130133 b2 = *src++;
131 l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * 0.705724361914764 );
132 /* Hint 0.35320727852735 == 255.0 / sqrt( (255)**2 + (255)**2 + (255)*2 )*/
133 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 ) {
134 printf ("%f %f %f\n", r2, g2, b2 );
135 }
134 l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * SCALE_FACTOR );
136135
136 // Clamp result to valid range
137 l = CLAMP(l, 0, 255);
137138
138139 *dst++ = (unsigned char) (l);
139140 *dst++ = (unsigned char) (l);
253253 step_line_u = (int32_t) ((u_right-u_left) >> GRID_SIZE_LOG);
254254 step_line_v = (int32_t) ((v_right-v_left) >> GRID_SIZE_LOG);
255255
256 for(block_x=0; block_x < GRID_SIZE; ++block_x)
257 {
256 for(block_x=0; block_x < GRID_SIZE; ++block_x)
257 {
258258 int uu = u_line_index >> 16;
259259 int vv = v_line_index >> 16;
260
261 u_line_index += step_line_u;
262 v_line_index += step_line_v;
263
264 *pos++ = src[uu + vv * w];
265 }
260
261 u_line_index += step_line_u;
262 v_line_index += step_line_v;
263
264 // Bounds checking to prevent buffer overrun
265 if (uu >= 0 && uu < (int)w && vv >= 0 && vv < (int)h) {
266 *pos++ = src[uu + vv * w];
267 } else {
268 *pos++ = 0; // Black pixel for out-of-bounds access
269 }
270 }
266271
267272 start_col_uu += step_start_col_u;
268273 end_col_uu += step_end_col_u;
0 set (SOURCES facebl0r.cpp)
1 set (TARGET facebl0r)
0 # facebl0r filter - requires OpenCV (and protobuf)
1 # This filter can cause conflicts with applications that also use protobuf
2 # such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
23
3 if (MSVC)
4 set (SOURCES ${SOURCES} ${FREI0R_DEF})
5 endif (MSVC)
4 if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
5 set (SOURCES facebl0r.cpp)
6 set (TARGET facebl0r)
67
7 include_directories(${OpenCV_INCLUDE_DIRS})
8 add_library (${TARGET} MODULE ${SOURCES})
9 set_target_properties (${TARGET} PROPERTIES PREFIX "")
10 target_link_libraries(${TARGET} ${OpenCV_LIBS})
8 if (MSVC)
9 set (SOURCES ${SOURCES} ${FREI0R_DEF})
10 endif (MSVC)
1111
12 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
12 include_directories(${OpenCV_INCLUDE_DIRS})
13 add_library (${TARGET} MODULE ${SOURCES})
14 set_target_properties (${TARGET} PROPERTIES PREFIX "")
15 target_link_libraries(${TARGET} ${OpenCV_LIBS})
16
17 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
18 endif()
0 set (SOURCES facedetect.cpp)
1 set (TARGET facedetect)
0 # facedetect filter - requires OpenCV (and protobuf)
1 # This filter can cause conflicts with applications that also use protobuf
2 # such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
23
3 if (MSVC)
4 set (SOURCES ${SOURCES} ${FREI0R_DEF})
5 endif (MSVC)
4 if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
5 set (SOURCES facedetect.cpp)
6 set (TARGET facedetect)
67
7 include_directories(${OpenCV_INCLUDE_DIRS})
8 add_library (${TARGET} MODULE ${SOURCES})
9 set_target_properties (${TARGET} PROPERTIES PREFIX "")
10 target_link_libraries(${TARGET} ${OpenCV_LIBS})
8 if (MSVC)
9 set (SOURCES ${SOURCES} ${FREI0R_DEF})
10 endif (MSVC)
1111
12 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
12 include_directories(${OpenCV_INCLUDE_DIRS})
13 add_library (${TARGET} MODULE ${SOURCES})
14 set_target_properties (${TARGET} PROPERTIES PREFIX "")
15 target_link_libraries(${TARGET} ${OpenCV_LIBS})
16
17 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
18 endif()
4444 short int howToDistort1;
4545 short int howToDistort2;
4646 short int passThisLine;
47 } g0r_state;
47 };
4848
4949 typedef struct glitch0r_instance
5050 {
5757 short int colorGlitchIntensity;
5858 short int doColorDistortion;
5959 short int glitchChance;
60
61 struct glitch0r_state state; // Instance-specific state
6062 } glitch0r_instance_t;
6163
6264
6769
6870 inline static void glitch0r_state_reset(glitch0r_instance_t *inst)
6971 {
70 g0r_state.currentPos = 0;
71 g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
72 g0r_state.blkShift = rnd(1, inst->maxBlockShift);
73 g0r_state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
72 inst->state.currentPos = 0;
73 inst->state.currentBlock = rnd(1, inst->maxBlockSize);
74 inst->state.blkShift = rnd(1, inst->maxBlockShift);
75 inst->state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
7476
7577 if (inst->doColorDistortion)
7678 {
77 g0r_state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
78 g0r_state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
79 g0r_state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
80 g0r_state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
79 inst->state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
80 inst->state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
81 inst->state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
82 inst->state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
8183 }
8284 }
8385
303305
304306 uint32_t* dst = outframe;
305307 const uint32_t* src = inframe;
306 uint32_t *pixel;
307
308 g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
308 uint32_t *pixel;
309
310 inst->state.currentBlock = rnd(1, inst->maxBlockSize);
309311
310312 for (y = 0; y < inst->height; y++)
311313 {
312314
313 if (g0r_state.currentPos > g0r_state.currentBlock)
315 if (inst->state.currentPos > inst->state.currentBlock)
314316 {
315317 glitch0r_state_reset(inst);
316318 }
317319 else
318 g0r_state.currentPos++;
319
320 g0r_state.currentY = y*inst->width;
321 pixel = dst + g0r_state.currentY;
322
323 if (g0r_state.passThisLine)
324 {
325 memcpy((uint32_t *)(dst + g0r_state.currentY),
326 (uint32_t *)(src + g0r_state.currentY),
320 inst->state.currentPos++;
321
322 inst->state.currentY = y*inst->width;
323 pixel = dst + inst->state.currentY;
324
325 if (inst->state.passThisLine)
326 {
327 memcpy((uint32_t *)(dst + inst->state.currentY),
328 (uint32_t *)(src + inst->state.currentY),
327329 (inst->width) * sizeof(uint32_t));
328330 continue;
329331 }
330332
331 for (x = g0r_state.blkShift; x < (inst->width); x++)
332 {
333 *(pixel) = *(src + g0r_state.currentY + x);
333 for (x = inst->state.blkShift; x < (inst->width); x++)
334 {
335 *(pixel) = *(src + inst->state.currentY + x);
334336
335337 if (inst->doColorDistortion)
336338 glitch0r_pixel_dist0rt(pixel,
337 g0r_state.distortionSeed1, g0r_state.howToDistort1);
339 inst->state.distortionSeed1, inst->state.howToDistort1);
338340
339341 pixel++;
340342 }
341343
342 for (x = 0; x < g0r_state.blkShift; x++)
343 {
344 *(pixel) = *(src + g0r_state.currentY + x);
344 for (x = 0; x < inst->state.blkShift; x++)
345 {
346 *(pixel) = *(src + inst->state.currentY + x);
345347
346348 if (inst->doColorDistortion)
347349 glitch0r_pixel_dist0rt(pixel,
348 g0r_state.distortionSeed2, g0r_state.howToDistort2);
350 inst->state.distortionSeed2, inst->state.howToDistort2);
349351
350352 pixel++;
351353 }
55 endif (MSVC)
66
77 add_library (${TARGET} MODULE ${SOURCES})
8 set_target_properties (${TARGET} PROPERTIES PREFIX "")
89
9 # No «lib» prefix (name.so instead of libname.so)
10 set_target_properties (${TARGET} PROPERTIES PREFIX "")
10 install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
9595 info->major_version = 0;
9696 info->minor_version = 1;
9797 info->num_params = 4;
98 info->explanation = "Performs a continious trichromatic tinting";
98 info->explanation = "Performs a continuous trichromatic tinting";
9999 }
100100
101101 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
121121 levelsInput = CLAMP(levelsInput, 0.0, 48.0) + 2.0;
122122 int numLevels = (int)levelsInput;
123123
124 // Prevent division by zero
125 if (numLevels < 2) numLevels = 2;
126
124127 // create levels table
125128 unsigned char levels[256];
126129 int i;
22 * It contains code from plug-ins/common/noise-rgb.c, see that for copyrights.
33 *
44 * rgbnoise.c
5 * Copyright 2012 Janne Liljeblad
5 * Copyright 2012 Janne Liljeblad
66 *
77 * This file is a Frei0r plugin.
88 *
2828 #include "frei0r.h"
2929 #include "frei0r/math.h"
3030
31 static int MY_MAX_RAND = 32767;// I assume RAND_MAX to be at least this big.
32 static double gaussian_lookup[32767];
33 static int TABLE_INITED = 0;
34 static int next_gaussian_index = 0;
35 static int last_in_range = 32766;
31 #define MY_MAX_RAND 32767 // assume RAND_MAX to be at least this big.
3632
3733 typedef struct rgbnoise_instance
3834 {
3935 unsigned int width;
4036 unsigned int height;
4137 double noise;
38 double gaussian_lookup[MY_MAX_RAND];
39 int table_inited;
40 int next_gaussian_index;
41 int last_in_range;
4242 } rgbnoise_instance_t;
4343
4444
5353 rgbnoiseInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
5454 rgbnoiseInfo->color_model = F0R_COLOR_MODEL_RGBA8888;
5555 rgbnoiseInfo->frei0r_version = FREI0R_MAJOR_VERSION;
56 rgbnoiseInfo->major_version = 0;
57 rgbnoiseInfo->minor_version = 9;
58 rgbnoiseInfo->num_params = 1;
56 rgbnoiseInfo->major_version = 0;
57 rgbnoiseInfo->minor_version = 9;
58 rgbnoiseInfo->num_params = 1;
5959 rgbnoiseInfo->explanation = "Adds RGB noise to image.";
6060 }
6161
7373 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
7474 {
7575 rgbnoise_instance_t* inst = (rgbnoise_instance_t*)calloc(1, sizeof(*inst));
76 inst->width = width;
76 inst->width = width;
7777 inst->height = height;
7878 inst->noise = 0.2;
79 inst->table_inited = 0;
80 inst->next_gaussian_index = 0;
81 inst->last_in_range = MY_MAX_RAND;
7982 return (f0r_instance_t)inst;
8083 }
8184
8487 free(instance);
8588 }
8689
87 void f0r_set_param_value(f0r_instance_t instance,
90 void f0r_set_param_value(f0r_instance_t instance,
8891 f0r_param_t param, int param_index)
8992 {
9093 rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
98101
99102 void f0r_get_param_value(f0r_instance_t instance,
100103 f0r_param_t param, int param_index)
101 {
104 {
102105 rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
103 switch (param_index)
106 switch (param_index)
104107 {
105108 case 0:
106109 *((double*)param) = inst->noise;
132135 return x;
133136 }
134137
135 static void create_new_lookup_range()
138 static void create_new_lookup_range(rgbnoise_instance_t* inst)
136139 {
137140 int first, last, tmp;
138141 first = rand() % (MY_MAX_RAND - 1);
143146 last = first;
144147 first = tmp;
145148 }
146 next_gaussian_index = first;
147 last_in_range = last;
148 }
149
150 static inline double next_gauss()
151 {
152 next_gaussian_index++;
153 if (next_gaussian_index >= last_in_range)
154 {
155 create_new_lookup_range();
156 }
157 return gaussian_lookup[next_gaussian_index];
158 }
159
160 static inline int addNoise(int sample, double noise)
149 inst->next_gaussian_index = first;
150 inst->last_in_range = last;
151 }
152
153 static inline double next_gauss(rgbnoise_instance_t* inst)
154 {
155 inst->next_gaussian_index++;
156 if (inst->next_gaussian_index >= inst->last_in_range)
157 {
158 create_new_lookup_range(inst);
159 }
160 return inst->gaussian_lookup[inst->next_gaussian_index];
161 }
162
163 static inline int addNoise(rgbnoise_instance_t* inst, int sample, double noise)
161164 {
162165 int byteNoise = 0;
163166 int noiseSample = 0;
164167
165 byteNoise = (int) (noise * next_gauss());
168 byteNoise = (int) (noise * next_gauss(inst));
166169 noiseSample = sample + byteNoise;
167170 noiseSample = CLAMP(noiseSample, 0, 255);
168171 return noiseSample;
169 }
172 }
170173
171174 int f0r_init()
172175 {
173 if (TABLE_INITED == 0)
176 return 1;
177 }
178
179 void rgb_noise(f0r_instance_t instance, double time,
180 const uint32_t* inframe, uint32_t* outframe)
181 {
182 rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
183 unsigned int len = inst->width * inst->height;
184
185 // Initialize the gaussian lookup table if not already done
186 if (inst->table_inited == 0)
174187 {
175188 int i;
176189 for( i = 0; i < MY_MAX_RAND; i++)
177190 {
178 gaussian_lookup[i] = gauss() * 127.0;
191 inst->gaussian_lookup[i] = gauss() * 127.0;
179192 }
180 TABLE_INITED = 1;
181 }
182 return 1;
183 }
184
185 void rgb_noise(f0r_instance_t instance, double time,
186 const uint32_t* inframe, uint32_t* outframe)
187 {
188 rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
189 unsigned int len = inst->width * inst->height;
193 inst->table_inited = 1;
194 inst->next_gaussian_index = 0;
195 inst->last_in_range = MY_MAX_RAND;
196 }
190197
191198 unsigned char* dst = (unsigned char*)outframe;
192199 const unsigned char* src = (unsigned char*)inframe;
196203 while (len--)
197204 {
198205 sample = *src++;
199 *dst++ = addNoise(sample, noise);
206 *dst++ = addNoise(inst, sample, noise);
200207 sample = *src++;
201 *dst++ = addNoise(sample, noise);
208 *dst++ = addNoise(inst, sample, noise);
202209 sample = *src++;
203 *dst++ = addNoise(sample, noise);
210 *dst++ = addNoise(inst, sample, noise);
204211 *dst++ = *src++;
205212 }
206213 }
212219 assert(instance);
213220 rgb_noise(instance, time, inframe, outframe);
214221 }
215
00 /* rgbsplit0r.c
11 * Copyright (C) 2016 IDENT Software ~ http://identsoft.org
22 * Inspired by the witch house and web culture
3 *
3 *
44 * This file is a Frei0r plugin.
55 *
66 * This program is free software; you can redistribute it and/or modify
110110 inst->width = width; inst->height = height;
111111 inst->shiftY = 0;
112112 inst->shiftX = 0;
113
114113 return (f0r_instance_t)inst;
115114 }
116115
119118 free(instance);
120119 }
121120
122 void f0r_set_param_value(f0r_instance_t instance,
121 void f0r_set_param_value(f0r_instance_t instance,
123122 f0r_param_t param, int param_index)
124123 {
125124 assert(instance);
134133 double shiftY = *((double*)param) - 0.5;
135134
136135 // Convert to range from 0 to one eighth of height
137 shiftY = ((inst->height / 8) * shiftY);
136 if (inst->height > 0)
137 shiftY = ((inst->height / 8) * shiftY);
138 else
139 shiftY = 0;
138140
139141 inst->shiftY = (unsigned int)shiftY;
140142 break;
144146 {
145147 // scale to [-1/16..1/16]
146148 double shiftX = *((double*)param) - 0.5;
147
149
148150 // Convert to range from 0 to one eighth of width
149 shiftX = ((inst->width / 8) * shiftX);
151 if (inst->width > 0)
152 shiftX = ((inst->width / 8) * shiftX);
153 else
154 shiftX = 0;
150155
151156 inst->shiftX = (unsigned int)shiftX;
152157 break;
166171 case 0 : // vertical shift
167172 {
168173 // convert plugin's param to frei0r range
169 *((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
174 if (inst->height > 0)
175 *((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
176 else
177 *((double*)param) = 0.5;
170178 break;
171179 }
172180
173181 case 1 : // horizontal shift
174182 {
175183 // convert plugin's param to frei0r range
176 *((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
184 if (inst->width > 0)
185 *((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
186 else
187 *((double*)param) = 0.5;
177188 break;
178189 }
179190 }
194205 uint32_t pxR = 0, pxG = 0, pxB = 0;
195206
196207 // First make a blue layer shifted back
197 if (((x - inst->shiftX) < inst->width) &&
198 ((y - inst->shiftY) < inst->height))
208 if (((int)x >= (int)inst->shiftX) &&
209 ((int)y >= (int)inst->shiftY))
199210 {
200211 rgbsplit0r_extract_color((uint32_t *)(src +
201212 (x - inst->shiftX) +
220231 *(dst + x + (y*inst->width)) = (pxG | pxB | pxR);
221232 }
222233 }
223
2525 public:
2626 sobel(unsigned int width, unsigned int height)
2727 {
28 this->width = width;
29 this->height = height;
2830 }
2931
3032 virtual void update(double time,
3133 uint32_t* out,
3234 const uint32_t* in)
3335 {
36 if (width == 0 || height == 0) return;
37
3438 std::copy(in, in + width*height, out);
3539 for (unsigned int y=1; y<height-1; ++y)
3640 {
4549 unsigned char *p7 = (unsigned char *)&in[(y+1)*width+(x-1)];
4650 unsigned char *p8 = (unsigned char *)&in[(y+1)*width+x];
4751 unsigned char *p9 = (unsigned char *)&in[(y+1)*width+(x+1)];
48
52
4953 unsigned char *g = (unsigned char *)&out[y*width+x];
50
54
5155 for (int i=0; i<3; ++i)
5256 g[i] = CLAMP0255(
5357 abs(p1[i] + p2[i]*2 + p3[i] - p7[i] - p8[i]*2 - p9[i]) +
2121 #include <stdlib.h>
2222 #include <assert.h>
2323
24 #ifdef __SSE4_1__
24 /* Check for SSE4.1 support */
25 #if defined(__SSE4_1__)
2526 #include <smmintrin.h>
27 #define USE_SSE4_1 1
28 #else
29 #define USE_SSE4_1 0
30 #endif
31
32 /* Check for other SIMD instruction sets */
33 #if defined(__AVX__) && defined(__AVX2__)
34 #include <immintrin.h>
35 #define USE_AVX2 1
36 #else
37 #define USE_AVX2 0
38 #endif
39
40 #if defined(__ARM_NEON__) || defined(__ARM_NEON)
41 #include <arm_neon.h>
42 #define USE_NEON 1
43 #else
44 #define USE_NEON 0
2645 #endif
2746
2847 #include <frei0r.h>
4564 void f0r_deinit()
4665 { /* no initialization required */ }
4766
48 void f0r_get_plugin_info(f0r_plugin_info_t* tint0r_instance_t)
49 {
50 tint0r_instance_t->name = "Tint0r";
51 tint0r_instance_t->author = "Maksim Golovkin & Cynthia";
52 tint0r_instance_t->plugin_type = F0R_PLUGIN_TYPE_FILTER;
53 tint0r_instance_t->color_model = F0R_COLOR_MODEL_BGRA8888;
54 tint0r_instance_t->frei0r_version = FREI0R_MAJOR_VERSION;
55 tint0r_instance_t->major_version = 0;
56 tint0r_instance_t->minor_version = 1;
57 tint0r_instance_t->num_params = 3;
58 tint0r_instance_t->explanation = "Tint a source image with specified colors";
67 void f0r_get_plugin_info(f0r_plugin_info_t* info)
68 {
69 info->name = "Tint0r";
70 info->author = "Maksim Golovkin & Cynthia";
71 info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
72 info->color_model = F0R_COLOR_MODEL_BGRA8888;
73 info->frei0r_version = FREI0R_MAJOR_VERSION;
74 info->major_version = 0;
75 info->minor_version = 1;
76 info->num_params = 3;
77 info->explanation = "Tint a source image with specified colors";
5978 }
6079
6180 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
142161 }
143162 }
144163
145 #ifndef __SSE4_1__
146164 static inline unsigned char map_color(double amount, double comp_amount, float color, float luma, float minColor, float maxColor)
147165 {
148166 double val = (comp_amount * color) + amount * (luma * (maxColor - minColor) + minColor);
149167 return (unsigned char)(255*CLAMP(val, 0, 1));
150168 }
151 #endif
152
153 void f0r_update(f0r_instance_t instance, double time,
154 const uint32_t* inframe, uint32_t* outframe)
155 {
156 assert(instance);
157 tint0r_instance_t* inst = (tint0r_instance_t*)instance;
158
159 #ifdef __SSE4_1__
160 size_t len = (inst->width * inst->height) / 4;
161
162 const __m128 weights = _mm_set_ps(0.0, 0.299, 0.587, 0.114),
163 amount = _mm_set1_ps(inst->amount),
169
170 #if USE_SSE4_1
171 static void tint_sse41(const uint32_t* inframe, uint32_t* outframe, size_t len,
172 double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
173 {
174 const __m128 weights = _mm_set_ps(0.0, 0.114, 0.587, 0.299),
175 sse_amount = _mm_set1_ps(amount),
164176 /* Pass the alpha channel */
165177 comp_amount = _mm_set_ps(1.0,
166 1.0 - inst->amount,
167 1.0 - inst->amount,
168 1.0 - inst->amount);
169
170 f0r_param_color_t black = inst->blackColor,
171 white = inst->whiteColor;
178 1.0 - amount,
179 1.0 - amount,
180 1.0 - amount);
172181
173182 /* Zero the alpha component to exclude it from calculations. */
174 const __m128 cmin = _mm_set_ps(0.0, black.r, black.g, black.b),
175 cdelta = _mm_sub_ps(_mm_set_ps(0.0, white.r, white.g, white.b), cmin),
176 tmp0 = _mm_mul_ps(cdelta, amount),
177 tmp1 = _mm_mul_ps(_mm_mul_ps(amount, _mm_set1_ps(255.0)), cmin);
183 const __m128 cmin = _mm_set_ps(0.0, blackColor.b, blackColor.g, blackColor.r),
184 cdelta = _mm_sub_ps(_mm_set_ps(0.0, whiteColor.b, whiteColor.g, whiteColor.r), cmin),
185 tmp0 = _mm_mul_ps(cdelta, sse_amount),
186 tmp1 = _mm_mul_ps(_mm_mul_ps(sse_amount, _mm_set1_ps(255.0)), cmin);
178187
179188 __m128 p, p0, p1, p2, p3, luma;
180 #else
181 unsigned int len = inst->width * inst->height;
182 double amount = inst->amount;
183 double comp_amount = 1.0 - inst->amount;
184
185 unsigned char* dst = (unsigned char*)outframe;
186 const unsigned char* src = (unsigned char*)inframe;
187 float b, g, r;
188 float luma;
189 #endif
190
191 while (len--)
192 {
193 #ifdef __SSE4_1__
189
190 // Process pixels in groups of 4
191 for (size_t i = 0; i < len; i++)
192 {
194193 /* Load four pixels at once. */
195 p = _mm_loadu_si128((__m128i*)inframe);
194 p = _mm_loadu_si128((__m128i*)(inframe + i * 4));
196195
197196 /* Extract four pixels into separate XMM registers and convert them to float. */
198197 p0 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(p));
199198 p1 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 4)));
200199 p2 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 8)));
201200 p3 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 12)));
202 #else
203 b = *src++ / 255.;
204 g = *src++ / 255.;
205 r = *src++ / 255.;
206 #endif
207
208 #ifdef __SSE4_1__
201
209202 #define tint(v) \
210203 luma = _mm_dp_ps((v), weights, 0x7F); \
211204 v = _mm_add_ps(_mm_mul_ps(comp_amount, (v)), \
218211 p = _mm_packus_epi16(_mm_packus_epi32(p0, p1),
219212 _mm_packus_epi32(p2, p3));
220213
221 _mm_storeu_si128((__m128i*)outframe, p);
222
223 /* Stride of 128 bits; i.e. 16 bytes */
224 inframe += 4;
225 outframe += 4;
226 #else
227 luma = (b * .114 + g * .587 + r * .299);
228
229 *dst++ = map_color(amount, comp_amount, b, luma, inst->blackColor.b, inst->whiteColor.b);
230 *dst++ = map_color(amount, comp_amount, g, luma, inst->blackColor.g, inst->whiteColor.g);
231 *dst++ = map_color(amount, comp_amount, r, luma, inst->blackColor.r, inst->whiteColor.r);
232 *dst++ = *src++;
233 #endif
234 }
235 }
236
214 _mm_storeu_si128((__m128i*)(outframe + i * 4), p);
215 }
216 }
217 #elif USE_AVX2
218 static void tint_avx2(const uint32_t* inframe, uint32_t* outframe, size_t len,
219 double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
220 {
221 // AVX2 implementation would go here
222 // For now, fall back to scalar implementation
223 // This is a placeholder for a future AVX2 implementation
224 }
225 #elif USE_NEON
226 static void tint_neon(const uint32_t* inframe, uint32_t* outframe, size_t len,
227 double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
228 {
229 // NEON implementation would go here
230 // For now, fall back to scalar implementation
231 // This is a placeholder for a future NEON implementation
232 }
233 #endif
234
235 static void tint_scalar(const uint32_t* inframe, uint32_t* outframe, size_t len,
236 double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
237 {
238 double comp_amount = 1.0 - amount;
239
240 const unsigned char* src = (const unsigned char*)inframe;
241 unsigned char* dst = (unsigned char*)outframe;
242
243 float b, g, r;
244 float luma;
245
246 while (len--)
247 {
248 b = src[0] / 255.0f;
249 g = src[1] / 255.0f;
250 r = src[2] / 255.0f;
251
252 luma = (b * 0.114f + g * 0.587f + r * 0.299f);
253
254 dst[0] = map_color(amount, comp_amount, b, luma, blackColor.b, whiteColor.b);
255 dst[1] = map_color(amount, comp_amount, g, luma, blackColor.g, whiteColor.g);
256 dst[2] = map_color(amount, comp_amount, r, luma, blackColor.r, whiteColor.r);
257 dst[3] = src[3]; // Copy alpha
258
259 src += 4;
260 dst += 4;
261 }
262 }
263
264 void f0r_update(f0r_instance_t instance, double time,
265 const uint32_t* inframe, uint32_t* outframe)
266 {
267 assert(instance);
268 tint0r_instance_t* inst = (tint0r_instance_t*)instance;
269 size_t len = inst->width * inst->height;
270
271 #if USE_SSE4_1
272 // Process in chunks of 4 pixels for SSE
273 size_t sse_len = len / 4;
274 size_t remainder = len % 4;
275
276 if (sse_len > 0) {
277 tint_sse41(inframe, outframe, sse_len, inst->amount, inst->blackColor, inst->whiteColor);
278 }
279
280 // Handle remaining pixels with scalar implementation
281 if (remainder > 0) {
282 const uint32_t* remaining_in = inframe + (sse_len * 4);
283 uint32_t* remaining_out = outframe + (sse_len * 4);
284 tint_scalar(remaining_in, remaining_out, remainder, inst->amount, inst->blackColor, inst->whiteColor);
285 }
286 #else
287 // Use scalar implementation for all pixels
288 tint_scalar(inframe, outframe, len, inst->amount, inst->blackColor, inst->whiteColor);
289 #endif
290 }
291
00 /* Water filter
11 *
2 * (c) Copyright 2000-2007 Denis Rojo <jaromil@dyne.org>
3 *
2 * (c) Copyright 2000-2025 Denis Roio <jaromil@dyne.org>
3 *
44 * from an original idea of water algorithm by Federico 'Pix' Feroldi
55 *
66 * this code contains optimizations by Jason Hood and Scott Scriven
99 * ported to C++ and frei0r plugin API in 2007
1010 *
1111 * This source code is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Public License as published
12 * modify it under the terms of the GNU Public License as published
1313 * by the Free Software Foundation; either version 2 of the License,
1414 * or (at your option) any later version.
1515 *
2121 * You should have received a copy of the GNU Public License along with
2222 * this source code; if not, write to:
2323 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * "$Id: water.c 193 2004-06-01 11:00:25Z jaromil $"
2624 *
2725 */
2826
8078 surfer = 0;
8179 distort = 0;
8280 smooth = 0;
83 position.x = 0;
84 position.y = 0;
81 position.x = 0.0;
82 position.y = 0.0;
83 //randomize_swirl = false;
8584 register_param(physics, "physics", "water density: from 0.0 to 1.0");
8685 register_param(swirl, "swirl", "swirling whirpool in the center");
8786 register_param(rain, "rain", "rain drops all over");
119118
120119 water_surfacesize = geo->size;
121120 calc_optimization = (height)*(width);
122
121
123122 xang = fastrand()%2048;
124123 yang = fastrand()%2048;
125124 swirlangle = fastrand()%2048;
126
125
127126 /* buffer allocation tango */
128127 if ( width*height > 0 ) {
129128 Height[0] = (uint32_t*)calloc(width*(height+1), sizeof(uint32_t));
134133 BkGdImage = (uint32_t*) malloc(geo->size);
135134 BkGdImagePost = (uint32_t*)malloc(geo->size);
136135 }
136
137 // Initialize surface to NULL
138 surface = NULL;
137139 }
138140
139141 ~Water() {
151153 memcpy(BkGdImage, in, width*height*sizeof(uint32_t));
152154 water_update(out);
153155 }
154
156
155157 private:
156158 ScreenGeometry *geo;
157159
161163 uint32_t *BkGdImagePre;
162164 uint32_t *BkGdImage;
163165 uint32_t *BkGdImagePost;
164
166
165167 // uint32_t *buffer;
166
168
167169 void *surface;
168
170
169171 /* water effect variables */
170172 int Hpage;
171173 int xang, yang;
173175 int x, y, ox, oy;
174176 int done;
175177 int mode;
176
178
177179 /* precalculated to optimize a bit */
178180 int water_surfacesize;
179181 int calc_optimization;
180
182
181183 /* density: water density (step 1)
182184 pheight: splash height (step 40)
183185 radius: waterdrop radius (step 1) */
184186 int density, pheight, radius;
185 int offset;
186
187 int offset;
188
187189 int raincount;
188190 int blend;
189191
190192 void water_clear();
191193 void water_distort();
192194 void water_setphysics(double physics);
193 void water_update(uint32_t* out);
195 void water_update(uint32_t *out);
194196 void water_drop(int x, int y);
195197 void water_bigsplash(int x, int y);
196198 void water_surfer();
197199 void water_swirl();
198200 void water_3swirls();
199
200 void DrawWater(int page,uint32_t* out);
201
202 void DrawWater(int page, uint32_t* out);
201203 void CalcWater(int npage, int density);
202204 void CalcWaterBigFilter(int npage, int density);
203
205
204206 void SmoothWater(int npage);
205
207
206208 void HeightBlob(int x, int y, int radius, int height, int page);
207209 void HeightBox (int x, int y, int radius, int height, int page);
208
210
209211 void WarpBlob(int x, int y, int radius, int height, int page);
210212 void SineBlob(int x, int y, int radius, int height, int page);
211213
214216 int FSin(int angle) { return FSinTab[angle&FSINMAX]; }
215217 int FCos(int angle) { return FCosTab[angle&FSINMAX]; }
216218 void FCreateSines() {
217 int i; double angle;
219 int i; double angle;
218220 for(i=0; i<2048; i++) {
219221 angle = (float)i * (PI/1024.0);
220222 FSinTab[i] = (int)(sin(angle) * (float)0x10000);
226228 uint32_t randval;
227229 uint32_t fastrand() { return (randval=randval*1103515245+12345); };
228230 void fastsrand(uint32_t seed) { randval = seed; };
229
231
230232 /* integer optimized square root by jaromil */
231233 int isqrt(unsigned int x) {
232234 unsigned int m, y, b; m = 0x40000000;
234236 if(x>=b) { x=x-b; y=y|m; }
235237 m=m>>2; } return y;
236238 }
237
239
238240 };
239241
240242 void Water::water_clear() {
305307 }
306308
307309 void Water::water_surfer() {
310 int x, y;
308311 x = (geo->w>>1)
309312 + ((
310313 (
321324 ) >> 16);
322325 xang += 13;
323326 yang += 12;
324
327
325328 if(mode & 0x4000)
326329 {
327330 offset = (oy+y)/2*geo->w + ((ox+x)>>1); // QUAAA
330333 Height[Hpage][offset - 1] =
331334 Height[Hpage][offset + geo->w] =
332335 Height[Hpage][offset - geo->w] = pheight >> 1;
333
336
334337 offset = y*geo->w + x;
335338 Height[Hpage][offset] = pheight<<1;
336339 Height[Hpage][offset + 1] =
343346 SineBlob(((ox+x)>>1), ((oy+y)>>1), 3, -1200, Hpage);
344347 SineBlob(x, y, 4, -2000, Hpage);
345348 }
346
349
347350 ox = x;
348 oy = y;
351 oy = y;
349352 }
350353
351354 void Water::water_swirl() {
355 int x, y;
352356 x = (geo->w>>1)
353357 + ((
354358 (FCos(swirlangle)) * (25)
355359 ) >> 16);
356
360
357361 y = (geo->h>>1)
358362 + ((
359363 (FSin(swirlangle)) * (25)
360364 ) >> 16);
361 x += position.x;
362 y += position.y;
365 x += (int)(position.x * geo->w);
366 y += (int)(position.y * geo->h);
363367
364368 swirlangle += 50;
365369 if(mode & 0x4000)
370374
371375 void Water::water_3swirls() {
372376 #define ANGLE 15
377 int x, y;
373378 x = (95)
374379 + ((
375380 (FCos(swirlangle)) * (ANGLE)
381386
382387 if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
383388 else WarpBlob(x, y, radius, pheight, Hpage);
384
389
385390 x = (95)
386391 + ((
387392 (FCos(swirlangle)) * (ANGLE)
390395 + ((
391396 (FSin(swirlangle)) * (ANGLE)
392397 ) >> 16);
393
398
394399 if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
395400 else WarpBlob(x, y, radius, pheight, Hpage);
396
401
397402 x = (345)
398403 + ((
399404 (FCos(swirlangle)) * (ANGLE)
402407 + ((
403408 (FSin(swirlangle)) * (ANGLE)
404409 ) >> 16);
405
410
406411 if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
407412 else WarpBlob(x, y, radius, pheight, Hpage);
408413
412417 /* internal physics routines */
413418 void Water::DrawWater(int page,uint32_t* out) {
414419 int dx, dy;
415 int x, y;
416 uint32_t offset=geo->w + 1;
417 uint32_t newoffset;
420 int offset=geo->w + 1;
421 int newoffset;
422 int maxoffset = geo->w * geo->h;
418423 int *ptr = (int*)&Height[page][0];
419 int maxoffset=geo->size/sizeof(uint32_t);
420
421 for (y = calc_optimization; offset < y; offset+=2) {
422 for (x = offset+geo->w-2; offset < x; offset++) {
423
424
425 for (int y = calc_optimization; offset < y; offset += 2) {
426 for (int x = offset+geo->w-2; offset < x; offset++) {
424427 dx = ptr[offset] - ptr[offset+1];
425428 dy = ptr[offset] - ptr[offset+geo->w];
426429 newoffset = offset + geo->w*(dy>>3) + (dx>>3);
427 if(newoffset<maxoffset)
430 if (newoffset < maxoffset) {
428431 out[offset] = BkGdImage[newoffset];
432 }
433
429434 offset++;
430
431435 dx = ptr[offset] - ptr[offset+1];
432436 dy = ptr[offset] - ptr[offset+geo->w];
433437 newoffset = offset + geo->w*(dy>>3) + (dx>>3);
434 if(newoffset<maxoffset)
438 if (newoffset < maxoffset) {
435439 out[offset] = BkGdImage[newoffset];
440 }
436441 }
437442 }
438443 }
442447 int count = geo->w + 1;
443448 int *newptr = (int*) &Height[npage][0];
444449 int *oldptr = (int*) &Height[npage^1][0];
445 int x, y;
446
447 for (y = calc_optimization; count < y; count += 2) {
448 for (x = count+geo->w-2; count < x; count++) {
450
451 for (int y = calc_optimization; count < y; count += 2) {
452 for (int x = count+geo->w-2; count < x; count++) {
449453 /* eight pixels */
450454 newh = ((oldptr[count + geo->w]
451455 + oldptr[count - geo->w]
467471 int count = geo->w + 1;
468472 int *newptr = (int*) &Height[npage][0];
469473 int *oldptr = (int*) &Height[npage^1][0];
470 int x, y;
471
472 for(y=1; y<geo->h-1; y++) {
473 for(x=1; x<geo->w-1; x++) {
474
475 for(int y=1; y<geo->h-1; y++) {
476 for(int x=1; x<geo->w-1; x++) {
474477 /* eight pixel */
475478 newh = ((oldptr[count + geo->w]
476479 + oldptr[count - geo->w]
482485 + oldptr[count + geo->w + 1]
483486 ) >> 3 )
484487 + newptr[count];
485
486
488
489
487490 newptr[count] = newh>>1;
488491 count++;
489492 }
496499 int count = (geo->w<<1) + 2;
497500 int *newptr = (int*) &Height[npage][0];
498501 int *oldptr = (int*) &Height[npage^1][0];
499 int x, y;
500
501 for(y=2; y<geo->h-2; y++) {
502 for(x=2; x<geo->w-2; x++) {
502
503 for(int y=2; y<geo->h-2; y++) {
504 for(int x=2; x<geo->w-2; x++) {
503505 /* 25 pixels */
504506 newh = (
505507 (
558560 for(cy = top; cy < bottom; cy++) {
559561 cyq = cy*cy;
560562 for(cx = left; cx < right; cx++) {
561 if(cx*cx + cyq < rquad)
562 Height[page][geo->w*(cy+y) + (cx+x)] += height;
563 if(cx*cx + cyq < rquad) {
564 int index = geo->w*(cy+y) + (cx+x);
565 // Bounds check
566 if (index >= 0 && index < geo->w * geo->h) {
567 Height[page][index] += height;
568 }
569 }
563570 }
564571 }
565572 }
571578
572579 if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
573580 if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
574
581
575582 left=-radius; right = radius;
576583 top=-radius; bottom = radius;
577
584
578585 CLIP_EDGES
579
586
580587 for(cy = top; cy < bottom; cy++) {
581588 for(cx = left; cx < right; cx++) {
582 Height[page][geo->w*(cy+y) + (cx+x)] = height;
583 }
584 }
589 int index = geo->w*(cy+y) + (cx+x);
590 // Bounds check
591 if (index >= 0 && index < geo->w * geo->h) {
592 Height[page][index] = height;
593 }
594 }
595 }
585596 }
586597
587598 void Water::WarpBlob(int x, int y, int radius, int height, int page) {
589600 int left,top,right,bottom;
590601 int square;
591602 int radsquare = radius * radius;
592
603
593604 radsquare = (radius*radius);
594
605
595606 height = height>>5;
596
607
597608 left=-radius; right = radius;
598609 top=-radius; bottom = radius;
599610
600611 CLIP_EDGES
601
612
602613 for(cy = top; cy < bottom; cy++) {
603614 for(cx = left; cx < right; cx++) {
604615 square = cy*cy + cx*cx;
605616 if(square < radsquare) {
606 Height[page][geo->w*(cy+y) + cx+x]
607 += (int)((radius-isqrt(square))*(float)(height));
617 int index = geo->w*(cy+y) + cx+x;
618 // Bounds check
619 if (index >= 0 && index < geo->w * geo->h) {
620 Height[page][index] += (int)((radius-isqrt(square))*(float)(height));
621 }
608622 }
609623 }
610624 }
616630 int square, dist;
617631 int radsquare = radius * radius;
618632 float length = (1024.0/(float)radius)*(1024.0/(float)radius);
619
633
620634 if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
621635 if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
622636
631645 square = cy*cy + cx*cx;
632646 if(square < radsquare) {
633647 dist = (int)(isqrt(square*length));
634 Height[page][geo->w*(cy+y) + cx+x]
635 += (int)((FCos(dist)+0xffff)*(height)) >> 19;
648 int index = geo->w*(cy+y) + cx+x;
649 // Bounds check
650 if (index >= 0 && index < geo->w * geo->h) {
651 Height[page][index] += (int)((FCos(dist)+0xffff)*(height)) >> 19;
652 }
636653 }
637654 }
638655 }
2828 public:
2929 blend(unsigned int width, unsigned int height)
3030 {
31 this->width = width;
32 this->height = height;
33 this->size = width * height;
3134 blend_factor = 0.5;
3235 register_param(blend_factor,"blend","blend factor");
3336 }
4447 const uint32_t* in1,
4548 const uint32_t* in2)
4649 {
50 // Validate inputs
51 if (!out || !in1 || !in2) {
52 return;
53 }
54
4755 const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
4856 const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
4957 uint8_t *dst = reinterpret_cast<uint8_t*>(out);
5159 const uint8_t one_minus_bf = (255 - bf);
5260 uint32_t w = size;
5361 uint32_t b;
54
62
63 // Validate size
64 if (w == 0) {
65 return;
66 }
67
5568 while (w--)
5669 {
5770 for (b = 0; b < NBYTES; b++)
5871 dst[b] = (src1[b] * one_minus_bf + src2[b] * bf) / 255;
59
72
6073 src1 += NBYTES;
6174 src2 += NBYTES;
6275 dst += NBYTES;
7676
7777 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
7878 {
79 // Validate inputs
80 if (width == 0 || height == 0) {
81 return NULL;
82 }
83
7984 cairo_blend_instance_t* inst = (cairo_blend_instance_t*)calloc(1, sizeof(*inst));
80 inst->width = width;
85 if (!inst) {
86 return NULL;
87 }
88
89 inst->width = width;
8190 inst->height = height;
8291
8392 inst->opacity = 1.0;
8493
85 const char* blend_val = NORMAL;
86 inst->blend_mode = (char*) malloc (strlen(blend_val) + 1 );
87 strcpy (inst->blend_mode, blend_val);
94 const char* blend_val = NORMAL;
95 inst->blend_mode = (char*) malloc (strlen(blend_val) + 1);
96 if (!inst->blend_mode) {
97 free(inst);
98 return NULL;
99 }
100 strcpy (inst->blend_mode, blend_val);
88101
89102 return (f0r_instance_t)inst;
90103 }
91104
92105 void f0r_destruct(f0r_instance_t instance)
93106 {
107 if (!instance) {
108 return;
109 }
110
94111 cairo_blend_instance_t* inst = (cairo_blend_instance_t*)instance;
95 free(inst->blend_mode);
112 if (inst->blend_mode) {
113 free(inst->blend_mode);
114 }
96115 free(instance);
97116 }
98117
103122 char* sval;
104123 switch(param_index) {
105124 case 0:
106 inst->opacity = *((double*)param);
125 // Validate double parameter
126 if (param) {
127 inst->opacity = *((double*)param);
128 }
107129 break;
108130 case 1:
109 sval = (*(char**)param);
110 inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
111 strcpy (inst->blend_mode, sval);
131 // Validate string parameter
132 if (param) {
133 sval = (*(char**)param);
134 if (sval) {
135 inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
136 if (inst->blend_mode) {
137 strcpy (inst->blend_mode, sval);
138 }
139 }
140 }
112141 break;
113142 }
114143 }
120149
121150 switch(param_index) {
122151 case 0:
123 *((double*)param) = inst->opacity;
152 if (param) {
153 *((double*)param) = inst->opacity;
154 }
124155 break;
125156 case 1:
126 *((f0r_param_string *)param) = inst->blend_mode;
157 if (param && inst->blend_mode) {
158 *((f0r_param_string *)param) = inst->blend_mode;
159 } else if (param) {
160 *((f0r_param_string *)param) = "";
161 }
127162 break;
128163 }
129164 }
133168 int w = inst->width;
134169 int h = inst->height;
135170 int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
171
172 // Validate inputs
173 if (!inst || !out || !src || w <= 0 || h <= 0) {
174 return;
175 }
136176
137177 cairo_surface_t* out_image = cairo_image_surface_create_for_data (out,
138178 CAIRO_FORMAT_ARGB32,
139179 w,
140180 h,
141181 stride);
182 // Check if surface creation succeeded
183 if (!out_image) {
184 return;
185 }
186
142187 cairo_t* cr = cairo_create (out_image);
188 // Check if context creation succeeded
189 if (!cr) {
190 cairo_surface_destroy (out_image);
191 return;
192 }
143193
144194 cairo_surface_t* src_image = cairo_image_surface_create_for_data ((unsigned char*)src,
145195 CAIRO_FORMAT_ARGB32,
146196 w,
147197 h,
148198 stride);
149
150 // Set source, blen mode and draw with current opacity
151 frei0r_cairo_set_operator(cr, inst->blend_mode);
199 // Check if surface creation succeeded
200 if (!src_image) {
201 cairo_destroy (cr);
202 cairo_surface_destroy (out_image);
203 return;
204 }
205
206 // Validate blend mode string
207 if (inst->blend_mode) {
208 // Set source, blend mode and draw with current opacity
209 frei0r_cairo_set_operator(cr, inst->blend_mode);
210 }
211
152212 cairo_set_source_surface (cr, src_image, 0, 0);
153213 cairo_paint_with_alpha (cr, inst->opacity);
154214
155 cairo_surface_destroy (out_image);
215 // Clean up in proper order
156216 cairo_surface_destroy (src_image);
157217 cairo_destroy (cr);
218 cairo_surface_destroy (out_image);
158219 }
159220
160221 void f0r_update(f0r_instance_t instance, double time,
166227 void f0r_update2(f0r_instance_t instance, double time, const uint32_t* inframe1,
167228 const uint32_t* inframe2, const uint32_t* inframe3, uint32_t* outframe)
168229 {
230 // Validate inputs
231 if (!instance || !inframe1 || !inframe2 || !outframe) {
232 return;
233 }
234
169235 assert(instance);
170236 cairo_blend_instance_t* inst = (cairo_blend_instance_t*) instance;
171237
174240 unsigned char* out = (unsigned char*)outframe;
175241 int pixels = inst->width * inst->height;
176242
243 // Validate dimensions
244 if (pixels <= 0) {
245 return;
246 }
247
177248 frei0r_cairo_premultiply_rgba2 (dst, out, pixels, -1);
178249 frei0r_cairo_premultiply_rgba (src, pixels, -1);
179250 draw_composite (inst, out, src, time);
2828 public:
2929 overlay(unsigned int width, unsigned int height)
3030 {
31 this->width = width;
32 this->height = height;
33 this->size = width * height;
3134 }
3235
3336 /**
4346 const uint32_t* in1,
4447 const uint32_t* in2)
4548 {
49 // Validate inputs
50 if (!out || !in1 || !in2) {
51 return;
52 }
53
4654 const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
4755 const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
4856 uint8_t *dst = reinterpret_cast<uint8_t*>(out);
4957 uint32_t sizeCounter = size;
50
58
59 // Validate size
60 if (sizeCounter == 0) {
61 return;
62 }
63
5164 uint32_t b, tmp, tmpM;
52
65
5366 while (sizeCounter--)
5467 {
5568 for (b = 0; b < ALPHA; b++)
5669 {
5770 dst[b] = INT_MULT(src1[b], src1[b] + INT_MULT(2 * src2[b], 255 - src1[b], tmpM), tmp);
5871 }
59
72
6073 dst[ALPHA] = MIN(src1[ALPHA], src2[ALPHA]);
61
74
6275 src1 += NBYTES;
6376 src2 += NBYTES;
6477 dst += NBYTES;