5d74b622666451d7472d3be83f9010d8e7431bfe
[platform/upstream/gst-plugins-good.git] / gst / goom / filters.c
1 /* filter.c version 0.7
2  * contient les filtres applicable a un buffer
3  * creation : 01/10/2000
4  *  -ajout de sinFilter()
5  *  -ajout de zoomFilter()
6  *  -copie de zoomFilter() en zoomFilterRGB(), gérant les 3 couleurs
7  *  -optimisation de sinFilter (utilisant une table de sin)
8  *      -asm
9  *      -optimisation de la procedure de génération du buffer de transformation
10  *              la vitesse est maintenant comprise dans [0..128] au lieu de [0..100]
11 */
12
13 /*#define _DEBUG_PIXEL; */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include "filters.h"
20 #include "graphic.h"
21 #include "goom_tools.h"
22 #include <stdlib.h>
23 #include <math.h>
24 #include <stdio.h>
25
26 #ifdef MMX
27 #define USE_ASM
28 #endif
29 #ifdef POWERPC
30 #define USE_ASM
31 #endif
32
33 #ifdef USE_ASM
34 #define EFFECT_DISTORS 4
35 #else
36 #define EFFECT_DISTORS 10
37 #endif
38
39
40 extern volatile guint32 resolx;
41 extern volatile guint32 resoly;
42
43 #ifdef USE_ASM
44
45 #ifdef MMX
46 int mmx_zoom () ;
47 guint32 mmx_zoom_size;
48 #endif /* MMX */
49
50 #ifdef POWERPC
51 extern unsigned int useAltivec;
52 extern void ppc_zoom(void);
53 extern void ppc_zoom_altivec(void);
54 unsigned int ppcsize4;
55 #endif /* PowerPC */
56
57 unsigned int *coeffs = 0, *freecoeffs = 0;
58 guint32 *expix1 = 0; /* pointeur exporte vers p1 */
59 guint32 *expix2 = 0; /* pointeur exporte vers p2 */
60 guint32 zoom_width;
61
62 #endif /* ASM */
63
64
65 static int sintable [0xffff] ;
66 static int vitesse = 127;
67 static char theMode = AMULETTE_MODE ;
68 static int vPlaneEffect = 0;
69 static int hPlaneEffect = 0;
70 static char noisify = 2;
71 static int middleX , middleY ;
72 static unsigned char sqrtperte = 16 ;
73
74 static int * firedec = 0 ;
75
76
77 /* retourne x>>s , en testant le signe de x */
78 inline int ShiftRight (int x, const unsigned char s)
79 {
80   if (x<0)
81         return -(-x >> s) ;
82   else
83         return x >> s ;
84 }
85
86 /*
87   calculer px et py en fonction de x,y,middleX,middleY et theMode
88   px et py indique la nouvelle position (en sqrtperte ieme de pixel)
89   (valeur * 16)
90 */
91 void calculatePXandPY (int x, int y, int *px, int *py)
92 {
93     if (theMode == WATER_MODE)
94     {
95         static int wave = 0 ;
96         static int wavesp = 0 ;
97         int yy ;
98
99         yy = y + RAND () % 4 + wave / 10 ;
100         yy -= RAND () % 4;
101         if (yy < 0) yy = 0 ;
102         if (yy >= resoly) yy = resoly - 1 ;
103           
104         *px = (x<<4) + firedec [yy] + (wave / 10) ;
105         *py = (y<<4) + 132 - ((vitesse < 132) ? vitesse : 131) ;
106
107         wavesp += RAND () % 3;
108         wavesp -= RAND () % 3;
109         if (wave < -10) wavesp += 2 ;
110         if (wave > 10) wavesp -= 2 ;
111         wave += (wavesp / 10) + RAND () % 3;
112         wave -= RAND () % 3;
113         if (wavesp > 100) wavesp = (wavesp * 9) / 10  ;
114     }
115     else
116     {
117         int dist ;
118         register int vx,vy ;
119         int fvitesse = vitesse << 4 ;
120
121         if (noisify)
122         {
123             x += RAND() % noisify;
124             x -= RAND() % noisify;
125             y += RAND() % noisify;
126             y -= RAND() % noisify;
127         }
128
129         if (hPlaneEffect) vx = ((x - middleX) << 9) + hPlaneEffect * (y - middleY);
130         else vx = (x - middleX) << 9 ;
131           
132         if (vPlaneEffect) vy = ((y - middleY) << 9) + vPlaneEffect * (x - middleX);
133         else vy = (y - middleY) << 9 ;
134           
135         switch (theMode)
136         {
137             case WAVE_MODE:
138                 dist = ShiftRight(vx,9) * ShiftRight(vx,9) + ShiftRight(vy,9) * ShiftRight(vy,9);
139                 fvitesse *= 1024 + ShiftRight (
140                                     sintable [(unsigned short)(0xffff*dist*EFFECT_DISTORS)],6);
141                 fvitesse /= 1024 ;
142                 break ;
143             case CRYSTAL_BALL_MODE:
144                 dist = ShiftRight(vx,9) * ShiftRight(vx,9) + ShiftRight(vy,9) * ShiftRight(vy,9);
145                 fvitesse += (dist * EFFECT_DISTORS >> 10);
146                 break;
147             case AMULETTE_MODE:
148                 dist = ShiftRight(vx,9) * ShiftRight(vx,9) + ShiftRight(vy,9) * ShiftRight(vy,9);
149                 fvitesse -= (dist * EFFECT_DISTORS >> 4);
150                 break;
151             case SCRUNCH_MODE:
152                 dist = ShiftRight(vx,9) * ShiftRight(vx,9) + ShiftRight(vy,9) * ShiftRight(vy,9);
153                 fvitesse -= (dist * EFFECT_DISTORS >> 9);
154                 break;
155         }
156         if (vx<0) *px = (middleX << 4) - (-(vx * fvitesse) >> 16) ;
157         else *px = (middleX << 4) + ((vx * fvitesse) >> 16) ;
158         if (vy<0) *py = (middleY << 4) - (-(vy * fvitesse) >> 16) ;
159         else *py = (middleY << 4) + ((vy * fvitesse) >> 16) ;
160     }
161 }
162
163 /*#define _DEBUG */
164
165 inline void setPixelRGB(Uint *buffer, Uint x, Uint y, Color c)
166 {
167 /*              buffer[ y*WIDTH + x ] = (c.r<<16)|(c.v<<8)|c.b */
168 #ifdef _DEBUG_PIXEL
169   if ( x+y*resolx >= resolx * resoly)
170         {
171           fprintf (stderr,"setPixel ERROR : hors du tableau... %i, %i\n", x,y) ;
172           /*exit (1) ; */
173         }
174 #endif
175   
176 #ifdef USE_DGA
177   buffer[ y*resolx + x ] = (c.b<<16)|(c.v<<8)|c.r ;
178 #else
179   buffer[ y*resolx + x ] = (c.r<<16)|(c.v<<8)|c.b ;
180 #endif
181 }
182
183
184 inline void setPixelRGB_ (Uint *buffer, Uint x, Color c)
185 {
186 #ifdef _DEBUG
187   if ( x >= resolx*resoly )
188         {
189           printf ("setPixel ERROR : hors du tableau... %i, %i\n", x,y) ;
190           exit (1) ;
191         }
192 #endif
193   
194 #ifdef USE_DGA
195   buffer[ x ] = (c.b<<16)|(c.v<<8)|c.r ;
196 #else
197   buffer[ x ] = (c.r<<16)|(c.v<<8)|c.b ;
198 #endif
199 }
200
201
202
203 inline void getPixelRGB (Uint *buffer, Uint x, Uint y, Color *c)
204 {
205         register unsigned char *tmp8;
206
207         #ifdef _DEBUG
208         if (x + y * resolx >= resolx*resoly)
209         {
210                 printf ("getPixel ERROR : hors du tableau... %i, %i\n", x,y) ;
211                 exit (1) ;
212         }
213         #endif
214
215 #ifdef __BIG_ENDIAN__
216         c->b = *(unsigned char *)(tmp8 = (unsigned char*)(buffer + (x + y*resolx)));
217     c->r = *(unsigned char *)(++tmp8);
218     c->v = *(unsigned char *)(++tmp8);
219         c->b = *(unsigned char *)(++tmp8);
220                         
221 #else
222         /* ATTENTION AU PETIT INDIEN  */
223         c->b = *(unsigned char *)(tmp8 = (unsigned char*)(buffer + (x + y*resolx)));
224         c->v = *(unsigned char *)(++tmp8);
225         c->r = *(unsigned char *)(++tmp8);
226 /*      *c = (Color) buffer[x+y*WIDTH] ; */
227 #endif
228 }
229
230
231 inline void getPixelRGB_ (Uint *buffer, Uint x, Color *c)
232 {
233         register unsigned char *tmp8;
234
235         #ifdef _DEBUG
236         if ( x >= resolx*resoly )
237         {
238                 printf ("getPixel ERROR : hors du tableau... %i\n", x) ;
239                 exit (1) ;
240         }
241         #endif
242
243 #ifdef __BIG_ENDIAN__
244         c->b = *(unsigned char *)(tmp8 = (unsigned char*)(buffer + x));
245     c->r = *(unsigned char *)(++tmp8);
246     c->v = *(unsigned char *)(++tmp8);
247         c->b = *(unsigned char *)(++tmp8);
248                         
249 #else
250         /* ATTENTION AU PETIT INDIEN  */
251         c->b = *(unsigned char *)(tmp8 = (unsigned char*)(buffer + x));
252         c->v = *(unsigned char *)(++tmp8);
253         c->r = *(unsigned char *)(++tmp8);
254 /*      *c = (Color) buffer[x+y*WIDTH] ; */
255 #endif
256 }
257
258
259 /*===============================================================*/
260 void zoomFilterFastRGB (Uint *pix1,
261                                                 Uint *pix2,
262                                                 ZoomFilterData *zf,
263                                                 Uint resx, Uint resy)
264 {
265   static guint32 prevX = 0, prevY = 0;
266
267   static char reverse = 0 ; /*vitesse inversé..(zoom out) */
268   /*    static int perte = 100; // 100 = normal */
269   static unsigned char pertedec = 8 ;
270   static char firstTime = 1;
271   
272   Uint x, y;
273
274 /*  static unsigned int prevX = 0, prevY = 0; */
275   
276 #ifdef USE_ASM
277   expix1 = pix1 ;
278   expix2 = pix2 ;
279 #else
280   Color couleur;
281   Color col1,col2,col3,col4;
282   Uint position ;
283
284   static unsigned int *pos10 = 0;
285   static unsigned int *c1 = 0,
286         *c2 = 0,
287         *c3 = 0,
288         *c4 = 0;
289 #endif
290   
291   if ((prevX != resx) || (prevY != resy))
292         {
293           prevX = resx;
294           prevY = resy;
295 #ifndef USE_ASM
296           if (c1) free (c1) ;
297           if (c2) free (c2) ;
298           if (c3) free (c3) ;
299           if (c4) free (c4) ;
300           if (pos10) free (pos10) ;
301           c1=c2=c3=c4=pos10=0;
302 #else
303           if (coeffs) free (freecoeffs) ;
304           coeffs = 0;
305 #endif
306           middleX = resx / 2 ;
307           middleY = resy - 1;
308           firstTime = 1 ;
309           if (firedec) free (firedec);
310           firedec=0;
311         }
312         
313         if (zf)
314           {
315                 reverse = zf->reverse ;
316                 vitesse = zf->vitesse ;
317                 if (reverse)
318                   vitesse = 256 - vitesse ;
319 #ifndef USE_ASM
320                 sqrtperte = zf->sqrtperte ;
321 #endif
322                 pertedec = zf->pertedec ;
323                 middleX = zf->middleX ;
324                 middleY = zf->middleY ;
325                 theMode = zf->mode ;
326                 hPlaneEffect = zf->hPlaneEffect;
327                 vPlaneEffect = zf->vPlaneEffect;
328                 noisify = zf->noisify;
329           }
330         
331         if (firstTime || zf)
332           {
333                 
334                 /* generation d'une table de sinus */
335                 if (firstTime)
336                   {
337                         unsigned short us ;
338
339                         firstTime = 0;
340 #ifdef USE_ASM
341                         freecoeffs = (unsigned int *)
342                           malloc (resx*resy*2*sizeof(unsigned int)+128);
343                         coeffs = (guint32 *)((1+((unsigned int)(freecoeffs))/128)*128);
344
345 #else
346                         pos10 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
347                         c1 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
348                         c2 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
349                         c3 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
350                         c4 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
351 #endif
352                         for (us=0; us<0xffff; us++)
353                           {
354                                 sintable [us] = (int)(1024.0f * sin (us*2*3.31415f/0xffff)) ;
355                           }
356                         
357                         {
358                           int loopv ;
359                           firedec = (int *) malloc (prevY * sizeof(int)) ;
360                           for (loopv = prevY ; loopv != 0 ;)
361                                 {
362                                   static int decc = 0 ;
363                                   static int spdc = 0 ;
364                                   static int accel = 0 ;
365                                   loopv -- ;
366                                   firedec [loopv] = decc ;
367                                   decc += spdc / 10 ;
368                                   spdc+= RAND () % 3;
369                                   spdc-= RAND () % 3;
370                                   
371                                   if (decc > 4)
372                                         spdc -= 1 ;
373                                   if (decc < -4)
374                                         spdc += 1 ;
375                                   
376                                   if (spdc > 30)
377                                         spdc = spdc - RAND () % 3 + accel / 10 ;
378                                   if (spdc < -30)
379                                         spdc = spdc + RAND () % 3 + accel / 10 ;
380                                   
381                                   if (decc > 8 && spdc > 1 )
382                                         spdc -= RAND () % 3 - 2 ;
383                                   
384                                   if (decc < -8 && spdc < -1 )
385                                         spdc += RAND () % 3 + 2 ;
386                                   
387                                   if (decc > 8 || decc < -8)
388                                         decc = decc * 8 / 9 ;
389                                   
390                                   accel += RAND () % 2;
391                                   accel -= RAND () % 2;
392                                   if (accel > 20)
393                                         accel -= 2 ;
394                                   if (accel < -20)
395                                         accel += 2 ;
396                                 }
397                         }
398                   }
399                 
400                 
401                 /* generation du buffer */
402                 for (y = 0 ; y < prevY ; y++)
403                   for (x = 0; x < prevX ; x++)
404                         {
405                           int px,py;
406                           unsigned char coefv,coefh;
407                           
408                           /* calculer px et py en fonction de */
409                           /*   x,y,middleX,middleY et theMode */
410                           calculatePXandPY (x,y,&px, &py) ;
411                           if ((px == x << 4) && (py == y << 4))
412                                 py += 8 ;
413
414                           if ( (py<0) || (px<0) ||
415                                    (py>=(prevY-1)*sqrtperte) ||
416                                    (px>=(prevX-1)*sqrtperte))
417                                 {
418 #ifdef USE_ASM
419                                   coeffs[(y*prevX+x)*2]=0 ;
420                                   coeffs[(y*prevX+x)*2+1]=0;
421 #else
422                                   pos10[y*prevX+x]=0 ;
423                                   c1[y*prevX+x] = 0 ;
424                                   c2[y*prevX+x] = 0 ;
425                                   c3[y*prevX+x] = 0 ;
426                                   c4[y*prevX+x] = 0 ;
427 #endif
428                                 }
429                           else
430                                 {
431                                   int npx10 ;
432                                   int npy10 ;
433                                   int pos;
434
435                                   npx10 = (px/sqrtperte) ;
436                                   npy10 = (py/sqrtperte) ;
437                                   
438 /*                        if (npx10 >= prevX) fprintf(stderr,"error npx:%d",npx10);
439                           if (npy10 >= prevY) fprintf(stderr,"error npy:%d",npy10);
440 */                                
441                                   coefh = px % sqrtperte ;
442                                   coefv = py % sqrtperte ;                                
443 #ifdef USE_ASM
444                                 pos = (y*prevX+x)*2;
445                                 coeffs[pos] = (npx10 + prevX * npy10) * 4;
446                                 
447                                 if (!(coefh || coefv))
448                                   coeffs[pos+1] = (sqrtperte*sqrtperte-1) ;
449                                 else
450                                   coeffs[pos+1] = (
451                                         (sqrtperte-coefh) *
452                                         (sqrtperte-coefv) );
453                                 
454                                 coeffs[pos+1] |= (coefh * (sqrtperte-coefv)) << 8 ;
455                                 coeffs[pos+1] |= ((sqrtperte-coefh) * coefv) << 16 ;
456                                 coeffs[pos+1] |= (coefh * coefv)<<24 ;
457 #else
458                                 pos = y*prevX+x;
459                                 pos10[pos]= npx10 + prevX * npy10 ;
460
461                                 if (!(coefh || coefv))
462                                         c1[pos] = sqrtperte*sqrtperte-1 ;
463                                 else
464                                         c1[pos] = (sqrtperte-coefh) * (sqrtperte-coefv);
465                                 
466                                 c2[pos] = coefh * (sqrtperte-coefv) ;
467                                 c3[pos] = (sqrtperte-coefh) * coefv ;
468                                 c4[pos] = coefh * coefv ;
469 #endif
470                                 }
471                         }
472           }
473         
474 #ifdef USE_ASM
475
476         #ifdef MMX
477         zoom_width = prevX ;
478         mmx_zoom_size = prevX * prevY ;
479         mmx_zoom () ;
480         #endif
481         
482         #ifdef POWERPC
483         zoom_width = prevX;
484         if (useAltivec)
485         {
486             ppcsize4 = ((unsigned int)(prevX*prevY))/4;
487             ppc_zoom_altivec();
488         }
489         else
490         {
491             ppcsize4 = ((unsigned int)(prevX*prevY));
492             ppc_zoom();        
493         }
494         #endif
495 #else
496         for (position=0; position<prevX*prevY; position++)
497           {
498                 getPixelRGB_(pix1,pos10[position],&col1);
499                 getPixelRGB_(pix1,pos10[position]+1,&col2);
500                 getPixelRGB_(pix1,pos10[position]+prevX,&col3);
501                 getPixelRGB_(pix1,pos10[position]+prevX+1,&col4);
502                 
503                 couleur.r = col1.r * c1[position]
504                     + col2.r * c2[position]
505                     + col3.r * c3[position]
506                     + col4.r * c4[position];
507                 couleur.r >>= pertedec ;
508
509                 couleur.v = col1.v * c1[position]
510                     + col2.v * c2[position]
511                     + col3.v * c3[position]
512                     + col4.v * c4[position];
513                 couleur.v >>= pertedec ;
514                 
515                 couleur.b = col1.b * c1[position]
516                     + col2.b * c2[position]
517                     + col3.b * c3[position]
518                     + col4.b * c4[position];
519                 couleur.b >>= pertedec ;
520                 
521                 setPixelRGB_(pix2,position,couleur);
522         }
523 #endif
524 }
525
526
527 void pointFilter(Uint *pix1, Color c,
528                                  float t1, float t2, float t3, float t4,
529                                  Uint cycle)
530 {
531   Uint x = (Uint)((int)middleX + (int)(t1*cos((float)cycle/t3)));
532   Uint y = (Uint)((int)middleY + (int)(t2*sin((float)cycle/t4)));
533   if ((x>1) && (y>1) && (x<resolx-2) && (y<resoly-2))
534         {
535           setPixelRGB(pix1, x+1, y, c);
536           setPixelRGB(pix1, x, y+1, c);
537           setPixelRGB(pix1, x+1, y+1, WHITE);
538           setPixelRGB(pix1, x+2, y+1, c);
539           setPixelRGB(pix1, x+1, y+2, c);
540         }
541 }