SDL Coordinates and Bliting
SDL Tutorials October 25th, 2007Using the first tutorial as our base, we’ll delve more into the world of SDL surfaces. As I attempted to explain in the last lesson, SDL Surfaces are basically images stored in memory. Imagine we have a blank 320×240 pixel surface. Illustrating the SDL coordinate system, we have something like this:

This coordinate system is quite different than the normal one you are familiar with. Notice how the Y coordinate increases going down, and the X coordinate increases going right. Understanding the SDL coordinate system is important in order to properly draw images on the screen.
Since we already have the main surface (Surf_Display) setup and ready, we are going to need a way to draw images on it. This process is called Blitting, where we basically transfer one image onto another. But before we can do that, we have to have a way to load these images into memory. SDL offers a simple function to do this called SDL_LoadBMP. Some pseudocode might look like this:
if((Surf_Temp = SDL_LoadBMP("mypicture.bmp")) == NULL) {
//Error!
}
It’s rather simple, SDL_LoadBMP takes a single argument, the file you want to load, and returns a surface. If the functions returns NULL, either the file is not found, corrupted, or some other error. Unfortunately, for the sake of effeciency, this method is not enough. Often the image loaded will be in a different pixel format than the display. Thus, when we draw an image to the display we can incurr performance loss, lose image colors, and the like. But, thanks to SDL, it offers a quick solution around this, SDL_DisplayFormat. This function takes a surface already loaded, and returns a new surface using the same format as the display.
Let’s take this process and throw it into a reusable class. Use SDL Tutorial 1 as the basis for you code, and add the following two new files: CSurface.h, CSurface.cpp. Open up CSurface.h and add the following:
#define _CSURFACE_H_
#include <SDL.h>
class CSurface {
public:
CSurface();
public:
static SDL_Surface* OnLoad(char* File);
};
#endif
We’ve created a simple static function, OnLoad, that will load a surface for us. Now open CSurface.cpp:
CSurface::CSurface() {
}
SDL_Surface* CSurface::OnLoad(char* File) {
SDL_Surface* Surf_Temp = NULL;
SDL_Surface* Surf_Return = NULL;
if((Surf_Temp = SDL_LoadBMP(File)) == NULL) {
return NULL;
}
Surf_Return = SDL_DisplayFormat(Surf_Temp);
SDL_FreeSurface(Surf_Temp);
return Surf_Return;
}
There are a couple of important things to note here. Firstly, always remember that when you make a pointer to set it to NULL, or 0. Many problems can come along later if you fail to do this. Secondly, notice how SDL_DisplayFormat returns a new Surface, and doesn’t overwrite the original. This important to remember because since it creates a new surface, we have to free the old one. Otherwise, we have a surface floating around in memory.
Now that we have a way of loading surfaces into memory, we are also going to need a way to draw them onto other surfaces. Just like SDL offers a function to load images, it also offers a function to draw (blit) images: SDL_BlitSurface. Unfortunately, this function is not as easy to use as the SDL_LoadBMP, but nonetheless, it’s simple enough. Open back up CSurface.h and add the following function prototype:
#define _CSURFACE_H_
#include <SDL.h>
class CSurface {
public:
CSurface();
public:
static SDL_Surface* OnLoad(char* File);
static bool OnDraw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y);
};
#endif
Now, open back up CSurface.cpp, and add the following:
CSurface::CSurface() {
}
SDL_Surface* CSurface::OnLoad(char* File) {
SDL_Surface* Surf_Temp = NULL;
SDL_Surface* Surf_Return = NULL;
if((Surf_Temp = SDL_LoadBMP(File)) == NULL) {
return NULL;
}
Surf_Return = SDL_DisplayFormat(Surf_Temp);
SDL_FreeSurface(Surf_Temp);
return Surf_Return;
}
bool CSurface::OnDraw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y) {
if(Surf_Dest == NULL || Surf_Src == NULL) {
return false;
}
SDL_Rect DestR;
DestR.x = X;
DestR.y = Y;
SDL_BlitSurface(Surf_Src, NULL, Surf_Dest, &DestR);
return true;
}
First of all, look at the arguments being passed to the OnDraw function. We have two surfaces, and two int variables. The first surface is the destination surface, or the surface we are going to draw on. The second surface is the source surface, or the surface we going to use to draw on another surface. Basically, we are putting Surf_Src on top of Surf_Dest. The X, Y variables is the position on the Surf_Dest where we are drawing this surface to.
The start of the function makes sure we have valid surfaces, if we don’t, return false. Next, we find SDL_Rect. This is a SDL structure that basically has four members: x, y, w, h. This, of course, creates the dimensions for a rectangle. We are only worried about where we are drawing to, not the size. So we assign X, Y coordinates to the destination surface. If you are wondering what NULL is within SDL_BlitSurface, it’s another parameter for a SDL_Rect. We’ll get to this later on in this lesson.
Lastly, we actualy call the function to draw the image, and then return true.
Now, to make sure all of this works, let’s create a test surface. Open up CApp.h, and create a new surface, and include the new created CSurface.h:
#define _CAPP_H_
#include <SDL.h>
#include "CSurface.h"
class CApp {
private:
bool Running;
SDL_Surface* Surf_Display;
SDL_Surface* Surf_Test;
public:
CApp();
int OnExecute();
public:
bool OnInit();
void OnEvent(SDL_Event* Event);
void OnLoop();
void OnRender();
void OnCleanup();
};
#endif
Also, initialize the surface to NULL in the constructor:
Surf_Test = NULL;
Surf_Display = NULL;
Running = true;
}
And, remember to cleanup:
void CApp::OnCleanup() {
SDL_FreeSurface(Surf_Test);
SDL_FreeSurface(Surf_Display);
SDL_Quit();
}
Now, lets actually load an image. Open up CApp_OnInit.cpp, and add the code to load a surface:
bool CApp::OnInit() {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return false;
}
if((Surf_Display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL) {
return false;
}
if((Surf_Test = CSurface::OnLoad("myimage.bmp")) == NULL) {
return false;
}
return true;
}
Be sure to replace “myimage.bmp” with an actual bitmap image you have. If you don’t have one, open mspaint and draw something real quick, and save it in the same folder where your executable goes.
Now that we have the image loaded, lets actually draw it. Open up CApp_OnRender.cpp and add the following:
void CApp::OnRender() {
CSurface::OnDraw(Surf_Display, Surf_Test, 0, 0);
SDL_Flip(Surf_Display);
}
Notice a new function here SDL_Flip. This basically refreshes the buffer and displays Surf_Display onto the screen. This is called double buffering. It’s the process of drawing everything into memory, and then finally drawing everything to the screen. If we didn’t do this, we would have images flickering on the screen. Remember the SDL_DOUBLEBUF flag? This is what turns double buffering on.
Compile your code, and make sure everything works correctly. You should see your image on the top left hand corner of the screen. If so, congratulations, you are one step closer to an actual game. If not, make sure you have the myimage.bmp in the same folder as your executable. Also insure it’s a valid bitmap file.

