PDA

Ver la versión completa : [SOURCE] Función de blitting con transformaciones (rotaciones, zooms...)



Puck2099
20/06/2006, 07:03
Hola,

Como algunos sabrán, llevo cerca de una semana currando en una función que permita realizar rotaciones de sprites en SDL y por fin la tengo terminada.

Sé que existe la librería SDL_gfx, pero todas las pruebas que he realizado terminan igual, con un segmentation fault (que por otro lado en PC van perfectamente), por eso decidí hacer mi propia función.

En principio solo la iba a usar para nuestro Ambassadors, pero como creo que puede ser útil al resto de programadores, la pongo aquí a vuestra disposición.

En esta librería llamada SDL_plusplus, de momento solo he metido esta función, pero iré actualizándola con nuevas funciones interesantes a medida que las vaya necesitando.

La función está hecha para que tire en SDL (tanto en GP32, GP2X, PC...), pero sería relativamente sencillo adaptarla a las minilib o similar. Me he basado en código interno de mi port de Fenix para su realización, usando la librería de punto fijo para las operaciones matemáticas, así que es relativamente rápida (bastante más de lo que era la SDL_gfx).

¿Qué incorpora la función?
Bien, podemos hacer rotaciones (en milésimas de grados), zooms (aumentando o disminuyendo independientemente el eje X e Y), clipping (para que solo se pinte en una zona de la superficie destino), seleccionar aplicar los "efectos" a la superficie entera o solo a una zona de ella (para transferir por ejemplo solo un sprite de una tira de ellos). Por otro lado, en conjunción con estos efectos, también podemos realizar mirroring ("reflejar" la imagen como si se viera en un espejo) vertical y/o horizontal.

¿Qué no incorpora?
Pues básicamente efectos de transparencias graduales, alpha blendings, etc., aunque sí que permite usarse un color como transparente.
Por otro lado, solo están soportadas profundidades de 8 y 16 bits de color, así que no funcionará con otras.

La cabecera de la función es:

void SDL_Blitfx (SDL_Surface * dest, SDL_Rect * clip, SDL_Rect * srcrect,
int scrx, int scry, int flags,
int angle, int scalex, int scaley,
SDL_Surface * src);

Donde:

dest -> Superficie destino donde transferir la imagen transformada.
clip -> Limita la region de destino donde transferir la imagen. Si se deja a NULL se puede hacer en cualquier zona de la superficie destino.
srcrect -> Limita la region de la superficie origen que se va a transferir. Si se deja a NULL se transferirá toda la superficie.
srcx, srcy -> Coordenadas de la superficie destino donde irá el CENTRO de la imagen transformada transferida.
flags -> Se pueden usar los siguientes valores (pueden usarse conjuntamente con ORs a nivel de bits): B_NONE, B_HMIRROR, B_VMIRROR. Respectivamente significan ningún mirroring, mirroring horizontal y mirroring vertical.
angle -> Ángulo en milésimas de grado para la rotación (por ejemplo, para 90 grados valdría 90000). Para no rotar usad un ángulo de 0 grados.
scalex, scaley -> Factor de zoom a aplicar a la imagen. Sin zoom sería un 100, para el doble de tamaño 200, etc.
src-> Superficie de origen usada para la transferencia.


Adjunto las librerías con un ejemplo bastante tonto para que lo veáis en funcionamiento.


http://www.gp32wip.com/screenshots/blitfx.png

Si os resulta útil y modificáis el fuente de la librería, agradecería que publicárais vuestros cambios para que salieramos todos beneficiados :)

Ah, quería agradecerle especialmente a Uncanny su ayuda y dedicación para probar la función :)

Saludos

alien8
20/06/2006, 07:51
Gracias Puck2099 :)

Ya puestos a rizar el rizo , seria posible que la imagen pudiera rotarse en perspectiva ( horizontal y vertical )? , vamos si no me explico bien me refiero a la imagen que adjunto , teniendo como imagen origen el cuadrado del centro poder girar la imagen en el eje "z" simulando profundidad.

