Subversion Repositories filter_foundry

Rev

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
};