Tag Archives: SDL2

Drawing Lines with SDL2

We’ve seen before how we can draw pixels using SDL2, similar to a basic Paint application. The next step is to draw lines. To do this, we can reuse our pixel drawing code with something like Bresenham’s line algorithm, or we can use SDL_RenderDrawLine(), which SDL2 gives us out of the box.

The source code for this article is available at the Gigi Labs BitBucket repository.

Let’s start with the following code, which gives us a basic empty window:

#include <SDL.h>

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

    bool quit = false;
    SDL_Event event;

    // init SDL

    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window * window = SDL_CreateWindow("SDL2 line drawing",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

    // handle events

    while (!quit)
    {
        SDL_Delay(10);
        SDL_PollEvent(&event);

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
            // TODO input handling code goes here
        }

        // clear window

        SDL_SetRenderDrawColor(renderer, 242, 242, 242, 255);
        SDL_RenderClear(renderer);

        // TODO rendering code goes here

        // render window

        SDL_RenderPresent(renderer);
    }

    // cleanup SDL

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

    return 0;
}

A line is usually drawn between two endpoints: (x1, y1) and (x2, y2). When the user presses the left mouse button, we’ll store the place he clicked as (x1, y1), and then draw a line to the current cursor position (x2, y2). When he lets go of the left mouse button, we’ll store that line.

Thus, we need an integer variable for each coordinate, and a boolean that indicates whether a line is being drawn (i.e. whether the left mouse button is pressed):

    int x1 = 0;
    int y1 = 0;
    int x2 = 0;
    int y2 = 0;
    bool drawing = false;

We can now add handlers for when the left mouse button is pressed and released. At a basic level, this involves toggling the drawing flag. However, when the left mouse button is pressed (i.e. when a new line is started), we also need to record the current cursor position as (x1, y1), and reset the value of (x2, y2).

            case SDL_MOUSEBUTTONDOWN:
                switch (event.button.button)
                {
                    case SDL_BUTTON_LEFT:
                        x1 = event.motion.x;
                        y1 = event.motion.y;
                        x2 = event.motion.x;
                        y2 = event.motion.y;
                        drawing = true;
                        break;
                }
                break;
            case SDL_MOUSEBUTTONUP:
                switch (event.button.button)
                {
                    case SDL_BUTTON_LEFT:
                        drawing = false;
                        break;
                }
                break;

An additional event handler, this time for mouse movement, updates the value of (x2, y2) while the left mouse button is pressed, giving a feel that the line is being dragged:

            case SDL_MOUSEMOTION:
                if (drawing)
                {
                    x2 = event.motion.x;
                    y2 = event.motion.y;
                }
                break;

We can now add code to actually draw the line, before the call to SDL_RenderPresent():

        // draw current line

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        if (drawing)
            SDL_RenderDrawLine(renderer, x1, y1, x2, y2);

Great, we now can draw lines by left-clicking and dragging the mouse:

…but the lines disappear whenever the left mouse button is released!

In order to keep the drawn lines in the window, we’ll need to store them, and draw them on each iteration of the game loop. We first need to declare a struct that represents each line we draw:

struct Line
{
    int x1;
    int y1;
    int x2;
    int y2;
};

We then need a simple data structure to store the lines, such as a list from the C++ standard library:

#include <list>

Let’s declare a variable for the list that will hold our lines:

std::list<Line> lines;

Then, we’ll add some code so that when the left mouse button is released, the new line is added to the list:

            case SDL_MOUSEBUTTONUP:
                switch (event.button.button)
                {
                    case SDL_BUTTON_LEFT:
                        drawing = false;
                        Line line = { x1, y1, x2, y2 };
                        lines.push_back(line);
                        break;
                }
                break;

Finally, before the code that draws the new line, let’s add some code that draws all the old ones:

        // draw stored lines

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

        for (std::list<Line>::const_iterator i = lines.begin(); i != lines.end(); ++i)
        {
            Line line = *i;
            SDL_RenderDrawLine(renderer, line.x1, line.y1, line.x2, line.y2);
        }

