Tag Archives: SDL2

SDL2 Pixel Drawing

This article was originally posted on 13th February 2014 at Programmer’s Ranch. It has been slightly updated here. The source code for this article is available at the Gigi Labs BitBucket repository.

Greetings! 🙂

In “Handling Keyboard and Mouse Events in SDL2“, we saw how we could handle keyboard and mouse events to allow the user to interact with whatever we are displaying on the screen. In today’s article, we’ll learn how to draw individual pixels onto our window, and we’ll use mouse events to create a drawing program similar to a limited version of Microsoft Paint.

We’ll start off with some code similar to that in “Showing an Empty Window in SDL2“:

#include <SDL.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window * window = SDL_CreateWindow("SDL2 Pixel Drawing",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
        }
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Since we’re going to draw pixels directly rather than load an image, our course of action in this article is going to be a little different from past articles. First, we need a renderer, so we use SDL_CreateRenderer() as we have been doing all along:

    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

But then, rather than creating a texture from a surface, we’re now going to create one from scratch using SDL_CreateTexture():

    SDL_Texture * texture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, 640, 480);

We pass in several parameters. The first one is the renderer, and the last two are the width and height of the texture.

The second parameter, which we have set to SDL_PIXELFORMAT_ARGB8888, is the pixel format. There are many possible formats (see SDL_CreateTexture() documentation), but in this case we’re saying that each pixel is a 32-bit value, where there are 8 bits for alpha (opacity/transparency), 8 bits for red, 8 bits for green and 8 bits for blue. These four items are collectively known as channels (e.g. the alpha channel), so each channel consists of one byte and it can range between 0 and 255. The arrangement below thus represents a single pixel:

Alpha Red Green Blue
8 bits 8 bits 8 bits 8 bits

The SDL_TEXTUREACCESS_STATIC defines a method of accessing the texture. Since we’re storing our pixels in CPU memory and then copying them over to the GPU, static access is suitable. On the other hand, streaming access is used to allocate pixels in a back buffer in video memory, and that’s suitable for more complex scenarios.

Finally, we initialise a set of pixels that we’ll be copying onto the window. When we draw stuff, we’ll modify these pixels, and then they’ll be copied onto the window to reflect the update.

    Uint32 * pixels = new Uint32[640 * 480];

We’ll need to clean up all the stuff we just allocated, so add the following just before the other cleanup calls at the end of the code:

    delete[] pixels;
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);

At the beginning of the while loop, we may now add the following call:

        SDL_UpdateTexture(texture, NULL, pixels, 640 * sizeof(Uint32));

In this code, we are using SDL_UpdateTexture() to copy our pixels onto the window. We pass it our texture, a region of the texture to update (in our case NULL means to update the entire texture), our array of pixels, and the size in bytes of a single row of pixels (called the pitch). In our case, our window has a width of 640 pixels. Therefore a single row consists of 640 4-byte pixels, hence the multiplication.

At the end of our while loop, we may now render our texture as we have done in previous articles:

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);

Great. So far, we have… uh… this:

sdl2-pixel-drawing-grey

Let’s clear the background to white, so that we can draw black pixels over it. We could do that using SDL_SetRenderDrawColor() as we did in “Handling Keyboard and Mouse Events in SDL2“. But since we can now manipulate pixels directly, let’s try something. First, add this at the top:

#include <iostream>

Now, we can use the standard function memset() to overwrite our pixels. Add this right after the declaration of pixels:

memset(pixels, 255, 640 * 480 * sizeof(Uint32));

Good, it’s white now:

sdl2-pixel-drawing-white

Now, let’s add some code to draw black pixels when the mouse is clicked. First, add the following flag at the beginning of main():

    bool leftMouseButtonDown = false;

Then, add this inside the switch statement:

        case SDL_MOUSEBUTTONUP:
            if (event.button.button == SDL_BUTTON_LEFT)
                leftMouseButtonDown = false;
            break;
        case SDL_MOUSEBUTTONDOWN:
            if (event.button.button == SDL_BUTTON_LEFT)
                leftMouseButtonDown = true;
        case SDL_MOUSEMOTION:
            if (leftMouseButtonDown)
            {
                int mouseX = event.motion.x;
                int mouseY = event.motion.y;
                pixels[mouseY * 640 + mouseX] = 0;
            }
            break;

