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