Rev 23 | Rev 71 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | toby | 1 | /* |
18 | toby | 2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
2 | toby | 3 | Copyright (C) 2003-5 Toby Thain, toby@telegraphics.com.au |
4 | |||
5 | This program is free software; you can redistribute it and/or modify |
||
6 | it under the terms of the GNU General Public License as published by |
||
7 | the Free Software Foundation; either version 2 of the License, or |
||
8 | (at your option) any later version. |
||
9 | |||
10 | This program is distributed in the hope that it will be useful, |
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | GNU General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU General Public License |
||
16 | along with this program; if not, write to the Free Software |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | */ |
||
19 | |||
20 | #ifdef MAC_ENV |
||
21 | #include <fp.h> |
||
22 | #endif |
||
23 | |||
24 | #include <math.h> |
||
25 | #include <stdlib.h> |
||
26 | |||
27 | #ifndef PARSERTEST |
||
28 | #include "ff.h" |
||
29 | #endif |
||
30 | #include "funcs.h" |
||
31 | #include "y.tab.h" |
||
32 | |||
33 | #define RINT //no rounding for now |
||
34 | |||
35 | //#if TARGET_API_MAC_CARBON |
||
36 | // this is another incompatibility between Classic stdclib and OS X stdclib |
||
37 | // ***FIXME: need to access real OS X includes for Carbon build |
||
38 | //#undef RAND_MAX |
||
39 | //#define RAND_MAX 0x7fffffff |
||
40 | //#endif |
||
41 | |||
42 | extern value_type slider[],cell[],var[],map[][0x100]; |
||
66 | toby | 43 | extern unsigned char *image_ptr; |
2 | toby | 44 | |
45 | /* src(x,y,z) Channel z for the pixel at coordinates x,y */ |
||
46 | value_type ff_src(value_type x,value_type y,value_type z){ |
||
47 | #ifdef PARSERTEST |
||
48 | return 0; |
||
49 | #else |
||
50 | if(x<0) |
||
51 | x = 0; |
||
52 | else if(x>=var['X']) |
||
53 | x = var['X']-1; |
||
54 | if(y<0) |
||
55 | y = 0; |
||
56 | else if(y>=var['Y']) |
||
57 | y = var['Y']-1; |
||
66 | toby | 58 | return z>=0 && z<var['Z'] ? image_ptr[ (long)gpb->inRowBytes*y + (long)nplanes*x + z ] : 0; |
2 | toby | 59 | #endif |
60 | } |
||
61 | |||
62 | /* rad(d,m,z) Channel z in the source image, which is m units away, at an |
||
63 | angle of d, from the center of the image */ |
||
64 | value_type ff_rad(value_type d,value_type m,value_type z){ |
||
65 | return ff_src(ff_r2x(d,m)+var['X']/2,ff_r2y(d,m)+var['Y']/2,z); |
||
66 | } |
||
67 | |||
68 | /* ctl(i) Value of slider i, where i is an integer between 0 and 7, inclusive */ |
||
69 | value_type ff_ctl(value_type i){ |
||
70 | return i>=0 && i<=7 ? slider[i] : 0; |
||
71 | } |
||
72 | |||
73 | /* val(i,a,b) Value of slider i, mapped onto the range a to b */ |
||
74 | value_type ff_val(value_type i,value_type a,value_type b){ |
||
75 | return ((long)ff_ctl(i)*(b-a))/255 + a; |
||
76 | } |
||
77 | |||
78 | /* map(i,n) Item n from mapping table i, where i is an integer between |
||
79 | |||
80 | inclusive */ |
||
81 | value_type ff_map(value_type i,value_type n){ |
||
82 | /* |
||
83 | if( i>=0 && i<=3 && n>=0 && n<=255 ){ |
||
84 | int H = slider[i*2],L = slider[i*2+1]; |
||
85 | return n<=L || H==L ? 0 : ( n>=H ? 255 : ((n-L)*255L)/(H-L) ); |
||
86 | }else |
||
87 | return 0; |
||
88 | */ |
||
89 | // this code is from GIMP User Filter |
||
90 | value_type x = ff_ctl(i*2), |
||
91 | y = ff_ctl(i*2+1); |
||
92 | return abs(((long)n*(y-x) / 255)+x); |
||
93 | } |
||
94 | |||
95 | /* min(a,b) Lesser of a and b */ |
||
96 | value_type ff_min(value_type a,value_type b){ |
||
97 | return a < b ? a : b; |
||
98 | } |
||
99 | |||
100 | /* max(a,b) Greater of a and b */ |
||
101 | value_type ff_max(value_type a,value_type b){ |
||
102 | return a > b ? a : b; |
||
103 | } |
||
104 | |||
105 | /* abs(a) Absolute value of a */ |
||
106 | value_type ff_abs(value_type a){ |
||
107 | return abs(a); |
||
108 | } |
||
109 | |||
110 | /* add(a,b,c) Sum of a and b, or c, whichever is lesser */ |
||
111 | value_type ff_add(value_type a,value_type b,value_type c){ |
||
112 | return ff_min(a+b,c); |
||
113 | } |
||
114 | |||
115 | /* sub(a,b,c) Difference of a and b, or c, whichever is greater */ |
||
116 | value_type ff_sub(value_type a,value_type b,value_type c){ |
||
117 | return ff_max(ff_dif(a,b),c); |
||
118 | } |
||
119 | |||
120 | /* dif(a,b) Absolute value of the difference of a and b */ |
||
121 | value_type ff_dif(value_type a,value_type b){ |
||
122 | return abs(a-b); |
||
123 | } |
||
124 | |||
125 | /* rnd(a,b) Random number between a and b, inclusive */ |
||
126 | value_type ff_rnd(value_type a,value_type b){ |
||
127 | return (int)((abs(a-b)+1)*(rand()/(RAND_MAX+1.))) + ff_min(a,b); |
||
128 | // return ((unsigned)rand() % (ff_dif(a,b)+1)) + ff_min(a,b); |
||
129 | } |
||
130 | |||
131 | /* mix(a,b,n,d) Mixture of a and b by fraction n/d, a*n/d+b*(d-n)/d */ |
||
132 | value_type ff_mix(value_type a,value_type b,value_type n,value_type d){ |
||
133 | return d ? ((long)a*n)/d + ((long)b*(d-n))/d : 0; |
||
134 | } |
||
135 | |||
136 | /* scl(a,il,ih,ol,oh) Scale a from input range (il to ih) |
||
137 | to output range (ol to oh) */ |
||
138 | value_type ff_scl(value_type a,value_type il,value_type ih, |
||
139 | value_type ol,value_type oh){ |
||
140 | return ih==il ? 0 : ol + ((long)(oh-ol)*(a-il))/(ih-il); |
||
141 | } |
||
142 | |||
143 | /* adapted from http://remus.rutgers.edu/~rhoads/Code/isqrt.c */ |
||
144 | /* also see http://www.freaknet.org/martin/tape/gos/misc/personal/msc/sqrt/sqrt.c */ |
||
145 | #define NBITS (sizeof(long)*8) |
||
146 | #define TOP2BITS(x) (x>>(NBITS-2)) |
||
147 | |||
148 | unsigned long isqrt (unsigned long x) |
||
149 | { |
||
23 | toby | 150 | unsigned i; |
2 | toby | 151 | unsigned long a = 0, e = 0, r = 0; |
152 | |||
153 | |||
154 | for (i=0; i < (NBITS >> 1); i++) |
||
155 | { |
||
156 | r <<= 2; |
||
157 | r += TOP2BITS(x); |
||
158 | x <<= 2; |
||
159 | |||
160 | a <<= 1; |
||
161 | e = (a<<1) | 1; |
||
162 | |||
163 | if (r >= e) |
||
164 | { |
||
165 | r -= e; |
||
166 | a++; |
||
167 | } |
||
168 | } |
||
169 | |||
170 | return a; |
||
171 | } |
||
172 | |||
173 | /* sqr(x) Square root of x */ |
||
174 | value_type ff_sqr(value_type x){ |
||
175 | return x < 0 ? 0 : isqrt(x); |
||
176 | } |
||
177 | |||
178 | /* sin(x) Sine function of x, where x is an integer between 0 and |
||
179 | 1024, inclusive, and the value returned is an integer |
||
180 | between -512 and 512, inclusive (Windows) or -1024 and |
||
181 | 1024, inclusive (Mac OS) */ |
||
182 | value_type ff_sin(value_type x){ |
||
183 | return ff_cos(x-256); //RINT(TRIGAMP*sin(FFANGLE(x))); |
||
184 | } |
||
185 | |||
186 | /* cos(x) Cosine function of x */ |
||
187 | value_type ff_cos(value_type x){ |
||
188 | return costab[abs(x) % COSTABSIZE]; //RINT(TRIGAMP*cos(FFANGLE(x))); |
||
189 | } |
||
190 | |||
191 | /* tan(x) |
||
192 | Bounded tangent function of x, where x is an integer |
||
193 | between -256 and 256, inclusive, and the value returned is |
||
194 | */ |
||
195 | value_type ff_tan(value_type x){ |
||
196 | return tantab[(x+256) % TANTABSIZE]; //RINT(TRIGAMP*tan(FFANGLE(x))); |
||
197 | } |
||
198 | |||
199 | /* r2x(d,m) x displacement of the pixel m units away, at an angle of d, |
||
200 | from an arbitrary center */ |
||
201 | value_type ff_r2x(value_type d,value_type m){ |
||
202 | return RINT(m*cos(FFANGLE(d))); |
||
203 | } |
||
204 | |||
205 | /* r2y(d,m) y displacement of the pixel m units away, at an angle of d, |
||
206 | from an arbitrary center */ |
||
207 | value_type ff_r2y(value_type d,value_type m){ |
||
208 | return RINT(m*sin(FFANGLE(d))); |
||
209 | } |
||
210 | |||
211 | /* c2d(x,y) Angle displacement of the pixel at coordinates x,y */ |
||
212 | /* note, sign of y difference is negated, as we are dealing with top-down coordinates |
||
213 | angle is "observed" */ |
||
214 | value_type ff_c2d(value_type x,value_type y){ |
||
215 | return RINT(TO_FFANGLE(atan2(-y,-x))); /* FIXME: why must we negate x here? */ |
||
216 | } |
||
217 | |||
218 | /* c2m(x,y) Magnitude displacement of the pixel at coordinates x,y */ |
||
219 | value_type ff_c2m(value_type x,value_type y){ |
||
220 | return isqrt((long)x*x + (long)y*y); |
||
221 | } |
||
222 | |||
223 | /* get(i) Returns the current cell value at i */ |
||
224 | value_type ff_get(value_type i){ |
||
225 | return i>=0 && i<=0xff ? cell[i] : 0; |
||
226 | } |
||
227 | |||
228 | /* put(v,i) Puts the new value v into cell i */ |
||
229 | value_type ff_put(value_type v,value_type i){ |
||
230 | if(i>=0 && i<=0xff) |
||
231 | cell[i] = v; |
||
232 | return v; |
||
233 | } |
||
234 | |||
235 | value_type ff_cnv(value_type m11,value_type m12,value_type m13, |
||
236 | value_type m21,value_type m22,value_type m23, |
||
237 | value_type m31,value_type m32,value_type m33, |
||
238 | value_type d ){ |
||
239 | long total = 0; |
||
240 | int x=var['x'],y=var['y']; |
||
66 | toby | 241 | unsigned char *p = image_ptr + y*(long)gpb->inRowBytes + (x-1)*(long)nplanes + var['z']; |
2 | toby | 242 | |
243 | /* left column */ |
||
244 | if(x > 0){ |
||
245 | if(y > 0) total += m11*p[ -gpb->inRowBytes ]; |
||
246 | total += m21*p[ 0 ]; |
||
247 | if(y < var['Y']-1) total += m31*p[ gpb->inRowBytes ]; |
||
248 | } |
||
249 | |||
250 | /* centre column */ |
||
251 | p += nplanes; |
||
252 | if(y > 0) total += m12*p[ -gpb->inRowBytes ]; |
||
253 | total += m22*p[ 0 ]; |
||
254 | if(y < var['Y']-1) total += m32*p[ gpb->inRowBytes ]; |
||
255 | |||
256 | /* right column */ |
||
257 | if(x < var['X']-1){ |
||
258 | p += nplanes; |
||
259 | if(y > 0) total += m13*p[ -gpb->inRowBytes ]; |
||
260 | total += m23*p[ 0 ]; |
||
261 | if(y < var['Y']-1) total += m33*p[ gpb->inRowBytes ]; |
||
262 | } |
||
263 | |||
264 | return d ? total/d : 0; |
||
265 | } |
||
266 | |||
267 | value_type zero_val = 0; |
||
268 | |||
269 | /* predefined symbols */ |
||
270 | struct sym_rec predefs[]={ |
||
271 | /* functions */ |
||
272 | {0,TOK_FN3,"src", (pfunc_type)ff_src, 0}, |
||
273 | {0,TOK_FN3,"rad", (pfunc_type)ff_rad, 0}, |
||
274 | {0,TOK_FN1,"ctl", (pfunc_type)ff_ctl, 0}, |
||
275 | {0,TOK_FN3,"val", (pfunc_type)ff_val, 0}, |
||
276 | {0,TOK_FN2,"map", (pfunc_type)ff_map, 0}, |
||
277 | {0,TOK_FN2,"min", (pfunc_type)ff_min, 0}, |
||
278 | {0,TOK_FN2,"max", (pfunc_type)ff_max, 0}, |
||
279 | {0,TOK_FN1,"abs", (pfunc_type)ff_abs, 0}, |
||
280 | {0,TOK_FN3,"add", (pfunc_type)ff_add, 0}, |
||
281 | {0,TOK_FN3,"sub", (pfunc_type)ff_sub, 0}, |
||
282 | {0,TOK_FN2,"dif", (pfunc_type)ff_dif, 0}, |
||
283 | {0,TOK_FN2,"rnd", (pfunc_type)ff_rnd, 0}, |
||
284 | {0,TOK_FN4,"mix", (pfunc_type)ff_mix, 0}, |
||
285 | {0,TOK_FN5,"scl", (pfunc_type)ff_scl, 0}, |
||
286 | {0,TOK_FN1,"sqr", (pfunc_type)ff_sqr, 0}, |
||
287 | {0,TOK_FN1,"sin", (pfunc_type)ff_sin, 0}, |
||
288 | {0,TOK_FN1,"cos", (pfunc_type)ff_cos, 0}, |
||
289 | {0,TOK_FN1,"tan", (pfunc_type)ff_tan, 0}, |
||
290 | {0,TOK_FN2,"r2x", (pfunc_type)ff_r2x, 0}, |
||
291 | {0,TOK_FN2,"r2y", (pfunc_type)ff_r2y, 0}, |
||
292 | {0,TOK_FN2,"c2d", (pfunc_type)ff_c2d, 0}, |
||
293 | {0,TOK_FN2,"c2m", (pfunc_type)ff_c2m, 0}, |
||
294 | {0,TOK_FN1,"get", (pfunc_type)ff_get, 0}, |
||
295 | {0,TOK_FN2,"put", (pfunc_type)ff_put, 0}, |
||
296 | {0,TOK_FN10,"cnv",(pfunc_type)ff_cnv, 0}, |
||
297 | /* predefined variables (names >1 characters) */ |
||
298 | {0,TOK_VAR,"dmin",0, &zero_val}, |
||
299 | {0,TOK_VAR,"mmin",0, &zero_val}, |
||
300 | {0,0,0,0,0} |
||
301 | }; |
||
302 |