Now, all the lines you draw will remain in the window:

SDL2 Bounding Box Collision Detection

One of the most basic and fundamental pieces of logic in a game is to check whether an object hit another object. This is known as collision detection. You can use it to check whether a bullet hit the player or an enemy, or to see if the player bumped into an impassable barrier, etc.

The source code for this article is available at the Gigi Labs BitBucket repository.

Although objects in a 2D game may have various shapes, it’s usually easiest to check for collisions by assuming a rectangular boundary (i.e. a bounding box) around each object, and testing those rectangles for intersections. This is both easy to write and efficient to compute, and although it may not be 100% faithful to the shape of the object, in most cases it’s good enough.

To see how this works, we’ll draw two rectangles, and test whether they intersect. We’ll start off with the following code, which is quite similar to what we had in earlier SDL2 articles here:

    // 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 Bounding Box Collision Detection",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_Rect rect1 = { x, y, 100, 100 };
    SDL_Rect rect2 = { 50, 50, 100, 80 };

    // handle events

    while (!quit)
    {
        SDL_Delay(10);
        SDL_PollEvent(&event);

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
            // TODO keyboard input handling goes here
        }

        // TODO rendering & collision detection goes here
    }

    // cleanup SDL

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

    return 0;

This doesn’t do anything other than render an empty window. We can draw a couple of rectangles by using SDL_RenderFillRect(). Add the following code in the place of the rendering and collision detection comment:

        SDL_SetRenderDrawColor(renderer, 242, 242, 242, 255);
        SDL_RenderClear(renderer);

        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
        SDL_RenderFillRect(renderer, &rect1);

        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
        SDL_RenderFillRect(renderer, &rect2);

        SDL_RenderPresent(renderer);

First we’re clearing the window to a light grayish colour with SDL_RenderClear(), and then we’re drawing two rectangles (one blue, one green) using SDL_RenderFillRect(). Before each of these calls, we must set the drawing colour using SDL_SetRenderDrawColor(). Finally, SDL_RenderPresent() will render everything to the window.

Now we have two rectangles:

Adding some simple keyboard handling code (as per “Handling Keyboard and Mouse Events in SDL2“) will allow us to move the green rectangle with the arrow keys on the keyboard:

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                    case SDLK_LEFT:  rect1.x--; break;
                    case SDLK_RIGHT: rect1.x++; break;
                    case SDLK_UP:    rect1.y--; break;
                    case SDLK_DOWN:  rect1.y++; break;
                }
                break;
        }

Now we can work on the actual collision detection: if you move the green rectangle such that it hits the blue one, we’ll change the colour of both to red. We could write the code to check whether the rectangles overlap (e.g. as in Lazy Foo’s collision detection tutorial), but why bother? SDL2 gives us a handy SDL_HasIntersection() function that we can use out of the box. Our rendering and collision detection code changes thus:

        SDL_bool collision = SDL_HasIntersection(&rect1, &rect2);

        SDL_SetRenderDrawColor(renderer, 242, 242, 242, 255);
        SDL_RenderClear(renderer);

        if (collision)
            SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        else
            SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
        SDL_RenderFillRect(renderer, &rect1);

        if (collision)
            SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        else
            SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
        SDL_RenderFillRect(renderer, &rect2);

        SDL_RenderPresent(renderer);

This code simply decides what colour to draw for each rectangle based on whether a collision occurred. Sure enough, when you drive the green rectangle into the blue one, both change to red:

Sweet! In this article, we learned how to draw rectangles and check whether they intersect using functions that SDL2 provides. Rectangle intersection is a simple way of checking for collision detection between the bounding boxes of objects in a 2D game. This is a simple and fast approach that works well enough for most situations. Sometimes though, you may need to use more appropriate geometry (e.g. a bounding circle works best for a ball).

Loading and Saving Images with SDL2

