Tag Archives: Game Development

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! 🙂

Setting up SDL2 with Visual Studio 2015

This article is based on “SDL2: Setting up SDL2 in Visual Studio (2013 or any other)“, which was published at Programmer’s Ranch on 10th February 2014. This article uses Visual Studio 2015 Community, and although the steps should mostly apply to any version of Visual Studio, I’ve included steps specific to VS2015 because of issues encountered. It also uses a more recent version of the SDL2 library. Finally, it adds a configuration step originally found in “SDL2: Displaying text with SDL_ttf” (Programmer’s Ranch, 29th March 2014). The source code for this article is available here at the Gigi Labs BitBucket repository

SDL2 is a great low-level library for developing games in C/C++ (other language bindings exist). It’s a little bit tedious to set up in Visual Studio the first time, so I’m going to guide you through the process.

For starters you’re going to want to head to the SDL2 download page and grab the latest Visual C++ Development Libraries (at the time of writing, that would be SDL2-devel-2.0.3-VC.zip):

sdl2-vs-devlib

Create a folder for your SDL2 libraries in a convenient location, say C:\sdl2. Extract the include and lib folders in the zip file here.

We can now create an empty Visual C++ project:

sdl2-vs-newproj

We now need to configure our project (via the project’s properties) so that it can work with SDL2.

First, we’ll tell Visual Studio where to look for the SDL2 header files, by adding the SDL2 include folder to the Include Directories in VC++ Directories:

sdl2-vs-include

In Linker -> General, set Additional Library Directories to the path to the SDL2 library – either x86 or x64:

sdl2-vs-library

Then in Linker -> Input, replace the value of Additional Dependencies with “SDL2.lib; SDL2main.lib“:

sdl2-vs-dependencies

Finally, in Linker -> System, set SubSystem to Windows (/SUBSYSTEM:WINDOWS):

sdl2-vs-subsystem

That should be all the configuration you need to get started.

Now, let’s add a new main.cpp file under Source Files, and add some code just to see whether it works:

#include <SDL.h>

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

    // game code eventually goes here

    SDL_Quit();

    return 0;
}

Press Ctrl+Shift+B to build, and lo and behold…

sdl2-vs-failed

Crap.

Well, until VS2013, these steps used to work, as you can see from the Programmer’s Ranch article “SDL2: Setting up SDL2 in Visual Studio (2013 or any other)“.

Some insights as to the nature of the problem can be found in this StackOverflow thread and this gamedev.net thread. Quoting the latter:

VS2015 contains a completely rewritten CRT with many bug and conformance fixes. It’s not surprising that this kind of breakage happened; it’s not clear if this is a temporary bug with the CRT being incompatible or if all static libraries (like SDL2main) will have to be recompiled for VS2015’s runtime.

So basically, until this is resolved, throw out your C:\sdl2 folder, and instead make a new one from the latest SDL2 build for Visual Studio. Be sure to rename your lib\win32 folder to lib\x86 so that the earlier settings will apply (or change the path in the settings). Sorry, you can’t use this method for x64 just yet.

Try building again, and it should now succeed.

Press F5 to run the program, and you should get a nice runtime error message:

sdl2-vs-nosdldll

Fortunately, the error is pretty clear. Grab SDL.dll from C:\sdl2\lib\x86 and put it in your project’s Debug folder, where the executable is being generated:

sdl2-vs-copydll

You should now be able to run the program without errors. It doesn’t do anything, but you can use it as a basis for any SDL2 code you’ll write. You can find this empty project here at the Gigi Labs BitBucket repository, or else follow the steps in TwinklebearDev’s tutorial to export a Visual Studio template from the project.

Finally, there’s an additional configuration setting that you’ll find handy if you’re going to be loading resources from files (e.g. images, fonts, etc). In your project’s properties, go to the Debugging section and change the value of Working Directory from $(ProjectDir) to $(SolutionDir)$(Configuration)\:

sdl2-vs-wd

Why are we doing this? By default, the program will use a different working directory depending on whether you run it from Visual Studio or directly from the executable. So if it has to look for a particular file in the current directory, this won’t work in both scenarios unless you copy the same file into both the project folder and the output folder. With the above setting, we are telling Visual Studio to run the program with its working directory as the Debug folder, thus aligning the two scenarios.

