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