Mostrar una imagen fue lo que vimos en el anterior post sobre SDL en C bajo GNU/Linux. En esta ocasión vamos a mostrar 2 imágenes. Una de fondo y otra que es un sprite con el que vamos a jugar para crear una animación de una persona andando.
Para que no tengas que picar mucho código y crear estructuras de directorios he empaquetado en un zip todo el tinglado: mostrarimagen.zip
Descargando ese zip no tendréis que andar bajando nada, no obstante voy a colocar las 2 imágenes que necesitaremos:
Si has descargado el zip y lo has descomprimido podrás compilar el código ejecutando make en el directorio en el que se encuentra mostrarimagen.c (directorio en el que estará también el makefile).
Se que no es común encontrar un bmp transparente pero … es posible crear bmps con fondo transparente y por eso quería probar si con SDL se podría jugar un poco y animar un sprite.
He bajado un sprite del juego Day of the tentacle. El sprite es basicamente una secuencia de los diferentes frames que podemos usar para que parezca que el personaje está andando. En este caso son 6.
Para saber cuanto tiene de ancho un frame de ese sprite tenemos que dividir entre 6 el ancho total
Dejo aquí el código para ver si se entiende lo realizado.
Y que se entienda que está duplicado con la finalidad de que sea más sencillo de entender inicialmente. Pero que lo ideal sería crear un código en el que no haga falta repetir la parte de carga de los frames :).
#include <SDL.h> #include <stdio.h> int main(void) { SDL_Window * ventana; SDL_Renderer * render; SDL_Surface * imagenEscenario; // Escenario SDL_Texture * texturaEscenario; // Escenario SDL_Surface * imagenPersonaje; // Personaje SDL_Texture * texturaPersonaje; // Personaje int x = 0; int y = 324; // 480 de alto del escenario - 112 del alto del personaje son 324. int s = 20; // los pixeles que avanzará el personae a cada paso. int alturaPersonaje = 112; // la altura del frame del personaje. int anchuraPersonaje = 156; // la anchura del frame del personaje. SDL_Rect srcrect1 = { 0, 0, alturaPersonaje, anchuraPersonaje }; // frame1 del personaje SDL_Rect srcrect2 = { 112, 0, alturaPersonaje, anchuraPersonaje }; // frame2 del personaje SDL_Rect srcrect3 = { 224, 0, alturaPersonaje, anchuraPersonaje }; // frame3 del personaje SDL_Rect srcrect4 = { 336, 0, alturaPersonaje, anchuraPersonaje }; // frame4 del personaje SDL_Rect srcrect5 = { 448, 0, alturaPersonaje, anchuraPersonaje }; // frame5 del personaje SDL_Rect srcrect6 = { 560, 0, alturaPersonaje, anchuraPersonaje }; // frame6 del personaje imagenEscenario = SDL_LoadBMP("res/escenario.bmp"); // Cargamos el bmp del escenario. El fondo. imagenPersonaje = SDL_LoadBMP("res/personaje.bmp"); // Cargamos el sprite para extraer todos los frames SDL_Init(SDL_INIT_VIDEO); ventana = SDL_CreateWindow("mostrando una imagen",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,480,SDL_WINDOW_OPENGL); if (ventana == NULL) { printf("No se pudo crear la ventana: %s\n", SDL_GetError()); return 1; } render = SDL_CreateRenderer(ventana, -1, 0); texturaEscenario = SDL_CreateTextureFromSurface(render, imagenEscenario); texturaPersonaje = SDL_CreateTextureFromSurface(render, imagenPersonaje); // Cargamos el escenario SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); // Cargamos el personaje en el frame 1 SDL_Rect dstrect1 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect1, &dstrect1); SDL_RenderPresent(render); SDL_Delay(250); // Cargamos el personaje en el frame 2 SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); x = x+s; SDL_Rect dstrect2 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect2, &dstrect2); SDL_RenderPresent(render); SDL_Delay(250); // Cargamos el personaje en el frame 3 SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); x = x+s; SDL_Rect dstrect3 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect3, &dstrect3); SDL_RenderPresent(render); SDL_Delay(250); // Cargamos el personaje en el frame 4 SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); x = x+s; SDL_Rect dstrect4 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect4, &dstrect4); SDL_RenderPresent(render); SDL_Delay(250); // Cargamos el personaje en el frame5 SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); x = x+s; SDL_Rect dstrect5 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect5, &dstrect5); SDL_RenderPresent(render); SDL_Delay(250); // Cargamos el personaje en el frame6 SDL_RenderCopy(render, texturaEscenario, NULL, NULL); SDL_RenderPresent(render); x = x+s; SDL_Rect dstrect6 = { x, y, alturaPersonaje, anchuraPersonaje }; SDL_RenderCopy(render, texturaPersonaje, &srcrect6, &dstrect6); SDL_RenderPresent(render); SDL_Delay(3000); SDL_DestroyTexture(texturaEscenario); SDL_FreeSurface(imagenEscenario); SDL_DestroyTexture(texturaPersonaje); SDL_FreeSurface(imagenPersonaje); SDL_DestroyRenderer(render); SDL_DestroyWindow(ventana); SDL_Quit(); return 0; }
Para que se entienda mejor y no tener que añadir código de control de eventos he ido poniendo cada frame con una espera de 250ms (un cuarto de segundo) seguidos. Se puede ver en el código todo lo que ya hemos visto en anteriores artículos.
Lo nuevo es que en vez de una imagen vemos que podemos añadir una sobre otra. Por ejemplo un programa que añadiese una mascara de agua a una foto. pues con esto ya sabríamos hacerlo (al menos para sobreponer 2 imágenes). Para guardar se necesitarían otras funciones.
Esto no incorpora mucho más a lo que ya hemos visto, no obstante es bueno saber que podemos coger solamente una parte de un mapa de bits y mostrarla donde queramos. Es por eso que quería realizar este ejemplo.
Para no liar demasiado en vez de crear un bucle he preferido simplemente colocarlo todo secuencialmente.
Es bueno darse también cuenta de que en un programa de verdad tendríamos que estar ya realizando funciones y trabajar en diferentes archivos para que fuese algo más modular y reutilizable.
Pero no son programas de verdad, de momento son ejemplos para ir viendo que cosas se pueden hacer con SDL programando en C sobre GNU/Linux.
Saludos cordiales.