For this tutorial, we require:
- The main SDL library, which can be found here if you don’t already have it.
- Your compiler linked to sdl_main and sdl, don’t forget compiler specific links like mingw32 if you need them
- The SDL API documentation
Actually getting a SDL window up and running is fairly painless, in keeping with the simple in SDL, especially in comparison to what you have to do to get a windows API window up. Unfortunately WordPress makes posting actual code nigh impossible as it refuses to maintain whitespace (I shudder to think the amount of work required to get the code highlighting). I will post the completed source files at the end of each post.
Not production code by any stretch of the imagination, but it does demonstrate the building blocks required to get a window up and drawing:
- SDL_Surface, which is a structure we use to hold image data in SDL. Pretty much every function uses pointers to surfaces, not the actual surface data.
- main(). You need to have those arguments (int argc, char *argv) or else the compiler is going to scream at you.
- Fun Fact: You don’t actually need SDL_Init() to get this program to run. This surprised me because I was under the assumption that you needed SDL_Init to do anything at all. It might be interesting to see how much you can actually accomplish without it, but we will always need what this enables (since we presumably want to do more than just draw a window). Attempting to use functions that depend on SDL_Init without calling it will cause your program to crash.
- SDL_SetVideoMode(). What this essentially does is creates a special surface in memory that is usually referred to as the framebuffer, and we’re taking the returned pointer to the data and assigning it to ‘screen’. The data in the framebuffer is what shows up on screen in our window. We’ll cover the nitty gritty details of the different arguments and flags in a ‘SDL !SCIENCE!’ section.
- SDL_Flip(). This tells SDL that we’re done messing around with the current frame and it can be shown to the user.
- SDL_Quit() just cleans up everything gracefully.
Now that was the quick and dirty way of getting things done. We’re attempting to create a robust modular framework that we can use in every project, this means we’re going to have to do this the slow and (hopefully) stable way (thus saving lots of work in the long run).
This is where my coding style and yours might begin to clash. I don’t use exception handling; if I’ve done something stupid I want it to crash hard, it’s a big noticeable effect instead of a bug I can forget that may become annoying to track down and fix later. I use classes more as code organization than any specific implementation of object orientation (and you’ll probably never see inheritance in my code). I don’t use switch statements. I name things fairly verbosely, because I’ve already learned that lesson the hard way. Yes, I know STL exists, I prefer to make lists and queues myself for the most part, as it helps keep my C++ memory-fu above “that was incredibly stupid” levels.
If you want to have the big header file with every function in it and a bunch of globals, you should be able to do that. If you want to adapt the code to use STL or Boost, that shouldn’t be too hard. If you want to object orient the heck out of it, that should be possible too. Making this code your own will do wonders to your understanding of it, and prevent you from grumbling at me because it isn’t perfect.
Not too much has changed here, most of the big stuff is out in our new files. I’ve formalized the program initialization and cleanup so we keep the main() nice and clean when we start adding in more libraries. The two main changes here are I’ve added a function called event update (which we’ll go over next), which is our default event handler, and I’ve stuck all the SDL initialization stuff in a specific class that I call sdl(which we’ll go over after). Also present is SDL_Delay() which we are using so that this simple program doesn’t use up as much CPU as it can get its hands on.
The SDL events system is incredibly flexible and useful, and I’ll go into it in detail in another post. For now we’re just using it to catch when we press the close button on the window and when we hit escape. SDL_PollEvent() pulls SDL_Events from the event queue and sticks it in our newly declared ‘event_handler’, which we then parse.
Here is the image for the last file (Base_SDL.h) in it’s entirety, as you can see, we may have made a few small additions. We’ll break it down below, but it can be useful to have the entire view available for context.
The next bunch of stuff should be pretty simple to understand. Resolution is a struct we use in our linked list of available resolutions. The sdl class is the object I store everything SDL initialization related in. write_config() saves current settings to our config file. revert_defaults() does what it says on the tin and creates a screen using the default values. read_config() does what you’d expect and pulls data from our config file. resolution_add() adds a valid resolution combination to our resolution linked list.
The resolution_check() function is slightly less straightforward. We’re using SDL_ListModes() and sticking the results in an array. This function can also return NULL or -1, which makes it dangerous if you assume you’re getting back an array of pointers to SDL_Rects. It also blatantly lies to you, but we’ll get into that in SDL !SCIENCE! #1. For now, accept that it does this particular job decently and has limited usefulness otherwise. We run through the array of returned resolutions and ignore any ones smaller than 800 pixels wide and any really weirdly scaled resolutions like 900 x 1200. You may want to change these. Any ones that meet our criteria are added to our linked list of resolutions for later usage.
After this function we have set_video(), which is where we’ve moved our SDL_SetVideoMode() stuff from earlier. We then have get_resolution_list() which returns the pointer to our linked list of resolutions. change_resolution() is our public facing way to affect the window after its been initialized. Finally init() is where we’ve put SDL_Init() and it drives the whole thing. You may notice that we’ve added a function called SDL_WM_SetCaption() into the mix, all this does is set the text in the window title.
Our program isn’t much to look at right now, but after the next post… It’ll still look pretty much the same. Frameworks aren’t exactly the most fun when you’re building them, but the payoff in work saved is immense.