How to set up SDL2 on Linux

This article explains how to get started with SDL2 in Linux. For other SDL2 tutorials (including setting up on Windows), check out my SDL2 Tutorials at Programmer’s Ranch.

Using apt-get

If you’re on a Debian-based Linux distribution, you can use the APT package manager to easily install the SDL2 development libraries. From a terminal, install the libsdl2-dev package:

sudo apt-get install libsdl2-dev

Installing from source

If for whatever reason you can’t use a package manager, you’ll have to compile SDL2 from the source code. To do this, you first have to download SDL2:

sdl2linux-download

After extracting the archive to a folder, cd to that folder and run:

./configure

When it’s done, run:

make all

Finally, run:

sudo make install

Testing it out

To verify that you can compile an SDL2 program, use the following code (it’s the same used in my “SDL2: Setting up SDL2 in Visual Studio 2010” article at Programmer’s Ranch):

#include <SDL2/SDL.h>

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

    return 0;
}

You can use vi or your favourite editor to create the source code:

sdl2linux-minimal

To compile this (assuming it’s called sdl2minimal.c), use the following command:

gcc sdl2minimal.c -lSDL2 -lSDL2main -o sdl2minimal

We need to link in the SDL2 libraries, which is why we add the -lSDL2 -lSDL2main. Be aware that those start with a lowercase L, not a 1. The program should compile. It won’t show you anything if you run it, but now you know that you’re all set up to write SDL2 programs on Linux.

sdl2linux-run

A* Pathfinding Example in C#

The A* pathfinding algorithm is one of the most popular ways of computing the shortest path between two points for game development. “Introduction to A* Pathfinding” by Johann Fradj illustrates the algorithm pretty nicely. I’ve written a C# implementation based on his example code, intended as nothing more than a learning exercise, and I am sharing it in this article. You can get the full source code directly from BitBucket; if you run it, you’ll see the algorithm run step by step.

Our A* algorithm will compute the shortest path between two points, A and B, on a small square grid of tiles. In order to really see it at work, we’ll introduce some obstacles, marked as X in the map below:

            string[] map = new string[]
            {
                "+------+",
                "|      |",
                "|A X   |",
                "|XXX   |",
                "|   X  |",
                "| B    |",
                "|      |",
                "+------+",
            };

The A* algorithm needs to keep track of the tiles it’s visited (closed list) and the ones it’s considering (open list). For this we define a Location class:

    class Location
    {
        public int X;
        public int Y;
        public int F;
        public int G;
        public int H;
        public Location Parent;
    }

Aside from the tile coordinates, each visited tile has three scores (F, G and H). The G score is the distance from the starting point, and the H score is the estimated distance from the destination (calculated as the city block distance). The F score is just G + H. For a full explanation of these values, read the reference article, “Introduction to A* Pathfinding“.

The H score is very simple to calculate – it’s just the horizontal and vertical distance from the current tile to the destination (ignoring any obstacles):

        static int ComputeHScore(int x, int y, int targetX, int targetY)
        {
            return Math.Abs(targetX - x) + Math.Abs(targetY - y);
        }

The Location class also has a Parent property. That’s used to store the previous tile, and it is needed to keep track of the path itself by the time the destination is reached.

Before we start the algorithm, we initialise some values:

            Location current = null;
            var start = new Location { X = 1, Y = 2 };
            var target = new Location { X = 2, Y = 5 };
            var openList = new List<Location>();
            var closedList = new List<Location>();
            int g = 0;

            // start by adding the original position to the open list
            openList.Add(start);

The g value is the G-score; remember it’s the distance from the starting location to the current tile. We keep track of this simply by incrementing its value each time we move to a new tile.

We add the starting location to the open list, so that the algorithm can begin working. The algorithm itself runs in a loop:

            while (openList.Count > 0)
            {
                // algorithm's logic goes here
            }

For each iteration, the A* algorithm will retrieve the tile with the lowest F-score:

                // get the square with the lowest F score
                var lowest = openList.Min(l => l.F);
                current = openList.First(l => l.F == lowest);

