564e29a875035e32d79cffe145c35e3a339286f4
[platform/upstream/gst-plugins-good.git] / gst / goom / filters.c
1 // --- CHUI EN TRAIN DE SUPPRIMER LES EXTERN RESOLX ET C_RESOLY ---
2
3 /* filter.c version 0.7
4 * contient les filtres applicable a un buffer
5 * creation : 01/10/2000
6 *  -ajout de sinFilter()
7 *  -ajout de zoomFilter()
8 *  -copie de zoomFilter() en zoomFilterRGB(), gerant les 3 couleurs
9 *  -optimisation de sinFilter (utilisant une table de sin)
10 *       -asm
11 *       -optimisation de la procedure de generation du buffer de transformation
12 *               la vitesse est maintenant comprise dans [0..128] au lieu de [0..100]
13 */
14
15 /* #define _DEBUG_PIXEL */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <string.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <stdio.h>
25
26 #ifdef HAVE_INTTYPES_H
27 #include <inttypes.h>
28 #endif
29
30 #include "goom_filters.h"
31 #include "goom_graphic.h"
32 #include "goom_tools.h"
33 #include "goom_plugin_info.h"
34 #include "goom_fx.h"
35 #include "v3d.h"
36
37 /* TODO : MOVE THIS AWAY !!! */
38 /* jeko: j'ai essayer de le virer, mais si on veut les laisser inline c'est un peu lourdo... */
39 static inline void
40 setPixelRGB (PluginInfo * goomInfo, Pixel * buffer, Uint x, Uint y, Color c)
41 {
42   Pixel i;
43
44   i.channels.b = c.b;
45   i.channels.g = c.v;
46   i.channels.r = c.r;
47   *(buffer + (x + y * goomInfo->screen.width)) = i;
48 }
49
50 static inline void
51 setPixelRGB_ (Pixel * buffer, Uint x, Color c)
52 {
53   buffer[x].channels.r = c.r;
54   buffer[x].channels.g = c.v;
55   buffer[x].channels.b = c.b;
56 }
57
58 static inline void
59 getPixelRGB (PluginInfo * goomInfo, Pixel * buffer, Uint x, Uint y, Color * c)
60 {
61   Pixel i = *(buffer + (x + y * goomInfo->screen.width));
62
63   c->b = i.channels.b;
64   c->v = i.channels.g;
65   c->r = i.channels.r;
66 }
67
68 static inline void
69 getPixelRGB_ (Pixel * buffer, Uint x, Color * c)
70 {
71   Pixel i = *(buffer + x);
72
73   c->b = i.channels.b;
74   c->v = i.channels.g;
75   c->r = i.channels.r;
76 }
77
78 /* END TODO */
79
80
81 /* DEPRECATED */
82 // retourne x>>s , en testant le signe de x
83 //#define ShiftRight(_x,_s) (((_x)<0) ? -(-(_x)>>(_s)) : ((_x)>>(_s)))
84 //#define EFFECT_DISTORS 4
85 //#define EFFECT_DISTORS_SL 2
86 //#define INTERLACE_ADD 9
87 //#define INTERLACE_AND 0xf
88 /* END DEPRECATED */
89
90 #define BUFFPOINTNB 16
91 #define BUFFPOINTNBF 16.0f
92 #define BUFFPOINTMASK 0xffff
93
94 #define sqrtperte 16
95 /* faire : a % sqrtperte <=> a & pertemask */
96 #define PERTEMASK 0xf
97 /* faire : a / sqrtperte <=> a >> PERTEDEC */
98 #define PERTEDEC 4
99
100 /* pure c version of the zoom filter */
101 static void c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX,
102     unsigned int prevY, signed int *brutS, signed int *brutD, int buffratio,
103     int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
104
105 /* simple wrapper to give it the same proto than the others */
106 void
107 zoom_filter_c (int sizeX, int sizeY, Pixel * src, Pixel * dest, int *brutS,
108     int *brutD, int buffratio, int precalCoef[16][16])
109 {
110   c_zoom (src, dest, sizeX, sizeY, brutS, brutD, buffratio, precalCoef);
111 }
112
113 static void generatePrecalCoef (int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
114
115
116 typedef struct _ZOOM_FILTER_FX_WRAPPER_DATA
117 {
118
119   PluginParam enabled_bp;
120   PluginParameters params;
121
122   unsigned int *coeffs, *freecoeffs;
123
124   signed int *brutS, *freebrutS;        /* source */
125   signed int *brutD, *freebrutD;        /* dest */
126   signed int *brutT, *freebrutT;        /* temp (en cours de generation) */
127
128   guint32 zoom_width;
129
130   unsigned int prevX, prevY;
131
132   float general_speed;
133   int reverse;                  /* reverse the speed */
134   char theMode;
135   int waveEffect;
136   int hypercosEffect;
137   int vPlaneEffect;
138   int hPlaneEffect;
139   char noisify;
140   int middleX, middleY;
141
142   int mustInitBuffers;
143   int interlace_start;
144
145     /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
146   int buffratio;
147   int *firedec;
148
149     /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
150   int precalCoef[BUFFPOINTNB][BUFFPOINTNB];
151
152     /** calculatePXandPY statics */
153   int wave;
154   int wavesp;
155
156 } ZoomFilterFXWrapperData;
157
158
159
160
161 static inline v2g
162 zoomVector (ZoomFilterFXWrapperData * data, float X, float Y)
163 {
164   v2g vecteur;
165   float vx, vy;
166   float sq_dist = X * X + Y * Y;
167
168   /*    sx = (X < 0.0f) ? -1.0f : 1.0f;
169      sy = (Y < 0.0f) ? -1.0f : 1.0f;
170    */
171   float coefVitesse = (1.0f + data->general_speed) / 50.0f;
172
173   // Effects
174
175   /* Centralized FX */
176
177   switch (data->theMode) {
178     case CRYSTAL_BALL_MODE:
179       coefVitesse -= (sq_dist - 0.3f) / 15.0f;
180       break;
181     case AMULETTE_MODE:
182       coefVitesse += sq_dist * 3.5f;
183       break;
184     case WAVE_MODE:
185       coefVitesse += sin (sq_dist * 20.0f) / 100.0f;
186       break;
187     case SCRUNCH_MODE:
188       coefVitesse += sq_dist / 10.0f;
189       break;
190       //case HYPERCOS1_MODE:
191       break;
192       //case HYPERCOS2_MODE:
193       break;
194       //case YONLY_MODE:
195       break;
196     case SPEEDWAY_MODE:
197       coefVitesse *= 4.0f * Y;
198       break;
199     default:
200       break;
201   }
202
203   if (coefVitesse < -2.01f)
204     coefVitesse = -2.01f;
205   if (coefVitesse > 2.01f)
206     coefVitesse = 2.01f;
207
208   vx = coefVitesse * X;
209   vy = coefVitesse * Y;
210
211   /* Amulette 2 */
212   // vx = X * tan(dist);
213   // vy = Y * tan(dist);
214
215   /* Rotate */
216   //vx = (X+Y)*0.1;
217   //vy = (Y-X)*0.1;
218
219
220   // Effects adds-on
221
222   /* Noise */
223   if (data->noisify) {
224     vx += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
225     vy += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
226   }
227
228   /* Hypercos */
229   if (data->hypercosEffect) {
230     vx += sin (Y * 10.0f) / 120.0f;
231     vy += sin (X * 10.0f) / 120.0f;
232   }
233
234   /* H Plane */
235   if (data->hPlaneEffect)
236     vx += Y * 0.0025f * data->hPlaneEffect;
237
238   /* V Plane */
239   if (data->vPlaneEffect)
240     vy += X * 0.0025f * data->vPlaneEffect;
241
242   /* TODO : Water Mode */
243   //    if (data->waveEffect)
244
245   vecteur.x = vx;
246   vecteur.y = vy;
247
248   return vecteur;
249 }
250
251
252 /*
253  * Makes a stripe of a transform buffer (brutT)
254  *
255  * The transform is (in order) :
256  * Translation (-data->middleX, -data->middleY)
257  * Homothetie (Center : 0,0   Coeff : 2/data->prevX)
258  */
259 static void
260 makeZoomBufferStripe (ZoomFilterFXWrapperData * data, int INTERLACE_INCR)
261 {
262   // Position of the pixel to compute in pixmap coordinates
263   Uint x, y;
264
265   // Where (verticaly) to stop generating the buffer stripe
266   int maxEnd = (data->interlace_start + INTERLACE_INCR);
267
268   // Ratio from pixmap to normalized coordinates
269   float ratio = 2.0f / ((float) data->prevX);
270
271   // Ratio from normalized to virtual pixmap coordinates
272   float inv_ratio = BUFFPOINTNBF / ratio;
273   float min = ratio / BUFFPOINTNBF;
274
275   // Y position of the pixel to compute in normalized coordinates
276   float Y = ((float) (data->interlace_start - data->middleY)) * ratio;
277
278   maxEnd = data->prevY;
279   if (maxEnd > (data->interlace_start + INTERLACE_INCR))
280     maxEnd = (data->interlace_start + INTERLACE_INCR);
281
282   for (y = data->interlace_start;
283       (y < data->prevY) && ((signed int) y < maxEnd); y++) {
284     Uint premul_y_prevX = y * data->prevX * 2;
285     float X = -((float) data->middleX) * ratio;
286
287     for (x = 0; x < data->prevX; x++) {
288       v2g vector = zoomVector (data, X, Y);
289
290       /* Finish and avoid null displacement */
291       if (fabs (vector.x) < min)
292         vector.x = (vector.x < 0.0f) ? -min : min;
293       if (fabs (vector.y) < min)
294         vector.y = (vector.y < 0.0f) ? -min : min;
295
296       data->brutT[premul_y_prevX] =
297           ((int) ((X - vector.x) * inv_ratio) +
298           ((int) (data->middleX * BUFFPOINTNB)));
299       data->brutT[premul_y_prevX + 1] =
300           ((int) ((Y - vector.y) * inv_ratio) +
301           ((int) (data->middleY * BUFFPOINTNB)));
302       premul_y_prevX += 2;
303       X += ratio;
304     }
305     Y += ratio;
306   }
307   data->interlace_start += INTERLACE_INCR;
308   if (y >= data->prevY - 1)
309     data->interlace_start = -1;
310 }
311
312
313 /*
314  * calculer px et py en fonction de x,y,middleX,middleY et theMode
315  * px et py indique la nouvelle position (en sqrtperte ieme de pixel)
316  * (valeur * 16)
317  
318  inline void calculatePXandPY (PluginInfo *goomInfo, ZoomFilterFXWrapperData *data, int x, int y, int *px, int *py)
319  {
320      if (data->theMode == WATER_MODE) {
321          int yy;
322          
323          yy = y + goom_irand(goomInfo->gRandom, 4) - goom_irand(goomInfo->gRandom, 4) + data->wave / 10;
324          if (yy < 0)
325              yy = 0;
326          if (yy >= (signed int)goomInfo->screen.height)
327              yy = goomInfo->screen.height - 1;
328          
329          *px = (x << 4) + data->firedec[yy] + (data->wave / 10);
330          *py = (y << 4) + 132 - ((data->vitesse < 131) ? data->vitesse : 130);
331          
332          data->wavesp += goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
333          if (data->wave < -10)
334              data->wavesp += 2;
335          if (data->wave > 10)
336              data->wavesp -= 2;
337          data->wave += (data->wavesp / 10) + goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
338          if (data->wavesp > 100)
339              data->wavesp = (data->wavesp * 9) / 10;
340      }
341      else {
342          int     dist = 0, vx9, vy9;
343          int     vx, vy;
344          int     ppx, ppy;
345          int     fvitesse = data->vitesse << 4;
346          
347          if (data->noisify) {
348              x += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
349              y += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
350          }
351          vx = (x - data->middleX) << 9;
352          vy = (y - data->middleY) << 9;
353          
354          if (data->hPlaneEffect)
355              vx += data->hPlaneEffect * (y - data->middleY);
356          
357          if (data->vPlaneEffect)
358              vy += data->vPlaneEffect * (x - data->middleX);
359          
360          if (data->waveEffect) {
361              fvitesse *=
362              1024 +
363              ShiftRight (goomInfo->sintable
364                          [(unsigned short) (dist * 0xffff + EFFECT_DISTORS)], 6);
365              fvitesse /= 1024;
366          }
367          
368          if (data->hypercosEffect) {
369              vx += ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
370              vy += ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
371          }
372          
373          vx9 = ShiftRight (vx, 9);
374          vy9 = ShiftRight (vy, 9);
375          dist = vx9 * vx9 + vy9 * vy9;
376          
377          switch (data->theMode) {
378              case WAVE_MODE:
379                  fvitesse *=
380                  1024 +
381                  ShiftRight (goomInfo->sintable
382                              [(unsigned short) (dist * 0xffff * EFFECT_DISTORS)], 6);
383                  fvitesse>>=10;
384                  break;
385              case CRYSTAL_BALL_MODE:
386                  fvitesse += (dist >> (10-EFFECT_DISTORS_SL));
387                  break;
388              case AMULETTE_MODE:
389                  fvitesse -= (dist >> (4 - EFFECT_DISTORS_SL));
390                  break;
391              case SCRUNCH_MODE:
392                  fvitesse -= (dist >> (10 - EFFECT_DISTORS_SL));
393                  break;
394              case HYPERCOS1_MODE:
395                  vx = vx + ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
396                  vy = vy + ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
397                  break;
398              case HYPERCOS2_MODE:
399                  vx =
400                  vx + ShiftRight (goomInfo->sintable[(-ShiftRight (vy, 1) + dist) & 0xffff], 0);
401                  vy =
402                      vy + ShiftRight (goomInfo->sintable[(ShiftRight (vx, 1) + dist) & 0xffff], 0);
403                  fvitesse = 128 << 4;
404                  break;
405              case YONLY_MODE:
406                  fvitesse *= 1024 + ShiftRight (goomInfo->sintable[vy & 0xffff], 6);
407                  fvitesse >>= 10;
408                  break;
409              case SPEEDWAY_MODE:
410                  fvitesse -= (ShiftRight(vy,10-EFFECT_DISTORS_SL));
411                  break;
412          }
413          
414          if (fvitesse < -3024)
415              fvitesse = -3024;
416          
417          if (vx < 0)                                                                    // pb avec decalage sur nb negatif
418              ppx = -(-(vx * fvitesse) >> 16);
419          // 16 = 9 + 7 (7 = nb chiffre virgule de vitesse * (v = 128 => immobile)
420          //    * * * * * 9 = nb chiffre virgule de vx) 
421          else
422              ppx = ((vx * fvitesse) >> 16);
423          
424          if (vy < 0)
425              ppy = -(-(vy * fvitesse) >> 16);
426          else
427              ppy = ((vy * fvitesse) >> 16);
428          
429          *px = (data->middleX << 4) + ppx;
430          *py = (data->middleY << 4) + ppy;
431      }
432  }
433  */
434
435
436
437 static void
438 c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX, unsigned int prevY,
439     signed int *brutS, signed int *brutD, int buffratio, int precalCoef[16][16])
440 {
441   int myPos, myPos2;
442   Color couleur;
443
444   unsigned int ax = (prevX - 1) << PERTEDEC, ay = (prevY - 1) << PERTEDEC;
445
446   int bufsize = prevX * prevY * 2;
447   int bufwidth = prevX;
448
449   expix1[0].val = expix1[prevX - 1].val = expix1[prevX * prevY - 1].val =
450       expix1[prevX * prevY - prevX].val = 0;
451
452   for (myPos = 0; myPos < bufsize; myPos += 2) {
453     Color col1, col2, col3, col4;
454     int c1, c2, c3, c4, px, py;
455     int pos;
456     int coeffs;
457
458     int brutSmypos = brutS[myPos];
459
460     myPos2 = myPos + 1;
461
462     px = brutSmypos + (((brutD[myPos] -
463                 brutSmypos) * buffratio) >> BUFFPOINTNB);
464     brutSmypos = brutS[myPos2];
465     py = brutSmypos + (((brutD[myPos2] -
466                 brutSmypos) * buffratio) >> BUFFPOINTNB);
467
468     if ((py >= ay) || (px >= ax)) {
469       pos = coeffs = 0;
470     } else {
471       pos = ((px >> PERTEDEC) + prevX * (py >> PERTEDEC));
472       /* coef en modulo 15 */
473       coeffs = precalCoef[px & PERTEMASK][py & PERTEMASK];
474     }
475     getPixelRGB_ (expix1, pos, &col1);
476     getPixelRGB_ (expix1, pos + 1, &col2);
477     getPixelRGB_ (expix1, pos + bufwidth, &col3);
478     getPixelRGB_ (expix1, pos + bufwidth + 1, &col4);
479
480     c1 = coeffs;
481     c2 = (c1 >> 8) & 0xFF;
482     c3 = (c1 >> 16) & 0xFF;
483     c4 = (c1 >> 24) & 0xFF;
484     c1 = c1 & 0xff;
485
486     couleur.r = col1.r * c1 + col2.r * c2 + col3.r * c3 + col4.r * c4;
487     if (couleur.r > 5)
488       couleur.r -= 5;
489     couleur.r >>= 8;
490
491     couleur.v = col1.v * c1 + col2.v * c2 + col3.v * c3 + col4.v * c4;
492     if (couleur.v > 5)
493       couleur.v -= 5;
494     couleur.v >>= 8;
495
496     couleur.b = col1.b * c1 + col2.b * c2 + col3.b * c3 + col4.b * c4;
497     if (couleur.b > 5)
498       couleur.b -= 5;
499     couleur.b >>= 8;
500
501     setPixelRGB_ (expix2, myPos >> 1, couleur);
502   }
503 }
504
505 /** generate the water fx horizontal direction buffer */
506 static void
507 generateTheWaterFXHorizontalDirectionBuffer (PluginInfo * goomInfo,
508     ZoomFilterFXWrapperData * data)
509 {
510
511   int loopv;
512   int decc = goom_irand (goomInfo->gRandom, 8) - 4;
513   int spdc = goom_irand (goomInfo->gRandom, 8) - 4;
514   int accel = goom_irand (goomInfo->gRandom, 8) - 4;
515
516   for (loopv = data->prevY; loopv != 0;) {
517
518     loopv--;
519     data->firedec[loopv] = decc;
520     decc += spdc / 10;
521     spdc +=
522         goom_irand (goomInfo->gRandom, 3) - goom_irand (goomInfo->gRandom, 3);
523
524     if (decc > 4)
525       spdc -= 1;
526     if (decc < -4)
527       spdc += 1;
528
529     if (spdc > 30)
530       spdc = spdc - goom_irand (goomInfo->gRandom, 3) + accel / 10;
531     if (spdc < -30)
532       spdc = spdc + goom_irand (goomInfo->gRandom, 3) + accel / 10;
533
534     if (decc > 8 && spdc > 1)
535       spdc -= goom_irand (goomInfo->gRandom, 3) - 2;
536
537     if (decc < -8 && spdc < -1)
538       spdc += goom_irand (goomInfo->gRandom, 3) + 2;
539
540     if (decc > 8 || decc < -8)
541       decc = decc * 8 / 9;
542
543     accel +=
544         goom_irand (goomInfo->gRandom, 2) - goom_irand (goomInfo->gRandom, 2);
545     if (accel > 20)
546       accel -= 2;
547     if (accel < -20)
548       accel += 2;
549   }
550 }
551
552
553
554 /**
555 * Main work for the dynamic displacement map.
556  * 
557  * Reads data from pix1, write to pix2.
558  *
559  * Useful datas for this FX are stored in ZoomFilterData.
560  * 
561  * If you think that this is a strange function name, let me say that a long time ago,
562  *  there has been a slow version and a gray-level only one. Then came these function,
563  *  fast and workin in RGB colorspace ! nice but it only was applying a zoom to the image.
564  *  So that is why you have this name, for the nostalgy of the first days of goom
565  *  when it was just a tiny program writen in Turbo Pascal on my i486...
566  */
567 void
568 zoomFilterFastRGB (PluginInfo * goomInfo, Pixel * pix1, Pixel * pix2,
569     ZoomFilterData * zf, Uint resx, Uint resy, int switchIncr, float switchMult)
570 {
571   Uint x, y;
572
573   ZoomFilterFXWrapperData *data =
574       (ZoomFilterFXWrapperData *) goomInfo->zoomFilter_fx.fx_data;
575
576   if (!BVAL (data->enabled_bp))
577     return;
578
579     /** changement de taille **/
580   if ((data->prevX != resx) || (data->prevY != resy)) {
581     data->prevX = resx;
582     data->prevY = resy;
583
584     if (data->brutS)
585       free (data->freebrutS);
586     data->brutS = 0;
587     if (data->brutD)
588       free (data->freebrutD);
589     data->brutD = 0;
590     if (data->brutT)
591       free (data->freebrutT);
592     data->brutT = 0;
593
594     data->middleX = resx / 2;
595     data->middleY = resy / 2;
596     data->mustInitBuffers = 1;
597     if (data->firedec)
598       free (data->firedec);
599     data->firedec = 0;
600   }
601
602   if (data->interlace_start != -2)
603     zf = NULL;
604
605     /** changement de config **/
606   if (zf) {
607     data->reverse = zf->reverse;
608     data->general_speed = (float) (zf->vitesse - 128) / 128.0f;
609     if (data->reverse)
610       data->general_speed = -data->general_speed;
611     data->middleX = zf->middleX;
612     data->middleY = zf->middleY;
613     data->theMode = zf->mode;
614     data->hPlaneEffect = zf->hPlaneEffect;
615     data->vPlaneEffect = zf->vPlaneEffect;
616     data->waveEffect = zf->waveEffect;
617     data->hypercosEffect = zf->hypercosEffect;
618     data->noisify = zf->noisify;
619     data->interlace_start = 0;
620   }
621
622
623   if (data->mustInitBuffers) {
624
625     data->mustInitBuffers = 0;
626     data->freebrutS =
627         (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
628     data->brutS =
629         (gint32 *) ((1 + ((uintptr_t) (data->freebrutS)) / 128) * 128);
630
631     data->freebrutD =
632         (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
633     data->brutD =
634         (gint32 *) ((1 + ((uintptr_t) (data->freebrutD)) / 128) * 128);
635
636     data->freebrutT =
637         (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
638     data->brutT =
639         (gint32 *) ((1 + ((uintptr_t) (data->freebrutT)) / 128) * 128);
640
641     data->buffratio = 0;
642
643     data->firedec = (int *) malloc (data->prevY * sizeof (int));
644     generateTheWaterFXHorizontalDirectionBuffer (goomInfo, data);
645
646     data->interlace_start = 0;
647     makeZoomBufferStripe (data, resy);
648
649     /* Copy the data from temp to dest and source */
650     memcpy (data->brutS, data->brutT, resx * resy * 2 * sizeof (int));
651     memcpy (data->brutD, data->brutT, resx * resy * 2 * sizeof (int));
652   }
653
654   /* generation du buffer de trans */
655   if (data->interlace_start == -1) {
656
657     /* sauvegarde de l'etat actuel dans la nouvelle source
658      * TODO: write that in MMX (has been done in previous version, but did not follow some new fonctionnalities) */
659     y = data->prevX * data->prevY * 2;
660     for (x = 0; x < y; x += 2) {
661       int brutSmypos = data->brutS[x];
662       int x2 = x + 1;
663
664       data->brutS[x] =
665           brutSmypos + (((data->brutD[x] -
666                   brutSmypos) * data->buffratio) >> BUFFPOINTNB);
667       brutSmypos = data->brutS[x2];
668       data->brutS[x2] =
669           brutSmypos + (((data->brutD[x2] -
670                   brutSmypos) * data->buffratio) >> BUFFPOINTNB);
671     }
672     data->buffratio = 0;
673   }
674
675   if (data->interlace_start == -1) {
676     signed int *tmp;
677
678     tmp = data->brutD;
679     data->brutD = data->brutT;
680     data->brutT = tmp;
681     tmp = data->freebrutD;
682     data->freebrutD = data->freebrutT;
683     data->freebrutT = tmp;
684     data->interlace_start = -2;
685   }
686
687   if (data->interlace_start >= 0) {
688     /* creation de la nouvelle destination */
689     makeZoomBufferStripe (data, resy / 16);
690   }
691
692   if (switchIncr != 0) {
693     data->buffratio += switchIncr;
694     if (data->buffratio > BUFFPOINTMASK)
695       data->buffratio = BUFFPOINTMASK;
696   }
697
698   if (switchMult != 1.0f) {
699     data->buffratio = (int) ((float) BUFFPOINTMASK * (1.0f - switchMult) +
700         (float) data->buffratio * switchMult);
701   }
702
703   data->zoom_width = data->prevX;
704
705   goomInfo->methods.zoom_filter (data->prevX, data->prevY, pix1, pix2,
706       data->brutS, data->brutD, data->buffratio, data->precalCoef);
707 }
708
709 static void
710 generatePrecalCoef (int precalCoef[16][16])
711 {
712   int coefh, coefv;
713
714   for (coefh = 0; coefh < 16; coefh++) {
715     for (coefv = 0; coefv < 16; coefv++) {
716
717       int i;
718       int diffcoeffh;
719       int diffcoeffv;
720
721       diffcoeffh = sqrtperte - coefh;
722       diffcoeffv = sqrtperte - coefv;
723
724       if (!(coefh || coefv)) {
725         i = 255;
726       } else {
727         int i1, i2, i3, i4;
728
729         i1 = diffcoeffh * diffcoeffv;
730         i2 = coefh * diffcoeffv;
731         i3 = diffcoeffh * coefv;
732         i4 = coefh * coefv;
733
734         // TODO: faire mieux...
735         if (i1)
736           i1--;
737         if (i2)
738           i2--;
739         if (i3)
740           i3--;
741         if (i4)
742           i4--;
743
744         i = (i1) | (i2 << 8) | (i3 << 16) | (i4 << 24);
745       }
746       precalCoef[coefh][coefv] = i;
747     }
748   }
749 }
750
751 /* VisualFX Wrapper */
752
753 static void
754 zoomFilterVisualFXWrapper_init (struct _VISUAL_FX *_this, PluginInfo * info)
755 {
756   ZoomFilterFXWrapperData *data =
757       (ZoomFilterFXWrapperData *) malloc (sizeof (ZoomFilterFXWrapperData));
758
759   data->coeffs = 0;
760   data->freecoeffs = 0;
761   data->brutS = 0;
762   data->freebrutS = 0;
763   data->brutD = 0;
764   data->freebrutD = 0;
765   data->brutT = 0;
766   data->freebrutT = 0;
767   data->prevX = 0;
768   data->prevY = 0;
769
770   data->mustInitBuffers = 1;
771   data->interlace_start = -2;
772
773   data->general_speed = 0.0f;
774   data->reverse = 0;
775   data->theMode = AMULETTE_MODE;
776   data->waveEffect = 0;
777   data->hypercosEffect = 0;
778   data->vPlaneEffect = 0;
779   data->hPlaneEffect = 0;
780   data->noisify = 2;
781
782     /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
783   data->buffratio = 0;
784   data->firedec = 0;
785
786   data->wave = data->wavesp = 0;
787
788   data->enabled_bp = secure_b_param ("Enabled", 1);
789
790   data->params = plugin_parameters ("Zoom Filter", 1);
791   data->params.params[0] = &data->enabled_bp;
792
793   _this->params = &data->params;
794   _this->fx_data = (void *) data;
795
796     /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
797   generatePrecalCoef (data->precalCoef);
798 }
799
800 static void
801 zoomFilterVisualFXWrapper_free (struct _VISUAL_FX *_this)
802 {
803   ZoomFilterFXWrapperData *data = (ZoomFilterFXWrapperData *) _this->fx_data;
804
805   if (data->freebrutT)
806     free (data->freebrutT);
807   if (data->freebrutS)
808     free (data->freebrutS);
809   if (data->freebrutD)
810     free (data->freebrutD);
811   if (data->firedec)
812     free (data->firedec);
813
814   goom_plugin_parameters_free (_this->params);
815
816   free (_this->fx_data);
817 }
818
819 static void
820 zoomFilterVisualFXWrapper_apply (struct _VISUAL_FX *_this, Pixel * src,
821     Pixel * dest, PluginInfo * info)
822 {
823 }
824
825 VisualFX
826 zoomFilterVisualFXWrapper_create (void)
827 {
828   VisualFX fx;
829
830   fx.init = zoomFilterVisualFXWrapper_init;
831   fx.free = zoomFilterVisualFXWrapper_free;
832   fx.apply = zoomFilterVisualFXWrapper_apply;
833   fx.params = NULL;
834   fx.fx_data = NULL;
835   return fx;
836 }
837
838
839 /* TODO : MOVE THIS AWAY */
840
841 void
842 pointFilter (PluginInfo * goomInfo, Pixel * pix1, Color c, float t1, float t2,
843     float t3, float t4, Uint cycle)
844 {
845   Uint x = (Uint) ((int) (goomInfo->screen.width / 2)
846       + (int) (t1 * cos ((float) cycle / t3)));
847   Uint y = (Uint) ((int) (goomInfo->screen.height / 2)
848       + (int) (t2 * sin ((float) cycle / t4)));
849
850   if ((x > 1) && (y > 1) && (x < goomInfo->screen.width - 2)
851       && (y < goomInfo->screen.height - 2)) {
852     setPixelRGB (goomInfo, pix1, x + 1, y, c);
853     setPixelRGB (goomInfo, pix1, x, y + 1, c);
854     setPixelRGB (goomInfo, pix1, x + 1, y + 1, WHITE);
855     setPixelRGB (goomInfo, pix1, x + 2, y + 1, c);
856     setPixelRGB (goomInfo, pix1, x + 1, y + 2, c);
857   }
858 }