SDL Hello World tutorial

From Guichan

Jump to: navigation, search

Contents


Purpose

The purpose of this tutorial is to give a quick start in how to set up Guichan with SDL given a small guided Hello World application. For information regarding SDL please read the official SDL documentation.

Tutorial

To be able to use Guichan and SDL in an application the Guichan header, the Guichan SDL header and the SDL header need to be included. The Guichan header contains everything needed from the core library, the Guichan SDL header includes everything for the SDL back end for Guichan. The iostream header is included so that we can print error messages with cout.

#include <iostream>
#include <guichan.hpp>
#include <guichan/sdl.hpp>
#include "SDL.h"

Every application needs a main function, including this one. Apart from the main function it's good practice to add a function to initialise the application, a function to run the application and a function to halt the application. We let the main function simply first call the initialisation function followed by the run function and the halt function.

void init() 
{

}

void run()
{

}

void halt()
{

}

int main(int argc, char **argv)
{
    init();
    run();  
    halt();

    return 1;
}

Guichan throws exception as soon as an error is encountered, we therefore alter our main function slightly to catch exceptions and print their error message.

int main(int argc, char **argv)
{
    try 
    {
        init();
        run();  
        halt();
    }
    catch (gcn::Exception e)
    {
        std::cout << e.getMessage() << std::endl;
    }
    catch (std::exception e)
    {
        std::cout << "Std exception: " << e.what() << std::endl;  
    }
    catch (...)
    {
        std::cout << "Unknown exception" << std::endl;
    }

    return 1;
}

To be able to use SDL we need a surface for the screen and an event struct for events. We add declarations variables for a surface and an event struct below the inclusion of the headers. To be able to use Guichan with SDL we need a couple of objects from the Guichan SDL back end to give Guichan the ability to use SDL. The objects are a SDLGraphics object, a SDLInput object and a SDLImageLoader object. We add declarations of variables for those objects below the other declared variables.

 
SDL_Surface* screen;
SDL_Event event;
gcn::SDLInput* input;
gcn::SDLGraphics* graphics;
gcn::SDLImageLoader* imageLoader;

As this tutorial shows a Hello World application we also need a couple of objects from Guichan in order to create a GUI. The objects are a Gui object, a Container object, a Label object and finally a Font object (in this case we use an ImageFont object).

gcn::Gui* gui;
gcn::Container* top;
gcn::ImageFont* font;
gcn::Label* label;

In the initialisation function we begin with initialising SDL. We need unicode enabled to get user input and key repeat enabled if we want keys to be repeated when held down.

void init()
{
    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);
    SDL_EnableUNICODE(1);
    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
}

After SDL has been initialised we initialise the Guichan SDL back end. We first instantiate a SDLImageLoader object. As all images in Guichan should use the SDLImageLoader when loading themselves we use a static function in Image to provide the image loader. After SDLImageLoader we instantiate the SDLGraphics object. SDLGraphics needs a surface to draw to and we provide the object with the screen surface as we want our GUI to be drawn to the screen. Finally we instantiate the SDLInput object, an object with no need of initialisation.

imageLoader = new gcn::SDLImageLoader();
gcn::Image::setImageLoader(imageLoader);
graphics = new gcn::SDLGraphics();
graphics->setTarget(screen);
input = new gcn::SDLInput();

After the Guichan SDL back end has been initialised we initialise Guichan. As we need to display text in a Hello World application we need a font. In Guichan there exists an easy to use font called ImageFont which we will be using. The ImageFont uses a normal image containing glyphs separated with a certain colour. When initialising the ImageFont you provide the filename along with a string with the characters the image contains. For convenience a static function in Widget exists to set a global font that all widgets should use unless a widget is given a specific font to use.

After the ImageFont has been instantiated and initialised we instantiate a Gui object. The Gui object is the core object in Guichan and it contains a GUI. After the initialisation we provide the Gui object with the SDLGraphics object and the SDLInput object so the Gui can utilise SDL for drawing and grabbing user input.

