Prerequisites:
Some knowledge of C or C++ (Variables, loops,
functions). Not prerequired:
A compiler/IDE, money.
Hello there! In this article, I want to get you set up with a
C or C++ build environment and help you to install the
Simple DirectMedia Layer (SDL - www.libsdl.org).
I personally use Windows XP
and Debian GNU/Linux, going between the two with the excellent
operating system portability of SDL. All of my SDL programs
compile without changes on either system. Oh yeah, it's the
life ;)
To help you out a little, I've colored specific paragraphs: Red
will be for Windows, and Green will be
for Linux.
First up, let's talk IDEs. IDE stands for Integrated
Development Environment. These are programs that help you to
write programs faster and easier than if you're just writing in a text
editor. They usually include a built-in editor, debugger, and
allow you to compile and test your program right there.
Technically, the IDE doesn't compile your programs. It asks a
compiler to do this for you. That means that you must have
a compiler suite installed as well.
On Windows,
your best bet is to use MinGW. This is the
Windows port of the free GNU Compiler Collection. If you're
already set with Microsoft Visual Studio, you can just skip ahead (but
I can't help you as much). Fortunately, my favorite IDE,
Code::Blocks, comes equipped with MinGW. I suggest you take a
look at CodeBlocks (www.codeblocks.org), since that's where I'm going
with this. Once you download the release candidate from the
official website (codeblocks-8.02mingw-setup.exe, 19Mb), you just run
it and install it. When you run it for the first time, you'll
choose your compiler and you should be all set to make a simple C/C++
program.
On Linux,
everyone uses the GNU Compiler Collection. Your
system almost definitely has it installed already. Your
kernel is probably built with it! Here let me differentiate
the
compilers. The C compiler is gcc. The C++ compiler
is g++. Just open a terminal and type:
gcc --version
or
g++ --version
Now, depending
on your Linux distribution, your installation of
CodeBlocks can vary. You can use a package manager like APT
on Debian and Ubuntu (As root: apt-get install codeblocks) or Yum on
others. You could also download what you need
from the CodeBlocks site. If you're on Debian or Ubuntu,
you'll need to extract the tar.gz file and then use dpkg to install the
packages:
dpkg -i package1 package2 ...
or
dpkg -i *.deb
Running
codeblocks in the terminal or finding it in your applications
menu will open the program and verify your compiler. Now
you're ready!
A
test program: Console output
Let's write a quick program to flex our new programming
muscles... Create a new project, choose "Console application"
(it has a shell in front of a 'shell'), and put this in your
main source
file:
#include "stdio.h"
int main(int argc, char* argv[])
{
printf("Hello World!\n");
printf("Hooooray!");
/* Use this on Windows if you want to
keep the console window open */
/*system("PAUSE");*/
return 0;
}
Hopefully this works right the first time. This is a C
program, as my other code here will be, so I don't have to worry about
compatibility. The only weird thing you might see is how I
defined main(). According to the standards, your main
function should return an integer. Zero means that everything
went fine. Any other number means that there was an
error. The parameters of main, argc and argv, are used for
working with command-line arguments. argc tells you the count
of how many arguments there are. argv holds the values of the
arguments. The first argument is, by default, your program's
name as it was called.
Here's an example -
If I run test.exe like so:
test.exe -c moreFPS
we have:
argc == 3
argv[0] is the string "test.exe"
argv[1] is "-c"
argv[2] is "moreFPS"
To apply
command-line arguments in Windows, you have to use the command
console (run: cmd). This command line stuff is
all very useful, but more importantly for now,
SDL 1.2 requires main() to be defined this way.
Installing
SDL (and libraries in general)
When you install a library you really start to understand the whole
process. When you compile a program, you also have to link
it. A compiler will spit out object files (.o).
These are then put together by a "linker" to make your
executable. A library is a precompiled chunk of code that you
can use in your programs instead of adding all of the original source
files into each of your projects. Static link libraries are
built into
your program when you link it after compiling. Dynamic link
libraries (or Shared libraries) are linked to your program at
runtime. When your program is being linked at compile-time,
it still needs to know which dynamic libraries you're using.
A common naming convention for libraries that you'll see a lot is:
"libmything.a".
On Windows,
dynamic libraries appear as .lib, .a, and .dll
files. MS Visual Studio uses .lib files. We'll be
using .a files. You link to the .a (or .lib) file when you
compile, and
then the program knows to look for the .dll when it runs.
Static link libraries also appear as .lib or .a files.
Sometimes, the library will have a 'd' appended to the file name to
signify dynamic linking.
On Linux,
shared (dynamic) libraries have .so extensions.
Static libraries appear as .a files.
To install a library, you need to drop some files into your compiler's
include/ folder and lib/ folder. If you got CodeBlocks with
MinGW, those folders are in the codeblocks\mingw\ directory.
If you're on Linux, your folders are /usr/include/ and
/usr/lib/. A library typically comes as header files (.h
usually) and the library files (.lib, .a, .dll, .so). Put the
header files into your include folder and the library files into your
lib folder.
That's the basic idea. There are some other ways about it
(devpaks), but that is the way it is often done.
On Windows,
you are usually presented with the binaries (precompiled
library files) and you just toss the files where they should
go. When you give someone else your program, include the .dll
files that it uses with it. The .dll files should be in the
same folder as your executable.
On Linux,
you're often presented with just plain source code.
If there is a Makefile with the code, you can usually just move into
that directory and type:
make
make install
If there's not
a Makefile, but there's a config or configure file, try:
./configure
make
make install
Alternatively,
many libraries occur as packages. Use APT to
get these. Most Linux
users can get the required libraries for themselves, but you
can include your .so files when you distribute your programs.
Now, finally, let's install SDL 1.2. On the SDL website
(www.libsdl.org),
you'll find "Runtime Libraries" and "Development
Libraries". You'll probably want both. The
Development Libraries are vital, however.
Installation is just like above, except that people usually treat SDL
as special. I put my headers into include/SDL/ so that I can
easily find them and add to them. You have to tell the
compiler to look there as well, but it keeps SDL nice and separate.
On Debian, you
can use APT (as root) to get the required packages:
apt-get install libsdl1.2-dev libsdl1.2debian
This does all
the work for you.
Okay. We've just installed SDL! It's time for a
program so we can see how SDL looks in the wild...
A
test program: Drawing rectangles and blitting a bitmap
SDL is pretty neat. Right here you have a library that gives
you cross-platform access to video and audio hardware, mouse and
keyboard, even joysticks and CD-ROMs. There are many good
tutorials out there. I suggest SDLTutorials.com, Sol, Lazy Foo', Cone3D,
and NeHe.
I'd like to keep my presentation fairly concise, so
I'll forgo the details of how everything works in SDL. I'll
just give you enough to get going. You should definitely
check out those tutorial sites to get a feel for how to do various
things
with SDL.
To make my quick example, let's load an image and draw some
rectangles. First, make a quick bitmap image. You
can use MS Paint, but I suggest the Gimp (GNU Image Manipulation
Program
- www.gimp.org) for both Windows and Linux. It's roughly on
the level with Adobe Photoshop, and costs exactly 100% less.
However you do it, make a quick drawing and save it as a .bmp file.
Put that into a new folder and open CodeBlocks. Make a new
console project and put it in that folder, too.
To set up the project to allow you to use a library, you need to do
three things. First, you have to make sure that the compiler
can find your library header files (it automatically checks the
include/ folder, but not subdirectories). Second, tell the
linker which libraries you're using in your specific project.
Third, write an include statement in your source code.
To tell the compiler where to find the headers, go into
CodeBlocks' "Settings" menu and choose "Compiler and
Debugger". The Global Compiler Settings should be
showing. Choose the "Search directories" tab, then add a new
location on the "Compiler" tab. Tell it the name of the
folder where SDL is (include/SDL/). If you're on Windows, you
should add a linker option, too. Go to the "Linker
Settings" tab and under "Other linker options", type -mwindows.
Alright, so your global compiler stuff is set. You only have
to do that once. Now you have to set your project's specific
libraries. Go to the "Project" menu and choose "Build
options". The screen should look familiar. Make
sure you have your main project selected (not just debug or release),
then click on the "Linker settings" tab. Here, click on the
"Add" button to add libraries. On Windows with MinGW, you
have to add mingw32 first. Now, add SDLmain and
SDL. This is also where you'd add other libraries.
For instance, if the library file is libSDL_image.a, you would add
SDL_image. On the command line, this translates to
-lSDL_image. Be aware that Linux is case-sensitive!
And the last part is in the code, so let's check it out:
/* Here are two rectangles */
/* I initialize rect.x, rect.y, rect.w,
and rect.h all at once */
SDL_Rect rect1 = {40, 40, 300, 200};
SDL_Rect rect2 = {200, 100, 160, 160};
/* Start the main loop */
SDL_Event event;
Uint8 done = 0;
while (!done)
{
/* Check for events */
while (SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
done = 1;
}
if(event.type == SDL_KEYDOWN)
{
if(event.key.keysym.sym == SDLK_ESCAPE)
{
done = 1;
}
}
}
/* Clear the screen */
SDL_FillRect(screen, NULL, 0x000000);
/* Red rectangle */
SDL_FillRect(screen, &rect1, SDL_MapRGB(screen->format,
200, 0, 0));
/* White rectangle */
SDL_FillRect(screen, &rect2, SDL_MapRGB(screen->format,
255, 255, 255));
/* Draw my picture */
SDL_BlitSurface(pic, NULL, screen, &destRect);
/* Send all this to the monitor */
SDL_Flip(screen);
}
/* Free up the picture memory */
SDL_FreeSurface(pic);
/* Initialize the screen surface */
screen = SDL_SetVideoMode(400, 300, 32,
SDL_SWSURFACE);
if ( screen == NULL )
return 0;
/* Now do whatever we want! */
startGame();
SDL_Quit();
return 0;
}
This code is very, very simple SDL stuff. I didn't even put
in framerate controls or mouse input, and I didn't give the user any
feedback when an error occurs. You can find a little more
code in my SDL example, but this will suit us fine for now.
What I've done here is just to initialize SDL, load that picture, then
enter the main loop and draw everything. There are many more
substantial examples in the tutorials that I mentioned earlier.
If there is no picture drawn, double-check the file name
(case-sensitive in Linux, remember).
Some
notes on SDL
As you can see, SDL uses event-based input. This has several
advantages, especially conceptually (easier to think about and
encapsulate). You can also check the state of certain input
devices for a different approach, but events are the usual thing to
work with.
SDL has fairly good documentation, thankfully. I keep a copy
on my computer for quick reference. If you can't find an
answer there, try checking out those tutorial sites. Failing
that, the SDL mailing list is quite active. Also, I will
occasionally post SDL resources, like my alpha-blending
table (which
does a better job than the official docs, if I may say so).
Colors in SDL are usually stored in Uint32 variables. This
type (and others) is defined by SDL so that you can be sure that you
get exactly 32 bits on every different platform/OS, rather than the
ambiguous 'unsigned int'. On a 32-bit surface, each color
component gets 8 bits. If I write a hexidecimal constant like
so: 0x50a600ff, and the pixel format is ARGB, then my components would
be alpha = 0x50 (80), red = 0xa6 (166), green = 0x00 (0), and blue =
0xff (255). There you can see that color components range
from 0 to 255 (256 values). These components can each be
stored in Uint8 variables.
SDL uses the standard coordinate axes for computer graphics.
The point (0, 0) is in the upper left-hand corner of the
screen. The x coordinate increases to the right, and the y
coordinate increases downward. This does have a small
side-effect that the coordinate system is left-handed (angles are
measured clockwise).
It
pays to wrap certain things in your own functions. For
example,
you can write a function that draws an image to the screen, taking just
the surface pointer and coordinates. I personally found it
very
easy to wrap both
keyboard and joystick handling into one function, so my game accepts
either input method for a particular player and the code to use it is
nice and
clean.
Well, that's just about all I have to say right now. I hope
to
hear from you if this all works out. See ya next time for an
emphasis on Sprig!