miq01
20/06/2006, 08:45
¡Gracias Puck (y Uncanny)!

La verdad es que he dejado de hacer algún proyecto en SDL por no tener rotaciones y esto me va a venir de perlas si en algún momento lo retomo. Hace un tiempo probé las SDL_gfx y la verdad es que el rendimiento dejaba bastante que desear, así que las descarté. Luego miré el código de Fenix y me dio bastante palo intentar entender lo que hacía y pasé del tema, y mira por dónde me lo has solucionado. :)

A ver si tengo un rato para probarlas.

Uncanny
20/06/2006, 09:16
Ah, quería agradecerle especialmente a Uncanny su ayuda y dedicación para probar la función :)A ti por dejarme probarla, además charlar contigo de estos temas es siempre muy aleccionador :)

Eso si, quiero dejar claro que todo el curro y merito es de Puck, que le ha puesto bastante dedicación, yo solo me he limitado a probarlo y a hablar con él para compartir ideas, de hecho al principio, hablando del tema con él, después de decirme el problema de SDL_gfx en la GP2X quise modificar la SDL_gfx para solucionarlo en la GP2X, pero al día siguiente él ya había adaptado una función de Fenix, y una vez que la probé supe que trabajar en SDL_gfx no era necesario, ya os digo que esta librería y, en especial esta función SDL_Blitfx, es muuuucho mejor (y tanto, trabaja con punto fijo usando además la cabecera math-sll.h), comparativamente, que la que probee SDL_gfx (solo le falta alpha blending o usar imagenes de más bpp con el canal alpha para transparencias, aunque se puede usar el "Color Key" para ello, nada que no se pueda implementar luego) y encima con extras como el mirroring de superficies :D

Logann
20/06/2006, 15:34
Gracias Puck2099 :)

Ya puestos a rizar el rizo , seria posible que la imagen pudiera rotarse en perspectiva ( horizontal y vertical )? , vamos si no me explico bien me refiero a la imagen que adjunto , teniendo como imagen origen el cuadrado del centro poder girar la imagen en el eje "z" simulando profundidad.

Creo que lo pudes hacer tu mismo antes de llamar la funcion.

1.8. Fórmula de proyección en la pantalla

Se considera que los puntos del escenario están situados detrás de la pantalla.
Para obtener las coordenadas 2D de la pantalla correspondientes a los puntos del espacio 3D basta realizar una proyección cónica, de centro en el ojo del observador, sobre el plano de la pantalla.

Sea p el punto a proyectar (de coordenadas (x,y,z)), d la distancia del ojo a la pantalla, y p' el punto proyectado (de coordenadas (x',y')) Debe cumplirse, según el teorema de Tales,
y'/y = d/z
x'/x = d/z
De donde deducimos la formula de transformación:

x'=x*d/z
y'=y*d/z

En las fórmulas de proyección hay que tener cuidado que el valor de la distancia d entre el observador y la pantalla no sea demasiado peque¤o, pues la imagen aparecería distorsionada. Esto es debido a que las personas poseen un campo de vision de 60 grados, y al proyectar sobre una pantalla demasiado próxima al observador, el cono de proyección podría tener un angulo superior a 60 grados.

sacado de: http://www.upv.es/protel/usr/jotrofer/graficos/3d.htm


Por cierto esto de rotar sprits puede ser muy pràctico, a ver cuando le puedo dar un vistazo. thx!

D_Skywalk
20/06/2006, 18:15
Joe Puck, justo esta mañana estaba buscando ejemplos para hacer mirrors de surfaces y me disponia a implementarlo en mi libreria de Sprites, asi que solo te puedo dar mil gracias :D

Los angulos en si, no creo que los use, siendo un juego isometrico... no se me ocurre nada xD

Un Saludo y gracias de nuevo sobretodo por compartirlo con el populacho xD

< - >
Puck, yo tengo un poco mas estricta mi compilacion con GCC y la funcion me fallaba, te dejo el parche para que la funcion compare_y no falle al compilar :D



