/* filter.c version 0.7 * contient les filtres applicable a un buffer * creation : 01/10/2000 * -ajout de sinFilter() * -ajout de zoomFilter() * -copie de zoomFilter() en zoomFilterRGB(), gérant les 3 couleurs * -optimisation de sinFilter (utilisant une table de sin) * -asm * -optimisation de la procedure de génération du buffer de transformation * la vitesse est maintenant comprise dans [0..128] au lieu de [0..100] */ /*#define _DEBUG_PIXEL; */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "filters.h" #include "graphic.h" #include "goom_tools.h" #include "goom_core.h" #include #include #include #ifdef MMX #define USE_ASM #endif #ifdef POWERPC #define USE_ASM #endif #ifdef USE_ASM #define EFFECT_DISTORS 4 #else #define EFFECT_DISTORS 10 #endif #ifdef USE_ASM #ifdef MMX int mmx_zoom (); guint32 mmx_zoom_size; #endif /* MMX */ #ifdef POWERPC extern unsigned int useAltivec; extern void ppc_zoom (void); extern void ppc_zoom_altivec (void); unsigned int ppcsize4; #endif /* PowerPC */ unsigned int *coeffs = 0, *freecoeffs = 0; guint32 *expix1 = 0; /* pointeur exporte vers p1 */ guint32 *expix2 = 0; /* pointeur exporte vers p2 */ guint32 zoom_width; #endif /* ASM */ static int firstTime = 1; static int sintable[0xffff]; ZoomFilterData * zoomFilterNew () { ZoomFilterData *zf = malloc (sizeof (ZoomFilterData)); zf->vitesse = 128; zf->pertedec = 8; zf->sqrtperte = 16; zf->middleX = 1; zf->middleY = 1; zf->reverse = 0; zf->mode = WAVE_MODE; zf->hPlaneEffect = 0; zf->vPlaneEffect = 0; zf->noisify = 0; zf->buffsize = 0; zf->res_x = 0; zf->res_y = 0; zf->buffer = NULL; zf->firedec = NULL; zf->wave = 0; zf->wavesp = 0; return zf; } /* retourne x>>s , en testant le signe de x */ static inline int ShiftRight (int x, const unsigned char s) { if (x < 0) return -(-x >> s); else return x >> s; } /* calculer px et py en fonction de x,y,middleX,middleY et theMode px et py indique la nouvelle position (en sqrtperte ieme de pixel) (valeur * 16) */ void calculatePXandPY (GoomData * gd, int x, int y, int *px, int *py) { ZoomFilterData *zf = gd->zfd; int middleX, middleY; guint32 resoly = zf->res_y; int vPlaneEffect = zf->vPlaneEffect; int hPlaneEffect = zf->hPlaneEffect; int vitesse = zf->vitesse; char theMode = zf->mode; if (theMode == WATER_MODE) { int wavesp = zf->wavesp; int wave = zf->wave; int yy = y + RAND (gd) % 4 + wave / 10; yy -= RAND (gd) % 4; if (yy < 0) yy = 0; if (yy >= resoly) yy = resoly - 1; *px = (x << 4) + zf->firedec[yy] + (wave / 10); *py = (y << 4) + 132 - ((vitesse < 132) ? vitesse : 131); wavesp += RAND (gd) % 3; wavesp -= RAND (gd) % 3; if (wave < -10) wavesp += 2; if (wave > 10) wavesp -= 2; wave += (wavesp / 10) + RAND (gd) % 3; wave -= RAND (gd) % 3; if (wavesp > 100) wavesp = (wavesp * 9) / 10; zf->wavesp = wavesp; zf->wave = wave; } else { int dist; register int vx, vy; int fvitesse = vitesse << 4; middleX = zf->middleX; middleY = zf->middleY; if (zf->noisify) { x += RAND (gd) % zf->noisify; x -= RAND (gd) % zf->noisify; y += RAND (gd) % zf->noisify; y -= RAND (gd) % zf->noisify; } if (hPlaneEffect) vx = ((x - middleX) << 9) + hPlaneEffect * (y - middleY); else vx = (x - middleX) << 9; if (vPlaneEffect) vy = ((y - middleY) << 9) + vPlaneEffect * (x - middleX); else vy = (y - middleY) << 9; switch (theMode) { case WAVE_MODE: dist = ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, 9) * ShiftRight (vy, 9); fvitesse *= 1024 + ShiftRight (sintable[(unsigned short) (0xffff * dist * EFFECT_DISTORS)], 6); fvitesse /= 1024; break; case CRYSTAL_BALL_MODE: dist = ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, 9) * ShiftRight (vy, 9); fvitesse += (dist * EFFECT_DISTORS >> 10); break; case AMULETTE_MODE: dist = ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, 9) * ShiftRight (vy, 9); fvitesse -= (dist * EFFECT_DISTORS >> 4); break; case SCRUNCH_MODE: dist = ShiftRight (vx, 9) * ShiftRight (vx, 9) + ShiftRight (vy, 9) * ShiftRight (vy, 9); fvitesse -= (dist * EFFECT_DISTORS >> 9); break; } if (vx < 0) *px = (middleX << 4) - (-(vx * fvitesse) >> 16); else *px = (middleX << 4) + ((vx * fvitesse) >> 16); if (vy < 0) *py = (middleY << 4) - (-(vy * fvitesse) >> 16); else *py = (middleY << 4) + ((vy * fvitesse) >> 16); } } /*#define _DEBUG */ static inline void setPixelRGB (Uint * buffer, Uint x, Uint y, Color c, guint32 resolx, guint32 resoly) { /* buffer[ y*WIDTH + x ] = (c.r<<16)|(c.v<<8)|c.b */ #ifdef _DEBUG_PIXEL if (x + y * resolx >= resolx * resoly) { fprintf (stderr, "setPixel ERROR : hors du tableau... %i, %i\n", x, y); /*exit (1) ; */ } #endif #ifdef USE_DGA buffer[y * resolx + x] = (c.b << 16) | (c.v << 8) | c.r; #else buffer[y * resolx + x] = (c.r << 16) | (c.v << 8) | c.b; #endif } static inline void setPixelRGB_ (Uint * buffer, Uint x, Color c, guint32 resolx, guint32 resoly) { #ifdef _DEBUG if (x >= resolx * resoly) { printf ("setPixel ERROR : hors du tableau... %i >= %i*%i (%i)\n", x, resolx, resoly, resolx * resoly); exit (1); } #endif #ifdef USE_DGA buffer[x] = (c.b << 16) | (c.v << 8) | c.r; #else buffer[x] = (c.r << 16) | (c.v << 8) | c.b; #endif } static inline void getPixelRGB (Uint * buffer, Uint x, Uint y, Color * c, guint32 resolx, guint32 resoly) { register unsigned char *tmp8; #ifdef _DEBUG if (x + y * resolx >= resolx * resoly) { printf ("getPixel ERROR : hors du tableau... %i, %i\n", x, y); exit (1); } #endif #ifdef __BIG_ENDIAN__ c->b = *(unsigned char *) (tmp8 = (unsigned char *) (buffer + (x + y * resolx))); c->r = *(unsigned char *) (++tmp8); c->v = *(unsigned char *) (++tmp8); c->b = *(unsigned char *) (++tmp8); #else /* ATTENTION AU PETIT INDIEN */ c->b = *(unsigned char *) (tmp8 = (unsigned char *) (buffer + (x + y * resolx))); c->v = *(unsigned char *) (++tmp8); c->r = *(unsigned char *) (++tmp8); /* *c = (Color) buffer[x+y*WIDTH] ; */ #endif } static inline void getPixelRGB_ (Uint * buffer, Uint x, Color * c, guint32 resolx, guint32 resoly) { register unsigned char *tmp8; #ifdef _DEBUG if (x >= resolx * resoly) { printf ("getPixel ERROR : hors du tableau... %i\n", x); exit (1); } #endif #ifdef __BIG_ENDIAN__ c->b = *(unsigned char *) (tmp8 = (unsigned char *) (buffer + x)); c->r = *(unsigned char *) (++tmp8); c->v = *(unsigned char *) (++tmp8); c->b = *(unsigned char *) (++tmp8); #else /* ATTENTION AU PETIT INDIEN */ tmp8 = (unsigned char *) (buffer + x); c->b = *(unsigned char *) (tmp8++); c->v = *(unsigned char *) (tmp8++); c->r = *(unsigned char *) (tmp8); /* *c = (Color) buffer[x+y*WIDTH] ; */ #endif } static void zoomFilterSetResolution (GoomData * gd, ZoomFilterData * zf) { unsigned short us; if (zf->buffsize >= gd->buffsize) { zf->res_x = gd->resolx; zf->res_y = gd->resoly; zf->middleX = gd->resolx / 2; zf->middleY = gd->resoly - 1; return; } #ifndef USE_ASM if (zf->buffer) free (zf->buffer); zf->buffer = 0; #else if (coeffs) free (freecoeffs); coeffs = 0; #endif zf->middleX = gd->resolx / 2; zf->middleY = gd->resoly - 1; zf->res_x = gd->resolx; zf->res_y = gd->resoly; if (zf->firedec) free (zf->firedec); zf->firedec = 0; zf->buffsize = gd->resolx * gd->resoly * sizeof (unsigned int); #ifdef USE_ASM freecoeffs = (unsigned int *) malloc (resx * resy * 2 * sizeof (unsigned int) + 128); coeffs = (guint32 *) ((1 + ((unsigned int) (freecoeffs)) / 128) * 128); #else zf->buffer = calloc (sizeof (guint32), zf->buffsize * 5); zf->pos10 = zf->buffer; zf->c[0] = zf->pos10 + zf->buffsize; zf->c[1] = zf->c[0] + zf->buffsize; zf->c[2] = zf->c[1] + zf->buffsize; zf->c[3] = zf->c[2] + zf->buffsize; #endif zf->firedec = (int *) malloc (zf->res_y * sizeof (int)); if (firstTime) { firstTime = 0; /* generation d'une table de sinus */ for (us = 0; us < 0xffff; us++) { sintable[us] = (int) (1024.0f * sin (us * 2 * 3.31415f / 0xffff)); } } { int loopv; for (loopv = zf->res_y; loopv != 0;) { int decc = 0; int spdc = 0; int accel = 0; loopv--; zf->firedec[loopv] = decc; decc += spdc / 10; spdc += RAND (gd) % 3; spdc -= RAND (gd) % 3; if (decc > 4) spdc -= 1; if (decc < -4) spdc += 1; if (spdc > 30) spdc = spdc - RAND (gd) % 3 + accel / 10; if (spdc < -30) spdc = spdc + RAND (gd) % 3 + accel / 10; if (decc > 8 && spdc > 1) spdc -= RAND (gd) % 3 - 2; if (decc < -8 && spdc < -1) spdc += RAND (gd) % 3 + 2; if (decc > 8 || decc < -8) decc = decc * 8 / 9; accel += RAND (gd) % 2; accel -= RAND (gd) % 2; if (accel > 20) accel -= 2; if (accel < -20) accel += 2; } } } void zoomFilterDestroy (ZoomFilterData * zf) { if (zf) { if (zf->firedec) free (zf->firedec); if (zf->buffer) free (zf->buffer); free (zf); } } /*===============================================================*/ void zoomFilterFastRGB (GoomData * goomdata, ZoomFilterData * zf, int zfd_update) { guint32 prevX = goomdata->resolx; guint32 prevY = goomdata->resoly; guint32 *pix1 = goomdata->p1; guint32 *pix2 = goomdata->p2; unsigned int *pos10; unsigned int **c; Uint x, y; /* static unsigned int prevX = 0, prevY = 0; */ #ifdef USE_ASM expix1 = pix1; expix2 = pix2; #else Color couleur; Color col1, col2, col3, col4; Uint position; #endif if ((goomdata->resolx != zf->res_x) || (goomdata->resoly != zf->res_y)) { zoomFilterSetResolution (goomdata, zf); } pos10 = zf->pos10; c = zf->c; if (zfd_update) { guchar sqrtperte = zf->sqrtperte; gint start_y = 0; if (zf->reverse) zf->vitesse = 256 - zf->vitesse; /* generation du buffer */ for (y = 0; y < zf->res_y; y++) { gint y_16 = y << 4; gint max_px = (prevX - 1) * sqrtperte; gint max_py = (prevY - 1) * sqrtperte; for (x = 0; x < zf->res_x; x++) { gint px, py; guchar coefv, coefh; /* calculer px et py en fonction de */ /* x,y,middleX,middleY et theMode */ calculatePXandPY (goomdata, x, y, &px, &py); if ((px == x << 4) && (py == y_16)) py += 8; if ((py < 0) || (px < 0) || (py >= max_py) || (px >= max_px)) { #ifdef USE_ASM coeffs[(y * prevX + x) * 2] = 0; coeffs[(y * prevX + x) * 2 + 1] = 0; #else pos10[start_y + x] = 0; c[0][start_y + x] = 0; c[1][start_y + x] = 0; c[2][start_y + x] = 0; c[3][start_y + x] = 0; #endif } else { int npx10; int npy10; int pos; npx10 = (px / sqrtperte); npy10 = (py / sqrtperte); /* if (npx10 >= prevX) fprintf(stderr,"error npx:%d",npx10); if (npy10 >= prevY) fprintf(stderr,"error npy:%d",npy10); */ coefh = px % sqrtperte; coefv = py % sqrtperte; #ifdef USE_ASM pos = (y * prevX + x) * 2; coeffs[pos] = (npx10 + prevX * npy10) * 4; if (!(coefh || coefv)) coeffs[pos + 1] = (sqrtperte * sqrtperte - 1); else coeffs[pos + 1] = ((sqrtperte - coefh) * (sqrtperte - coefv)); coeffs[pos + 1] |= (coefh * (sqrtperte - coefv)) << 8; coeffs[pos + 1] |= ((sqrtperte - coefh) * coefv) << 16; coeffs[pos + 1] |= (coefh * coefv) << 24; #else pos = start_y + x; pos10[pos] = npx10 + prevX * npy10; if (!(coefh || coefv)) c[0][pos] = sqrtperte * sqrtperte - 1; else c[0][pos] = (sqrtperte - coefh) * (sqrtperte - coefv); c[1][pos] = coefh * (sqrtperte - coefv); c[2][pos] = (sqrtperte - coefh) * coefv; c[3][pos] = coefh * coefv; #endif } } /* Advance start of line index */ start_y += prevX; } } #ifdef USE_ASM #ifdef MMX zoom_width = prevX; mmx_zoom_size = prevX * prevY; mmx_zoom (); #endif #ifdef POWERPC zoom_width = prevX; if (useAltivec) { ppcsize4 = ((unsigned int) (prevX * prevY)) / 4; ppc_zoom_altivec (); } else { ppcsize4 = ((unsigned int) (prevX * prevY)); ppc_zoom (); } #endif #else for (position = 0; position < prevX * prevY; position++) { getPixelRGB_ (pix1, pos10[position], &col1, goomdata->resolx, goomdata->resoly); getPixelRGB_ (pix1, pos10[position] + 1, &col2, goomdata->resolx, goomdata->resoly); getPixelRGB_ (pix1, pos10[position] + prevX, &col3, goomdata->resolx, goomdata->resoly); getPixelRGB_ (pix1, pos10[position] + prevX + 1, &col4, goomdata->resolx, goomdata->resoly); couleur.r = col1.r * c[0][position] + col2.r * c[1][position] + col3.r * c[2][position] + col4.r * c[3][position]; couleur.r >>= zf->pertedec; couleur.v = col1.v * c[0][position] + col2.v * c[1][position] + col3.v * c[2][position] + col4.v * c[3][position]; couleur.v >>= zf->pertedec; couleur.b = col1.b * c[0][position] + col2.b * c[1][position] + col3.b * c[2][position] + col4.b * c[3][position]; couleur.b >>= zf->pertedec; setPixelRGB_ (pix2, position, couleur, goomdata->resolx, goomdata->resoly); } #endif } void pointFilter (GoomData * goomdata, Color c, float t1, float t2, float t3, float t4, Uint cycle) { Uint *pix1 = goomdata->p1; ZoomFilterData *zf = goomdata->zfd; Uint x = (Uint) (zf->middleX + (int) (t1 * cos ((float) cycle / t3))); Uint y = (Uint) (zf->middleY + (int) (t2 * sin ((float) cycle / t4))); if ((x > 1) && (y > 1) && (x < goomdata->resolx - 2) && (y < goomdata->resoly - 2)) { setPixelRGB (pix1, x + 1, y, c, goomdata->resolx, goomdata->resoly); setPixelRGB (pix1, x, y + 1, c, goomdata->resolx, goomdata->resoly); setPixelRGB (pix1, x + 1, y + 1, WHITE, goomdata->resolx, goomdata->resoly); setPixelRGB (pix1, x + 2, y + 1, c, goomdata->resolx, goomdata->resoly); setPixelRGB (pix1, x + 1, y + 2, c, goomdata->resolx, goomdata->resoly); } }