Today, we
will create a simple image displaying program with SDL 2.0 and Mingw. This will
help you understand some of the program structure related to C++ and how SDL
used objects to render images on screen. We will be making a class to hold our
program logic, and using that class to render an image to the screen.
Create header file; this file will hold our class, the one we will be building
our program with. With a class, an entire object, with it’s variables and
methods, can be encapsulated into a single object, to be used as needed or
desired by a program. In our example, this class will run the loop for
displaying our image to the screen, and for testing for user input.
Add the two includes at the very top of the file:
#include "SDL2/SDL.h"
#include <stdio.h>
And enter
the following to start the class definition: class cpp_Application {
The class keyword will start the class
definition for this header file, defining the name for the class as cpp_Application when an object of this
class is created. After this definition, enter the next line below and type public: . This will define any method
or variable with a public scope, meaning any method or variable can be used or
see by anywhere in the program.
On the lines
below, define the following 4 methods:
cpp_Application() //The default constructor for C++ classes
~cpp_Application() //The default constructor for C++ classes
Int executeProgram(); //Method to run the program in a loop; this
method will be called to call all other loops
Int getInputEvent(SDL_Event* event) //This method takes in a parameter of ‘SDL_Event’
type to check for user input. For this tutorial, it simply tests for
interaction with the window.
Then, while
still defining the class in the header file, type private: . This will define any methods and variables defined after
this line only viewable and usable to this class only. This helps with a lot of
the concepts that make C++, such as enabling data encapsulation to protect the
data from being altered by another component in the program. In the next few
lines in the header file, below the private:
declaration, enter the following few variables:
bool running; //Boolean for program
execution
SDL_Event applicationEvent; //Event object for user
interaction
SDL_Window* applicationWindow = NULL; //The window to
open and use for our program
SDL_Surface* windowSurface = NULL;
//Surface object to be used with window for rendering.
SDL_Surface* testImage = NULL;
//Basic bmp image for tutorial use
End the
class definitions with };, like any other method. Please remember the
semi-colon ‘;’, this tells the compiler that our class definition is done
at this point.
Create another file, this time a .cpp file, but name it after the .h file. When
this file is opened, type #include “headerName.h”.
This line will ‘include’ the header file in the source when compiling this cpp
file, looking at it for the definitions and boundaries of the data. Don’t forget to also include the “SDL2/SDL.h”
file as well.
In the cpp file, we add the definitions to all the methods defined in the class
in the header file. Starting with the constructor method:
CPP_Application::CPP_Application(void)
//Default constructor
{
running = true; //Set running boolean to true
SDL_Init( SDL_INIT_VIDEO ); //Initialize SDL
applicationWindow = SDL_CreateWindow("SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED , 800, 600, SDL_WINDOW_SHOWN);
//Create Window for SDL
windowSurface = SDL_GetWindowSurface( applicationWindow ); //Get the
surface for the created window, and return it to a Surface object
testImage = SDL_LoadBMP( "imagefilename" );
if( testImage == NULL ) //Tests to see if image loaded properly, if not,
then an error message is displayed
{
printf( "Unable to load image %s! SDL Error: %s\n",
"testImage.bmp", SDL_GetError() );
running = false; }
};
First note, this method starts with the class name and :: . This is because we
are defining the function of the method declared in the class, and ‘::’ tells
the compiler that this function’s scope is being defined for that classes
method. So every method declared in a class that needs a definition should start
with the original classes name and ::.
This first method is the constructor method, which is called first every time
an object of className type is
created. This constructor method will initialize every variable needed to start
this class; in our case, it will set the running
Boolean variable to true, initialize SDL with SDL_Init(SDL_INIT_VIDEO), and
initialize all the objects in our class by calling the appropriate methods. applicationWindow will be created when SDL_CreateWindow() returns; windowSurface will be initialized with SDL_GetWindowSurface(), that method
being passed the already created window for our program. And finally, our image
object testImage will be called and
initialize with our image file to display with SDL_LoadBMP(). If the image file is NULL, our program tests for
this, and ends execution if the testImage
is NULL. Note that the window
dimensions are 800 to 600, this
will e important for our image. Note also our image being loaded is a .bmp
file; we will need this format for this tutorial. This image format is
easily found in MS Paint, which will suffice for our needs.
With our constructor defined, defining our destructor will be easier. Enter the
following:
CPP_Application::~CPP_Application(void)
//Default destructor
{
SDL_Quit();
};
Again, note the class name and use of :: for scope definition. This method
simply calls SDL_Quit(), which will
end execution and use of SDL and close all objects related to SDL before
closing the object itself. Also note the tilde ‘~’ character by the number 1 on
your keyboard; this character is specifically for defining a destructor.
The next method to define will give us our program loop:
int CPP_Application::executeApplication()
//Function to run when program starts execution, main loop
{
while(running)
{
//Render the image
SDL_BlitSurface(testImage, NULL, windowSurface, NULL);
SDL_UpdateWindowSurface(applicationWindow);
//Get the input from the window
getUserInput(&applicationEvent);
};
};
The function
starts with a while loop, with our running
Boolean as a conditional; when this Boolean is set to false, this loop ends and
the program with it. While this loop executes, the following methods will be
called repeatedly:
SDL_BlitSurface() : Taking four
arguments, this method will blit, or draw an image to our surface. The first
parameter is our image to blit, the second one is NULL (normally used to define
the boundary size for the first parameter), the third parameter is our window
surface (the one defined in the constructor), and the fourth is NULL (again,
used for boundary sized for the third parameter). This method tells the
computer to draw this first image unto the latter image defined in the third
parameter.
SDL_UpdateWindowSurface() : Taking
the SDL_Window object as an argument, this method simply redraws our window to
display our current image.
And the third method called in the loop is the fourth method defined in our
class, getUserInput().
The fourth method defined in our class is the getUserInput(SDL_Event) method. This method takes an SDL_Event pointer
object as a parameter, which is a way for SDL to check for user input from
various devices. When a user event is detected, this method will call to check
for what kind of even has happened by calling SDL_PollEvent(event) != 0 . If
the event object isn’t NULL, then it is compared to several flags that indicate
the current status of the program: in our tutorial, all we do is check for end
program conditions, and set the running
Boolean to false if the window was
exited out of by the button at the top-right.
From here, in the .cpp file, define the main() method below the other
definitions. Once ready, simply enter the following code in the main:
CPP_Application application;
application.executeApplication();
return 0;
These lines will define as object of our class by name for its type, and by the
name application for its object name.
The object name is the name called by the program to reference the object of
the class type defined. This object will have its executeApplication() method called, which will start the
loop to run the program and display our image. And the last line will return 0, ending our program execution
after the loop exits.
With these two files, create and enter a new directory and find the SDL2.dll –
you will need to move that .dll into your new directory to make this program,
or any program that uses SDL2 to even start up. When you have the .dll file for
SDL2 inside the same directory as your .h and .cpp files, start up MS Paint.
In MS Paint, simply create an image of 800 by 600 pixels (or as close as you
can) and add whatever colors, text, or drawing you would like to see displayed
to the window. Remember to save this image as a .bmp file, so that our program
can load it into our Surface object. Save this file in the same directory as
the other files, and save it to an easily remembered name, like test.bmp or image.bmp. Before compiling the source code, remember to go back
into the .cpp file and add the image file name to the SDL_LoadBMP method
between two quotation marks, with the .bmp file type at the end (i.e : “image.bmp”).
With all this done, enter the command prompt and maneuver to the directory with
all the files you’ve just made. Enter the following command to compile and link
this program:
g++ -o SDL2.exe cpp_Application.h
cpp_Application.cpp –lmingw32 –lSDL2main –lSDL2
If the compilation and linking goes well, the execution of your program should
display the image you just drew in MS Paint!