Right, so we’re keeping track of whether the left mouse button is pressed. When it’s pressed (SDL_MOUSEBUTTONDOWN), leftMouseButtonDown is set to true, and when it’s released (SDL_MOUSEBUTTONUP), leftMouseButtonDown is set to false.

If the mouse is moving (SDL_MOUSEMOTION) and the left mouse button is currently down, then the pixel at its location is set to black (or zero, which is the same thing). Note that I intentionally left out a break statement at the end of the SDL_MOUSEBUTTONDOWN case, so that the drawing code in SDL_MOUSEMOTION is executed along with its own.

So now we can draw our hearts out:

sdl2-pixel-drawing-final

Sweet! That was all we needed in order to draw pixels directly onto our window.

In this article, we learned how to draw pixels directly using SDL2. This involved first creating an SDL2 texture with a specified pixel format, then allocating an array to store those pixels, and finally copying the pixels from the array to the texture. We also used a variety of mouse events to allow the user to actually draw pixels onto the window with the mouse, which is like a simplified version of Microsoft Paint.

Handling Keyboard and Mouse Events in SDL2

This article was originally posted as “SDL2: Keyboard and Mouse Movement (Events)” at Programmer’s Ranch on 12th February 2014. It is slightly updated here. The source code and spaceship bitmap are available at the Gigi Labs BitBucket repository.

Hi there! 🙂

In this article, we’ll learn how to handle keyboard and mouse events, and we’ll use them to move an object around the window. Hooray! 🙂

We’ll start with an image. I made this 64×64 bitmap:

spaceship

As you can see, I can’t draw to save my life. But since this is a bitmap, we don’t need the SDL_image extension.

Once you have an image, you’ll want to create a new Visual Studio project, wire it up to work with SDL2, and then add some code to display a window and the spaceship in it. If you don’t remember how, these past articles should help:

  1. Setting up SDL2 with Visual Studio 2015
  2. Showing an Empty Window in SDL2
  3. Displaying an Image in an SDL2 Window

You should end up with code that looks something like this:

#include <SDL.h>

int main(int argc, char ** argv)
{
    // variables

    bool quit = false;
    SDL_Event event;
    int x = 288;
    int y = 208;

    // init SDL

    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window * window = SDL_CreateWindow("SDL2 Keyboard/Mouse events",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_Surface * image = SDL_LoadBMP("spaceship.bmp");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);
    SDL_FreeSurface(image);

    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

    // handle events

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_Rect dstrect = { x, y, 64, 64 };

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, &dstrect);
        SDL_RenderPresent(renderer);
    }

    // cleanup SDL

    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

You’ll also want to place spaceship.bmp into your Debug folder (along with SDL2.dll) so that the program can find the files it needs..

Once you actually run the program, you should see this:

sdl2-kbd-kickoff

I set the window’s background to white to match the spaceship’s white background by setting the clear colour using SDL_SetRenderDrawColor(), and then calling SDL_RenderClear() to clear the window to that colour.

In order to handle keyboard and mouse events, we need an SDL_Event. Well, what do you know: we have been using one all along, in order to take action when the window is closed. What we need now is to handle a different event type. So let’s add a new case statement after the one that handles SDL_QUIT:

            case SDL_KEYDOWN:

                break;

Within this case statement, let us now determine which key was actually pressed, and move the spaceship accordingly:

            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                    case SDLK_LEFT:  x--; break;
                    case SDLK_RIGHT: x++; break;
                    case SDLK_UP:    y--; break;
                    case SDLK_DOWN:  y++; break;
                }
                break;

If you now run the program, you’ll find that you can move the spaceship using the arrow keys:

sdl2-kbd-moving-slow

You’ll notice that it seems to move pretty slowly, and you have to keep pressing for quite a while to make any significant movement. Now, in your code, replace SDL_WaitEvent with SDL_PollEvent:

        SDL_PollEvent(&event);

Now, try running it again:

sdl2-kbd-moving-fast

Swoosh! In less than half a second, the spaceship hits the edge of the window. It’s actually too fast. To get this down to something manageable, add a small delay at the beginning of your while loop:

        SDL_Delay(20);

SDL_PollEvent() is better than SDL_WaitEvent() when you want to continuously check (i.e. poll) for events, but it consumes more CPU power (you can see this if you open Task Manager). SDL_WaitEvent() is okay when your window is mostly sitting idle so you don’t need to check for events that often.

Handling mouse events is also very easy. All you need to do is handle the appropriate event. Let’s see how to handle a mouse click:

            case SDL_MOUSEBUTTONDOWN:
                switch (event.button.button)
                {
                    case SDL_BUTTON_LEFT:
                        SDL_ShowSimpleMessageBox(0, "Mouse", "Left button was pressed!", window);
                        break;
                    case SDL_BUTTON_RIGHT:
                        SDL_ShowSimpleMessageBox(0, "Mouse", "Right button was pressed!", window);
                        break;
                    default:
                        SDL_ShowSimpleMessageBox(0, "Mouse", "Some other button was pressed!", window);
                        break;
                }
                break;

And this is what happens when you run it, and click somewhere in the window:

sdl2-kbd-left-click

You can also track mouse motion and obtain the current coordinates of the mouse pointer. This is useful when moving things with the mouse (e.g. moving an object by mouse-dragging it). The following code obtains the mouse coordinates and displays them in the window title:

            case SDL_MOUSEMOTION:
                int mouseX = event.motion.x;
                int mouseY = event.motion.y;

                std::stringstream ss;
                ss << "X: " << mouseX << " Y: " << mouseY;

                SDL_SetWindowTitle(window, ss.str().c_str());
                break;

Note that you’ll need to add the following at the top of your main.cpp to make the above code work:

#include <sstream>

You will now notice the mouse coordinates in the window title:

sdl2-kbd-mouse-coords

Wonderful! You should now have an idea of how to capture and handle keyboard and mouse events in SDL2. We will see more of these in an upcoming article dealing with drawing pixels in the window, so stay tuned to learn more! 🙂

Loading Images in SDL2 with SDL_image

This article was originally posted as “SDL2: Loading Images with SDL_image” on 25th November 2013 at Programmer’s Ranch, and has been updated before being reposted here. The source code for this article is available at the Gigi Labs BitBucket repository.

In “SDL2: Displaying an Image in the Window“, we saw how we could load bitmaps using the SDL_LoadBMP() function. Unfortunately, working with bitmaps is very limiting, and the core SDL2 library does not provide the means to work with other image formats. However, such functionality is provided by an extension library called SDL_image. In this article, we will learn how to set up SDL_image and also how to use it to load other image formats.

Setting up SDL_image is not very different from setting up SDL 2.0 itself. You need to go to the SDL_image homepage and download the development libraries:

sdl_image-downloads2

Extract the include and lib folders inside the zip file over the ones you have in your sdl2 folder. You should get an SDL_image.h file in your include folder, and in your lib\x86 and lib\x64 folders you should get SDL2_image.lib and a whole bunch of DLLs including SDL2_image.dll.

We’ll start off with the same code we had in “Displaying an Image in an SDL2 Window” (you can just grab the source code if you’re lazy). I’ve modified the code so that the image fills the window:

#include <SDL.h>        

int main(int argc, char ** argv)
{
	bool quit = false;
	SDL_Event event;

	SDL_Init(SDL_INIT_VIDEO);

	SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

	SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
	SDL_Surface * image = SDL_LoadBMP("image.bmp");
	SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);

	while (!quit)
	{
		SDL_WaitEvent(&event);

		switch (event.type)
		{
			case SDL_QUIT:
				quit = true;
				break;
		}

		//SDL_Rect dstrect = { 5, 5, 320, 240 };
		//SDL_RenderCopy(renderer, texture, NULL, &dstrect);
		SDL_RenderCopy(renderer, texture, NULL, NULL);
		SDL_RenderPresent(renderer);
	}

	SDL_DestroyTexture(texture);
	SDL_FreeSurface(image);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);

	SDL_Quit();

	return 0;
}

Now since we’ve introduced a new statically-linked library (i.e. SDL2_image.lib), the first thing we need to do is add it to the Linker -> Input in the project properties:

sdl_image-linker

The entry there should now look like this:

SDL2.lib;SDL2main.lib;SDL2_image.lib