This is not necessarily the most efficient way of doing this, but works pretty well for this example. Also note that if there are multiple locations with the same F-score, it doesn’t really matter which is chosen (here we just take the first one) – again see “Introduction to A* Pathfinding” for details.

                // add the current square to the closed list
                closedList.Add(current);

                // remove it from the open list
                openList.Remove(current);

Here we add the current tile to the closed list, and remove it from the open list, to prevent it from being revisited in a subsequent iteration.

                // show current square on the map
                Console.SetCursorPosition(current.X, current.Y);
                Console.Write('.');
                Console.SetCursorPosition(current.X, current.Y);
                System.Threading.Thread.Sleep(1000);

The code above is not part of the A* algorithm. It simply marks the current tile with a dot and waits for a second so that you can follow the algorithm’s progress interactively.

                // if we added the destination to the closed list, we've found a path
                if (closedList.FirstOrDefault(l => l.X == target.X && l.Y == target.Y) != null)
                    break;

There are two conditions that allow the A* algorithm to terminate. One is that there are no more tiles in the open list to process, which would indicate that there is no path between A and B (we aren’t catering for this scenario in this example). The other is when the path is actually found, and that is catered for by the code above.

The rest of the algorithm evaluates adjacent tiles (i.e. the ones immediately one tile left, right, up and down from the current one):

                var adjacentSquares = GetWalkableAdjacentSquares(current.X, current.Y, map);
                g++;

GetWalkableAdjacentSquares() is defined thusly:

        static List<Location> GetWalkableAdjacentSquares(int x, int y, string[] map)
        {
            var proposedLocations = new List<Location>()
            {
                new Location { X = x, Y = y - 1 },
                new Location { X = x, Y = y + 1 },
                new Location { X = x - 1, Y = y },
                new Location { X = x + 1, Y = y },
            };

            return proposedLocations.Where(
                l => map[l.Y][l.X] == ' ' || map[l.Y][l.X] == 'B').ToList();
        }

So back in the algorithm’s loop, we then have a loop over adjacent squares, computing their scores and adding them to the open list when it makes sense to do so:

                foreach(var adjacentSquare in adjacentSquares)
                {
                    // if this adjacent square is already in the closed list, ignore it
                    if (closedList.FirstOrDefault(l => l.X == adjacentSquare.X
                            && l.Y == adjacentSquare.Y) != null)
                        continue;

                    // if it's not in the open list...
                    if (openList.FirstOrDefault(l => l.X == adjacentSquare.X
                            && l.Y == adjacentSquare.Y) == null)
                    {
                        // compute its score, set the parent
                        adjacentSquare.G = g;
                        adjacentSquare.H = ComputeHScore(adjacentSquare.X,
                            adjacentSquare.Y, target.X, target.Y);
                        adjacentSquare.F = adjacentSquare.G + adjacentSquare.H;
                        adjacentSquare.Parent = current;

                        // and add it to the open list
                        openList.Insert(0, adjacentSquare);
                    }
                    else
                    {
                        // test if using the current G score makes the adjacent square's F score
                        // lower, if yes update the parent because it means it's a better path
                        if (g + adjacentSquare.H < adjacentSquare.F)
                        {
                            adjacentSquare.G = g;
                            adjacentSquare.F = adjacentSquare.G + adjacentSquare.H;
                            adjacentSquare.Parent = current;
                        }
                    }
                }

There’s some duplicate code in the if/else statement above, but I preferred to leave it that way as it’s more readable (which is more important here), especially if you’re following along with “Introduction to A* Pathfinding“.

That’s the last thing in the algorithm itself. So once it’s done, you can see the locations that were examined thanks to the dots drawn on the map:

astar-pathfinding-1

When it’s done, the program will run the following code, tracing its way back from destination to start by following the Parent property:

            // assume path was found; let's show it
            while (current != null)
            {
                Console.SetCursorPosition(current.X, current.Y);
                Console.Write('_');
                Console.SetCursorPosition(current.X, current.Y);
                current = current.Parent;
                System.Threading.Thread.Sleep(1000);
            }

This illustrates the actual shortest path by transforming the dots to underscores:

astar-pathfinding-2

You’ll notice that there is in fact a location that was examined but not used in the final path. That’s pretty normal, as A* may need to backtrack at times.