d0921047af972f7cf0bf4f8056af00640c9b63e8
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-utils.h"
16 #include <math.h>
18 namespace NR {
20 FilterTurbulence::FilterTurbulence()
21 : XbaseFrequency(0),
22 YbaseFrequency(0),
23 numOctaves(1),
24 seed(0),
25 updated(false),
26 pix(NULL),
27 fTileWidth(10), //guessed
28 fTileHeight(10), //guessed
29 fTileX(1), //guessed
30 fTileY(1) //guessed
31 {
32 }
34 FilterPrimitive * FilterTurbulence::create() {
35 return new FilterTurbulence();
36 }
38 FilterTurbulence::~FilterTurbulence()
39 {}
41 void FilterTurbulence::set_baseFrequency(int axis, double freq){
42 if (axis==0) XbaseFrequency=freq;
43 if (axis==1) YbaseFrequency=freq;
44 }
46 void FilterTurbulence::set_numOctaves(int num){
47 numOctaves=num;
48 }
50 void FilterTurbulence::set_seed(double s){
51 seed=s;
52 }
54 void FilterTurbulence::set_stitchTiles(bool st){
55 stitchTiles=st;
56 }
58 void FilterTurbulence::set_type(FilterTurbulenceType t){
59 type=t;
60 }
62 void FilterTurbulence::set_updated(bool u){
63 updated=u;
64 }
66 void FilterTurbulence::update_pixbuffer(FilterSlot &slot) {
67 //g_warning("update_pixbuf");
68 int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0;
69 int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0;
70 int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1;
71 int bbox_y1 = (int) slot.get_arenaitem()->bbox.y1;
73 int w = bbox_x1 - bbox_x0;
74 int h = bbox_y1 - bbox_y0;
75 int x,y;
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;
107 }
109 int FilterTurbulence::render(FilterSlot &slot, Matrix const &trans) {
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;
138 }
140 long FilterTurbulence::Turbulence_setup_seed(long lSeed)
141 {
142 if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1;
143 if (lSeed > RAND_m - 1) lSeed = RAND_m - 1;
144 return lSeed;
145 }
147 long FilterTurbulence::TurbulenceRandom(long lSeed)
148 {
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;
153 }
155 void FilterTurbulence::TurbulenceInit(long lSeed)
156 {
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 }
186 }
188 double FilterTurbulence::TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo)
189 {
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);
234 }
236 double FilterTurbulence::turbulence(int nColorChannel, double *point)
237 {
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;
296 }
298 } /* namespace NR */
300 /*
301 Local Variables:
302 mode:c++
303 c-file-style:"stroustrup"
304 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
305 indent-tabs-mode:nil
306 fill-column:99
307 End:
308 */
309 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :