Code

Warning cleanup
[inkscape.git] / src / display / nr-filter-turbulence.cpp
1 /*
2  * feTurbulence filter primitive renderer
3  *
4  * Authors:
5  *   Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com>
6  *
7  * Copyright (C) 2007 authors
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
12 #include "display/nr-arena-item.h"
13 #include "display/nr-filter.h"
14 #include "display/nr-filter-turbulence.h"
15 #include "display/nr-filter-units.h"
16 #include "display/nr-filter-utils.h"
17 #include <math.h>
19 namespace NR {
21 FilterTurbulence::FilterTurbulence()
22 : XbaseFrequency(0),
23   YbaseFrequency(0),
24   numOctaves(1),
25   seed(0),
26   updated(false),
27   pix(NULL),
28   fTileWidth(10), //guessed
29   fTileHeight(10), //guessed
30   fTileX(1), //guessed
31   fTileY(1) //guessed
32 {
33 }
35 FilterPrimitive * FilterTurbulence::create() {
36     return new FilterTurbulence();
37 }
39 FilterTurbulence::~FilterTurbulence()
40 {}
42 void FilterTurbulence::set_baseFrequency(int axis, double freq){
43     if (axis==0) XbaseFrequency=freq;
44     if (axis==1) YbaseFrequency=freq;
45 }
47 void FilterTurbulence::set_numOctaves(int num){
48     numOctaves=num;
49 }
51 void FilterTurbulence::set_seed(double s){
52     seed=s;
53 }
55 void FilterTurbulence::set_stitchTiles(bool st){
56     stitchTiles=st;
57 }
59 void FilterTurbulence::set_type(FilterTurbulenceType t){
60     type=t;
61 }
63 void FilterTurbulence::set_updated(bool u){
64     updated=u;
65 }
67 void FilterTurbulence::update_pixbuffer(FilterSlot &slot) {
68 //g_warning("update_pixbuf");
69     int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0;
70     int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0;
71     int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1;
72     int bbox_y1 = (int) slot.get_arenaitem()->bbox.y1;
74     int w = bbox_x1 - bbox_x0;
75     int h = bbox_y1 - bbox_y0;
77     if (!pix){
78         pix = new NRPixBlock;
79         nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8P, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true);
80         pix_data = NR_PIXBLOCK_PX(pix);
81     }
83     TurbulenceInit((long)seed);
85     double point[2];
87     if (type==TURBULENCE_TURBULENCE){
88         for (point[0]=0; point[0] < w; point[0]++){
89             for (point[1]=0; point[1] < h; point[1]++){
90                 pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( turbulence(0,point)*255 );
91                 pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( turbulence(1,point)*255 );
92                 pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( turbulence(2,point)*255 );
93                 pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( turbulence(3,point)*255 );
94             }
95         }
96     } else {
97         for (point[0]=0; point[0] < w; point[0]++){
98             for (point[1]=0; point[1] < h; point[1]++){
99                 pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( ((turbulence(0,point)*255) +255)/2 );
100                 pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( ((turbulence(1,point)*255)+255)/2 );
101                 pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( ((turbulence(2,point)*255) +255)/2 );
102                 pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( ((turbulence(3,point)*255) +255)/2 );
103             }
104         }
105     }
106     updated=true;
109 int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &/*units*/) {
110 //g_warning("render");
111     if (!updated) update_pixbuffer(slot);
113     NRPixBlock *in = slot.get(_input);
114     NRPixBlock *out = new NRPixBlock;
115     int x,y;
116     int x0 = in->area.x0, y0 = in->area.y0;
117     int x1 = in->area.x1, y1 = in->area.y1;
118     int w = x1 - x0;
119     nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true);
121     int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0;
122     int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0;
123     int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1;
124     int bbox_w = bbox_x1 - bbox_x0;
126     unsigned char *out_data = NR_PIXBLOCK_PX(out);
127     for (x=x0; x < x1; x++){
128         for (y=y0; y < y1; y++){
129             out_data[4*((x - x0)+w*(y - y0))] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0)) ];
130             out_data[4*((x - x0)+w*(y - y0)) + 1] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+1];
131             out_data[4*((x - x0)+w*(y - y0)) + 2] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+2];
132             out_data[4*((x - x0)+w*(y - y0)) + 3] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+3];
133         }
134     }
135     out->empty = FALSE;
136     slot.set(_output, out);
137     return 0;
140 long FilterTurbulence::Turbulence_setup_seed(long lSeed)
142   if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1;
143   if (lSeed > RAND_m - 1) lSeed = RAND_m - 1;
144   return lSeed;
147 long FilterTurbulence::TurbulenceRandom(long lSeed)
149   long result;
150   result = RAND_a * (lSeed % RAND_q) - RAND_r * (lSeed / RAND_q);
151   if (result <= 0) result += RAND_m;
152   return result;
155 void FilterTurbulence::TurbulenceInit(long lSeed)
157 g_warning("init");
158   double s;
159   int i, j, k;
160   lSeed = Turbulence_setup_seed(lSeed);
161   for(k = 0; k < 4; k++)
162   {
163     for(i = 0; i < BSize; i++)
164     {
165       uLatticeSelector[i] = i;
166       for (j = 0; j < 2; j++)
167         fGradient[k][i][j] = (double)(((lSeed = TurbulenceRandom(lSeed)) % (BSize + BSize)) - BSize) / BSize;
168       s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1]));
169       fGradient[k][i][0] /= s;
170       fGradient[k][i][1] /= s;
171     }
172   }
173   while(--i)
174   {
175     k = uLatticeSelector[i];
176     uLatticeSelector[i] = uLatticeSelector[j = (lSeed = TurbulenceRandom(lSeed)) % BSize];
177     uLatticeSelector[j] = k;
178   }
179   for(i = 0; i < BSize + 2; i++)
180   {
181     uLatticeSelector[BSize + i] = uLatticeSelector[i];
182     for(k = 0; k < 4; k++)
183       for(j = 0; j < 2; j++)
184         fGradient[k][BSize + i][j] = fGradient[k][i][j];
185   }
188 double FilterTurbulence::TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo)
190   int bx0, bx1, by0, by1, b00, b10, b01, b11;
191   double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
192   int i, j;
193   t = vec[0] + PerlinN;
194   bx0 = (int)t;
195   bx1 = bx0+1;
196   rx0 = t - (int)t;
197   rx1 = rx0 - 1.0f;
198   t = vec[1] + PerlinN;
199   by0 = (int)t;
200   by1 = by0+1;
201   ry0 = t - (int)t;
202   ry1 = ry0 - 1.0f;
203   // If stitching, adjust lattice points accordingly.
204   if(pStitchInfo != NULL)
205   {
206     if(bx0 >= pStitchInfo->nWrapX)
207       bx0 -= pStitchInfo->nWidth;
208     if(bx1 >= pStitchInfo->nWrapX)
209       bx1 -= pStitchInfo->nWidth;
210     if(by0 >= pStitchInfo->nWrapY)
211       by0 -= pStitchInfo->nHeight;
212     if(by1 >= pStitchInfo->nWrapY)
213       by1 -= pStitchInfo->nHeight;
214   }
215   bx0 &= BM;
216   bx1 &= BM;
217   by0 &= BM;
218   by1 &= BM;
219   i = uLatticeSelector[bx0];
220   j = uLatticeSelector[bx1];
221   b00 = uLatticeSelector[i + by0];
222   b10 = uLatticeSelector[j + by0];
223   b01 = uLatticeSelector[i + by1];
224   b11 = uLatticeSelector[j + by1];
225   sx = double(s_curve(rx0));
226   sy = double(s_curve(ry0));
227   q = fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1];
228   q = fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1];
229   a = turb_lerp(sx, u, v);
230   q = fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1];
231   q = fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1];
232   b = turb_lerp(sx, u, v);
233   return turb_lerp(sy, a, b);
236 double FilterTurbulence::turbulence(int nColorChannel, double *point)
238 //g_warning("turbulence");
239   StitchInfo stitch;
240   StitchInfo *pStitchInfo = NULL; // Not stitching when NULL.
241   // Adjust the base frequencies if necessary for stitching.
242   if(stitchTiles)
243   {
244     // When stitching tiled turbulence, the frequencies must be adjusted
245     // so that the tile borders will be continuous.
246     if(XbaseFrequency != 0.0)
247     {
248       double fLoFreq = double(floor(fTileWidth * XbaseFrequency)) / fTileWidth;
249       double fHiFreq = double(ceil(fTileWidth * XbaseFrequency)) / fTileWidth;
250       if(XbaseFrequency / fLoFreq < fHiFreq / XbaseFrequency)
251         XbaseFrequency = fLoFreq;
252       else
253         XbaseFrequency = fHiFreq;
254     }
255     if(YbaseFrequency != 0.0)
256     {
257       double fLoFreq = double(floor(fTileHeight * YbaseFrequency)) / fTileHeight;
258       double fHiFreq = double(ceil(fTileHeight * YbaseFrequency)) / fTileHeight;
259       if(YbaseFrequency / fLoFreq < fHiFreq / YbaseFrequency)
260         YbaseFrequency = fLoFreq;
261       else
262         YbaseFrequency = fHiFreq;
263     }
264     // Set up TurbulenceInitial stitch values.
265     pStitchInfo = &stitch;
266     stitch.nWidth = int(fTileWidth * XbaseFrequency + 0.5f);
267     stitch.nWrapX = int(fTileX * XbaseFrequency + PerlinN + stitch.nWidth);
268     stitch.nHeight = int(fTileHeight * YbaseFrequency + 0.5f);
269     stitch.nWrapY = int(fTileY * YbaseFrequency + PerlinN + stitch.nHeight);
270   }
271   double fSum = 0.0f;
272   double vec[2];
273   vec[0] = point[0] * XbaseFrequency;
274   vec[1] = point[1] * YbaseFrequency;
275   double ratio = 1;
276   for(int nOctave = 0; nOctave < numOctaves; nOctave++)
277   {
278     if(type==TURBULENCE_FRACTALNOISE)
279       fSum += double(TurbulenceNoise2(nColorChannel, vec, pStitchInfo) / ratio);
280     else
281       fSum += double(fabs(TurbulenceNoise2(nColorChannel, vec, pStitchInfo)) / ratio);
282     vec[0] *= 2;
283     vec[1] *= 2;
284     ratio *= 2;
285     if(pStitchInfo != NULL)
286     {
287       // Update stitch values. Subtracting PerlinN before the multiplication and
288       // adding it afterward simplifies to subtracting it once.
289       stitch.nWidth *= 2;
290       stitch.nWrapX = 2 * stitch.nWrapX - PerlinN;
291       stitch.nHeight *= 2;
292       stitch.nWrapY = 2 * stitch.nWrapY - PerlinN;
293     }
294   }
295   return fSum;
298 FilterTraits FilterTurbulence::get_input_traits() {
299     return TRAIT_PARALLER;
302 } /* namespace NR */
304 /*
305   Local Variables:
306   mode:c++
307   c-file-style:"stroustrup"
308   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
309   indent-tabs-mode:nil
310   fill-column:99
311   End:
312 */
313 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :