Capítulo 6: Superficie Optimizada y Estiramiento Suave
Hasta ahora hemos trabajado con imágenes sin tratar (en bruto), como
simplemente mostrábamos una imágen, no importaba. Pero si estás haciendo un
juego, trabajar con imágenes sin tratar lo ralentizará. Así que a estas
imágenes vamos a convertirlas en un formato optimizado para aumentar la
velocidad.
SDL 2 tiene también una nueva función para superficies llamada estiramiento suave (soft stretching) que permite escalar una imagen y ajustarla a un tamaño diferente. En este capítulo del tutorial cargaremos una imagen pequeña y la vamos a estirar al tamaño de la ventana. Primeramente debemos declarar una función personalizada para cargar la imagen y devuelva una superficie con la imagen ya optimizada.
SDL 2 tiene también una nueva función para superficies llamada estiramiento suave (soft stretching) que permite escalar una imagen y ajustarla a un tamaño diferente. En este capítulo del tutorial cargaremos una imagen pequeña y la vamos a estirar al tamaño de la ventana. Primeramente debemos declarar una función personalizada para cargar la imagen y devuelva una superficie con la imagen ya optimizada.
//Declaración de la funciones
bool Inicializar(); //Inicialización de SDL y creación de Ventanas
bool cargarMedios(); //Carga los medios
void cerrar(); //Libera los medios y cierra SDL
SDL_Surface* cargarSuperficie(string ruta); //Funcion para automatizar la carga de la superficie
bool Inicializar(); //Inicialización de SDL y creación de Ventanas
bool cargarMedios(); //Carga los medios
void cerrar(); //Libera los medios y cierra SDL
SDL_Surface* cargarSuperficie(string ruta); //Funcion para automatizar la carga de la superficie
En la declaración de las funciones, declaramos una
función denominada
cargarSuperficie
que devuelve un puntero de una superficie de la imagen ya optimizada y tiene como parámetro la ruta del archivo.
En la función cargarMedios
llamamos a esta función.
bool cargarMedios(){
//Bandera de carga correcta
bool correcto = true;
//Carga cada una de las imágenes
ImagenMostrada = cargarSuperficie("mapaBits.bmp");
if(ImagenMostrada == NULL){
correcto = false;
}
//Salimos de la función
return correcto;
}
//Bandera de carga correcta
bool correcto = true;
//Carga cada una de las imágenes
ImagenMostrada = cargarSuperficie("mapaBits.bmp");
if(ImagenMostrada == NULL){
correcto = false;
}
//Salimos de la función
return correcto;
}
Como se puede ver en el código anterior, cargamos la imagen que vamos a mostrar con la función
cargarSuperficie
y le damos como parametro la ruta del archivo.
La función cargarSuperficie
cargar la imagen y de una vez
la optimiza como veremos:
SDL_Surface* cargarSuperficie(string ruta){
//La superficie de la imagen optimizada
SDL_Surface* superficieOptimizada = NULL;
//La superficie temporal de la imagen que se va a cargar
SDL_Surface* tmpSuperficieACargar = SDL_LoadBMP(ruta.c_str());
if(tmpSuperficieACargar == NULL){
cout << "No se pudo cargar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
else{
//Convierte la superficie al formato de la Superficie que se va a mostrar
superficieOptimizada = SDL_ConvertSurface(tmpSuperficieACargar, Superficie->format, NULL);
if(superficieOptimizada == NULL){
cout << "No se pudo optimizar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
//Liberamos la superficie cargada temporalmente
SDL_FreeSurface(tmpSuperficieACargar);
}
//Retorna la superficie cargada
return superficieOptimizada;
}
//La superficie de la imagen optimizada
SDL_Surface* superficieOptimizada = NULL;
//La superficie temporal de la imagen que se va a cargar
SDL_Surface* tmpSuperficieACargar = SDL_LoadBMP(ruta.c_str());
if(tmpSuperficieACargar == NULL){
cout << "No se pudo cargar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
else{
//Convierte la superficie al formato de la Superficie que se va a mostrar
superficieOptimizada = SDL_ConvertSurface(tmpSuperficieACargar, Superficie->format, NULL);
if(superficieOptimizada == NULL){
cout << "No se pudo optimizar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
//Liberamos la superficie cargada temporalmente
SDL_FreeSurface(tmpSuperficieACargar);
}
//Retorna la superficie cargada
return superficieOptimizada;
}
En esta función declaramos
una superficie llamada
superficieOptimizada
donde vamos a
colocar la imagen tratada. Luego declaramos una superficie temporal llamada tmpSuperficieACargar
donde cargamos la
imagen sin tratar
con la función SDL_LoadBMP
, al que le pasamos como
parámetro la ruta del archivo. Luego optimizamos la superficie superficieOptimizada
con la función SDL_ConvertSurface
al que le pasaremos como primer parámetro la superficie temporal
con la imagen cargada, luego le pasamos al segundo parámetro el formato
de la superficie a la que vamos finalmente a mostrar y al último
parámetro le pasamos un argumento nulo. Cuando cargamos el mapa de bits,
éste es de 24bits de profundidad de color, pero las tarjetas de video
normalmente trabaja con 32bits, esta función convierte la imagen para
adaptarla a la configuración del adaptador de pantalla para que pueda ejecutarse lo más rápido posible. Luego liberamos la
superficie temporal con la función SDL_FreeSurface
y por último
retornamos la superficie optimizada. Ahora nos queda solamente estirar
la imagen y mostrarla en pantalla, esto lo hacemos
en el bucle principal.
//Rectangulo del tamaño de la ventana
SDL_Rect rectEstiramiento;
rectEstiramiento.x = 0;
rectEstiramiento.y = 0;
rectEstiramiento.w = 640;
rectEstiramiento.h = 480;
//Aplicamos estirando la imagen en la superficie de la ventana
SDL_BlitScaled(ImagenMostrada, NULL, Superficie, &rectEstiramiento);
//Actualizamos la superficie de la ventana
SDL_UpdateWindowSurface(Ventana);
SDL_Rect rectEstiramiento;
rectEstiramiento.x = 0;
rectEstiramiento.y = 0;
rectEstiramiento.w = 640;
rectEstiramiento.h = 480;
//Aplicamos estirando la imagen en la superficie de la ventana
SDL_BlitScaled(ImagenMostrada, NULL, Superficie, &rectEstiramiento);
//Actualizamos la superficie de la ventana
SDL_UpdateWindowSurface(Ventana);
Primeramente creamos un rectangulo llamado
rectEstiramiento
al que le daremos las coordenadas de la ventana a la que finalmente vamos a mostrar la imagen.
La función SDL_BlitScaled
es semejante a la función SDL_BlitSurface
con la diferencia de que esta puede escalar
o estirar la imagen, así que
el último parámetro le enviamos las coordenadas del rectangulo para que
abarque toda la pantalla, si usted quiere ver que pasa si no le
colocamos el rectángulo, simplemente cambie el último parámetro
a NULL
. Puede comentar
los resultados en la caja de comentarios. El código fuente debe quedar de la siguiente forma:
//Inclusión de los encabezados utilizados en nuestros
programas
#include <SDL.h>
#include <iostream>
#include <string>
//Usamos el namespace std
using namespace std;
//Declaración de la funciones
bool Inicializar(); //Inicialización de SDL y creación de Ventanas
bool cargarMedios(); //Carga los medios
void cerrar(); //Libera los medios y cierra SDL
SDL_Surface* cargarSuperficie(string ruta); //Funcion para automatizar la carga de la superficie
//Inicialización de la ventana, la superficie y la imagen
SDL_Window* Ventana = NULL; //La ventana donde se renderizará la imagen
SDL_Surface* Superficie = NULL; //La superficie que contendrá la ventana
SDL_Surface* ImagenMostrada = NULL; //La imagen que se mostrará en la superficie
bool Inicializar(){
//Bandera de inicialización es correcta
bool correcto = true;
//Inicializa el subsistema de Video
if(SDL_Init(SDL_INIT_VIDEO) < 0){
cout << "ERROR: No se pudo inicializar SDL, Error SDL: " << SDL_GetError() << "\n";
correcto = false;
}
else{
//Se crea la ventana principal
Ventana = SDL_CreateWindow("Tutorial SDL 2", 50, 50, 640, 480, SDL_WINDOW_SHOWN);
if(Ventana == NULL){
cout << "ERROR: No se pudo crear la ventana, SDL_Error: " << SDL_GetError() << "\n";
correcto = false;
}
else{
//Se crea la superficie para la ventana principal
Superficie = SDL_GetWindowSurface(Ventana);
}
}
//Salimos de la función
return correcto;
}
bool cargarMedios(){
//Bandera de carga correcta
bool correcto = true;
//Carga cada una de las imágenes
ImagenMostrada = cargarSuperficie("mapaBits.bmp");
if(ImagenMostrada == NULL){
correcto = false;
}
//Salimos de la función
return correcto;
}
void cerrar(){
//Liberamos la superficie utilizada
SDL_FreeSurface(ImagenMostrada);
ImagenMostrada = NULL;
//Destruimos la Ventana para liberar recursos.
SDL_DestroyWindow(Ventana);
//Quitamos el subsistema de SDL.
SDL_Quit();
}
SDL_Surface* cargarSuperficie(string ruta){
//La superficie de la imagen optimizada
SDL_Surface* superficieOptimizada = NULL;
//La superficie temporal de la imagen que se va a cargar
SDL_Surface* tmpSuperficieACargar = SDL_LoadBMP(ruta.c_str());
if(tmpSuperficieACargar == NULL){
cout << "No se pudo cargar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
else{
//Convierte la superficie al formato de la Superficie que se va a mostrar
superficieOptimizada = SDL_ConvertSurface(tmpSuperficieACargar, Superficie->format, NULL);
if(superficieOptimizada == NULL){
cout << "No se pudo optimizar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
//Liberamos la superficie cargada temporalmente
SDL_FreeSurface(tmpSuperficieACargar);
}
//Retorna la superficie cargada
return superficieOptimizada;
}
int main(int argc, char* args[]){
//Inicializa SDL y crea las ventanas
if(!Inicializar()){
cout << "No se pudo inicializar\n";
}
else{
//Carga los medios
if(!cargarMedios()){
cout << "No se pudo cargar los medios\n";
}
else{
//Bandera del bucle principal
bool quitar = false;
//Controlador de Eventos
SDL_Event e;
//Bucle principal
while(!quitar){
//Maneja la cola de eventos
while(SDL_PollEvent(&e) != 0){
//Si el usuario quiere salir
if(e.type == SDL_QUIT){
quitar = true;
}
//Si el usuario presiona las escape, sale de la aplicación
else if(e.type == SDL_KEYDOWN){
if(e.key.keysym.sym == SDLK_ESCAPE){
quitar = true;
}
}
}
//Rectangulo del tamaño de la ventana
SDL_Rect rectEstiramiento;
rectEstiramiento.x = 0;
rectEstiramiento.y = 0;
rectEstiramiento.w = 640;
rectEstiramiento.h = 480;
//Aplicamos estirando la imagen en la superficie de la ventana
SDL_BlitScaled(ImagenMostrada, NULL, Superficie, &rectEstiramiento);
//Actualizamos la superficie de la ventana
SDL_UpdateWindowSurface(Ventana);
}
}
}
//Liberamos los recursos y cerramos SDL
cerrar();
//Salimos de main
return 0;
}
#include <SDL.h>
#include <iostream>
#include <string>
//Usamos el namespace std
using namespace std;
//Declaración de la funciones
bool Inicializar(); //Inicialización de SDL y creación de Ventanas
bool cargarMedios(); //Carga los medios
void cerrar(); //Libera los medios y cierra SDL
SDL_Surface* cargarSuperficie(string ruta); //Funcion para automatizar la carga de la superficie
//Inicialización de la ventana, la superficie y la imagen
SDL_Window* Ventana = NULL; //La ventana donde se renderizará la imagen
SDL_Surface* Superficie = NULL; //La superficie que contendrá la ventana
SDL_Surface* ImagenMostrada = NULL; //La imagen que se mostrará en la superficie
bool Inicializar(){
//Bandera de inicialización es correcta
bool correcto = true;
//Inicializa el subsistema de Video
if(SDL_Init(SDL_INIT_VIDEO) < 0){
cout << "ERROR: No se pudo inicializar SDL, Error SDL: " << SDL_GetError() << "\n";
correcto = false;
}
else{
//Se crea la ventana principal
Ventana = SDL_CreateWindow("Tutorial SDL 2", 50, 50, 640, 480, SDL_WINDOW_SHOWN);
if(Ventana == NULL){
cout << "ERROR: No se pudo crear la ventana, SDL_Error: " << SDL_GetError() << "\n";
correcto = false;
}
else{
//Se crea la superficie para la ventana principal
Superficie = SDL_GetWindowSurface(Ventana);
}
}
//Salimos de la función
return correcto;
}
bool cargarMedios(){
//Bandera de carga correcta
bool correcto = true;
//Carga cada una de las imágenes
ImagenMostrada = cargarSuperficie("mapaBits.bmp");
if(ImagenMostrada == NULL){
correcto = false;
}
//Salimos de la función
return correcto;
}
void cerrar(){
//Liberamos la superficie utilizada
SDL_FreeSurface(ImagenMostrada);
ImagenMostrada = NULL;
//Destruimos la Ventana para liberar recursos.
SDL_DestroyWindow(Ventana);
//Quitamos el subsistema de SDL.
SDL_Quit();
}
SDL_Surface* cargarSuperficie(string ruta){
//La superficie de la imagen optimizada
SDL_Surface* superficieOptimizada = NULL;
//La superficie temporal de la imagen que se va a cargar
SDL_Surface* tmpSuperficieACargar = SDL_LoadBMP(ruta.c_str());
if(tmpSuperficieACargar == NULL){
cout << "No se pudo cargar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
else{
//Convierte la superficie al formato de la Superficie que se va a mostrar
superficieOptimizada = SDL_ConvertSurface(tmpSuperficieACargar, Superficie->format, NULL);
if(superficieOptimizada == NULL){
cout << "No se pudo optimizar la imagen " << ruta.c_str() << " SDL Error: " << SDL_GetError() << "\n";
}
//Liberamos la superficie cargada temporalmente
SDL_FreeSurface(tmpSuperficieACargar);
}
//Retorna la superficie cargada
return superficieOptimizada;
}
int main(int argc, char* args[]){
//Inicializa SDL y crea las ventanas
if(!Inicializar()){
cout << "No se pudo inicializar\n";
}
else{
//Carga los medios
if(!cargarMedios()){
cout << "No se pudo cargar los medios\n";
}
else{
//Bandera del bucle principal
bool quitar = false;
//Controlador de Eventos
SDL_Event e;
//Bucle principal
while(!quitar){
//Maneja la cola de eventos
while(SDL_PollEvent(&e) != 0){
//Si el usuario quiere salir
if(e.type == SDL_QUIT){
quitar = true;
}
//Si el usuario presiona las escape, sale de la aplicación
else if(e.type == SDL_KEYDOWN){
if(e.key.keysym.sym == SDLK_ESCAPE){
quitar = true;
}
}
}
//Rectangulo del tamaño de la ventana
SDL_Rect rectEstiramiento;
rectEstiramiento.x = 0;
rectEstiramiento.y = 0;
rectEstiramiento.w = 640;
rectEstiramiento.h = 480;
//Aplicamos estirando la imagen en la superficie de la ventana
SDL_BlitScaled(ImagenMostrada, NULL, Superficie, &rectEstiramiento);
//Actualizamos la superficie de la ventana
SDL_UpdateWindowSurface(Ventana);
}
}
}
//Liberamos los recursos y cerramos SDL
cerrar();
//Salimos de main
return 0;
}
Hasta aquí hemos visto como
trabajar con superficies optimizadas y estiramiento suave de imágenes
con SDL_2. Puedes descargar el código completo
aquí.
Capítulo 7:
No hay comentarios:
Publicar un comentario