Now, we’re going to load this nice photo (.jpg format) taken in Gardaland in 2006:

sdl_image-pict3159

Doing this is quite simple. First, we need to include the appropriate header:

#include <SDL_image.h>

Then, we initialise SDL_image by calling IMG_Init() right after the call to SDL_Init():

IMG_Init(IMG_INIT_JPG);

…and before the call to SDL_Quit(), we shut down SDL_Image using IMG_Quit():

IMG_Quit();

All we have left to do now is replace the line calling SDL_LoadBMP() with one that uses IMG_Load() instead:

SDL_Surface * image = IMG_Load("PICT3159.JPG");

You should now be able to build this program (Ctrl+Shift+B). Before you run it, though, make sure that SDL2.dll is in the same folder as your executable. You’ll also need to toss in all the DLLs from the appropriate lib folder (most likely the x86 one is what you’ll be using by default) – that includes SDL2_image.dll along with format-specific files such as libjpeg-9.dll, libpng16-16.dll, etc. And your image file will need to be there too.

And voilà:

sdl_image-result

Isn’t that sweet? The SDL_image library allows you to load a large variety of image formats, by just replacing SDL_LoadBMP() with IMG_Load(). You’ll need to initialise and cleanup the library (although it seems to work even without this) and remember to link the library and include the appropriate header file. But as you can see, it’s pretty straightforward.

Displaying an Image in an SDL2 Window

This article was originally posted as “SDL2: Displaying an Image in the Window” on 17th November 2013 at Programmer’s Ranch. It has been updated, and the part about detecting and displaying errors has been removed as it is better addressed by configuring the project’s working directory. The source code for this article is available at the Gigi Labs BitBucket repository.

In this article we’re going to learn how to load a bitmap image from disk and display it in an SDL2 window. In order to follow along, you’ll need to set up a project to work with SDL2 (see Setting up SDL2 with Visual Studio 2015), and start off with the following basic empty window code, which is practically the same as what we did in Showing an Empty Window in SDL2:

#include <SDL.h>        

int main(int argc, char ** argv)
{
	bool quit = false;
	SDL_Event event;

	SDL_Init(SDL_INIT_VIDEO);

	SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

	while (!quit)
	{
		SDL_WaitEvent(&event);

		switch (event.type)
		{
		case SDL_QUIT:
			quit = true;
			break;
		}
	}

	SDL_Quit();

	return 0;
}

OK, we can now create an SDL_Renderer:

SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

We use SDL_CreateRenderer() to get an instance of SDL_Renderer. This renderer represents the output device (usually your graphics card) to which your code will be drawing. In fact it’s the final destination of our image, because we’ll be following the steps below:

sdl2-displayimage-workflow

SDL_CreateRenderer() takes three parameters. The first is the window where we are drawing. The second allows us to select different rendering drivers; in our case we don’t care, and we can set it to -1 and get the default one. The last parameter allows us to set SDL_RendererFlags to control how the rendering occurs. We can set it to zero to default to hardware rendering. If any of this sounds confusing, don’t worry about it and just use SDL_CreateRenderer() as it is here.

We can now load the image from disk using the SDL_LoadBMP() function, which takes a path to a bitmap and loads it into an SDL_Surface:

SDL_Surface * image = SDL_LoadBMP("image.bmp");

I’m using the following photo of the Grand Harbour in Valletta, Malta, which I took back in 2005, and which has a width of 320 pixels and a height of 240 pixels:

sdl2-displayimage-image

Place the image in your Debug folder, where your executable is located.

Next, we need to create a texture.

SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);

A texture is memory close to the graphics card (see image below), and we use SDL_CreateTextureFromSurface() to directly map our surface (which contains the image we loaded) to a texture.

sdl2-displayimage-surface-textures

Now that we have a texture, let’s display it in the window. At the end of the while loop, just after the switch statement, add the following:

		SDL_RenderCopy(renderer, texture, NULL, NULL);
		SDL_RenderPresent(renderer);

We use SDL_RenderCopy() to copy the texture to the output device. There are also a couple of other parameters that we’re setting to NULL – more on these in a minute. Finally, SDL_RenderPresent() is what commits the texture to the video memory, displaying the image.

