2 * Copyright (C) <2003> iOS-Software
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 // --- CHUI EN TRAIN DE SUPPRIMER LES EXTERN RESOLX ET C_RESOLY ---
21 /* filter.c version 0.7
22 * contient les filtres applicable a un buffer
23 * creation : 01/10/2000
24 * -ajout de sinFilter()
25 * -ajout de zoomFilter()
26 * -copie de zoomFilter() en zoomFilterRGB(), gerant les 3 couleurs
27 * -optimisation de sinFilter (utilisant une table de sin)
29 * -optimisation de la procedure de generation du buffer de transformation
30 * la vitesse est maintenant comprise dans [0..128] au lieu de [0..100]
33 /* #define _DEBUG_PIXEL */
44 #ifdef HAVE_INTTYPES_H
48 #include "goom_filters.h"
49 #include "goom_graphic.h"
50 #include "goom_tools.h"
51 #include "goom_plugin_info.h"
55 /* TODO : MOVE THIS AWAY !!! */
56 /* jeko: j'ai essayer de le virer, mais si on veut les laisser inline c'est un peu lourdo... */
58 setPixelRGB (PluginInfo * goomInfo, Pixel * buffer, Uint x, Uint y, Color c)
65 *(buffer + (x + y * goomInfo->screen.width)) = i;
69 setPixelRGB_ (Pixel * buffer, Uint x, Color c)
71 buffer[x].channels.r = c.r;
72 buffer[x].channels.g = c.v;
73 buffer[x].channels.b = c.b;
77 getPixelRGB (PluginInfo * goomInfo, Pixel * buffer, Uint x, Uint y, Color * c)
79 Pixel i = *(buffer + (x + y * goomInfo->screen.width));
87 getPixelRGB_ (Pixel * buffer, Uint x, Color * c)
89 Pixel i = *(buffer + x);
100 // retourne x>>s , en testant le signe de x
101 //#define ShiftRight(_x,_s) (((_x)<0) ? -(-(_x)>>(_s)) : ((_x)>>(_s)))
102 //#define EFFECT_DISTORS 4
103 //#define EFFECT_DISTORS_SL 2
104 //#define INTERLACE_ADD 9
105 //#define INTERLACE_AND 0xf
108 #define BUFFPOINTNB 16
109 #define BUFFPOINTNBF 16.0f
110 #define BUFFPOINTMASK 0xffff
113 /* faire : a % sqrtperte <=> a & pertemask */
114 #define PERTEMASK 0xf
115 /* faire : a / sqrtperte <=> a >> PERTEDEC */
118 /* pure c version of the zoom filter */
119 static void c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX,
120 unsigned int prevY, signed int *brutS, signed int *brutD, int buffratio,
121 int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
123 /* simple wrapper to give it the same proto than the others */
125 zoom_filter_c (int sizeX, int sizeY, Pixel * src, Pixel * dest, int *brutS,
126 int *brutD, int buffratio, int precalCoef[16][16])
128 c_zoom (src, dest, sizeX, sizeY, brutS, brutD, buffratio, precalCoef);
131 static void generatePrecalCoef (int precalCoef[BUFFPOINTNB][BUFFPOINTNB]);
134 typedef struct _ZOOM_FILTER_FX_WRAPPER_DATA
137 PluginParam enabled_bp;
138 PluginParameters params;
140 unsigned int *coeffs, *freecoeffs;
142 signed int *brutS, *freebrutS; /* source */
143 signed int *brutD, *freebrutD; /* dest */
144 signed int *brutT, *freebrutT; /* temp (en cours de generation) */
148 unsigned int prevX, prevY;
151 int reverse; /* reverse the speed */
158 int middleX, middleY;
163 /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
167 /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
168 int precalCoef[BUFFPOINTNB][BUFFPOINTNB];
170 /** calculatePXandPY statics */
174 } ZoomFilterFXWrapperData;
180 zoomVector (ZoomFilterFXWrapperData * data, float X, float Y)
184 float sq_dist = X * X + Y * Y;
186 /* sx = (X < 0.0f) ? -1.0f : 1.0f;
187 sy = (Y < 0.0f) ? -1.0f : 1.0f;
189 float coefVitesse = (1.0f + data->general_speed) / 50.0f;
195 switch (data->theMode) {
196 case CRYSTAL_BALL_MODE:
197 coefVitesse -= (sq_dist - 0.3f) / 15.0f;
200 coefVitesse += sq_dist * 3.5f;
203 coefVitesse += sin (sq_dist * 20.0f) / 100.0f;
206 coefVitesse += sq_dist / 10.0f;
208 //case HYPERCOS1_MODE:
210 //case HYPERCOS2_MODE:
215 coefVitesse *= 4.0f * Y;
221 if (coefVitesse < -2.01f)
222 coefVitesse = -2.01f;
223 if (coefVitesse > 2.01f)
226 vx = coefVitesse * X;
227 vy = coefVitesse * Y;
230 // vx = X * tan(dist);
231 // vy = Y * tan(dist);
242 vx += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
243 vy += (((float) rand ()) / ((float) RAND_MAX) - 0.5f) / 50.0f;
247 if (data->hypercosEffect) {
248 vx += sin (Y * 10.0f) / 120.0f;
249 vy += sin (X * 10.0f) / 120.0f;
253 if (data->hPlaneEffect)
254 vx += Y * 0.0025f * data->hPlaneEffect;
257 if (data->vPlaneEffect)
258 vy += X * 0.0025f * data->vPlaneEffect;
260 /* TODO : Water Mode */
261 // if (data->waveEffect)
271 * Makes a stripe of a transform buffer (brutT)
273 * The transform is (in order) :
274 * Translation (-data->middleX, -data->middleY)
275 * Homothetie (Center : 0,0 Coeff : 2/data->prevX)
278 makeZoomBufferStripe (ZoomFilterFXWrapperData * data, int INTERLACE_INCR)
280 // Position of the pixel to compute in pixmap coordinates
283 // Where (verticaly) to stop generating the buffer stripe
284 int maxEnd = (data->interlace_start + INTERLACE_INCR);
286 // Ratio from pixmap to normalized coordinates
287 float ratio = 2.0f / ((float) data->prevX);
289 // Ratio from normalized to virtual pixmap coordinates
290 float inv_ratio = BUFFPOINTNBF / ratio;
291 float min = ratio / BUFFPOINTNBF;
293 // Y position of the pixel to compute in normalized coordinates
294 float Y = ((float) (data->interlace_start - data->middleY)) * ratio;
296 maxEnd = data->prevY;
297 if (maxEnd > (data->interlace_start + INTERLACE_INCR))
298 maxEnd = (data->interlace_start + INTERLACE_INCR);
300 for (y = data->interlace_start;
301 (y < data->prevY) && ((signed int) y < maxEnd); y++) {
302 Uint premul_y_prevX = y * data->prevX * 2;
303 float X = -((float) data->middleX) * ratio;
305 for (x = 0; x < data->prevX; x++) {
306 v2g vector = zoomVector (data, X, Y);
308 /* Finish and avoid null displacement */
309 if (fabs (vector.x) < min)
310 vector.x = (vector.x < 0.0f) ? -min : min;
311 if (fabs (vector.y) < min)
312 vector.y = (vector.y < 0.0f) ? -min : min;
314 data->brutT[premul_y_prevX] =
315 ((int) ((X - vector.x) * inv_ratio) +
316 ((int) (data->middleX * BUFFPOINTNB)));
317 data->brutT[premul_y_prevX + 1] =
318 ((int) ((Y - vector.y) * inv_ratio) +
319 ((int) (data->middleY * BUFFPOINTNB)));
325 data->interlace_start += INTERLACE_INCR;
326 if (y >= data->prevY - 1)
327 data->interlace_start = -1;
332 * calculer px et py en fonction de x,y,middleX,middleY et theMode
333 * px et py indique la nouvelle position (en sqrtperte ieme de pixel)
336 inline void calculatePXandPY (PluginInfo *goomInfo, ZoomFilterFXWrapperData *data, int x, int y, int *px, int *py)
338 if (data->theMode == WATER_MODE) {
341 yy = y + goom_irand(goomInfo->gRandom, 4) - goom_irand(goomInfo->gRandom, 4) + data->wave / 10;
344 if (yy >= (signed int)goomInfo->screen.height)
345 yy = goomInfo->screen.height - 1;
347 *px = (x << 4) + data->firedec[yy] + (data->wave / 10);
348 *py = (y << 4) + 132 - ((data->vitesse < 131) ? data->vitesse : 130);
350 data->wavesp += goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
351 if (data->wave < -10)
355 data->wave += (data->wavesp / 10) + goom_irand(goomInfo->gRandom, 3) - goom_irand(goomInfo->gRandom, 3);
356 if (data->wavesp > 100)
357 data->wavesp = (data->wavesp * 9) / 10;
360 int dist = 0, vx9, vy9;
363 int fvitesse = data->vitesse << 4;
366 x += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
367 y += goom_irand(goomInfo->gRandom, data->noisify) - goom_irand(goomInfo->gRandom, data->noisify);
369 vx = (x - data->middleX) << 9;
370 vy = (y - data->middleY) << 9;
372 if (data->hPlaneEffect)
373 vx += data->hPlaneEffect * (y - data->middleY);
375 if (data->vPlaneEffect)
376 vy += data->vPlaneEffect * (x - data->middleX);
378 if (data->waveEffect) {
381 ShiftRight (goomInfo->sintable
382 [(unsigned short) (dist * 0xffff + EFFECT_DISTORS)], 6);
386 if (data->hypercosEffect) {
387 vx += ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
388 vy += ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
391 vx9 = ShiftRight (vx, 9);
392 vy9 = ShiftRight (vy, 9);
393 dist = vx9 * vx9 + vy9 * vy9;
395 switch (data->theMode) {
399 ShiftRight (goomInfo->sintable
400 [(unsigned short) (dist * 0xffff * EFFECT_DISTORS)], 6);
403 case CRYSTAL_BALL_MODE:
404 fvitesse += (dist >> (10-EFFECT_DISTORS_SL));
407 fvitesse -= (dist >> (4 - EFFECT_DISTORS_SL));
410 fvitesse -= (dist >> (10 - EFFECT_DISTORS_SL));
413 vx = vx + ShiftRight (goomInfo->sintable[(-vy + dist) & 0xffff], 1);
414 vy = vy + ShiftRight (goomInfo->sintable[(vx + dist) & 0xffff], 1);
418 vx + ShiftRight (goomInfo->sintable[(-ShiftRight (vy, 1) + dist) & 0xffff], 0);
420 vy + ShiftRight (goomInfo->sintable[(ShiftRight (vx, 1) + dist) & 0xffff], 0);
424 fvitesse *= 1024 + ShiftRight (goomInfo->sintable[vy & 0xffff], 6);
428 fvitesse -= (ShiftRight(vy,10-EFFECT_DISTORS_SL));
432 if (fvitesse < -3024)
435 if (vx < 0) // pb avec decalage sur nb negatif
436 ppx = -(-(vx * fvitesse) >> 16);
437 // 16 = 9 + 7 (7 = nb chiffre virgule de vitesse * (v = 128 => immobile)
438 // * * * * * 9 = nb chiffre virgule de vx)
440 ppx = ((vx * fvitesse) >> 16);
443 ppy = -(-(vy * fvitesse) >> 16);
445 ppy = ((vy * fvitesse) >> 16);
447 *px = (data->middleX << 4) + ppx;
448 *py = (data->middleY << 4) + ppy;
456 c_zoom (Pixel * expix1, Pixel * expix2, unsigned int prevX, unsigned int prevY,
457 signed int *brutS, signed int *brutD, int buffratio, int precalCoef[16][16])
462 unsigned int ax = (prevX - 1) << PERTEDEC, ay = (prevY - 1) << PERTEDEC;
464 int bufsize = prevX * prevY * 2;
465 int bufwidth = prevX;
467 expix1[0].val = expix1[prevX - 1].val = expix1[prevX * prevY - 1].val =
468 expix1[prevX * prevY - prevX].val = 0;
470 for (myPos = 0; myPos < bufsize; myPos += 2) {
471 Color col1, col2, col3, col4;
472 int c1, c2, c3, c4, px, py;
476 int brutSmypos = brutS[myPos];
480 px = brutSmypos + (((brutD[myPos] -
481 brutSmypos) * buffratio) >> BUFFPOINTNB);
482 brutSmypos = brutS[myPos2];
483 py = brutSmypos + (((brutD[myPos2] -
484 brutSmypos) * buffratio) >> BUFFPOINTNB);
486 if ((py >= ay) || (px >= ax)) {
489 pos = ((px >> PERTEDEC) + prevX * (py >> PERTEDEC));
490 /* coef en modulo 15 */
491 coeffs = precalCoef[px & PERTEMASK][py & PERTEMASK];
493 getPixelRGB_ (expix1, pos, &col1);
494 getPixelRGB_ (expix1, pos + 1, &col2);
495 getPixelRGB_ (expix1, pos + bufwidth, &col3);
496 getPixelRGB_ (expix1, pos + bufwidth + 1, &col4);
499 c2 = (c1 >> 8) & 0xFF;
500 c3 = (c1 >> 16) & 0xFF;
501 c4 = (c1 >> 24) & 0xFF;
504 couleur.r = col1.r * c1 + col2.r * c2 + col3.r * c3 + col4.r * c4;
509 couleur.v = col1.v * c1 + col2.v * c2 + col3.v * c3 + col4.v * c4;
514 couleur.b = col1.b * c1 + col2.b * c2 + col3.b * c3 + col4.b * c4;
519 setPixelRGB_ (expix2, myPos >> 1, couleur);
523 /** generate the water fx horizontal direction buffer */
525 generateTheWaterFXHorizontalDirectionBuffer (PluginInfo * goomInfo,
526 ZoomFilterFXWrapperData * data)
530 int decc = goom_irand (goomInfo->gRandom, 8) - 4;
531 int spdc = goom_irand (goomInfo->gRandom, 8) - 4;
532 int accel = goom_irand (goomInfo->gRandom, 8) - 4;
534 for (loopv = data->prevY; loopv != 0;) {
537 data->firedec[loopv] = decc;
540 goom_irand (goomInfo->gRandom, 3) - goom_irand (goomInfo->gRandom, 3);
548 spdc = spdc - goom_irand (goomInfo->gRandom, 3) + accel / 10;
550 spdc = spdc + goom_irand (goomInfo->gRandom, 3) + accel / 10;
552 if (decc > 8 && spdc > 1)
553 spdc -= goom_irand (goomInfo->gRandom, 3) - 2;
555 if (decc < -8 && spdc < -1)
556 spdc += goom_irand (goomInfo->gRandom, 3) + 2;
558 if (decc > 8 || decc < -8)
562 goom_irand (goomInfo->gRandom, 2) - goom_irand (goomInfo->gRandom, 2);
573 * Main work for the dynamic displacement map.
575 * Reads data from pix1, write to pix2.
577 * Useful datas for this FX are stored in ZoomFilterData.
579 * If you think that this is a strange function name, let me say that a long time ago,
580 * there has been a slow version and a gray-level only one. Then came these function,
581 * fast and workin in RGB colorspace ! nice but it only was applying a zoom to the image.
582 * So that is why you have this name, for the nostalgy of the first days of goom
583 * when it was just a tiny program writen in Turbo Pascal on my i486...
586 zoomFilterFastRGB (PluginInfo * goomInfo, Pixel * pix1, Pixel * pix2,
587 ZoomFilterData * zf, Uint resx, Uint resy, int switchIncr, float switchMult)
591 ZoomFilterFXWrapperData *data =
592 (ZoomFilterFXWrapperData *) goomInfo->zoomFilter_fx.fx_data;
594 if (!BVAL (data->enabled_bp))
597 /** changement de taille **/
598 if ((data->prevX != resx) || (data->prevY != resy)) {
603 free (data->freebrutS);
606 free (data->freebrutD);
609 free (data->freebrutT);
612 data->middleX = resx / 2;
613 data->middleY = resy / 2;
614 data->mustInitBuffers = 1;
616 free (data->firedec);
620 if (data->interlace_start != -2)
623 /** changement de config **/
625 data->reverse = zf->reverse;
626 data->general_speed = (float) (zf->vitesse - 128) / 128.0f;
628 data->general_speed = -data->general_speed;
629 data->middleX = zf->middleX;
630 data->middleY = zf->middleY;
631 data->theMode = zf->mode;
632 data->hPlaneEffect = zf->hPlaneEffect;
633 data->vPlaneEffect = zf->vPlaneEffect;
634 data->waveEffect = zf->waveEffect;
635 data->hypercosEffect = zf->hypercosEffect;
636 data->noisify = zf->noisify;
637 data->interlace_start = 0;
641 if (data->mustInitBuffers) {
643 data->mustInitBuffers = 0;
645 (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
647 (gint32 *) ((1 + ((uintptr_t) (data->freebrutS)) / 128) * 128);
650 (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
652 (gint32 *) ((1 + ((uintptr_t) (data->freebrutD)) / 128) * 128);
655 (signed int *) calloc (resx * resy * 2 + 128, sizeof (unsigned int));
657 (gint32 *) ((1 + ((uintptr_t) (data->freebrutT)) / 128) * 128);
661 data->firedec = (int *) malloc (data->prevY * sizeof (int));
662 generateTheWaterFXHorizontalDirectionBuffer (goomInfo, data);
664 data->interlace_start = 0;
665 makeZoomBufferStripe (data, resy);
667 /* Copy the data from temp to dest and source */
668 memcpy (data->brutS, data->brutT, resx * resy * 2 * sizeof (int));
669 memcpy (data->brutD, data->brutT, resx * resy * 2 * sizeof (int));
672 /* generation du buffer de trans */
673 if (data->interlace_start == -1) {
675 /* sauvegarde de l'etat actuel dans la nouvelle source
676 * TODO: write that in MMX (has been done in previous version, but did not follow some new fonctionnalities) */
677 y = data->prevX * data->prevY * 2;
678 for (x = 0; x < y; x += 2) {
679 int brutSmypos = data->brutS[x];
683 brutSmypos + (((data->brutD[x] -
684 brutSmypos) * data->buffratio) >> BUFFPOINTNB);
685 brutSmypos = data->brutS[x2];
687 brutSmypos + (((data->brutD[x2] -
688 brutSmypos) * data->buffratio) >> BUFFPOINTNB);
693 if (data->interlace_start == -1) {
697 data->brutD = data->brutT;
699 tmp = data->freebrutD;
700 data->freebrutD = data->freebrutT;
701 data->freebrutT = tmp;
702 data->interlace_start = -2;
705 if (data->interlace_start >= 0) {
706 /* creation de la nouvelle destination */
707 makeZoomBufferStripe (data, resy / 16);
710 if (switchIncr != 0) {
711 data->buffratio += switchIncr;
712 if (data->buffratio > BUFFPOINTMASK)
713 data->buffratio = BUFFPOINTMASK;
716 if (switchMult != 1.0f) {
717 data->buffratio = (int) ((float) BUFFPOINTMASK * (1.0f - switchMult) +
718 (float) data->buffratio * switchMult);
721 data->zoom_width = data->prevX;
723 goomInfo->methods.zoom_filter (data->prevX, data->prevY, pix1, pix2,
724 data->brutS, data->brutD, data->buffratio, data->precalCoef);
728 generatePrecalCoef (int precalCoef[16][16])
732 for (coefh = 0; coefh < 16; coefh++) {
733 for (coefv = 0; coefv < 16; coefv++) {
739 diffcoeffh = sqrtperte - coefh;
740 diffcoeffv = sqrtperte - coefv;
742 if (!(coefh || coefv)) {
747 i1 = diffcoeffh * diffcoeffv;
748 i2 = coefh * diffcoeffv;
749 i3 = diffcoeffh * coefv;
752 // TODO: faire mieux...
762 i = (i1) | (i2 << 8) | (i3 << 16) | (i4 << 24);
764 precalCoef[coefh][coefv] = i;
769 /* VisualFX Wrapper */
772 zoomFilterVisualFXWrapper_init (struct _VISUAL_FX *_this, PluginInfo * info)
774 ZoomFilterFXWrapperData *data =
775 (ZoomFilterFXWrapperData *) malloc (sizeof (ZoomFilterFXWrapperData));
778 data->freecoeffs = 0;
788 data->mustInitBuffers = 1;
789 data->interlace_start = -2;
791 data->general_speed = 0.0f;
793 data->theMode = AMULETTE_MODE;
794 data->waveEffect = 0;
795 data->hypercosEffect = 0;
796 data->vPlaneEffect = 0;
797 data->hPlaneEffect = 0;
800 /** modif by jeko : fixedpoint : buffration = (16:16) (donc 0<=buffration<=2^16) */
804 data->wave = data->wavesp = 0;
806 data->enabled_bp = secure_b_param ("Enabled", 1);
808 data->params = plugin_parameters ("Zoom Filter", 1);
809 data->params.params[0] = &data->enabled_bp;
811 _this->params = &data->params;
812 _this->fx_data = (void *) data;
814 /** modif d'optim by Jeko : precalcul des 4 coefs resultant des 2 pos */
815 generatePrecalCoef (data->precalCoef);
819 zoomFilterVisualFXWrapper_free (struct _VISUAL_FX *_this)
821 ZoomFilterFXWrapperData *data = (ZoomFilterFXWrapperData *) _this->fx_data;
824 free (data->freebrutT);
826 free (data->freebrutS);
828 free (data->freebrutD);
830 free (data->firedec);
832 goom_plugin_parameters_free (_this->params);
834 free (_this->fx_data);
838 zoomFilterVisualFXWrapper_apply (struct _VISUAL_FX *_this, Pixel * src,
839 Pixel * dest, PluginInfo * info)
844 zoomFilterVisualFXWrapper_create (void)
848 fx.init = zoomFilterVisualFXWrapper_init;
849 fx.free = zoomFilterVisualFXWrapper_free;
850 fx.apply = zoomFilterVisualFXWrapper_apply;
857 /* TODO : MOVE THIS AWAY */
860 pointFilter (PluginInfo * goomInfo, Pixel * pix1, Color c, float t1, float t2,
861 float t3, float t4, Uint cycle)
863 Uint x = (Uint) ((int) (goomInfo->screen.width / 2)
864 + (int) (t1 * cos ((float) cycle / t3)));
865 Uint y = (Uint) ((int) (goomInfo->screen.height / 2)
866 + (int) (t2 * sin ((float) cycle / t4)));
868 if ((x > 1) && (y > 1) && (x < goomInfo->screen.width - 2)
869 && (y < goomInfo->screen.height - 2)) {
870 setPixelRGB (goomInfo, pix1, x + 1, y, c);
871 setPixelRGB (goomInfo, pix1, x, y + 1, c);
872 setPixelRGB (goomInfo, pix1, x + 1, y + 1, WHITE);
873 setPixelRGB (goomInfo, pix1, x + 2, y + 1, c);
874 setPixelRGB (goomInfo, pix1, x + 1, y + 2, c);