We have seen in past articles how we can load basic image formats (such as BMP, PNG and JPG) using SDL2 and SDL_image 2.0. In this article, we’re going to learn a bit more about the image formats we can load and save with these libraries.

Saving BMPs

Just like SDL2 gives us SDL_LoadBMP() to load BMP images, it also gives us SDL_SaveBMP() to save them. There is no need for SDL_image to use either of these functions, because they are in core SDL2.

Since we know from past articles that we can use SDL_image to load a few other formats, it is then easy to write a small program to convert from PNG (or any other of the supported format) to a BMP:

#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    SDL_Surface * image = IMG_Load("image.png");
    SDL_SaveBMP(image, "out.bmp");
    SDL_FreeSurface(image);

    return 0;
}

As you can see, it is not even necessary to initialize SDL2. We simply load the PNG file, and save it back to disk as BMP.

Saving PNGs

As someone pointed out in this forum thread, there are two undocumented functions that allow you to save a PNG:

sdl2-savepng

Thus, we can use this function to do the opposite conversion from BMP to PNG:

    SDL_Surface * image = SDL_LoadBMP("image.bmp");
    IMG_SavePNG(image, "out.png");
    SDL_FreeSurface(image);

Loading other formats

Disgracefully, there is no documentation for SDL_image 2.0 at the time of writing this article. The ‘documentation’ links on the SDL_image 2.0 homepage are actually for SDL_image 1.2.8, which is very misleading.

The old documentation for IMG_Init() shows three supported flag values you can pass in: IMG_INIT_JPG, IMG_INIT_PNG and IMG_INIT_TIF. Through intellisense I’ve discovered a fourth one for the WEBP format:

sdl2-init-webp

I’ve also found that calling IMG_Init() and IMG_Quit() is completely unnecessary, as everything seems to work without them.

Finally, despite the few init flags mentioned above, there are many more formats support by IMG_Load(). I’ve tested WEBP, PCX, GIF, PPM, TIF, TGA and BMP with success; and there are other formats in the old documentation that may be supported.

Animations with Sprite Sheets in SDL2

This is an updated version of “SDL2: Animations with Sprite Sheets“, originally posted on 30th March 2014 at Programmer’s Ranch. The source code is available at the Gigi Labs BitBucket repository.

Many of the previous SDL2 tutorials have involved working with images. In this article, we’re going to take this to the next level, using a very simple technique to animate our images and make them feel more alive.

Our project setup for this article is just the same as in “Loading Images in SDL2 with SDL_image“, and in fact our starting code is adapted from that article:

#include <SDL.h>
#include <SDL_image.h>

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

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("spritesheet.png");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);

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

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

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

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

    return 0;
}

sdl2-spritesheet-borders

This image is 128 pixels wide and 64 pixels high. It consists of 4 sub-images (called sprites or frames), each 32 pixels wide. If we can rapidly render each image in quick succession, just like a cartoon, then we have an animation! 😀
Now, those ugly borders in the image above are just for demonstration purposes. Here’s the same image, without borders and with transparency:

sdl2-spritesheet-actual

If we now try to draw the above on the default black background, we’re not going to see anything, are we? Fortunately, it’s easy to change the background colour, and we’ve done it before in “Handling Keyboard and Mouse Events in SDL2“. Just add the following two lines before the while loop:

    SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
    SDL_RenderClear(renderer);

Now we get an early peek at what the output is going to look like. Press Ctrl+Shift+B to build the project, and then copy SDL2.dll, all the SDL_image DLLs, and the spritesheet into the Debug folder where the executable is generated.

Once that is done, hit F5:

sdl2-spritesheet-early

So at this point, there are two issues we want to address. First, we don’t want our image to take up the whole window, as it’s doing above. Secondly, we only want to draw one sprite at a time. Both of these are pretty easy to solve if you remember SDL_RenderCopy()‘s last two parameters: a source rectangle (to draw only a portion of the image) and a destination rectangle (to draw the image only to a portion of the screen).