Before we run the program, we must always remember to clean up every resource that we initialise. In our case, that means adding the following just before the call to SDL_Quit():

	SDL_DestroyTexture(texture);
	SDL_FreeSurface(image);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);

If you now run the program from within Visual Studio, you should see the image in your window:

sdl2-displayimage-stretched

Fantastic! The image is right there in the window! But… can you see what happened? The image, which has dimensions 320×240, has been stretched to fill the window, which has dimensions 640×480. That’s sometimes convenient, because we get scaling for free. However, it makes photos look messy. Let’s change our call to SDL_RenderCopy() to fix this:

		SDL_Rect dstrect = { 5, 5, 320, 240 };
		SDL_RenderCopy(renderer, texture, NULL, &dstrect);

Remember those two parameters at the end of SDL_RenderCopy() that we were setting to NULL? If you look at the documentation for SDL_RenderCopy(), you’ll see that the last one defines a destination region (which part of the texture will the image be copied to). If it’s set to NULL, then the image is stretched to fill the texture – which is what happened above.

By setting dstrect (the last parameter), we can render to only a portion of the window. We set it to an SDL_Rect, with x and y set to 5, and width and height corresponding to the dimensions of the image. When we run the program, we get this:

sdl2-displayimage-original-size

Excellent! 🙂 In this article we looked at how to create renderers, surfaces and textures. We used these to load bitmaps and display them on the screen. We also saw the difference between copying the image to a region of the window, and making it fill the entire window.

Showing an Empty Window in SDL2

This article was originally posted as “SDL2: Empty Window” on 31st August 2013 at Programmer’s Ranch. It has been slightly updated and now enjoys syntax highlighting. The source code for this article is available at the Gigi Labs BitBucket repository.

Yesterday’s article dealt with setting up SDL2 in Visual Studio. Today we’re going to continue what we did there by showing an empty window and allowing the user to exit by pressing the X at the top-right of the window.

It takes very little to show an empty window. Use the following code:

#include <SDL.h>

int main(int argc, char ** argv)
{
	SDL_Init(SDL_INIT_VIDEO);

	SDL_Window * screen = SDL_CreateWindow("My SDL Empty Window",
		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

	SDL_Quit();

	return 0;
}

We use SDL_Init() to initialise SDL, and tell it which subsystems we need – in this case video is enough. At the end, we use SDL_Quit() to clean up. It is possible to set up SDL_Quit() with atexit(), as the SDL_Quit() documentation shows.

We create a window using SDL_CreateWindow(). This is quite different from how we used to do it in SDL 1.2.x. We pass it the window caption, initial coordinates where to put the window (not important in our case), window width and height, and flags (e.g. fullscreen).

If you try and run the code, it will work, but the window will flash for half a second and then disappear. You can put a call to SDL_Delay() to make it persist for a certain number of milliseconds:

SDL_Delay(3000);

Now, let’s make the window actually remain until it is closed. Use the following code:

#include <SDL.h>

int main(int argc, char ** argv)
{
	bool quit = false;
	SDL_Event event;

	SDL_Init(SDL_INIT_VIDEO);

	SDL_Window * screen = SDL_CreateWindow("My SDL Empty Window",
		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

	while (!quit)
	{
		SDL_WaitEvent(&event);

		switch (event.type)
		{
			case SDL_QUIT:
				quit = true;
				break;
		}
	}

	SDL_Quit();

	return 0;
}

The while (!quit) part is very typical in games and is in fact called a game loop. We basically loop forever, until the conditions necessary for quitting occur.

We use SDL_WaitEvent() to wait for an event (e.g. keypress) to happen, and we pass a reference to an SDL_Event structure. Another possibility is to use SDL_PollEvent(), which checks continuously for events and consumes a lot of CPU cycles (SDL_WaitEvent() basically just sleeps until an event occurs, so it’s much more lightweight).

The event type gives you an idea of what happened. It could be a key press, mouse wheel movement, touch interaction, etc. In our case we’re interested in the SDL_QUIT event type, which means the user clicked the window’s top-right X button to close it.

We can now run this code, and the window remains until you close it:

sdl2-empty-window

Wasn’t that easy? You can use this as a starting point to start drawing stuff in your window. Have fun, and come back again for more tutorials! 🙂