font = new gcn::ImageFont("fixedfont.bmp", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
gcn::Widget::setGlobalFont(font); 

gui = new gcn::Gui();
gui->setGraphics(graphics);
gui->setInput(input);

Gui can actually only contain one widget, the widget is referred to as the top widget. To make Gui able to contain more than one widget the top widget has to be a container widget which is a widget that can contain other widgets. In this tutorial we are going to make a Hello World application that only needs one widget - Label widget - to display text, but for completeness we set a container as the top widget as that is the most common thing to do. To make the container as big as the screen we set it's dimension the dimension of the screen.

Finally we instantiate a Label widget, provide the label with the caption "Hello World" and add the label to the GUI by adding it to the top container. Before we add the container we set the label's position to be somewhere in the middle of the screen.

top = new gcn::Container();    
top->setDimension(gcn::Rectangle(0, 0, 640, 480));
gui->setTop(top);

label = new gcn::Label("Hello World");
label->setPosition(280, 220);
top->add(label); 

In the run function we begin by adding a while loop as the main application loop. We let the loop run until a boolean variable, running, is set to false. In the beginning of the while loop we checking for user input. This is done by traversing the SDL event queue and passing events to the SDLInput object for the GUI to handle. As it would be nice to be able to quit the application by pressing the escape key we interrupt pressing of escape, don't pass the event to the SDLInput object (as we are going to quit anyway) and set the running boolean variable to false making the main while loop stop.

After input has been checked we tell the Gui object to perform logic and to draw itself. Finally we flip the screen surface so the screen will be updated.

void run()
{
    bool running = true;

    while (running)
    {
        while(SDL_PollEvent(&event))
        {
            if (event.type == SDL_KEYDOWN)
            {
                if (event.key.keysym.sym == SDLK_ESCAPE)
                {  
                    running = false;
                }
       
            }
            else if(event.type == SDL_QUIT)
            {
                running = false;
            }
      
           input->pushInput(event);
        }
    
        gui->logic();
        gui->draw();
    
        SDL_Flip(screen);
    } 
}

In the halt function we simply clean up all the instantiated objects and tell SDL to quit.

void halt()
{
    delete label;
    delete font;
    delete top;
    delete gui;
  
    delete input;  
    delete graphics;
    delete imageLoader;
    
    SDL_Quit();
}

And that's all there is to it to make a Hello World application.

OpenGL

If you're using SDL with OpenGL, you need to make a few slight changes from the given SDL tutorial code.

  • Add: #include "guichan/opengl/openglsdlimageloader.hpp"
  • Change: gcn::SDLGraphics to gcn::OpenGLGraphics
  • Change: gcn::SDLImageLoader to gcn::OpenGLSDLImageLoader
  • Change: When creating the OpenGLGraphics object, you will need to pass in the canvas width/height: gcn::OpenGLGraphics(SCREEN_WIDTH, SCREEN_HEIGHT)

Complete code

#include <iostream>
#include <guichan.hpp>
#include <guichan/sdl.hpp>
#include "SDL.h"

SDL_Surface* screen;
SDL_Event event;
gcn::SDLInput* input;
gcn::SDLGraphics* graphics;
gcn::SDLImageLoader* imageLoader;

gcn::Gui* gui;
gcn::Container* top;
gcn::ImageFont* font;
gcn::Label* label;

void init()
{
    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);
    SDL_EnableUNICODE(1);
    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

    imageLoader = new gcn::SDLImageLoader();
    gcn::Image::setImageLoader(imageLoader);
    graphics = new gcn::SDLGraphics();
    graphics->setTarget(screen);
    input = new gcn::SDLInput();

    font = new gcn::ImageFont("fixedfont.bmp", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    gcn::Widget::setGlobalFont(font); 

    gui = new gcn::Gui();
    gui->setGraphics(graphics);
    gui->setInput(input);

    top = new gcn::Container();    
    top->setDimension(gcn::Rectangle(0, 0, 640, 480));
    gui->setTop(top);

    label = new gcn::Label("Hello World");
    label->setPosition(280, 220);
    top->add(label); 
}

void run()
{
    bool running = true;

    while (running)
    {
        while(SDL_PollEvent(&event))
        {
            if (event.type == SDL_KEYDOWN)
            {
                if (event.key.keysym.sym == SDLK_ESCAPE)
                {  
                    running = false;
                }
       
            }
            else if(event.type == SDL_QUIT)
            {
                running = false;
            }
      
           input->pushInput(event);
        }

       gui->logic();
       gui->draw();
    
       SDL_Flip(screen);
    }
}

void halt()
{
    delete label;
    delete font;
    delete top;
    delete gui;
  
    delete input;
    delete graphics;
    delete imageLoader;
    
    SDL_Quit();
}

int main(int argc, char **argv)
{
    try 
    {
        init();
        run();  
        halt();
    }
    catch (gcn::Exception e)
    {
        std::cout << e.getMessage() << std::endl;
    }
    catch (std::exception e)
    {
        std::cout << "Std exception: " << e.what() << std::endl;  
    }
    catch (...)
    {
        std::cout << "Unknown exception" << std::endl;
    }

    return 1;
}

Personal tools
community