Now lets take this process a little bit further. While it’s nice and all to draw images to the screen, often we’ll need to draw only parts of an image. Take, for example, a tileset:

Though this is one single image, we only want to draw a part of it. Open back up CSurface.h, and add the following code:
#define _CSURFACE_H_
#include <SDL.h>
class CSurface {
public:
CSurface();
public:
static SDL_Surface* OnLoad(char* File);
static bool OnDraw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y);
static bool OnDraw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int X2, int Y2, int W, int H);
};
#endif
Open back up CSurface.cpp, and add the following function:
if(Surf_Dest == NULL || Surf_Src == NULL) {
return false;
}
SDL_Rect DestR;
DestR.x = X;
DestR.y = Y;
SDL_Rect SrcR;
SrcR.x = X2;
SrcR.y = Y2;
SrcR.w = W;
SrcR.h = H;
SDL_BlitSurface(Surf_Src, &SrcR, Surf_Dest, &DestR);
return true;
}
Notice that it’s basically the same function as our first one, except we’ve added another SDL_Rect. This source rect allows use to specify what pixels from the source to copy over to the destination. If we specified 0, 0, 50, 50 as parameters for X2…H, it would only draw upper left part of the surface (a 50×50 square).

Lets also test this new function out, open back up CApp_OnRender.cpp, and add the following:
void CApp::OnRender() {
CSurface::OnDraw(Surf_Display, Surf_Test, 0, 0);
CSurface::OnDraw(Surf_Display, Surf_Test, 100, 100, 0, 0, 50, 50);
SDL_Flip(Surf_Display);
}
You should notice that your image is drawn at 100, 100 and only part of it is being displayed. You should take special care understanding how these functions work, and how the SDL coordinate system is setup, you will be using this quite a bit.
Jump on over to the next SDL tutorial, where we’ll look more at SDL events, and how to make that process a whole lot simpler.
SDL Coordinates and Bliting - Tutorial Files:
Win32: Zip, Rar
Linux: Tar (Thanks Gaten)














