Tutorial SDL 2 en Español - Capítulo 6

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.
//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
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;
}
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;
}
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);
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;
}
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