So let’s add the following at the beginning of the while loop:

        SDL_Rect srcrect = { 0, 0, 32, 64 };
        SDL_Rect dstrect = { 10, 10, 32, 64 };

…and then update our SDL_RenderCopy() call as follows:

        SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);

Note that the syntax we’re using to initialise our SDL_Rects is just shorthand to set all of the x, y, w (width) and h (height) members all at once.

Let’s run the program again and see what it looks like:

sdl2-spritesheet-clipped

Okay, so like this we are just rendering the first sprite to a part of the window. Now, let’s work on actually animating this. At the beginning of the while loop, add the following:

        Uint32 ticks = SDL_GetTicks();

SDL_GetTicks() gives us the number of milliseconds that passed since the program started. Thanks to this, we can use the current time when calculating which sprite to use. We can then simply divide by 1000 to convert milliseconds to seconds:

        Uint32 seconds = ticks / 1000;

We then divide the seconds by the number of sprites in our spritesheet, in this case 4. Using the modulus operator ensures that the sprite number wraps around, so it is never greater than 3 (remember that counting is always zero-based, so our sprites are numbered 0 to 3).

        Uint32 sprite = seconds % 4;

Finally, we replace our srcrect declaration by the following:

        SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };

Instead of using an x value of zero, as we did before, we’re passing in the sprite value (between 0 and 3, based on the current time) multiplied by 32 (the width of a single sprite). So with each second that passes, the sprite will be extracted from the image at x=0, then x=32, then x=64, then x=96, back to x=0, and so on.

Let’s run this again:

sdl2-spritesheet-irregular

You’ll notice two problems at this stage. First, the animation is very irregular, in fact it doesn’t animate at all unless you move the mouse or something. Second, the sprites seem to be dumped onto one another, as shown by the messy image above.

Fortunately, both of these problems can be solved with code we’ve already used in “Handling Keyboard and Mouse Events in SDL2“. The first issue is because we’re using SDL_WaitEvent(), so the program doesn’t do anything unless some event occurs. Thus, we need to replace our call to SDL_WaitEvent() with a call to SDL_PollEvent():

        while (SDL_PollEvent(&event) != NULL)
        {
            switch (event.type)
            {
                case SDL_QUIT:
                    quit = true;
                    break;
            }
        }

The second problem is because we are drawing sprites without clearing the ones we drew before. All we need to do is add a call to SDL_RenderClear() before we call SDL_RenderCopy():

        SDL_RenderClear(renderer);

Great! You can now admire our little character shuffling at one frame per second:

sdl2-spritesheet-goodslow

It’s good, but it’s a bit slow. We can make it faster by replacing the animation code before the srcrect declaration with the following (10 frames per second):

        Uint32 ticks = SDL_GetTicks();
        Uint32 sprite = (ticks / 100) % 4;

Woohoo! 😀 Look at that little guy dance! (The image below is animated, but this seems only to work in Firefox.)

sdl2-spritesheet-animated

So in this article, we learned how to animate simple characters using sprite sheets, which are really just a digital version of a cartoon. We used SDL_RenderCopy()‘s srcrect parameter to draw just a single sprite from the sheet at a time, and selected that sprite using the current time based on SDL_GetTicks().

Displaying Text in SDL2 with SDL_ttf

This is an updated version of the article originally posted on 29th March 2014 at Programmer’s Ranch. The source code for this article is available at the Gigi Labs BitBucket repository.

In this article, we’re going to learn how we can write text in our window. To do this, we’ll use the SDL_ttf library. Setting it up is almost identical to how we set up SDL_image in “Loading Images in SDL2 with SDL_image“. You need to download the Visual C++ development libraries from the SDL_ttf homepage:

sdl2ttf-download

Then, extract the lib and include folders over the ones you have in your sdl2 folder. You should end up with an SDL_ttf.h in your include folder, and you should get SDL2_ttf.lib and a few DLLs including SDL_ttf.dll in your lib\x86 and lib\x64 folders.