February 12th, 2008 at 7:57 am
This is a great tutorial. But I have a question.
Why are “OnDraw” and “OnLoad” functions declared as static?
February 12th, 2008 at 8:10 am
Thank you for your comments! The reason I declared the functions as static is for OOP purposes. Since there is no practical reason to instantiate objects every time we want to Draw or Load a surface, we declare them as static. This is the same idea from .NET, or Java, when we call a function through a method heirarchy, like System.println(). We don’t create a new System object just to call println, because it’s not necessary. So, in simple terms, CSurface is a singleton in the sense that all the members are static, but each function is also independent from each other.
February 22nd, 2008 at 7:52 am
free tutorials are really helpful, thanks for the above
February 28th, 2008 at 12:03 am
Linux source: http://gaten.homelinux.net/sdltuts/sdl_coords_and_blitting.tar.gz
March 3rd, 2008 at 12:30 pm
Very nice as i’ve allreadytold. Dont forget ppl to download the image extension library for more ease and size. Simply go here: http://www.libsdl.org/projects/SDL_image/
Then just include the header #include
then switch
SDL_LoadBMP
with
IMG_Load
just in-case you didn’t know
March 3rd, 2008 at 1:00 pm
Thanks Blommis. The SDL library build for Windows I provide on here under “Libraries” also comes with SDL_image, SDL_ttf, SDL_ffmpeg, and SDL_mixer. We will make the switch to SDL_image sometime in the next tutorials though.
March 18th, 2008 at 1:00 pm
Your tutorials are really helpfull. Keep up the good work man!
March 26th, 2008 at 12:02 am
When I try to compile I get “obj\Debug\CApp_OnRender.o||In function `_ZN4CApp8OnRenderEv’:|
C:\Documents and Settings\macr0ss\Desktop\test\SDL Tutorial 1\CApp_OnRender.cpp|4|undefined reference to `CSurface::OnDraw(SDL_Surface*, SDL_Surface*, int, int)’|
||=== Build finished: 1 errors, 0 warnings ===|” when I take out the first static bool ondraw statement from csurface.h it compiles and runs fine, am I not supposed to have to of those statements? or why is it failing?
March 26th, 2008 at 6:22 am
Are you compiling from the project file, or are you going through this tutorial yourself? But yes, all the functions within CSurface are static. An “undefined reference” error means that the function has not been fully defined elsewhere. It’s like putting in the prototype for a function, calling that function somewhere in your program, but failing to actually define the function. Like:
void MyFunction();
int main() {
MyFunction();
return -1;
}
The above will cause a linker error of “undefined reference” because the function actually wasn’t defined. Check to see if the OnDraw function is in there; remember, we have two OnDraw functions we made in this tutorial. I hope that helps!
March 30th, 2008 at 10:06 am
Is there a specific reason you’re not using the newbie-friendly standard library’s “string” object instead of the highly protean “char*”?
March 31st, 2008 at 7:08 am
Cats: no, not really. There will probably be certain instances that I will use std::string over char, but there is no benefit in the current tutorials for using std::string over char.
April 5th, 2008 at 2:49 pm
I would recommend making the constructor of CSurface private. There should be no reason to ever create an instance of the class, and that could prevent a mistake later on. Just my opinion.
April 7th, 2008 at 6:57 am
That all depends, I’ve recommended to someone before extending this CSurface class as a wrapper to an SDL_Surface.
June 1st, 2008 at 1:56 pm
For some reason, when I compile and run the first half of the tutorial (just the bitmap loading part), the screen pops up, flickers, and closes instantly. Why is this happening?
June 2nd, 2008 at 2:49 am
Really lots of thanks for the tutorials! I’m using them to learn SDL and it works really well! ^^
I really hope all the rest tutorials is this high standard ^^ Then I will have no need to fear to not learn SDL ^^
June 2nd, 2008 at 6:42 am
Arseniy, I am guessing that your surface image cannot be found. Make sure you have a good, 24bit, BMP image (which I called “myimage.bmp” in this tutorial). It needs to be in the same folder as your exe. You can also check this by doing this when loading your picture:
if((Surf_Test = CSurface::OnLoad(”myimage.bmp”)) == NULL) {
printf(”Image not found!”);
return false;
}
The error will print to a stderr.txt file. Let me know if that helps.
Mackyman, I’m glad you like my tutorials. I hope I can keep the coming tutorials just as good.
June 2nd, 2008 at 9:06 am
The same problem persists. I added:
printf(”Image not found!”);
to CApp_OnInit.cpp, where you told me, but it still just runs and closes again automatically. I uploaded the files I made to this site, can you download them and see if you can find the problem?
http://www.mediafire.com/?9gdyojbmxun
Thanks again for helping. I love your tutorials too btw! (If only they’d work hehe).
- Arseniy
June 2nd, 2008 at 9:23 am
Arseniy, I saw that you are using CodeBlocks, are you on Windows as well? Also, what version of CodeBlocks are you using? When I opened your project file, I found a bunch of missing settings, or what not. First, it wouldn’t compile for me at all, I needed to add mingw32 and SDLmain to the linkers. Also, I needed to check all cpp files under targets to set them to compile. Then, I had to change your int main() to int main(int argc, char* argv[]) (because that is what SDL needs). If yours it setup alright, then disregard what I said above (but somehow it wasn’t for me).
Next, I noticed you had your BMP with the source files, and not with the exe. So, I moved it into the same folder. I tried running it, it closed. So, I went ahead and opened the image in a paint editor (mspaint), and resaved as a 24bit BMP (important). It then worked.
Hopefully this all helps.
June 2nd, 2008 at 9:35 am
Linux (Ubuntu), and svn 5074, a nightly.
I wasn’t able to add SDLMain to the linkers, but SDL was okay.
Hehe I thought int main() was supposed to stay argument free lol. But that didn’t change it. And the .cpp’s are all checked under targets.
The BMP…I tried re-saving it again with GIMP as a 24-bit BMP and OMG IT WORKED!!!
Thanks a lot for looking at my code lol, I appreciate it.
Do you know why it did what it did with an apparently non-24bit BMP? Why is that important?
June 2nd, 2008 at 9:51 am
Okay, I asked what OS you were on, because that will determine your settings (I am working on Windows).
SDL_LoadBMP only accepts 24bit BMPs, anything else, and SDL_LoadBMP will return NULL. So, even if it was finding the image, it was still returning NULL (and thus, returning false on our OnInit function), which was closing your program.
FYI - SDL_LoadBMP is only temporarily used within these tutorials. You’ll notice an SDL_image side tutorial on this site, which is meant to show you how to replace SDL_LoadBMP with a better library. I don’t recommend BMPs for any software purposes, especially games.
Glad that I could help, don’t hesitate to ask again.
June 2nd, 2008 at 12:01 pm
Alright everything works great! I tried to implement my own little tileset thing, but for some reason it’s not working right. Can you check and see if I did everything correctly? There are six files and I’ll upload them in the same way.
http://www.mediafire.com/?mmnnppm1qyl
Thanks!
June 8th, 2008 at 4:50 am
Thanks for the great tutorials they have really been helpful
I can for the life of me make the transparency work. I’m using .png with SDL_image instead of bmp but I no matter what I do in CSurface I can’t get the pink to become transparent. I’ve read a few tutorials now and still can’t get it to work. Any Ideas?
June 12th, 2008 at 10:20 am
Norm,
I think the problem is that you are trying to make the pink disappear; the problem is that the PNG has an alpha layer on it, meaning, SDL_SetColorKey becomes useless to you. So, the preferred method of achieving transparency is to put it in via Photoshop, or GIMP. This image is a good one to test with:
http://wiki.sdltutorials.com/images/c/c9/Charlie.png
If that shows up as transparent, then your code is just fine. You’ll need to a get a image editor, and select all the pink, and make it transparent. Then save the new PNG. If you need that software, as not everyone can afford Photoshop, try these sites: http://www.getpaint.net/, or http://www.gimp.org/.
If the above image I provided to test doesn’t work, I’d be glad to look at some code.
June 27th, 2008 at 10:42 am
Thanks for this tutorial. I’m waiting for more
July 13th, 2008 at 12:39 pm
Is this necessary in OnCleanup()?
SDL_FreeSurface(Surf_Display);
I thought this is handled in SDL_Quit()?
From man SDL_SetVideoMode:
RETURN VALUE
The framebuffer surface, or NULL if it fails.
The surface returned is freed by SDL_Quit() and
should nt be freed by the caller.
July 15th, 2008 at 1:03 pm
NoArms,
Technically I guess you’re right. I’ve never run into any problems with it before, but perhaps on some different system with SDL there might be. When I have time I’ll fix all the tutorials.