gstreamer/gst/goom/filters.c

542 lines
13 KiB
C
Raw Normal View History

/* 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<EFBFBD>rant les 3 couleurs
* -optimisation de sinFilter (utilisant une table de sin)
* -asm
* -optimisation de la procedure de g<EFBFBD>n<EFBFBD>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 <stdlib.h>
#include <math.h>
#include <stdio.h>
#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
extern volatile guint32 resolx;
extern volatile guint32 resoly;
#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 sintable [0xffff] ;
static int vitesse = 127;
static char theMode = AMULETTE_MODE ;
static int vPlaneEffect = 0;
static int hPlaneEffect = 0;
static char noisify = 2;
static int middleX , middleY ;
static unsigned char sqrtperte = 16 ;
static int * firedec = 0 ;
/* retourne x>>s , en testant le signe de x */
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 (int x, int y, int *px, int *py)
{
if (theMode == WATER_MODE)
{
static int wave = 0 ;
static int wavesp = 0 ;
int yy ;
yy = y + RAND () % 4 + wave / 10 ;
yy -= RAND () % 4;
if (yy < 0) yy = 0 ;
if (yy >= resoly) yy = resoly - 1 ;
*px = (x<<4) + firedec [yy] + (wave / 10) ;
*py = (y<<4) + 132 - ((vitesse < 132) ? vitesse : 131) ;
wavesp += RAND () % 3;
wavesp -= RAND () % 3;
if (wave < -10) wavesp += 2 ;
if (wave > 10) wavesp -= 2 ;
wave += (wavesp / 10) + RAND () % 3;
wave -= RAND () % 3;
if (wavesp > 100) wavesp = (wavesp * 9) / 10 ;
}
else
{
int dist ;
register int vx,vy ;
int fvitesse = vitesse << 4 ;
if (noisify)
{
x += RAND() % noisify;
x -= RAND() % noisify;
y += RAND() % noisify;
y -= RAND() % 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 */
inline void setPixelRGB(Uint *buffer, Uint x, Uint y, Color c)
{
/* 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
}
inline void setPixelRGB_ (Uint *buffer, Uint x, Color c)
{
#ifdef _DEBUG
if ( x >= resolx*resoly )
{
printf ("setPixel ERROR : hors du tableau... %i, %i\n", x,y) ;
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
}
inline void getPixelRGB (Uint *buffer, Uint x, Uint y, Color *c)
{
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
}
inline void getPixelRGB_ (Uint *buffer, Uint x, Color *c)
{
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 */
c->b = *(unsigned char *)(tmp8 = (unsigned char*)(buffer + x));
c->v = *(unsigned char *)(++tmp8);
c->r = *(unsigned char *)(++tmp8);
/* *c = (Color) buffer[x+y*WIDTH] ; */
#endif
}
/*===============================================================*/
void zoomFilterFastRGB (Uint *pix1,
Uint *pix2,
ZoomFilterData *zf,
Uint resx, Uint resy)
{
static guint32 prevX = 0, prevY = 0;
static char reverse = 0 ; /*vitesse invers<72>..(zoom out) */
/* static int perte = 100; // 100 = normal */
static unsigned char pertedec = 8 ;
static char firstTime = 1;
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 ;
static unsigned int *pos10 = 0;
static unsigned int *c1 = 0,
*c2 = 0,
*c3 = 0,
*c4 = 0;
#endif
if ((prevX != resx) || (prevY != resy))
{
prevX = resx;
prevY = resy;
#ifndef USE_ASM
if (c1) free (c1) ;
if (c2) free (c2) ;
if (c3) free (c3) ;
if (c4) free (c4) ;
if (pos10) free (pos10) ;
c1=c2=c3=c4=pos10=0;
#else
if (coeffs) free (freecoeffs) ;
coeffs = 0;
#endif
middleX = resx / 2 ;
middleY = resy - 1;
firstTime = 1 ;
if (firedec) free (firedec);
firedec=0;
}
if (zf)
{
reverse = zf->reverse ;
vitesse = zf->vitesse ;
if (reverse)
vitesse = 256 - vitesse ;
#ifndef USE_ASM
sqrtperte = zf->sqrtperte ;
#endif
pertedec = zf->pertedec ;
middleX = zf->middleX ;
middleY = zf->middleY ;
theMode = zf->mode ;
hPlaneEffect = zf->hPlaneEffect;
vPlaneEffect = zf->vPlaneEffect;
noisify = zf->noisify;
}
if (firstTime || zf)
{
/* generation d'une table de sinus */
if (firstTime)
{
unsigned short us ;
firstTime = 0;
#ifdef USE_ASM
freecoeffs = (unsigned int *)
malloc (resx*resy*2*sizeof(unsigned int)+128);
coeffs = (guint32 *)((1+((unsigned int)(freecoeffs))/128)*128);
#else
pos10 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
c1 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
c2 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
c3 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
c4 = (unsigned int *) malloc (resx*resy*sizeof(unsigned int)) ;
#endif
for (us=0; us<0xffff; us++)
{
sintable [us] = (int)(1024.0f * sin (us*2*3.31415f/0xffff)) ;
}
{
int loopv ;
firedec = (int *) malloc (prevY * sizeof(int)) ;
for (loopv = prevY ; loopv != 0 ;)
{
static int decc = 0 ;
static int spdc = 0 ;
static int accel = 0 ;
loopv -- ;
firedec [loopv] = decc ;
decc += spdc / 10 ;
spdc+= RAND () % 3;
spdc-= RAND () % 3;
if (decc > 4)
spdc -= 1 ;
if (decc < -4)
spdc += 1 ;
if (spdc > 30)
spdc = spdc - RAND () % 3 + accel / 10 ;
if (spdc < -30)
spdc = spdc + RAND () % 3 + accel / 10 ;
if (decc > 8 && spdc > 1 )
spdc -= RAND () % 3 - 2 ;
if (decc < -8 && spdc < -1 )
spdc += RAND () % 3 + 2 ;
if (decc > 8 || decc < -8)
decc = decc * 8 / 9 ;
accel += RAND () % 2;
accel -= RAND () % 2;
if (accel > 20)
accel -= 2 ;
if (accel < -20)
accel += 2 ;
}
}
}
/* generation du buffer */
for (y = 0 ; y < prevY ; y++)
for (x = 0; x < prevX ; x++)
{
int px,py;
unsigned char coefv,coefh;
/* calculer px et py en fonction de */
/* x,y,middleX,middleY et theMode */
calculatePXandPY (x,y,&px, &py) ;
if ((px == x << 4) && (py == y << 4))
py += 8 ;
if ( (py<0) || (px<0) ||
(py>=(prevY-1)*sqrtperte) ||
(px>=(prevX-1)*sqrtperte))
{
#ifdef USE_ASM
coeffs[(y*prevX+x)*2]=0 ;
coeffs[(y*prevX+x)*2+1]=0;
#else
pos10[y*prevX+x]=0 ;
c1[y*prevX+x] = 0 ;
c2[y*prevX+x] = 0 ;
c3[y*prevX+x] = 0 ;
c4[y*prevX+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 = y*prevX+x;
pos10[pos]= npx10 + prevX * npy10 ;
if (!(coefh || coefv))
c1[pos] = sqrtperte*sqrtperte-1 ;
else
c1[pos] = (sqrtperte-coefh) * (sqrtperte-coefv);
c2[pos] = coefh * (sqrtperte-coefv) ;
c3[pos] = (sqrtperte-coefh) * coefv ;
c4[pos] = coefh * coefv ;
#endif
}
}
}
#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);
getPixelRGB_(pix1,pos10[position]+1,&col2);
getPixelRGB_(pix1,pos10[position]+prevX,&col3);
getPixelRGB_(pix1,pos10[position]+prevX+1,&col4);
couleur.r = col1.r * c1[position]
+ col2.r * c2[position]
+ col3.r * c3[position]
+ col4.r * c4[position];
couleur.r >>= pertedec ;
couleur.v = col1.v * c1[position]
+ col2.v * c2[position]
+ col3.v * c3[position]
+ col4.v * c4[position];
couleur.v >>= pertedec ;
couleur.b = col1.b * c1[position]
+ col2.b * c2[position]
+ col3.b * c3[position]
+ col4.b * c4[position];
couleur.b >>= pertedec ;
setPixelRGB_(pix2,position,couleur);
}
#endif
}
void pointFilter(Uint *pix1, Color c,
float t1, float t2, float t3, float t4,
Uint cycle)
{
Uint x = (Uint)((int)middleX + (int)(t1*cos((float)cycle/t3)));
Uint y = (Uint)((int)middleY + (int)(t2*sin((float)cycle/t4)));
if ((x>1) && (y>1) && (x<resolx-2) && (y<resoly-2))
{
setPixelRGB(pix1, x+1, y, c);
setPixelRGB(pix1, x, y+1, c);
setPixelRGB(pix1, x+1, y+1, WHITE);
setPixelRGB(pix1, x+2, y+1, c);
setPixelRGB(pix1, x+1, y+2, c);
}
}