In your Linker -> Input, you’ll then need to add SDL2_ttf.lib:

sdl2ttf-linker-input

Good. Now, let’s start with the following code which is a modified version of the code from about halfway through “Displaying an Image in an SDL2 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("SDL_ttf in SDL2",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
        480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

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

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

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

    return 0;
}

The first thing we need to do in order to use SDL_ttf is include the relevant header file:

#include <SDL_ttf.h>

Then, we initialise the SDL_ttf library right after we call SDL_Init():

TTF_Init();

…and we clean it up just before we call SDL_Quit():

TTF_Quit();

Right after we initialise our renderer, we can now load a font into memory:

 TTF_Font * font = TTF_OpenFont("arial.ttf", 25);

TTF_OpenFont() takes two parameters. The first is the path to the TrueType Font (TTF) that it needs to load. The second is the font size (in points, not pixels). In this case we’re loading Arial with a size of 25.

A font is a resource like any other, so we need to free the resources it uses near the end:

TTF_CloseFont(font);

We can now render some text to an SDL_Surface using TTF_RenderText_Solid(). which takes the font we just created, a string to render, and an SDL_Color which we are passing in as white in this case:

 SDL_Color color = { 255, 255, 255 };
 SDL_Surface * surface = TTF_RenderText_Solid(font,
  "Welcome to Gigi Labs", color);

We can then create a texture from this surface as we did in “Displaying an Image in an SDL2 Window“:

    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);

And yet again, we should not forget to release the resources we just allocated near the end, so let’s do that right away:

 SDL_DestroyTexture(texture);
 SDL_FreeSurface(surface);

Now all we need is to actually render the texture. We’ve done this before; just add the following just before the end of your while loop:

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

Okay, now before we actually run this program, we need to put our Arial TTF font somewhere where our program can find it. Go to C:\Windows\Fonts, and from there copy the Arial font into the Debug folder where your executable is compiled. This will result in several TTF files, although we’re only going to use arial.ttf. We will also need the usual SDL2.dll, along with the SDL_ttf DLLs (libfreetype-6.dll, zlib1.dll and SDL2_ttf.dll):

sdl2ttf-fonts

Great, now let’s admire the fruit of our work:

sdl2ttf-blocky2

Nooooooooooooooo! This isn’t quite what we were expecting, right? This is happening because the texture is being stretched to fill the contents of the window. The solution is to supply the dimensions occupied by the text in the dstrect parameter of SDL_RenderCopy() (as we did in “Displaying an Image in an SDL2 Window“). But how can we know these dimensions?

If you check out Will Usher’s SDL_ttf tutorial, you’ll realise that a function called SDL_QueryTexture() can give you exactly this information (and more). So before our while loop, let’s add the following code:

    int texW = 0;
    int texH = 0;
    SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
    SDL_Rect dstrect = { 0, 0, texW, texH };

Finally, we can pass dstrect in our call to SDL_RenderCopy():

SDL_RenderCopy(renderer, texture, NULL, &dstrect);

Let’s run the program now:

sdl2ttf-text2

Much better! 🙂

In this article, we learned how to use the SDL_ttf to render text using TTF fonts in SDL2. Using the SDL_ttf library in a project was just the same as with SDL_image. To actually use fonts, we first rendered text to a surface, then passed it to a texture, and finally to the GPU. We used SDL_QueryTexture() to obtain the dimensions of the texture, so that we could render the text in exactly as much space as it needed. We also learned how we can set up our project to use the same path regardless of whether we’re running from Visual Studio or directly from the executable.

Converting an Image to Negative using SDL2

The source code for this article is available at the Gigi Labs BitBucket repository. It’s the same as in the Grayscale article, plus the code for the Negative effect in this article.

In “Converting an Image to Grayscale using SDL2”, we manipulated the pixels of an existing image in order to convert it to grayscale. It is now very easy to add all sorts of effects by changing pixel values in different ways.

