1 /*
2 * Particle generator
3 * (c) Copyright 2004-2007 Denis Roio aka jaromil <jaromil@dyne.org>
4 *
5 * blossom original algo is (c) 2003 by ragnar (waves 1.2)
6 * http://home.uninet.ee/~ragnar/waves
7 * further optimizations and changes followed
8 *
9 * This source code is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Public License as published
11 * by the Free Software Foundation; either version 2 of the License,
12 * or (at your option) any later version.
13 *
14 * This source code is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * Please refer to the GNU Public License for more details.
18 *
19 * You should have received a copy of the GNU Public License along with
20 * this source code; if not, write to:
21 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * "$Id: gen_layer.cpp 845 2007-04-03 07:04:47Z jaromil $"
24 *
25 */
26
27
28 #include "frei0r.hpp"
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <algorithm>
34 #if defined(_MSC_VER)
35 #define _USE_MATH_DEFINES
36 #endif /* _MSC_VER */
37 #include <cmath>
38
39 #include <time.h>
40 #include <inttypes.h>
41 #include <limits.h>
42
43 /* defines for blob size and roundness */
44 #define LIM 8 // 25
45 #define NB_BLOB 16 // 25
46
47 #define PRIMES 11
48
49 class Partik0l: public frei0r::source {
50 public:
51
52 Partik0l(unsigned int width, unsigned int height);
53 ~Partik0l();
54
55 void update(double time,
56 uint32_t* out);
57
58 int w, h;
59
60 double up;
61 double down;
62
63 private:
64
65 uint32_t size;
66
67 /* blossom vars */
68 double blossom_count;
69 double blossom_m;
70 double blossom_n;
71 double blossom_i;
72 double blossom_j;
73 double blossom_k;
74 double blossom_l;
75 float blossom_r;
76 float blossom_a;
77
78 /* primes */
79 int prime[11];
80
81 float pi2;
82 double wd, hd;
83
84
85 void blob(uint32_t* out, int x, int y);
86 void blossom(uint32_t* out);
87 void blob_init(int ray);
88 void blossom_recal(bool r);
89
90 /* surface buffer */
91 // uint32_t *pixels;
92 uint32_t *blob_buf;
93 int blob_size;
94
95 void fastsrand(uint32_t seed);
96 uint32_t fastrand();
97
98 uint32_t randval;
99 };
100
Partik0l(unsigned int width,unsigned int height)101 Partik0l::Partik0l(unsigned int width, unsigned int height) {
102
103 register_param(up, "up", "blossom on a higher prime number");
104 register_param(down, "down", "blossom on a lower prime number");
105
106 /* initialize prime numbers */
107 prime[0] = 2;
108 prime[1] = 3;
109 prime[2] = 5;
110 prime[3] = 7;
111 prime[4] = 11;
112 prime[5] = 13;
113 prime[6] = 17;
114 prime[7] = 19;
115 prime[8] = 23;
116 prime[9] = 29;
117 prime[10] = 31;
118
119 /* blossom vars */
120 blossom_count = 0;
121 blossom_m = 0;
122 blossom_n = 0;
123 blossom_i = 0;
124 blossom_j = 0;
125 blossom_k = 0;
126 blossom_l = 0;
127 blossom_r = 1;
128 blossom_a = 0;
129
130 up = 0;
131 down = 0;
132
133 pi2 = 2.0*M_PI;
134
135 fastsrand( ::time(NULL) );
136
137 w = width;
138 h = height;
139 size = w * h * 4; // 32bit pixels
140 // pixels = (uint32_t*)malloc(size);
141
142
143 blob_buf = NULL;
144
145 blossom_recal(true);
146
147 /* blob initialization */
148 blob_init(8);
149
150
151 }
152
~Partik0l()153 Partik0l::~Partik0l() {
154 // if(pixels) free(pixels);
155 if(blob_buf) free(blob_buf);
156 }
157
158
159
update(double time,uint32_t * out)160 void Partik0l::update(double time,
161 uint32_t* out) {
162 /* automatic random recalculation:
163 if( !blossom_count ) {
164 recalculate();
165 blossom_count = 100+(50.0)*rand()/RAND_MAX;
166 } else {
167 blossom_count--;
168 */
169
170 if(up) {
171 blossom_recal(false);
172 up = false;
173 } else if(down) {
174 blossom_recal(true);
175 down = false;
176 }
177
178 blossom_a += 0.01;
179 if( blossom_a > pi2 )
180 blossom_a -= pi2;
181
182
183 memset(out,0,size);
184
185 blossom(out);
186
187 }
188
blossom_recal(bool r)189 void Partik0l::blossom_recal(bool r) {
190
191 float z = ((PRIMES-2)*fastrand()/INT_MAX)+1;
192 blossom_m = 1.0+(30.0)*fastrand()/INT_MAX;
193 blossom_n = 1.0+(30.0)*fastrand()/INT_MAX;
194 blossom_i = prime[ (int) (z*fastrand()/INT_MAX) ];
195 blossom_j = prime[ (int) (z*fastrand()/INT_MAX) ];
196 blossom_k = prime[ (int) (z*fastrand()/INT_MAX) ];
197 blossom_l = prime[ (int) (z*fastrand()/INT_MAX) ];
198 wd = (double)w;
199 hd = (double)h;
200 if(r)
201 blossom_r = (blossom_r>=1.0)?1.0:blossom_r+0.1;
202 else
203 blossom_r = (blossom_r<=0.1)?0.1:blossom_r-0.1;
204 }
205
blossom(uint32_t * out)206 void Partik0l::blossom(uint32_t* out) {
207
208 float a;
209 int x, y;
210 double zx, zy;
211
212 /* here place a formula that draws on the screen
213 the surface being drawed at this point is always blank */
214 for( a=0.0 ; a<pi2; a+=0.005 ) {
215 zx = blossom_m*a;
216 zy = blossom_n*a;
217 x = (int)(wd*(0.47+ (blossom_r*sin(blossom_i*zx+blossom_a)+
218 (1.0-blossom_r)*sin(blossom_k*zy+blossom_a)) /2.2 ));
219
220 y = (int)(hd*(0.47+ (blossom_r*cos(blossom_j*zx+blossom_a)+
221 (1.0-blossom_r)*cos(blossom_l*zy+blossom_a)) /2.2 ));
222
223 blob(out, x,y);
224
225 }
226
227 }
228
blob_init(int ray)229 void Partik0l::blob_init(int ray) {
230 uint8_t col;
231
232 blob_size = ray*2;
233
234 /* there is the blob gradient sphere here
235 Niels helps me with this: calculating a circle
236 while(theta <= 360) {
237 double radians = (theta / 180.0) * PI;
238 double dx = ( origin[0] + cos( radians ) * radius );
239 double dy = ( origin[1] + sin( radians ) * radius );
240
241 (there are always some basics you learn at school and then forget)
242 */
243 uint32_t dx,dy;
244 double rad, th;
245 int c;
246 srand(::time(NULL));
247 if(blob_buf) free(blob_buf);
248
249 blob_buf = (uint32_t*) calloc(ray*2*ray*2*2,sizeof(uint32_t));
250 // memset(blob_buf,0,ray*2*ray*2*sizeof(uint32_t));
251
252 for(th=1;th<=360;th++) {
253 rad = (th / 180.0) * M_PI;
254 for(c=ray;c>0;c--) {
255 dx = ( (ray) + cos( rad ) * c );
256 dy = ( (ray) + sin( rad ) * c );
257 // col = (int)(10.0*rand()/(RAND_MAX+1.0))/c;
258 // col += 0x99/c * 0.8;
259 col = 0x99/c * 0.8;
260 blob_buf[ (dx+((ray*2)*dy)) ] =
261 col|(col<<8)|(col<<16)|(col<<24);
262 }
263 }
264
265 }
266
267
blob(uint32_t * out,int x,int y)268 void Partik0l::blob(uint32_t* out, int x, int y) {
269 // if(y>h-blob_size) return;
270 // if(x>w-blob_size) return;
271
272 int i, j;
273 int stride = (w-blob_size)>>1;
274
275 uint64_t *tmp_scr = (uint64_t*)out + ((x + y*w)>>1);
276 uint64_t *tmp_blob = (uint64_t*)blob_buf;
277
278 #ifdef HAVE_MMX
279 /* using mmx packed unsaturated addition on bytes
280 for cleaner and shiny result */
281 for(j=blob_size; j>0; j--) {
282 for(i=blob_size>>4; i>0; i--) {
283
284 asm volatile("movq (%1),%%mm0;"
285 "movq 8(%1),%%mm1;"
286 "movq 16(%1),%%mm2;"
287 "movq 24(%1),%%mm3;"
288 "movq 32(%1),%%mm4;"
289 "movq 40(%1),%%mm5;"
290 "movq 48(%1),%%mm6;"
291 "movq 56(%1),%%mm7;"
292
293 "paddusb (%0),%%mm0;" // packed add unsaturated on bytes
294 "paddusb 8(%0),%%mm1;" // addizione clippata
295 "paddusb 16(%0),%%mm2;"
296 "paddusb 24(%0),%%mm3;"
297 "paddusb 32(%0),%%mm4;"
298 "paddusb 40(%0),%%mm5;"
299 "paddusb 48(%0),%%mm6;"
300 "paddusb 56(%0),%%mm7;"
301
302 "movq %%mm0,(%0);"
303 "movq %%mm1,8(%0);"
304 "movq %%mm2,16(%0);"
305 "movq %%mm3,24(%0);"
306 "movq %%mm4,32(%0);"
307 "movq %%mm5,40(%0);"
308 "movq %%mm6,48(%0);"
309 "movq %%mm7,56(%0);"
310 // "paddsw %0, %%mm0;"// halo violetto?
311 :
312 :"r"(tmp_scr),"r"(tmp_blob)
313 :"memory");
314 tmp_scr+=8;
315 tmp_blob+=8;
316 }
317 tmp_scr += stride;
318 }
319 asm("emms;");
320
321
322 #else // ! HAVE_MMX
323 for(j=blob_size; j>0; j--) {
324 for(i=blob_size>>1; i>0; i--) {
325 *(tmp_scr++) += *(tmp_blob++);
326 }
327 tmp_scr += stride;
328 }
329 #endif
330
331 }
332
333 /*
334 * fastrand - fast fake random number generator
335 * by Fukuchi Kentarou
336 * Warning: The low-order bits of numbers generated by fastrand()
337 * are bad as random numbers. For example, fastrand()%4
338 * generates 1,2,3,0,1,2,3,0...
339 * You should use high-order bits.
340 *
341 */
342
343
344
fastrand()345 uint32_t Partik0l::fastrand()
346 {
347 // kentaro's original one:
348 // return (randval=randval*1103515245+12345);
349 //15:55 <salsaman2> mine uses two prime numbers and the cycling is much reduced
350 //15:55 <salsaman2> return (randval=randval*1073741789+32749);
351 return(randval = randval * 1073741789 + 32749 );
352 }
353
fastsrand(uint32_t seed)354 void Partik0l::fastsrand(uint32_t seed)
355 {
356 randval = seed;
357 }
358
359 /*
360 bool Partik0l::keypress(int key) {
361 if(key=='p')
362 blossom_recal(true);
363 else if(key=='o')
364 blossom_recal(false);
365 else return(false);
366
367 return(true);
368 }
369 */
370 frei0r::construct<Partik0l> plugin("Partik0l",
371 "Particles generated on prime number sinusoidal blossoming",
372 "Jaromil",
373 0,3);
374