adrigm
11/21/2013 - 10:37 AM

App.cpp

#include <GDE/Core/App.hpp>
#include <GDE/Core/Log.hpp>
#include <GDE/Core/StringsUtil.hpp>
#include <GDE/Core/ConfigReader.hpp>
#include <GDE/Core/ConfigCreate.hpp>
#include <fstream>

static std::ofstream logFile;

namespace GDE
{

App* App::uniqueInstance = 0;

App::App()
        : window()
        , exitCode(GDE::StatusNoError)
        , running(false)
        , initialScene(NULL)
{
        // Se abre el archivo donde se guardará el loggin
        logFile.open("log.txt", std::ios::app);

        // Se inicializa el sistema de loggin con el archivo
        GDE::Log::init(logFile);
        
        GDE_LOG_INFO("App: constructor llamado");
}

App::~App()
{
        // Termina el sistema de loggin antes de cerrar el archivo
        GDE::Log::close();
        GDE_LOG_INFO("App: destructor llamado");
}

App* App::instance()
{
        if (uniqueInstance == 0)
        {
                uniqueInstance = new App();
        }
        return uniqueInstance;
}

void App::release()
{
        if (uniqueInstance)
        {
                delete uniqueInstance;
        }
        uniqueInstance = 0;
}

sf::RenderWindow& App::getWindow()
{
        return this->window;
}

bool App::isRunning() const
{
        return this->running;
}

void App::quit(sf::Int16 theExitCode)
{
        this->exitCode = theExitCode;
        this->running = false;
}

void App::setFirstScene(Scene* scene)
{
        if (this->initialScene == NULL)
        {
                initialScene = scene;
                GDE_LOG_INFO("App::setFirstScene(): establecida escena inicial ID =" << scene->getID());
        }
        else
        {
                GDE_LOG_WARNING("App::setFirstScene(): ya se ha establecido una escena inicial");
        }
}

sf::Int16 App::run()
{
        // Establecemos running a true para arrancar la aplicación
        this->running = true;
        // Crea la ventana de la aplicación
        this->createWindow();
        // Arranca todos los subsistemas necesarios
        this->init();
        // Entra en el Bucle del juego hasta que runnig sea false
        this->gameLoop();
        // Se encarga de la limpieza y cerrar todos los subsistemas
        this->cleanup();
        // Escribimos en el log el código de salida
        GDE_LOG_DEBUG("App: Código de salida: " << this->exitCode);
        // Salimos con el código de salida generado
        return this->exitCode;
}

void App::init()
{
        // Se crea la instancia única del SceneManager
        sceneManager = GDE::SceneManager::instance();
        
        // Establecemos la escene inicial
        if (initialScene != 0)
        {
                // Añadimos la primera escena
                this->sceneManager->addScene(this->initialScene);
                // La establecemos como escena activa
                this->sceneManager->setActiveScene(this->initialScene->getID());
                this->sceneManager->changeScene(this->sceneManager->nextScene);
        }
        else
        {
                GDE_LOG_ERROR("App::init(): no se ha establecido escena inicial. LLamar a App::setFirstScene() primero");
                // Salimos con código -2
                quit(GDE::StatusAppInitFailed);
        }

        GDE_LOG_DEBUG("App::init(): completado");
}

void App::createWindow()
{
        // Creamos un modo de video con los valores por defecto
        sf::VideoMode videoMode(this->DEFAULT_VIDEO_WIDTH, this->DEFAULT_VIDEO_HEIGHT, this->DEFAULT_VIDEO_BPP);
        // Creamos un estilo por defecto
        sf::Int32 style = sf::Style::Default;
        // Establecemos fullscreen a false
        bool fullscreen = false;
        // Valor inicial del redisionamiento de la ventana
        bool resize = true;
        // Activamos la sincronización vertical por defecto
        bool vsync = true;

        GDE::ConfigReader conf;
        // Si existe un archivo de configuración lo usamos para cargar los datos
        if(conf.loadFromFile("window.cfg")) // FIX: Deberá ser argado con el gestor de recursos
        {
                // Comprobamos si esta activado el modo fullscreen
                if (conf.getBool("window", "fullscreen", false))
                {
                        fullscreen = true;
                        // Si esta en modo fullscreen obtenemos la resolución del escritorio
                        videoMode = sf::VideoMode::getDesktopMode();
                        // Establecemos el estilo de fullScreen
                        style = sf::Style::Fullscreen;
                }
                else
                {
                        // Establecemos la configuración obtenida del archivo
                        videoMode.width = conf.getUint32("window", "width", this->DEFAULT_VIDEO_WIDTH);
                        videoMode.height = conf.getUint32("window", "height", this->DEFAULT_VIDEO_HEIGHT);
                        videoMode.bitsPerPixel = conf.getUint32("window", "bpp", this->DEFAULT_VIDEO_BPP);
                        // Comprobamos si la ventana se puede redimensionar
                        if (!conf.getBool("window", "resize", true))
                        {
                                resize = false;
                                style = sf::Style::Close | sf::Style::Titlebar;
                        }
                }

                // Comprobamos si vsync está activado
                vsync = (conf.getBool("this->window", "vsync", true));
        }

        // Creamos la ventana con los valores resulantes
        this->window.create(videoMode, "Genbeta Dev Engine", style);
        // FIX: Hay que dar opción también a usar setFrameLimit
        this->window.setVerticalSyncEnabled(vsync);

        // Escribimos la configuración en el archivo
        GDE::ConfigCreate newConf;
        newConf.open("window.cfg");
        newConf.putSection("window");
        newConf.putValue("width", GDE::convertInt32(videoMode.width));
        newConf.putValue("height", GDE::convertInt32(videoMode.height));
        newConf.putValue("bpp", GDE::convertInt32(videoMode.bitsPerPixel));
        newConf.putValue("fullscreen", GDE::convertBool(fullscreen));
        newConf.putValue("resize", GDE::convertBool(resize));
        newConf.putValue("vsync", GDE::convertBool(vsync));
        newConf.close();

        // Escribimos en el log
        GDE_LOG_INFO("App::createWindow(): ventana creada");
        GDE_LOG_INFO("Modo de Video:" << GDE::Log::nospace
                                        << videoMode.width << "x" << videoMode.height << "x" << videoMode.bitsPerPixel);
        GDE_LOG_INFO("Vsync:" << vsync);
        GDE_LOG_INFO("Fullscreen:" << fullscreen);
}

void App::gameLoop()
{
        // Bucle mientras se está ejecutando y la ventana está abierta
        while (this->isRunning() && this->window.isOpen())
        {
                
                // Gestionamos los eventos de la aplicación
                sf::Event event;
                while (window.pollEvent(event))
                {
                        switch (event.type)
                        {
                        case sf::Event::Closed:                        // La ventana es cerrada
                                quit(StatusAppOK); // FIX: Dar la opción de parar el evento a la escena
                                break;
                        case sf::Event::GainedFocus:        // La ventana obtiene el foco
                                this->sceneManager->resumeScene();
                                break;
                        case sf::Event::LostFocus:                // La ventana pierde el foco
                                this->sceneManager->pauseScene();
                                break;
                        default:        // Otros eventos se los pasamos a la ecena activa
                                 this->sceneManager->eventScene(event);
                        } // switch (event.Type)
                } // while (window.GetEvent(event))
                
                // Llamamos al método Update() de la escena activa
                this->sceneManager->updateScene();
                
                // Establecemos el color de fondo de limpieza
                this->window.clear(sceneManager->getActiveScene()->getBackgroundColor());
                
                // Llamamos al método Draw() de la escena activa
                this->sceneManager->drawScene();
                
                // Actualizamos la ventana
                this->window.display();
                
                // Comprobamos cambios de escena
                if (this->sceneManager->handleChangeScene())
                {
                        // Cambiamos el puntero de la escena activa
                        this->sceneManager->changeScene(this->sceneManager->nextScene);
                }
        }
}

void App::cleanup()
{
        // Se elimina todas las escenas
        sceneManager->removeAllScene();
        
        // Eliminamos el SceneManager
        sceneManager->release();
        sceneManager = NULL;
        
        GDE_LOG_DEBUG("App::cleanup(): completado");
}
        
} // namespace GDE