Another effect we can apply is the Negative of an image. This means that the dark areas become light, and the light areas become dark. For instance, if we have this image of a Canadian goose:

sdl2-negative-goose-positive

By using any image editor, say Irfanview, we can get the following Negative:

sdl2-negative-goose-negative

This is a very easy effect to apply. Since each of the Red, Green and Blue channels is represented by a byte, its value is in the range between 0 and 255. So we can compute the Negative by subtracting each value from 255. That way a bright value (e.g. 210) will become dark (e.g. 45), and vice versa.

Here’s the code for the Negative image effect:

            case SDLK_n:
                for (int y = 0; y < image->h; y++)
                {
                    for (int x = 0; x < image->w; x++)
                    {
                        Uint32 pixel = pixels[y * image->w + x];

                        Uint8 r = pixel >> 16 & 0xFF;
                        Uint8 g = pixel >> 8 & 0xFF;
                        Uint8 b = pixel & 0xFF;

                        r = 255 - r;
                        g = 255 - g;
                        b = 255 - b;

                        pixel = (0xFF << 24) | (r << 16) | (g << 8) | b;
                        pixels[y * image->w + x] = pixel;
                    }
                }
                break;

The code for Negative is very similar to Grayscale in that we’re looping over each pixel, calculating new values for Red, Green and Blue, and then applying the new value to the pixel.

Let’s try this out with a photo I took of Eldon House in London, Canada last September. Here’s the photo in its normal state:

sdl2-negative-eldon-positive

When I press the N key to apply the Negative effect, here’s the result:

sdl2-negative-eldon-negative

I can also press N again to apply Negative on the Negative, and end up with the original image again:

sdl2-negative-eldon-positive

That’s an important difference between Grayscale and Negative. Grayscale is an operation that loses colour information, and you can’t go back. Negative, on the other hand, is symmetric, and you can go back to the original image simply by applying the same operation again.

Converting an Image to Grayscale using SDL2

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

In the previous article, “SDL2 Pixel Drawing“, we saw how to draw pixels onto a blank texture that we created in code. Today, on the other hand, we’ll see how we can manipulate pixels on an existing image, such as a photo we loaded from disk. We’ll also learn how to manipulate individual bits in an integer using what are called bitwise operators, and ultimately we’ll convert an image to grayscale.

The first thing we’re going to do is load an image from disk. Fortunately, we’ve covered that already in “Loading Images in SDL2 with SDL_image“, so refer back to it to set things up. We’ll also start off with the code from the article, which, adapted a little bit, is this:

#include <SDL.h>
#include <SDL_image.h>

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

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_JPG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Grayscale",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("PICT3159.JPG");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

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

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

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

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

    return 0;
}

You see, the problem here is that we can’t quite touch the texture pixels directly. So instead, we need to work a little bit similarly to “SDL2 Pixel Drawing“: we create our own texture, and then copy the surface pixels over to it. So we throw out the line calling SDL_CreateTextureFromSurface(), and replace it with the following:

    SDL_Texture * texture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
        image->w, image->h);

Then, at the beginning of the while loop, add this:

        SDL_UpdateTexture(texture, NULL, image->pixels,
            image->w * sizeof(Uint32));

If you try and run program now, it will pretty much explode. That’s because our code is assuming that our image uses 4 bytes per pixel (ARGB – see “SDL2 Pixel Drawing“). That’s something that depends on the image, and this particular JPG image is most likely 3 bytes per pixel. I don’t know much about the JPG format, but I’m certain that it doesn’t support transparency, so the alpha channel is out.

The good news is that it’s possible to convert the surface into one that has a familiar pixel format. To do this, we use SDL_ConvertSurfaceFormat(). Add the following before the while loop:

    SDL_Surface * originalImage = image;
    image = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_ARGB8888, 0);
    SDL_FreeSurface(originalImage);

