hermes PS2R
19/06/2006, 05:19
Buenas,ultimamente no me prodigo mucho por estos foros, pero hoy me ha dado por programar un poco y una de las cosas que siempre me han interesado, es hacer una rutina que hiciese filtrado bilineal en una textura.
La teoria de este metodo, consiste en averiguar el color de un pixel intermedio en la textura de origen, usando los pixeles mas proximos y el resultado, es esta pequeña funcion que comparto con vosotros por si quereis darle utilidad.
La rutina no la he probado en la GP2X, asi que no puedo dar detalle sobre su funcionamiento ahi (si es rapida o lenta, por ejemplo)
static unsigned inline get_pix_rel(int x,int y, unsigned *text,int tx1,int ty1,int factx,int facty)
{
static unsigned dummy=0; // color dummy
unsigned a,b,c,rel;
unsigned char *t1=(unsigned char *) &dummy,*t2=(unsigned char *) &dummy;
unsigned char *t3=(unsigned char *) &dummy,*t4=(unsigned char *) &dummy;
// rel contiene la posicion relativa vertical de textura
rel=tx1*y;
// obtiene puntero color x,y en t1 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t1=(unsigned char *) &text[x+rel];
x++;
// obtiene puntero color x+1,y en t2 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t2=(unsigned char *) &text[x+rel];
y++;x--;rel+=tx1;
// obtiene puntero color x,y+1 en t3 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t3=(unsigned char *) &text[x+rel];
x++;
// obtiene puntero color x+1,y+1 en t4 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t4=(unsigned char *) &text[x+rel];
/* obtiene color R interpolado de t1 y t2 (horizontal)*/
a=(((t2[0]-t1[0])*factx)>>8)+t1[0];
/* obtiene color R interpolado de t3 y t4 (horizontal)*/
b=(((t4[0]-t3[0])*factx)>>8)+t3[0];
/* obtiene color R interpolando a y b (vertical) y lo almacena en c */
c=((((b-a)*facty)>>8)+a);
/* obtiene color G interpolado de t1 y t2 (horizontal)*/
a=(((t2[1]-t1[1])*factx)>>8)+t1[1];
/* obtiene color G interpolado de t3 y t4 (horizontal)*/
b=(((t4[1]-t3[1])*factx)>>8)+t3[1];
/* obtiene color G interpolando a y b (vertical) y lo almacena en c */
c+=((((b-a)*facty)>>8)+a)<<8;
/* obtiene color B interpolado de t1 y t2 (horizontal)*/
a=(((t2[2]-t1[2])*factx)>>8)+t1[2];
/* obtiene color B interpolado de t3 y t4 (horizontal)*/
b=(((t4[2]-t3[2])*factx)>>8)+t3[2];
/* obtiene color B interpolando a y b (vertical) y lo almacena en c */
c+=((((b-a)*facty)>>8)+a)<<16;
/* NOTA: el factor de interpolacion (decimal) tiene un rango de 0 a 255 */
return c; // retorna color interpolado
}
/* text_bilineal: Uso.
text-> textura origen (4 bytes)
tx1-> ancho de textura origen en pixels
ty1-> alto textura origen en pixels
text2-> textura destino (4 bytes)
tx2-> ancho textura destino en pixels
ty2-> alto textura origen en pixels
*/
void text_bilineal(unsigned *text,int tx1,int ty1,unsigned *text2,int tx2,int ty2)
{
int n,m;
int xx,yy,rel;
unsigned col1;
int fx,fy;
for(n=0;n<ty2;n++)
{
/* calcula coordenada Y en textura de origen usando enteros con 8 bits de coma fija */
fy=(((n*ty1)<<8)/ty2);
/* obtiene la Y de textura sin la parte 'decimal' */
yy=fy>>8;
/* deja en fy la parte 'decimal' de Y */
fy&=255;
/* calcula en rel la posicion relativa Y en textura destino*/
rel=n*tx2;
for(m=0;m<tx2;m++)
{
/* calcula coordenada X en textura de origen usando enteros con 8 bits de coma fija */
fx=(((m*tx1)<<8)/tx2);
/* obtiene la X de textura sin la parte 'decimal' */
xx=fx>>8;
/* deja en fx la parte 'decimal' de X */
fx&=255;
/* llama a la funcion que obtiene el color medio en textura origen */
col1=get_pix_rel(xx, yy, text, tx1,ty1, fx, fy);
/* escribe el color calculado en textura destino */
text2[m+rel]=col1;
}
}
}
COMO SE USA
El uso es muy sencillo, la funcion es text_bilineal() y recibe como entrada una textura de color 32 bit color y su ancho y alto en pixeles y una textura de salida tambien a 32 bits, junto con su ancho y alto correspondiente (se calculan solo los 24 bits mas bajos correspondientes a R,G,B)
No creo que tengais mucho problema en poder adaptar la rutina para una textura de entrada de 8 bits (con paleta) o 16 bits, para una salida a 16-32 bits (como se obtienen colores intermedios, no seria muy conveniente usar 8 bits color de salida), o eso espero ;)
La teoria de este metodo, consiste en averiguar el color de un pixel intermedio en la textura de origen, usando los pixeles mas proximos y el resultado, es esta pequeña funcion que comparto con vosotros por si quereis darle utilidad.
La rutina no la he probado en la GP2X, asi que no puedo dar detalle sobre su funcionamiento ahi (si es rapida o lenta, por ejemplo)
static unsigned inline get_pix_rel(int x,int y, unsigned *text,int tx1,int ty1,int factx,int facty)
{
static unsigned dummy=0; // color dummy
unsigned a,b,c,rel;
unsigned char *t1=(unsigned char *) &dummy,*t2=(unsigned char *) &dummy;
unsigned char *t3=(unsigned char *) &dummy,*t4=(unsigned char *) &dummy;
// rel contiene la posicion relativa vertical de textura
rel=tx1*y;
// obtiene puntero color x,y en t1 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t1=(unsigned char *) &text[x+rel];
x++;
// obtiene puntero color x+1,y en t2 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t2=(unsigned char *) &text[x+rel];
y++;x--;rel+=tx1;
// obtiene puntero color x,y+1 en t3 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t3=(unsigned char *) &text[x+rel];
x++;
// obtiene puntero color x+1,y+1 en t4 */
if(!(x<0 || y<0 || x>=tx1 || y>=ty1)) t4=(unsigned char *) &text[x+rel];
/* obtiene color R interpolado de t1 y t2 (horizontal)*/
a=(((t2[0]-t1[0])*factx)>>8)+t1[0];
/* obtiene color R interpolado de t3 y t4 (horizontal)*/
b=(((t4[0]-t3[0])*factx)>>8)+t3[0];
/* obtiene color R interpolando a y b (vertical) y lo almacena en c */
c=((((b-a)*facty)>>8)+a);
/* obtiene color G interpolado de t1 y t2 (horizontal)*/
a=(((t2[1]-t1[1])*factx)>>8)+t1[1];
/* obtiene color G interpolado de t3 y t4 (horizontal)*/
b=(((t4[1]-t3[1])*factx)>>8)+t3[1];
/* obtiene color G interpolando a y b (vertical) y lo almacena en c */
c+=((((b-a)*facty)>>8)+a)<<8;
/* obtiene color B interpolado de t1 y t2 (horizontal)*/
a=(((t2[2]-t1[2])*factx)>>8)+t1[2];
/* obtiene color B interpolado de t3 y t4 (horizontal)*/
b=(((t4[2]-t3[2])*factx)>>8)+t3[2];
/* obtiene color B interpolando a y b (vertical) y lo almacena en c */
c+=((((b-a)*facty)>>8)+a)<<16;
/* NOTA: el factor de interpolacion (decimal) tiene un rango de 0 a 255 */
return c; // retorna color interpolado
}
/* text_bilineal: Uso.
text-> textura origen (4 bytes)
tx1-> ancho de textura origen en pixels
ty1-> alto textura origen en pixels
text2-> textura destino (4 bytes)
tx2-> ancho textura destino en pixels
ty2-> alto textura origen en pixels
*/
void text_bilineal(unsigned *text,int tx1,int ty1,unsigned *text2,int tx2,int ty2)
{
int n,m;
int xx,yy,rel;
unsigned col1;
int fx,fy;
for(n=0;n<ty2;n++)
{
/* calcula coordenada Y en textura de origen usando enteros con 8 bits de coma fija */
fy=(((n*ty1)<<8)/ty2);
/* obtiene la Y de textura sin la parte 'decimal' */
yy=fy>>8;
/* deja en fy la parte 'decimal' de Y */
fy&=255;
/* calcula en rel la posicion relativa Y en textura destino*/
rel=n*tx2;
for(m=0;m<tx2;m++)
{
/* calcula coordenada X en textura de origen usando enteros con 8 bits de coma fija */
fx=(((m*tx1)<<8)/tx2);
/* obtiene la X de textura sin la parte 'decimal' */
xx=fx>>8;
/* deja en fx la parte 'decimal' de X */
fx&=255;
/* llama a la funcion que obtiene el color medio en textura origen */
col1=get_pix_rel(xx, yy, text, tx1,ty1, fx, fy);
/* escribe el color calculado en textura destino */
text2[m+rel]=col1;
}
}
}
COMO SE USA
El uso es muy sencillo, la funcion es text_bilineal() y recibe como entrada una textura de color 32 bit color y su ancho y alto en pixeles y una textura de salida tambien a 32 bits, junto con su ancho y alto correspondiente (se calculan solo los 24 bits mas bajos correspondientes a R,G,B)
No creo que tengais mucho problema en poder adaptar la rutina para una textura de entrada de 8 bits (con paleta) o 16 bits, para una salida a 16-32 bits (como se obtienen colores intermedios, no seria muy conveniente usar 8 bits color de salida), o eso espero ;)