static inline int compare_vertex_y (const void * a, const void * b)
{
if ((*(VERTEX *)a).y == (*(VERTEX *)b).y)
return (*(VERTEX *)a).x - (*(VERTEX *)b).x;
else
return (*(VERTEX *)a).y - (*(VERTEX *)b).y;
}


Un saludo y gracias de nuevo por compartirla, si encuentro alguna mejora mas ya la posteo :)

Puck2099
20/06/2006, 20:13
Puck, yo tengo un poco mas estricta mi compilacion con GCC y la funcion me fallaba, te dejo el parche para que la funcion compare_y no falle al compilar :D



static inline int compare_vertex_y (const void * a, const void * b)
{
if ((*(VERTEX *)a).y == (*(VERTEX *)b).y)
return (*(VERTEX *)a).x - (*(VERTEX *)b).x;
else
return (*(VERTEX *)a).y - (*(VERTEX *)b).y;
}


Un saludo y gracias de nuevo por compartirla, si encuentro alguna mejora mas ya la posteo :)

Gracias tío, cuando llegue a casa la parcheo y resubo :)

< - >
Archivo resubido con la modificación de D_Skywalk :brindis:

Waninkoko
20/06/2006, 22:55
Muy buena Puck ;)
Ayer estuve trabajando en una pequeña lib para rotar surfaces y casi la tenia pero viendo lo que has hecho lo dejo xDD

< - >
Puck, ¿me das permiso para meter tu lib en mis sdl2X? ^^ Tengo intencion de mejorarla (si es que se puede mejorar xD).

una-i
20/06/2006, 23:58
Muy buena Puck ;)
Ayer estuve trabajando en una pequeña lib para rotar surfaces y casi la tenia pero viendo lo que has hecho lo dejo xDD

< - >
Puck, ¿me das permiso para meter tu lib en mis sdl2X? ^^ Tengo intencion de mejorarla (si es que se puede mejorar xD).

Y digo yo, en vez de sdl2X y SDL_plusplus , no podriais hacer sdl2X++ entre los dos :P

Unai.

Waninkoko
21/06/2006, 03:00
Y digo yo, en vez de sdl2X y SDL_plusplus , no podriais hacer sdl2X++ entre los dos :P

Unai.

Es que el nombre queda muy feo xDD

idaho
21/06/2006, 20:06
SDL_Surface * tmp = IMG_Load_RW(SDL_RWFromMem(&printtest_bmp, sizeof(printtest_bmp)),0);
printtest=SDL_DisplayFormat(tmp);
SDL_FreeSurface(tmp);
tmp = SDL_LoadBMP("gp32wipl.bmp");
SDL_Surface * bitmap = SDL_DisplayFormat(tmp);
SDL_FreeSurface(tmp);


No entiendo esta parte del código del ejemplo. ¿Alguien me lo puede explicar como si fuera mongolito? Gracias!

< - >



SDL_Surface * tmp = IMG_Load_RW(SDL_RWFromMem(&printtest_bmp, sizeof(printtest_bmp)),0);
printtest=SDL_DisplayFormat(tmp);
SDL_FreeSurface(tmp);
tmp = SDL_LoadBMP("gp32wipl.bmp");
SDL_Surface * bitmap = SDL_DisplayFormat(tmp);
SDL_FreeSurface(tmp);


No entiendo esta parte del código del ejemplo. ¿Alguien me lo puede explicar como si fuera mongolito? Gracias!

Vale, ya lo he visto... printtest contiene los numeritos para los fotogramas por segundo y bitmap es la imagen en si. tmp se usa para adaptar la imagen al bpp de la pantalla.

Puck2099
21/06/2006, 20:15
Vale, ya lo he visto... printtest contiene los numeritos para los fotogramas por segundo y bitmap es la imagen en si. tmp se usa para adaptar la imagen al bpp de la pantalla.

Sí, exacto, es como dices :)

La imagen printtest está así porque es código "heredado" directamente del Lady Killer :D