What this does is take our surface (in this case the one that image points to) and return an equivalent surface with the pixel format we specify. Now that the new image has the familiar ARGB format, we can easily access and manipulate the pixels. Add the following after the line you just added (before the while loop) to typecast the surface pixels from void * to Uint32 * which we can work with:

    Uint32 * pixels = (Uint32 *)image->pixels;

So far so good:

sdl2-grayscale-display-normal-image

Now, let’s add some code do our grayscale conversion. We’re going to convert the image to grayscale when the user presses the ‘G’ key, so let us first add some code within the switch statement to handle that:

        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_g:
                for (int y = 0; y < image->h; y++)
                {
                    for (int x = 0; x < image->w; x++)
                    {
                        Uint32 pixel = pixels[y * image->w + x];
                        // TODO convert pixel to grayscale here
                    }
                }
                break;
            }
            break;

This is where bit manipulation comes in. You see, each pixel is a 32-bit integer which in concept looks something like this (actual values are invented, just for illustration):

Alpha Red Green Blue
11111111 10110101 10101000 01101111

So let’s say we want to extract the Red component. Its value is 10110101 in binary, or 181 in decimal. But since it’s in the third byte from right, its value is much greater than that. So we first shift the bits to the right by 16 spaces to move it to the first byte from right:

Alpha Red
00000000 00000000 11111111 10110101

…but we still can’t interpret the integer as just red, since the alpha value is still there. We want to extract just that last byte. To do that, we perform a bitwise AND operation:

Pixel 11111111 10110101
Mask 00000000 11111111
Pixel AND Mask 00000000 10110101

We do an AND operation between our pixel value and a value where only the last byte worth of bits are set to 1. That allows us to extract our red value.

In code, this is how it works:

                            Uint8 r = pixel >> 16 & 0xFF;
                            Uint8 g = pixel >> 8 & 0xFF;
                            Uint8 b = pixel & 0xFF;

The >> operator shifts bits to the right, and the & is a bitwise AND operator. Each colour byte is shifted to the last byte and then ANDed with the value 0xFF, which is hexadecimal notation for what would be 255 in decimal, or 11111111 in binary. That way, we can extract all three colours individually.

We can finally perform the actual grayscaling operation. A simple way to do this might be to average the three colours and set each component to that average:

                            Uint8 v = (r + g + b) / 3;

Then, we pack the individual colour bytes back into a 32-bit integer. We follow the opposite method that we used to extract them in the first place: they are each already at the last byte, so all we need to do is left-shift them into position. Once that is done, we replace the actual pixel in the surface with the grayscaled one:

                            pixel = (0xFF << 24) | (v << 16) | (v << 8) | v;
                            pixels[y * image->w + x] = pixel;

If we now run the program and press the ‘G’ key, this is what we get:

sdl2-grayscale-average-grayscale

It looks right, doesn’t it? Well, it’s not. There’s an actual formula for calculating the correct grayscale value (v in our code), which according to Real-Time Rendering is:

grayscale-formula

The origin of this formula is beyond the scope of this article, but it’s due to the fact that humans are sensitive to different colours in different ways – in fact there is a particular affinity to green, hence why it is allocated the greatest portion of the pixel colour. So now all we have to do is replace the declaration of v with the following:

                            Uint8 v = 0.212671f * r + 0.715160f * g + 0.072169f * b;

And with this, the image appears somewhat different:

sdl2-grayscale-correct-grayscale

This approach gives us a more even distribution of grey shades – in particular certain areas such as the trees are much lighter and we can make out the details more easily.

That’s all, folks! 🙂 In this article, we learned how to convert an image to grayscale by working on each individual pixel. To do this, we had to resort to converting an image surface to a pixel format we could work with, and then copy the pixels over to a texture for display in the window. To actually perform the grayscale conversion, we learned about bitwise operators which assisted us in dealing with the individual colours. Finally, although averaging the colour channels gives us something in terms of shades of grey, there is a formula that is used for proper grayscale conversion.

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.