Rev 289 | Rev 291 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
259 | daniel-mar | 1 | /* |
2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
||
3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au |
||
4 | Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft |
||
5 | |||
6 | This program is free software; you can redistribute it and/or modify |
||
7 | it under the terms of the GNU General Public License as published by |
||
8 | the Free Software Foundation; either version 2 of the License, or |
||
9 | (at your option) any later version. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
15 | |||
16 | You should have received a copy of the GNU General Public License |
||
17 | along with this program; if not, write to the Free Software |
||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
21 | #ifdef MAC_ENV |
||
268 | daniel-mar | 22 | #include <fp.h> |
259 | daniel-mar | 23 | #endif |
24 | |||
25 | #include <math.h> |
||
26 | #include <stdlib.h> |
||
27 | |||
28 | #ifndef PARSERTEST |
||
29 | #include "ff.h" |
||
30 | #endif |
||
268 | daniel-mar | 31 | |
259 | daniel-mar | 32 | #include "funcs.h" |
33 | #include "y.tab.h" |
||
34 | |||
35 | #include "node.h" // for symbol "var[]" |
||
36 | |||
37 | #define RINT //no rounding for now |
||
38 | |||
39 | //#if TARGET_API_MAC_CARBON |
||
40 | // this is another incompatibility between Classic stdclib and OS X stdclib |
||
41 | // ***FIXME: need to access real OS X includes for Carbon build |
||
42 | //#undef RAND_MAX |
||
43 | //#define RAND_MAX 0x7fffffff |
||
44 | //#endif |
||
45 | |||
46 | extern value_type slider[],cell[],var[],map[][0x100]; |
||
47 | extern unsigned char *image_ptr; |
||
48 | |||
49 | double costab[COSTABSIZE]; |
||
50 | double tantab[TANTABSIZE]; |
||
51 | void init_trigtab(){ |
||
52 | int i; |
||
53 | for(i=0;i<COSTABSIZE;++i){ |
||
54 | costab[i] = cos(FFANGLE(i)); |
||
55 | } |
||
56 | for(i=0;i<TANTABSIZE;++i){ |
||
57 | if (i>=TANTABSIZE/2) { |
||
58 | /* the last '-1' in the expression '512-i-1' is for FilterFactory compatibility, and to avoid the undefined pi/2 area */ |
||
59 | tantab[i] = -tantab[TANTABSIZE-i-1]; |
||
60 | } else { |
||
61 | tantab[i] = tan(FFANGLE(i)); |
||
62 | } |
||
63 | } |
||
64 | } |
||
65 | |||
66 | /* Channel z for the input pixel at coordinates x,y. |
||
67 | * Coordinates are relative to the input image data (pb->inData) */ |
||
68 | static value_type rawsrc(value_type x,value_type y,value_type z){ |
||
69 | if (HAS_BIG_DOC(gpb)) { |
||
70 | if (x < BIGDOC_IN_RECT(gpb).left) |
||
71 | x = BIGDOC_IN_RECT(gpb).left; |
||
72 | else if (x >= BIGDOC_IN_RECT(gpb).right) |
||
73 | x = BIGDOC_IN_RECT(gpb).right - 1; |
||
74 | if (y < BIGDOC_IN_RECT(gpb).top) |
||
75 | y = BIGDOC_IN_RECT(gpb).top; |
||
76 | else if (y >= BIGDOC_IN_RECT(gpb).bottom) |
||
77 | y = BIGDOC_IN_RECT(gpb).bottom - 1; |
||
78 | return ((unsigned char*)gpb->inData)[(long)gpb->inRowBytes * (y - BIGDOC_IN_RECT(gpb).top) |
||
79 | + (long)nplanes * (x - BIGDOC_IN_RECT(gpb).left) + z]; |
||
80 | } else { |
||
81 | if (x < IN_RECT(gpb).left) |
||
82 | x = IN_RECT(gpb).left; |
||
83 | else if (x >= IN_RECT(gpb).right) |
||
84 | x = IN_RECT(gpb).right - 1; |
||
85 | if (y < IN_RECT(gpb).top) |
||
86 | y = IN_RECT(gpb).top; |
||
87 | else if (y >= IN_RECT(gpb).bottom) |
||
88 | y = IN_RECT(gpb).bottom - 1; |
||
89 | return ((unsigned char*)gpb->inData)[(long)gpb->inRowBytes * (y - IN_RECT(gpb).top) |
||
90 | + (long)nplanes * (x - IN_RECT(gpb).left) + z]; |
||
91 | } |
||
92 | } |
||
93 | |||
94 | /* src(x,y,z) Channel z for the pixel at coordinates x,y. |
||
95 | * Coordinates are relative to filtered area (selection). */ |
||
96 | value_type ff_src(value_type x,value_type y,value_type z){ |
||
268 | daniel-mar | 97 | #ifdef PARSERTEST |
259 | daniel-mar | 98 | return 0; |
268 | daniel-mar | 99 | #else |
259 | daniel-mar | 100 | if(x < 0) |
101 | x = 0; |
||
102 | else if(x >= var['X']) |
||
103 | x = var['X']-1; |
||
104 | if(y < 0) |
||
105 | y = 0; |
||
106 | else if(y >= var['Y']) |
||
107 | y = var['Y']-1; |
||
108 | return z >= 0 && z < var['Z'] ? |
||
109 | image_ptr[(long)gpb->inRowBytes*y + (long)nplanes*x + z] : 0; |
||
268 | daniel-mar | 110 | #endif |
259 | daniel-mar | 111 | } |
112 | |||
113 | /* rad(d,m,z) Channel z in the source image, which is m units away, |
||
114 | at an angle of d, from the center of the image */ |
||
115 | value_type ff_rad(value_type d,value_type m,value_type z){ |
||
116 | return ff_src(ff_r2x(d,m) + var['X']/2, ff_r2y(d,m) + var['Y']/2, z); |
||
117 | } |
||
118 | |||
119 | /* ctl(i) Value of slider i, where i is an integer between 0 and 7, inclusive */ |
||
120 | value_type ff_ctl(value_type i){ |
||
121 | return i>=0 && i<=7 ? slider[i] : 0; |
||
122 | } |
||
123 | |||
124 | /* val(i,a,b) Value of slider i, mapped onto the range a to b */ |
||
125 | value_type ff_val(value_type i,value_type a,value_type b){ |
||
126 | return ((long)ff_ctl(i)*(b-a))/255 + a; |
||
127 | } |
||
128 | |||
129 | /* map(i,n) Item n from mapping table i, where i is an integer between |
||
130 | |||
131 | inclusive */ |
||
132 | value_type ff_map(value_type i,value_type n){ |
||
133 | /* |
||
134 | if( i>=0 && i<=3 && n>=0 && n<=255 ){ |
||
135 | int H = slider[i*2],L = slider[i*2+1]; |
||
136 | return n<=L || H==L ? 0 : ( n>=H ? 255 : ((n-L)*255L)/(H-L) ); |
||
137 | }else |
||
138 | return 0; |
||
139 | */ |
||
140 | // this code is from GIMP User Filter |
||
141 | value_type x = ff_ctl(i*2), |
||
142 | y = ff_ctl(i*2+1); |
||
143 | return abs(((long)n*(y-x) / 255)+x); |
||
144 | } |
||
145 | |||
146 | /* min(a,b) Lesser of a and b */ |
||
147 | value_type ff_min(value_type a,value_type b){ |
||
148 | return a < b ? a : b; |
||
149 | } |
||
150 | |||
151 | /* max(a,b) Greater of a and b */ |
||
152 | value_type ff_max(value_type a,value_type b){ |
||
153 | return a > b ? a : b; |
||
154 | } |
||
155 | |||
156 | /* abs(a) Absolute value of a */ |
||
157 | value_type ff_abs(value_type a){ |
||
158 | return abs(a); |
||
159 | } |
||
160 | |||
161 | /* add(a,b,c) Sum of a and b, or c, whichever is lesser */ |
||
162 | value_type ff_add(value_type a,value_type b,value_type c){ |
||
163 | return ff_min(a+b,c); |
||
164 | } |
||
165 | |||
166 | /* sub(a,b,c) Difference of a and b, or c, whichever is greater */ |
||
167 | value_type ff_sub(value_type a,value_type b,value_type c){ |
||
168 | return ff_max(ff_dif(a,b),c); |
||
169 | } |
||
170 | |||
171 | /* dif(a,b) Absolute value of the difference of a and b */ |
||
172 | value_type ff_dif(value_type a,value_type b){ |
||
173 | return abs(a-b); |
||
174 | } |
||
175 | |||
290 | daniel-mar | 176 | struct factoryRngState { |
177 | uint16_t gFactoryRndIndexCounter1; |
||
178 | uint16_t gFactoryRndIndexCounter2; |
||
179 | uint32_t gFactoryRndLookup[56]; |
||
180 | uint32_t gFactoryRndSeed; |
||
181 | uint32_t gFactoryRndSeedSave; |
||
182 | } gRngState; |
||
286 | daniel-mar | 183 | |
290 | daniel-mar | 184 | void factory_fill_rnd_lookup(uint32_t seed, struct factoryRngState* state) { |
185 | // Algorithm of Filter Factory |
||
186 | // Filter Factory uses Donald E.Knuth's subtractive |
||
187 | // random number generator algorithm ("ran3"), which has been published |
||
188 | // in Page 283 of "The Art of Computer Programming, volume 2: Seminumerical Algorithms", |
||
189 | // Addison-Wesley, Reading, MA, second edition, 1981. |
||
190 | // https://www.cec.uchile.cl/cinetica/pcordero/MC_libros/NumericalRecipesinC.pdf (PDF Page 307) |
||
286 | daniel-mar | 191 | |
290 | daniel-mar | 192 | long mj, mk; |
193 | int i, ii, k; |
||
194 | |||
195 | // 161803398 = 1.61803398 * 10^8 ~= phi * 10^8 |
||
196 | mj = 161803398 - (seed & 0x7fff); |
||
197 | state->gFactoryRndLookup[55] = mj; |
||
198 | |||
199 | mk = 1; |
||
200 | ii = 0; |
||
201 | for (i=1; i<=54; ++i) { |
||
202 | if ((ii += 21) >= 55) ii -= 55; // ii = (21*i)%55; |
||
203 | state->gFactoryRndLookup[ii] = mk; |
||
204 | mk = mj - mk; |
||
205 | mj = state->gFactoryRndLookup[ii]; |
||
206 | } |
||
207 | |||
208 | for (k=1; k<=4; ++k) { |
||
209 | ii = 30; |
||
210 | for (i=1; i<=55; ++i) { |
||
211 | if ((ii += 1) >= 55) ii -= 55; |
||
212 | state->gFactoryRndLookup[i] -= state->gFactoryRndLookup[1 + ii]; // 1 + (i+30)%55 |
||
213 | } |
||
214 | } |
||
215 | |||
216 | state->gFactoryRndSeedSave = seed; |
||
217 | |||
218 | return; |
||
219 | } |
||
220 | |||
221 | uint32_t factory_rnd(uint32_t a, uint32_t b, struct factoryRngState* state) { |
||
289 | daniel-mar | 222 | uint32_t mj; // Note: This must be "uint32_t". With "long" (as described by Knuth), it won't match FilterFactory's algorithm |
223 | int range; |
||
286 | daniel-mar | 224 | |
290 | daniel-mar | 225 | if (state->gFactoryRndSeed != state->gFactoryRndSeedSave) { |
288 | daniel-mar | 226 | // (Intentional) behavior of Filter Foundry |
290 | daniel-mar | 227 | factory_fill_rnd_lookup(state->gFactoryRndSeed, &gRngState); |
228 | state->gFactoryRndIndexCounter1 = 0; |
||
229 | state->gFactoryRndIndexCounter2 = 31; |
||
288 | daniel-mar | 230 | } |
231 | |||
232 | // Algorithm of Filter Factory |
||
289 | daniel-mar | 233 | // Filter Factory uses Donald E.Knuth's subtractive |
234 | // random number generator algorithm ("ran3"), which has been published |
||
235 | // in Page 283 of "The Art of Computer Programming, volume 2: Seminumerical Algorithms", |
||
236 | // Addison-Wesley, Reading, MA, second edition, 1981. |
||
237 | // https://www.cec.uchile.cl/cinetica/pcordero/MC_libros/NumericalRecipesinC.pdf (PDF Page 307) |
||
288 | daniel-mar | 238 | |
290 | daniel-mar | 239 | if (++state->gFactoryRndIndexCounter1 == 56) state->gFactoryRndIndexCounter1 = 1; |
240 | if (++state->gFactoryRndIndexCounter2 == 56) state->gFactoryRndIndexCounter2 = 1; |
||
286 | daniel-mar | 241 | |
290 | daniel-mar | 242 | mj = state->gFactoryRndLookup[state->gFactoryRndIndexCounter1] - |
243 | state->gFactoryRndLookup[state->gFactoryRndIndexCounter2]; |
||
244 | state->gFactoryRndLookup[state->gFactoryRndIndexCounter1] = mj; |
||
286 | daniel-mar | 245 | |
289 | daniel-mar | 246 | // This is Filter Factory specific: |
290 | daniel-mar | 247 | // Reduce result into interval [a..b] by applying (a + (mj % (b - a + 1)) |
248 | // Try to avoid modulo in order to increase performance |
||
249 | range = b - a; |
||
250 | if (range < 0) return 0; |
||
251 | switch (range) { |
||
289 | daniel-mar | 252 | case 255: |
290 | daniel-mar | 253 | return a + (mj & 0xFF); |
289 | daniel-mar | 254 | case 127: |
290 | daniel-mar | 255 | return a + (mj & 0x7F); |
289 | daniel-mar | 256 | case 63: |
290 | daniel-mar | 257 | return a + (mj & 0x3F); |
289 | daniel-mar | 258 | case 31: |
290 | daniel-mar | 259 | return a + (mj & 0x1F); |
289 | daniel-mar | 260 | case 15: |
290 | daniel-mar | 261 | return a + (mj & 0xF); |
289 | daniel-mar | 262 | case 7: |
290 | daniel-mar | 263 | return a + (mj & 0x7); |
289 | daniel-mar | 264 | case 3: |
290 | daniel-mar | 265 | return a + (mj & 0x3); |
289 | daniel-mar | 266 | case 1: |
290 | daniel-mar | 267 | return a + (mj & 0x1); |
268 | case 0: |
||
269 | return a; |
||
270 | default: |
||
271 | return a + (mj % (range + 1)); |
||
289 | daniel-mar | 272 | } |
286 | daniel-mar | 273 | } |
274 | |||
290 | daniel-mar | 275 | int32_t factory_rst(uint32_t seed, struct factoryRngState* state) { |
276 | // We implement rst(i) completely differently in Filter Foundry: |
||
277 | // Every call of rst() will renew the lookup table. |
||
278 | // In Filter Factory, there are strange/buggy things going |
||
279 | // on: rst(i) only sets a seed and the lookup table is renewed |
||
280 | // at the NEXT invocation of the filter. Furthermore, in FilterFactory, |
||
281 | // the state is not reset between invocations, therefore, the preview image |
||
282 | // will influence the PRNG state of the final image... |
||
283 | // More information at "Filter Factory Compatibility.md" |
||
286 | daniel-mar | 284 | |
290 | daniel-mar | 285 | state->gFactoryRndSeed = seed; |
286 | daniel-mar | 286 | |
290 | daniel-mar | 287 | // Force renewal of the PRNG state in the next rnd(a,b) call. |
288 | // This allows us to use: |
||
289 | // (x==0?rst(1):0), rnd(0,255) |
||
290 | // But it is slower and this won't work anymore: |
||
291 | // rst(0), rnd(0,255) |
||
292 | state->gFactoryRndSeedSave = seed+1; |
||
286 | daniel-mar | 293 | |
287 | daniel-mar | 294 | return 0; |
286 | daniel-mar | 295 | } |
296 | |||
287 | daniel-mar | 297 | void factory_initialize_rnd_variables() { |
290 | daniel-mar | 298 | gRngState.gFactoryRndSeed = 0; // default seed |
299 | gRngState.gFactoryRndSeedSave = gRngState.gFactoryRndSeed + 1; // force rnd() to call factory_fill_rnd_lookup() |
||
287 | daniel-mar | 300 | } |
301 | |||
259 | daniel-mar | 302 | /* rnd(a,b) Random number between a and b, inclusive */ |
303 | value_type ff_rnd(value_type a,value_type b){ |
||
290 | daniel-mar | 304 | return factory_rnd(a,b,&gRngState); |
286 | daniel-mar | 305 | // return (int)((abs(a-b)+1)*(rand()/(RAND_MAX+1.))) + ff_min(a,b); |
259 | daniel-mar | 306 | // return ((unsigned)rand() % (ff_dif(a,b)+1)) + ff_min(a,b); |
307 | } |
||
308 | |||
309 | /* mix(a,b,n,d) Mixture of a and b by fraction n/d, a*n/d+b*(d-n)/d */ |
||
310 | value_type ff_mix(value_type a,value_type b,value_type n,value_type d){ |
||
311 | return d ? ((long)a*n)/d + ((long)b*(d-n))/d : 0; |
||
312 | } |
||
313 | |||
314 | /* scl(a,il,ih,ol,oh) Scale a from input range (il to ih) |
||
315 | to output range (ol to oh) */ |
||
316 | value_type ff_scl(value_type a,value_type il,value_type ih, |
||
317 | value_type ol,value_type oh){ |
||
318 | return ih==il ? 0 : ol + ((long)(oh-ol)*(a-il))/(ih-il); |
||
319 | } |
||
320 | |||
321 | static uint32_t isqrt(uint32_t x) { |
||
322 | // based on https://gist.github.com/orlp/3481770 |
||
323 | |||
324 | static uint32_t lkpSquares[65535]; |
||
325 | static int lkpInitialized = 0; |
||
326 | const uint32_t *p; |
||
327 | int i; |
||
328 | |||
329 | while (lkpInitialized == 1) { /* If other thread is currently creating the lookup table, then wait */ } |
||
330 | if (!lkpInitialized) { |
||
331 | lkpInitialized = 1; |
||
332 | for (i = 0; i < 65535; ++i) { |
||
333 | lkpSquares[i] = i * i; |
||
334 | } |
||
335 | lkpInitialized = 2; |
||
336 | } |
||
337 | |||
338 | p = lkpSquares; |
||
339 | |||
340 | if (p[32768] <= x) p += 32768; |
||
341 | if (p[16384] <= x) p += 16384; |
||
342 | if (p[8192] <= x) p += 8192; |
||
343 | if (p[4096] <= x) p += 4096; |
||
344 | if (p[2048] <= x) p += 2048; |
||
345 | if (p[1024] <= x) p += 1024; |
||
346 | if (p[512] <= x) p += 512; |
||
347 | if (p[256] <= x) p += 256; |
||
348 | if (p[128] <= x) p += 128; |
||
349 | if (p[64] <= x) p += 64; |
||
350 | if (p[32] <= x) p += 32; |
||
351 | if (p[16] <= x) p += 16; |
||
352 | if (p[8] <= x) p += 8; |
||
353 | if (p[4] <= x) p += 4; |
||
354 | if (p[2] <= x) p += 2; |
||
355 | if (p[1] <= x) p += 1; |
||
356 | |||
357 | return (uint32_t)(p - lkpSquares); |
||
358 | } |
||
359 | |||
360 | /* sqr(x) Square root of x */ |
||
361 | value_type ff_sqr(value_type x){ |
||
362 | return x < 0 ? 0 : isqrt(x); |
||
363 | } |
||
364 | |||
365 | /* sin(x) Sine function of x, where x is an integer between 0 and |
||
366 | 1024, inclusive, and the value returned is an integer |
||
367 | between -512 and 512, inclusive (Windows) or -1024 and |
||
368 | 1024, inclusive (Mac OS) */ |
||
369 | value_type ff_sin(value_type x){ |
||
370 | //return RINT(TRIGAMP*sin(FFANGLE(x))); |
||
371 | return ff_cos(x-256); |
||
372 | } |
||
373 | |||
374 | /* cos(x) Cosine function of x, where x is an integer between 0 and |
||
375 | 1024, inclusive, and the value returned is an integer |
||
376 | between -512 and 512, inclusive (Windows) or -1024 and |
||
377 | 1024, inclusive (Mac OS) */ |
||
378 | value_type ff_cos(value_type x){ |
||
379 | //return RINT(TRIGAMP*cos(FFANGLE(x))); |
||
380 | return (value_type)RINT(TRIGAMP*costab[abs(x) % COSTABSIZE]); |
||
381 | } |
||
382 | |||
383 | /* tan(x) Tangent function of x, where x is an integer |
||
384 | between -256 and 256, inclusive. Althought the Filter Factory manual |
||
385 | stated that the return value is bounded to -512 and 512, inclusive (Windows) or |
||
386 | -1024 and 1024, inclusive (Mac OS), the output is actually NOT bounded! */ |
||
387 | value_type ff_tan(value_type x){ |
||
388 | // Following filter shows that the Filter Factory manual differs from the implementation. |
||
389 | // R = cos(x) > 1024 || cos(x) < -1024 || cos(-x) > 1024 || cos(-x) < -1024 ? 255 : 0 |
||
390 | // G = tan(x) > 1024 || tan(x) < -1024 || tan(-x) > 1024 || tan(-x) < -1024 ? 255 : 0 |
||
391 | // B = sin(x) > 1024 || sin(x) < -1024 || sin(-x) > 1024 || sin(-x) < -1024 ? 255 : 0 |
||
392 | // It outputs green stripes, showing that the output of tan() is not bounded. |
||
393 | // So, we do it the same way to stay compatible. |
||
394 | if (x < 0) x--; /* required for Filter Factory compatibility */ |
||
395 | while (x < 0) x += TANTABSIZE; |
||
396 | return (value_type)RINT(2*TRIGAMP*tantab[x % TANTABSIZE]); // We need the x2 multiplicator for some reason |
||
397 | } |
||
398 | |||
399 | /* r2x(d,m) x displacement of the pixel m units away, at an angle of d, |
||
400 | from an arbitrary center */ |
||
401 | value_type ff_r2x(value_type d,value_type m){ |
||
402 | return (value_type)RINT(m*costab[abs(d) % COSTABSIZE]); |
||
403 | } |
||
404 | |||
405 | /* r2y(d,m) y displacement of the pixel m units away, at an angle of d, |
||
406 | from an arbitrary center */ |
||
407 | value_type ff_r2y(value_type d,value_type m){ |
||
408 | return (value_type)RINT(m*costab[abs(d-256) % COSTABSIZE]); |
||
409 | } |
||
410 | |||
411 | /* Attention! This is NOT a function. It is internally used to calculate the variable "d". */ |
||
412 | value_type ff_c2d_negated(value_type x, value_type y) { |
||
413 | // NOTE: FilterFactory uses c2d(x,y):=atan2(y,x), but d:=atan2(-y,-x) |
||
414 | // Due to compatibility reasons, we implement it the same way! |
||
415 | // Sign of y difference is negated, as we are dealing with top-down coordinates angle is "observed" |
||
416 | return (value_type)RINT(TO_FFANGLE(atan2(-y,-x))); |
||
417 | } |
||
418 | |||
419 | /* c2d(x,y) Angle displacement of the pixel at coordinates x,y */ |
||
420 | value_type ff_c2d(value_type x,value_type y){ |
||
421 | // Behavior of FilterFoundry <1.7: |
||
422 | //return ff_c2d_negated(x,y); |
||
423 | |||
424 | // Behavior in FilterFoundry 1.7+: Matches FilterFactory |
||
425 | return (value_type)RINT(TO_FFANGLE(atan2(y,x))); |
||
426 | } |
||
427 | |||
428 | /* c2m(x,y) Magnitude displacement of the pixel at coordinates x,y */ |
||
429 | value_type ff_c2m(value_type x,value_type y){ |
||
430 | return isqrt((long)x*x + (long)y*y); |
||
431 | } |
||
432 | |||
433 | /* get(i) Returns the current cell value at i */ |
||
434 | value_type ff_get(value_type i){ |
||
435 | // Filter Factory: |
||
436 | //return i>=0 && i<NUM_CELLS ? cell[i] : i; |
||
437 | |||
438 | // Filter Foundry: |
||
439 | return i>=0 && i<NUM_CELLS ? cell[i] : 0; |
||
440 | } |
||
441 | |||
442 | /* put(v,i) Puts the new value v into cell i */ |
||
443 | value_type ff_put(value_type v,value_type i){ |
||
444 | if(i>=0 && i<NUM_CELLS) |
||
445 | cell[i] = v; |
||
446 | return v; |
||
447 | } |
||
448 | |||
449 | /* Convolve. Applies a convolution matrix and divides with d. */ |
||
450 | value_type ff_cnv(value_type m11,value_type m12,value_type m13, |
||
451 | value_type m21,value_type m22,value_type m23, |
||
452 | value_type m31,value_type m32,value_type m33, |
||
453 | value_type d) |
||
454 | { |
||
268 | daniel-mar | 455 | #ifdef PARSERTEST |
259 | daniel-mar | 456 | return 0; |
268 | daniel-mar | 457 | #else |
259 | daniel-mar | 458 | long total; |
459 | int x, y, z; |
||
460 | // shift x,y from selection-relative to image relative |
||
461 | if (HAS_BIG_DOC(gpb)) { |
||
462 | x = var['x'] + BIGDOC_FILTER_RECT(gpb).left; |
||
463 | y = var['y'] + BIGDOC_FILTER_RECT(gpb).top; |
||
464 | } else { |
||
465 | x = var['x'] + FILTER_RECT(gpb).left; |
||
466 | y = var['y'] + FILTER_RECT(gpb).top; |
||
467 | } |
||
468 | z = var['z']; |
||
469 | |||
470 | if(z >= 0 && z < var['Z']) |
||
471 | total = m11*rawsrc(x-1,y-1,z) + m12*rawsrc(x,y-1,z) + m13*rawsrc(x+1,y-1,z) |
||
472 | + m21*rawsrc(x-1,y, z) + m22*rawsrc(x,y, z) + m23*rawsrc(x+1,y, z) |
||
473 | + m31*rawsrc(x-1,y+1,z) + m32*rawsrc(x,y+1,z) + m33*rawsrc(x+1,y+1,z); |
||
474 | else |
||
475 | total = 0; |
||
476 | |||
477 | return d ? total/d : 0; |
||
268 | daniel-mar | 478 | #endif |
259 | daniel-mar | 479 | } |
480 | |||
481 | /* rst(i) sets a random seed and returns 0. (undocumented Filter Factory function). |
||
482 | Added by DM, 18 Dec 2018 */ |
||
483 | value_type ff_rst(value_type seed){ |
||
290 | daniel-mar | 484 | factory_rst(seed,&gRngState); |
286 | daniel-mar | 485 | // srand(seed); |
259 | daniel-mar | 486 | return 0; |
487 | } |
||
488 | |||
489 | value_type zero_val = 0; |
||
490 | value_type one_val = 1; |
||
491 | value_type max_channel_val = 255; |
||
492 | |||
493 | /* predefined symbols */ |
||
494 | struct sym_rec predefs[]={ |
||
495 | /* functions */ |
||
496 | |||
497 | {0,TOK_FN3,"src", (pfunc_type)ff_src, 0}, |
||
498 | {0,TOK_FN3,"rad", (pfunc_type)ff_rad, 0}, |
||
499 | {0,TOK_FN1,"ctl", (pfunc_type)ff_ctl, 0}, |
||
500 | {0,TOK_FN3,"val", (pfunc_type)ff_val, 0}, |
||
501 | {0,TOK_FN2,"map", (pfunc_type)ff_map, 0}, |
||
502 | {0,TOK_FN2,"min", (pfunc_type)ff_min, 0}, |
||
503 | {0,TOK_FN2,"max", (pfunc_type)ff_max, 0}, |
||
504 | {0,TOK_FN1,"abs", (pfunc_type)ff_abs, 0}, |
||
505 | {0,TOK_FN3,"add", (pfunc_type)ff_add, 0}, |
||
506 | {0,TOK_FN3,"sub", (pfunc_type)ff_sub, 0}, |
||
507 | {0,TOK_FN2,"dif", (pfunc_type)ff_dif, 0}, |
||
508 | {0,TOK_FN2,"rnd", (pfunc_type)ff_rnd, 0}, |
||
509 | {0,TOK_FN4,"mix", (pfunc_type)ff_mix, 0}, |
||
510 | {0,TOK_FN5,"scl", (pfunc_type)ff_scl, 0}, |
||
511 | {0,TOK_FN1,"sqr", (pfunc_type)ff_sqr, 0}, |
||
512 | {0,TOK_FN1,"sqrt", (pfunc_type)ff_sqr, 0}, // sqrt() is synonym to sqr() in Premiere |
||
513 | {0,TOK_FN1,"sin", (pfunc_type)ff_sin, 0}, |
||
514 | {0,TOK_FN1,"cos", (pfunc_type)ff_cos, 0}, |
||
515 | {0,TOK_FN1,"tan", (pfunc_type)ff_tan, 0}, |
||
516 | {0,TOK_FN2,"r2x", (pfunc_type)ff_r2x, 0}, |
||
517 | {0,TOK_FN2,"r2y", (pfunc_type)ff_r2y, 0}, |
||
518 | {0,TOK_FN2,"c2d", (pfunc_type)ff_c2d, 0}, |
||
519 | {0,TOK_FN2,"c2m", (pfunc_type)ff_c2m, 0}, |
||
520 | {0,TOK_FN1,"get", (pfunc_type)ff_get, 0}, |
||
521 | {0,TOK_FN2,"put", (pfunc_type)ff_put, 0}, |
||
522 | {0,TOK_FN10,"cnv",(pfunc_type)ff_cnv, 0}, |
||
523 | {0,TOK_FN1,"rst", (pfunc_type)ff_rst, 0}, // undocumented FilterFactory function |
||
524 | |||
525 | /* predefined variables (names with more than 1 character); most of them are undocumented in FilterFactory */ |
||
526 | /* the predefined variables with 1 character are defined in lexer.l and process.c */ |
||
527 | /* in this table, you must not add TOK_VAR with only 1 character (since this case is not defined in parser.y) */ |
||
528 | |||
529 | {0,TOK_VAR,"rmax",0, &max_channel_val}, // alias of 'R' (defined in lexer.l, line 129) |
||
530 | {0,TOK_VAR,"gmax",0, &max_channel_val}, // alias of 'G' (defined in lexer.l, line 129) |
||
531 | {0,TOK_VAR,"bmax",0, &max_channel_val}, // alias of 'B' (defined in lexer.l, line 129) |
||
532 | {0,TOK_VAR,"amax",0, &max_channel_val}, // alias of 'A' (defined in lexer.l, line 129) |
||
533 | {0,TOK_VAR,"cmax",0, &max_channel_val}, // alias of 'C' (defined in lexer.l, line 129) |
||
534 | {0,TOK_VAR,"imax",0, &max_channel_val}, // alias of 'I' (defined in lexer.l, line 129) |
||
535 | {0,TOK_VAR,"umax",0, &max_channel_val}, // alias of 'U' (defined in lexer.l, line 129) |
||
536 | {0,TOK_VAR,"vmax",0, &max_channel_val}, // alias of 'V' (defined in lexer.l, line 129) |
||
537 | {0,TOK_VAR,"dmax",0, &var['D']}, |
||
538 | {0,TOK_VAR,"mmax",0, &var['M']}, |
||
539 | {0,TOK_VAR,"pmax",0, &var['Z']}, |
||
540 | {0,TOK_VAR,"xmax",0, &var['X']}, |
||
541 | {0,TOK_VAR,"ymax",0, &var['Y']}, |
||
542 | {0,TOK_VAR,"zmax",0, &var['Z']}, |
||
543 | |||
544 | {0,TOK_VAR,"rmin",0, &zero_val}, |
||
545 | {0,TOK_VAR,"gmin",0, &zero_val}, |
||
546 | {0,TOK_VAR,"bmin",0, &zero_val}, |
||
547 | {0,TOK_VAR,"amin",0, &zero_val}, |
||
548 | {0,TOK_VAR,"cmin",0, &zero_val}, |
||
549 | {0,TOK_VAR,"imin",0, &zero_val}, |
||
550 | {0,TOK_VAR,"umin",0, &zero_val}, |
||
551 | {0,TOK_VAR,"vmin",0, &zero_val}, |
||
552 | {0,TOK_VAR,"dmin",0, &zero_val}, |
||
553 | {0,TOK_VAR,"mmin",0, &zero_val}, |
||
554 | {0,TOK_VAR,"pmin",0, &zero_val}, |
||
555 | {0,TOK_VAR,"xmin",0, &zero_val}, |
||
556 | {0,TOK_VAR,"ymin",0, &zero_val}, |
||
557 | {0,TOK_VAR,"zmin",0, &zero_val}, |
||
558 | |||
559 | /* Undocumented synonyms of FilterFactory for compatibility with Premiere */ |
||
560 | {0,TOK_FN10,"cnv0",(pfunc_type)ff_cnv, 0}, |
||
561 | {0,TOK_FN3,"src0", (pfunc_type)ff_src, 0}, |
||
562 | {0,TOK_FN3,"rad0", (pfunc_type)ff_rad, 0}, |
||
563 | {0,TOK_FN10,"cnv1",(pfunc_type)ff_cnv, 0}, |
||
564 | {0,TOK_FN3,"src1", (pfunc_type)ff_src, 0}, |
||
565 | {0,TOK_FN3,"rad1", (pfunc_type)ff_rad, 0}, |
||
566 | {0,TOK_VAR,"r0",0, &var['r']}, |
||
567 | {0,TOK_VAR,"g0",0, &var['g']}, |
||
568 | {0,TOK_VAR,"b0",0, &var['b']}, |
||
569 | {0,TOK_VAR,"a0",0, &var['a']}, |
||
570 | {0,TOK_VAR,"c0",0, &var['c']}, |
||
571 | {0,TOK_VAR,"i0",0, &var['i']}, |
||
572 | {0,TOK_VAR,"u0",0, &var['u']}, |
||
573 | {0,TOK_VAR,"v0",0, &var['v']}, |
||
574 | {0,TOK_VAR,"d0",0, &var['d']}, |
||
575 | {0,TOK_VAR,"m0",0, &var['m']}, |
||
576 | {0,TOK_VAR,"r1",0, &var['r']}, |
||
577 | {0,TOK_VAR,"g1",0, &var['g']}, |
||
578 | {0,TOK_VAR,"b1",0, &var['b']}, |
||
579 | {0,TOK_VAR,"a1",0, &var['a']}, |
||
580 | {0,TOK_VAR,"c1",0, &var['c']}, |
||
581 | {0,TOK_VAR,"i1",0, &var['i']}, |
||
582 | {0,TOK_VAR,"u1",0, &var['u']}, |
||
583 | {0,TOK_VAR,"v1",0, &var['v']}, |
||
584 | {0,TOK_VAR,"d1",0, &var['d']}, |
||
585 | {0,TOK_VAR,"m1",0, &var['m']}, |
||
586 | {0,TOK_VAR,"tmin",0, &zero_val}, |
||
587 | {0,TOK_VAR,"tmax",0, &one_val}, |
||
588 | {0,TOK_VAR,"total",0, &one_val}, |
||
589 | |||
590 | {0,0,0,0,0} |
||
591 | }; |