Tag Archives: sdl

Chapter 3: Displaying a picture (JEDI-SDL)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

Working with the video subsystem assumes that you understand the concept behind. In SDL the surface is a central concept. Surfaces are parts of the memory (RAM) where an image is saved. Every surface can have its own size (pixels x pixels, e.g. 640 x 480) and properties (e.g. with or without alpha channel for transparency effects). You can copy(=blit) a part or the whole surface to any other surface. This is the second very important concept and is called blitting

There is a special surface: the display surface. Everything that got blit to this surface gets displayed on the physical screen (monitor) after refreshing (SDL_FLIP(…), SDL_UPDATERECT(…))!

For example in demo03.pas / demo03.exe from a modified SDL4Free Pascal demo file the ball, the paddle and the black background (display surface background color) are surfaces. The ball and the paddle are copied(=blitted) onto the black screen surface again and again slightly moved up. So the ball and the paddle seem to move.

left: ball and paddle erased between each frame; right: ball and paddle not erased between framesIf you think carefully about this or check the source code you will notice that between every blitting process the ball and paddle of the previous frame have to be overdrawn by black rectangles erasing them (left), otherwise the result would look like the right example.

diagram showing path from image file to displaySo our task is to create a display surface. Furthermore we need a surface that contains a picture. Eventually the picture should get copied onto the display surface. After that the picture should be displayed at the physical screen. The whole code looks like this.

PROGRAM chap3;
USES SDL, CRT;
VAR
screen,picture:pSDL_SURFACE;
source_rect,destination_rect:pSDL_RECT;

BEGIN
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,32,SDL_SWSURFACE);
IF screen=NIL THEN HALT;

picture:=SDL_LOADBMP('C:\FPC\2.0.4\bin\i386-win32\test\fpsdl.bmp');
IF picture=NIL THEN HALT;

NEW(source_rect);
source_rect^.x:=0;
source_rect^.y:=0;
source_rect^.w:=200;
source_rect^.h:=200;
NEW(destination_rect);
destination_rect^.x:=0;
destination_rect^.y:=0;
destination_rect^.w:=200;
destination_rect^.h:=200;

REPEAT
  SDL_BLITSURFACE(picture,source_rect,screen,destination_rect);
  SDL_FLIP(screen);
  DEC(source_rect^.w);
  DEC(source_rect^.h);
  INC(destination_rect^.x);
  INC(destination_rect^.y);
  DEC(destination_rect^.w);
  DEC(destination_rect^.h);
  SDL_DELAY(30);
  IF source_rect^.w=1 THEN
  BEGIN
    source_rect^.x:=0;
    source_rect^.y:=0;
    source_rect^.w:=200;
    source_rect^.h:=200;
    destination_rect^.x:=0;
    destination_rect^.y:=0;
    destination_rect^.w:=200;
    destination_rect^.h:=200;
  END;
UNTIL keypressed;

SDL_FREESURFACE(picture);
SDL_FREESURFACE(screen);

DISPOSE(source_rect);
DISPOSE(destination_rect);

SDL_QUIT;
END.

Now we need a command to create a display surface. Creating a surface is always introduced by setting up a surface variable. The variable type is pSDL_SURFACE and is kind of pointer type as indicated by the “p” in front of it. pSDL_SURFACE is used for the display surface and any other surface.

PROGRAM chap3;
USES SDL, CRT;
VAR
screen,picture:pSDL_SURFACE;
source_rect,destination_rect:pSDL_RECT;

The first line determines the program name. Then we again define that we want to use the SDL unit to be loaded. We introduce the CRT unit which is a basic Pascal unit (check Chapter 2 for more details on CRT). It is needed to detect in a simple way when the user presses a key to stop the repeat/until loop (in Chapter 6 we will learn how SDL handles keyboard interactions). Finally we decide to set up two surfaces. The display surface (screen) has some special properties that can be set. The surface “picture” will store the picutre from a bitmap file. The two variabes “source_rect” and “destination_rect” will be used later to define some rectangles. More details on this later in this chapter.

After using surfaces you have to clean the memory if you don’t need them anymore. Therefore you use the procedure SDL_FREESURFACE(surface:pSDL_Surface) which you have to call for any surface (including the display surface).

BEGIN
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,32,SDL_SWSURFACE);
IF screen=NIL THEN HALT;

After initializing SDL as seen in the previous chapter already we now go into details on the set up of the display surface. The function to define a surface as display surface is SDL_SETVIDEOMODE(width,height,bpp:INTEGER; flags:UInt32):pSDL_SURFACE and returns NIL if an errors occurs meaning no pointer for a display surface could be set up. The first parameter determines the width, the second one the height in pixels. The third parameter determines the colordepth in bits (32 bit for now) and the last one the appearance (windowed or fullscreen, with or without border) and space handling (software or hardware memory used). The first three parameters are of integer type, the last one UInt32 (check Chapter 2 for more details on UInt32). There are some very interesting flags. The chosen one, SDL_SWSURFACE, is used if you want to store the surface in system memory (RAM). Alternatively you could chose SDL_HWSURFACE what causes a storage in video memory. Both will create windowed screens that cannot be resized. SDL_NOFRAME would create a windowed screen without a frame. Eventually there is SDL_FULLSCREEN which leads to a fullscreen display. You also can combine several flags by “OR” keyword. So setting up this same window without a frame would be screen:=SDL_SETVIDEOMODE(200,200,32,SDL_SWSURFACE OR SDL_NOFRAME).

Direct loading of a picture to the screen surface is impossible so it is necessary to create another surface that contains the picture. Fourtunately there is a function called SDL_LOADBMP(filename:pCHAR):pSDL_SURFACE. Make sure you give the FULL path for “filename”; relative pathes are not allowed. If you drew something onto the screen and would like to save it as a bitmap file the corresponding function is called SDL_SAVEBMP(surface:pSDL_SURFACE; filename:pCHAR):INTEGER. The surface you want to save doesn’t have to be necessarily the screen surface. It returns 0 on success and -1 on error. Incidentally there is no such import/export feature for other graphic formats (that doesn’t mean there are no other easy ways to use other important graphic formats ;), check Chapter 3a for details on this).

Free Pascal meets SDL sample image bmp format
download (right click and “save as”)

This picture (8 bit) is the one that will be copied to the screen. The pictures width and height are both exactly 200 pixels.

{add the correct path here}
picture:=SDL_LOADBMP('C:\FPC\2.0.4\test\fpsdl.bmp');
{if the path is wrong you will get an abortion}
IF picture=NIL THEN HALT;

The surface is named “picture” here and the file fpsdl.bmp is located at the given directory, “C:\FPC\2.0.4\test”. As already known from setting of the screen variable the SDL_LOADBMP(path) function returns NIL if something is wrong. The path has to be of type pCHAR.

Actually we now could copy the loaded picture from the picture surface to the display surface. Remember: This process is called blitting. But to demonstrate another quite usable feature strongly related to picture blitting we will now define some rectangles. Instead of blitting the whole image we are then also able to blit just parts of the source image.

NEW(source_rect);
source_rect^.x:=0;
source_rect^.y:=0;
source_rect^.w:=200;
source_rect^.h:=200;
NEW(destination_rect);
destination_rect^.x:=0;
destination_rect^.y:=0;
destination_rect^.w:=200;
destination_rect^.h:=200;

Now let’s have a look at the code. We define the rectangles called source_rect and destination_rect which store what part of the source image will be copied to what position at the destination surface (here: display surface). The command NEW(pointer) is a common Pascal command and should be known. source_rect and destination_rect are of type pSDL_RECT and are simple records which store a (x,y) and a (width, height) pair. The values set for both rectangles are identical. They are further exactly of the same size as our display surface and our image. The coordinates of x and y relate to the corresponding surface so (x/y) is (0/0) here for both rectangles and corresponds to the left upper corner. From this point to the right direction the width is 200 pixels. The height is from this point 200 pixels down to the bottom side of the display surface. The following image may explain this.

The display surfaceNext we will enter the repeat/until loop.

REPEAT
  SDL_BLITSURFACE(picture,source_rect,screen,destination_rect);
  SDL_FLIP(screen);
  DEC(source_rect^.w);
  DEC(source_rect^.h);
  INC(destination_rect^.x);
  INC(destination_rect^.y);
  DEC(destination_rect^.w);
  DEC(destination_rect^.h);
  SDL_DELAY(30);

SDL_BLITSURFACE(src:pSDL_SURFACE; srcrect:pSDL_RECT; dst:pSDL_SURFACE; dstrect:pSDL_RECT):INTEGER is the needed command for blit processes. For successful blitting (copying) four parameters are requested. The first determines the source surface, the third the destination surface. The second and the fourth parameter can be NIL. Then the whole source surface is blitted to the (0,0) position (upper left corner) of the destination surface. If you want to blit the source surface to any other position on the destination surface (which is usually the case) you have to provide the coordinates by usage of the pSDL_RECT record. In the first run the content of surface “picture” within the defined rectangle of “source_rect” (x/y)=(0/0) and (w/h)=(200/200) is blitted to the display surface within the defined rectangle of “destination_rect” (x/y)=(0/0) and (w/h)=(200/200). Actually this means the complete content of the “picture” surface is blitted to the display surface.

After the blit process is finished the display surface has to be refreshed. Procedure SDL_UPDATERECT(screen:pSDL_SURFACE; x,y:SInt32; w,h:UInt32) or function SDL_FLIP(screen:pSDL_SURFACE):INTEGER are doing that. The SDL_FLIP(screen surface) command you use if you want to refresh the whole screen surface and furthermore if you want to use double buffering. For most applications and games therefore the SDL_FLIP(screen surface) is much more common. It is equal to SDL_UPDATERECT(screen surface,0,0,0,0) if double buffering is disabled. In comparision to SDL_UPDATERECT, SDL_FLIP furthermore returns an error value, 0 if successful and -1 on error.

The SDL_UPDATERECT command requests five parameters. The first parameter determines which surface has to be refreshed (usually the display surface). The next four ones determine a rectangel with: x-position, y-position (from top to bottom), width (relative to x,y-position), height (relative to x,y-position). If all of these paramters are “0” the whole surface will get updated.

In the example for any further cycle though the x, y, w and h values get incremented or decremented as shown. The destination-x and y values get incremented by one each cycle so it is progressing to the right bottom corner. This leads to the impression that the picture is slipping to the right bottom corner. The width and height values are fit respectivly.

The new introduced SDL_Delay(msec: UInt32) procedure works the same way as the common delay command of the CRT unit in Pascal. It delays the run of the program for the given time in milli seconds. This is a key procedure for nearly any program. If you would remove the delay procedure the program is running so fast, you wouldn’t be able to recognise the shifting but see some flickering. Since this sometimes even leads to abortions of the program I do not advise you to try it out.

ATTENTION: For a fast and clean blitting you should note that both surfaces (source and destination surface) should have the same bit depth! In our example we use a 32 bit screen surface (screen) and blit an 8 bit source surface (picture) onto it (because we loaded an 8 bit image file (fpsdl.bmp) to this surface). This is just an example and therefore it is okay, but you should avoid this especially if you plan to create games or applications where the FPS (frames per second) count is important.

IF source_rect^.w=1 THEN
  BEGIN
    source_rect^.x:=0;
    source_rect^.y:=0;
    source_rect^.w:=200;
    source_rect^.h:=200;
    destination_rect^.x:=0;
    destination_rect^.y:=0;
    destination_rect^.w:=200;
    destination_rect^.h:=200;
  END;
UNTIL keypressed;

The Repeat loop shrinkens the source rectangle from bottom right corner. At the same time the position at the destination surface is increased at the same rate. When the rectangles are of size 1 all values get restored.

When any key is pressed the loop is exited.

SDL_FREESURFACE(picture);
SDL_FREESURFACE(screen);

DISPOSE(source_rect);
DISPOSE(destination_rect);

SDL_QUIT;
END.

The allocated memory of the picture and the display surface and of both rectangles get disposed. Finally SDL has to be quit and so has the program.

This file contains the source code: chap3.pas (right click and “save as”).
This file contains the executable: chap3.exe (right click and “save as”).

Hope you are successful and have fun. The final result should look and behave like this: The blue box with the text “Free Pascal meets SDL” is slipping to the right bottom corner. When it disappears the scene is reset.

Result of example program

Chapter 2: First steps using SDL (JEDI-SDL)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

You should be slightly experienced in programming Free Pascal. That means you should be familiar with procedures, functions, loops and usual commands of Free Pascal. If this is not the case you may have problems because this tutorial deals with the features and usage of the SDL library and will not explain basic concepts of Pascal programming. Here I have to set the CRT unit off which was provided along with Turbo Pascal and is also available for Free Pascal by default. It was used in Turbo Pascal for screen and keyboard handling. In many chapters this unit will be used becaused it allows a simple way to recognize if a user pressed a key by a REPEAT … UNTIL keypressed statement. However, this unit is not related to SDL. SDL’s own advanced keyboard handling described in Chapter 6 is not used to keep the code short.

In the original SDL library there are several standard units (called headers in C/C++) whereas in JEDI-SDL all of them got merged to only one unit called “SDL”. To prepare your Free Pascal program for the usage of SDL you just have to call this unit at the uses clause. The SDL unit is the heart of every SDL application!

The different features of SDL (screen handling, audio handling, keyboard handling, cdrom handling, and so on) have to be initilized using the SDL_INIT(flags:UInt32):INTEGER function. You may wonder about the variable type UInt32 of “flags”. The U stands for “unsigned” (values greater or euqal zero only!), the Int stands for “integer” and the number stands for the bit value. So it is an 32 bit unsigned integer (which corresponds to Free Pascal’s longword). Such integer types (which we will see in other chapters again) originate from the original C/C++ SDL code, and for an easier translation to Pascal they were kept.

In the first example we want to initialize the SDL video subsystem for screen handling. The following code example shows the frame of a SDL application.

PROGRAM chap2;
USES SDL;

BEGIN
SDL_INIT(SDL_INIT_VIDEO);

{further code}

SDL_QUIT;
END.

Instead of SDL_INIT_VIDEO you could initilize the respective subsystem by using SDL_INIT_AUDIO, SDL_INIT_CDROM, SDL_INIT_JOYSTICK, SDL_INIT_TIMER, SDL_INIT_NOPARACHUTE, SDL_INIT_EVENTTHREAD, SDL_INIT_EVERYTHING. So if you want to use the features provided by the library for sound handling you should initialize it by using SDL_INIT_AUDIO. If you use SDL_INIT_EVERYTHING all subsystems are initialized. You also can combine several components by the OR keyword, e.g. “SDL_INIT(SDL_INIT_VIDEO OR SDL_INIT_AUDIO)” to initilize video and audio support. If you are running some subsystems already but need to load further ones you would use SDL_INITSUBSYSTEM(flags:UInt32):INTEGER respectivly.

If you look at the exact definition carefully you may wonder about the integer value the function returns. You shoud notice that every SDL function usually returns an error value for you to check if the function runs properly at runtime. There is no general rule what values correspond to which status. Usually values like 0 and 1 correspond to a status “function runs successfully”, values 0 and -1 correspond to a status “function couldn’t be run, something is wrong”. For SDL_INIT the function is run successfully if it returns 0, otherwise there is something wrong. However, in most cases I won’t do error checking to keep code examples short but will mention the error values to be expected.

Every SDL program has to be closed by SDL_QUIT. It cleans up your system. Never forget it! This procedure ensures that all subsystems initilized get unloaded. There is a corresponding procedure to unload specific subsystems defined as SDL_QUITSUBSYSTEM(flags:UInt32 ). The same arguments you use to load subsystems you can use here to unload them.

Now you can try the example program.

Well, we have initilized the video subsystem and released it afterwards. Simple Directmedia Layer deserves its name, isn’t it?

Chapter 6: Event handling (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

If the user is moving the mouse, pressing/releasing a button on the keyboard or pressing/releasing the fire key on the joystick then you speak of events. Further events are resizing a window or switching between several applications. For games though the events described first are much more important. SDL provides a quite easy way to notice and react to such events, which is called event handling.

First of all using event handling means to understand the concept of event handling. Events have a special structure you should know about. For example an pressed key is an event or a moved mouse is an event. SDL differs altogether fourteen such events. Every event stores different information depending on its kind. For example the key board event stores the information which key was pressed. The mouse motion event stores the information to which position the mouse got moved. If you got a mouse motion event you can’t read out key information and so on. Therefore you have the following general structure to the event data: event.eventstructure.data.

To make event handling possible you have to include the unit SDL_EVENTS. The event handling subsystem is automatically initialized along with the video subsystem.

We have to create an event variable which is of pointer type pSDL_EVENT. We will create a second variable of boolean type just to control the while loop.

PROGRAM chap6_1;
USES crt, SDL, SDL_VIDEO, SDL_EVENTS;

VAR
screen:pSDL_SURFACE;
loopstop:boolean=FALSE;
test_event:pSDL_EVENT;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
IF screen=NIL THEN HALT;

NEW(test_event);

DISPOSE(test_event);
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

We want to check the program if any event occured and if so, we want to know which kind of event happened. So we make a while loop which will run until loopstop gets true.

The command SDL_POLLEVENT(parameter) checks if there are pending events and if so it will take the oldest and save it to parameter which is an event record of pSDL_EVENT type. For example if the user presses (then releases) left mouse button, then presses (then releases) space button on keyboard and finally moves the mouse there are altogether five events: 1. left mouse button pressed, 2. left mouse button released, 3. space key pressed, 4. space key released, 5. mouse moved. If you poll for events now you will get the first event (left mouse button pressed) and saved it’s properties to the event variable we specified as parameter. The next poll will save the properties of next event (left mouse button released) to event variable and so on. SDL_POLLEVENT(parameter) will return 1 if it has found pending event or 0 if there wasn’t any pending event.

Fortunately you don’t have to notice any event which is made by the user ;). By event^.eventtype you can easily check which type of event you got. In the case described before it would be 1. SDL_MOUSEBUTTONDOWN, 2. SDL_MOUSEBUTTONUP, 3. SDL_KEYDOWN, 4. SDL_KEYUP, 5. SDL_MOUSEMOTION. It should be senseful to check for the event kind by using the case command.

PROGRAM chap6_1;
USES crt, SDL, SDL_VIDEO, SDL_EVENTS;

VAR
screen:pSDL_SURFACE;
loopstop:boolean=FALSE;
test_event:pSDL_EVENT;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
IF screen=NIL THEN HALT;

NEW(test_event);

WHILE loopstop=FALSE DO
BEGIN
IF SDL_POLLEVENT(test_event)=1 THEN
BEGIN
write('pending event: ');

CASE test_event^.eventtype OF
SDL_EVENTACTIVE: writeln('Application is/is not active');
SDL_KEYDOWN: writeln('Key pressed ');
SDL_KEYUP: writeln('Key released');
SDL_MOUSEMOTION: writeln('Mouse motion');
SDL_MOUSEBUTTONDOWN: writeln('Mouse button down');
SDL_MOUSEBUTTONUP: writeln('Mouse button up');
SDL_JOYAXISMOTION: writeln('Joystick axis motion');
SDL_JOYBALLMOTION: writeln('Joystick's trackball motion');
SDL_JOYHATMOTION: writeln('Joystick's hat position changed');
SDL_JOYBUTTONDOWN: writeln('Joystick button pressed');
SDL_JOYBUTTONUP: writeln('Joystick button released');
SDL_EVENTQUIT: writeln('User-requested quit');
END;

END ELSE writeln('no pending events');
DELAY(150);
END;
DISPOSE(test_event);
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

Actually you shouldn’t try this source as it is written there because it will end up in an endless loop. The DELAY command is used because otherwise you won’t notice any pending events because they are polled too fast and it seems as if there would never be any pending events (just remove DELAY to confirm).

We now want to try the program to read out which key the user pressed on the keyboard. If the key is the escape-key (Esc) the program should stop. We already check the type of the event we polled. So if the event is a keyboard event the further checking should proceed. In our case especially if a key gets pressed. An keyboard event record contains a field called keysym. Keysym is a record of SDL_KEYSYM. SDL_KEYSYM is defined in SDL_KEYBOARD unit. It contains four fields. Scancode which is hardware dependent scancode should be avoided if you want to make hardware independent programs. It is usual integer variable. Next is sym which stores SDLKEY. These SDL keys are independent and it is strongly recommended to use them! In the example we want break up if escape key gets pressed. Its SDL key code is 27. If you want to know what SDL keys are defined look up in the table page. The variable modifier stores modifier keys (like shift, ctrl,…) pressed and stores SDLMod. SDL modifier keys can be found at table page as well. The fourth variable is unicode which may be used to read out unicode characters but to use this you have to enable it what is not described in this tutorial.

To read out or compare the key the user pressed we must use the expression test_event^.key.keysym.sym. Do you remember the general structure of an event (event.eventstructure.data)? – test_event^ is the event, the event structure is defined as an key event by key and the data we want to know is the key pressed contained in keysym.sym.

PROGRAM chap6_1;
USES crt, SDL, SDL_VIDEO, SDL_EVENTS;

VAR
screen:pSDL_SURFACE;
loopstop:boolean=FALSE;
test_event:pSDL_EVENT;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
IF screen=NIL THEN HALT;

NEW(test_event);

WHILE loopstop=FALSE DO
BEGIN
IF SDL_POLLEVENT(test_event)=1 THEN
BEGIN
write('pending event: ');

CASE test_event^.eventtype OF
SDL_EVENTACTIVE: writeln('Application is/is not active');
SDL_KEYDOWN:

BEGIN
write('Key pressed ');
writeln('(SDLKey=',test_event^.key.keysym.sym,')');
IF test_event^.key.keysym.sym=27 THEN loopstop:=true;
END;

SDL_KEYUP: writeln('Key released');
SDL_MOUSEMOTION: writeln('Mouse motion');
SDL_MOUSEBUTTONDOWN: writeln('Mouse button down');
SDL_MOUSEBUTTONUP: writeln('Mouse button up');
SDL_JOYAXISMOTION: writeln('Joystick axis motion');
SDL_JOYBALLMOTION: writeln('Joystick's trackball motion');
SDL_JOYHATMOTION: writeln('Joystick's hat position changed');
SDL_JOYBUTTONDOWN: writeln('Joystick button pressed');
SDL_JOYBUTTONUP: writeln('Joystick button released');
SDL_EVENTQUIT: writeln('User-requested quit');
END;

END ELSE writeln('no pending events');
DELAY(150);
END;
DISPOSE(test_event);
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

Actually this is easy, isn’t it?

This file contains the source code: chap6_1.pas (right click and “save as”)
This file is the executable: chap6_1.exe (right click and “save as”)

ATTENTION: This is just the first part. The second part will describe mouse handling, which is much easier.

Chapter 3: Displaying a picture (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

Working with the video subsystem assumes that you understand the concept behind. The screen is supposed to be a surface (everything on this surface gets displayed on the physical screen!). Every object you want to display on the screen can be an own surface. Every object can be copied to the screen surface. Surfaces can be manipulated.

For example in the demo03.pp from the SDL4Freepascal files the ball, the paddle and the black background (screen) are surfaces. The ball and the paddle are copied onto the screen surface again and again slightly moved up. So the ball and the paddle are giving the impression that they are moving.

So our task is to create a screen surface. Furthermore we need a surface that contains a picture. Eventually the picture should get copied onto the screen surface. After that the picture should be displayed at the physical screen.

PROGRAM test;
USES crt, SDL, SDL_video;

BEGIN
SDL_INIT(SDL_INIT_VIDEO);

{further code}

SDL_QUIT;
END.

That is where we stopped last chapter. Now we need a command to create a screen surface. Creating a surface is always introduced by setting up a surface variable. The variable type is pSDL_SURFACE and is kind of pointer type as indicated by the “p” in front of it.

The screen surface is a special kind of surface. It has some special properties that can be set. You can set appearance, height, width and colordepth that is displayed by it. The command to make a surface to a screen surface is SDL_SETVIDEOMODE(parameters).

Similar to the SDL_QUIT procedure, after using surfaces you have to clean the memory if you don’t need them anymore. Therefore you use SDL_FREESURFACE(surface).

PROGRAM test;
USES crt, SDL, SDL_video;

VAR
screen:pSDL_SURFACE;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

readln;
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

The function to set the screen surface returns nil if an errors occurs. The first parameter determines the width, the second one the height. The third parameter determines the colordepth (8 bit for now) and the last one the appearance (video mode) and space handling. The first three parameters are longint typ, the last one Uint32, where the U stands for “unsigned” (values greater or euqal nil only!), the int stands for “integer” and the number stands for the bit per pixel count. So it is an 32 bit unsigned integer. There are some very interesting values. The chosen one, SDL_SWSURFACE, is used if you want to store the surface in system memory (RAM). Alternatively you could chose SDL_HWSURFACE what causes a storage in video memory. Both will create windowed screens that cannot be resized. SDL_NOFRAME would create a windowed screen without a frame. Eventually there is SDL_FULLSCREEN which leads to a fullscreen display. There are some other possibilities which may be told about in further chapters.

If you run the program you see a black window because nothing is located on the screen surface.

It is necessary to create another surface that contains the picture. Then we need a possibility to load the picture to the surface. Fourtunately there is a command called SDL_LOADBMP(file). The corresponding command is called SDL_SAVEBMP(surface,file) if you drew something onto the screen and would like to save it as a bitmap file. Incidentally there is no such import/export feature for other graphic formats (that doesn’t mean there are no other easy ways to use other important graphic formats ;)).

Free Pascal meets SDL sample image bmp format
download (right click and “save as”)

This picture (8 bit) is the one that will be copied to the screen. The pictures width and height are both exactly 200 pixels.

PROGRAM test;
USES crt, SDL, SDL_video;

VAR
screen,picture:pSDL_SURFACE;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

picture:=SDL_LOADBMP('fpsdl.bmp');
if picture=nil then HALT;

readln;
SDL_FREESURFACE(picture);
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

The surface is named “picture” here and the file fpsdl.bmp is located in the same directory as the source file. As already known from setting of the screen variable the SDL_LOADBMP command returns nil if something’s wrong.

In the end we need to copy the loaded picture from the picture surface to the screen surface. This process is called blitting and is made by this command: SDL_BLITSURFACE(parameters).

After the blit process the screen surface has to be refreshed. SDL_UPDATERECT(parameters) is doing that.

PROGRAM test;
USES crt, SDL, SDL_video;

VAR
screen,picture:pSDL_SURFACE;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

picture:=SDL_LOADBMP('fpsdl.bmp');
if picture=nil then HALT;

SDL_BLITSURFACE(picture,nil,screen,nil);
SDL_UPDATERECT(screen,15,15,170,170);

readln;
SDL_FREESURFACE(picture);
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

For successful blitting four parameters are requested. The first determines the source surface, the third the destination surface. The second and the fourth parameter can be used if you don’t want to blit the whole surface but a certain rectangle. So you could determine that you want to blit just the upper left quarter of the picture surface (second parameter). Furthermore you could want it copied to the lower right quarter of the screen surface (fourth parameter). If these parameters are nil it means the whole surface is blitted.

As you can see the SDL_UPDATERECT command requests five parameters. The first of them determines which surface has to be refreshed. The next four determine a rectangel with: x-direction, y-direction (from top to bottom), width (relative to x,y-position), height (relative to x,y.position). If all of these paramters are “0” the whole surface will get updated.

This file contains the source code: test.pas (right click and “save as”). The file and the graphic file have to be in the same folder.

Hope you are successful and have fun.

Chapter 5: Writing and using fonts (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

What you need:

Software Source Description
sdl_ttf.pp http://cvs.sourceforge.net/viewcvs.py/sdl4fp/extras/
Downloads
Unit file to handle fonts.
SDL_ttf.dll http://www.freetype.org/index2.html
Windows: http://gnuwin32.sourceforge.net/packages/freetype.htm
This is the corresponding dynamic link library file.

This chapter will introduce you on how to load fonts and write to the screen. There are two things to do for preparation. First of all we have to change the compiler settings because a new unit, called SDL_TTF, gets included. This unit uses the “result” command to return values of functions. This is a command from Object Pascal. So the compiler has to support it’s syntax otherwise he won’t accept this command. To let the compiler support the Object Pascal syntax go to “Options” and then “Compiler…” A new window will pop up. From “Syntax” mark the option “Object pascal support”. Now SDL_TTF can be used.

In version 1.2.0.0 of SDL4Freepascal this unit isn’t included. It has to be separately downloaded. You can download it here: http://cvs.sourceforge.net/viewcvs.py/sdl4fp/extras/ or from the download section. The file “sdl_ttf.pp” has to be copied to the sdl unit folder where all the other sdl units are located (e.g. C:\FPC\units\).

Analogous to SDL.dll in chapter 1 you have to download the last stable release of FreeType which can be found here: http://www.freetype.org/index2.html (Windows: http://gnuwin32.sourceforge.net/packages/freetype.htm ). You should extract the file and get two files. A text file and the important SDL_ttf.dll. These files you copy to the system32-folder.

Now let’s begin with the interessting part. The goal is to get a text with a certain font and colour to the screen. Of course we need the screen surface again and a surface onto which can be written. Furthermore the new unit has to be loaded.

PROGRAM chap5;
USES crt, SDL, SDL_VIDEO, SDL_TTF;

VAR
screen,fontface:pSDL_SURFACE;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

readln;
SDL_FREESURFACE(screen);
SDL_FREESURFACE(fontface);
SDL_QUIT;
END.

To initialize the TTF (True type font) system you have to use TTF_INIT which returns -1 if something goes wrong. Notice that the whole true type support is an own additional project to the SDL library, so this has not to be initilized by the SDL_INIT command.

To load a certain font you use TTF_OPENFONT(font,point size). This command is a function that returns a usual pointer! The parameters are the path to the font (e.g. C:\WINDOWS\fonts\arial.ttf) and the point size which detemines the size of the letters. Furthermore as SDL surface has to be free’d and SDL system has to be quit so has TTF system. The commands TTF_CLOSEFONT(font) and TTF_QUIT have to be used to do this.

PROGRAM chap5;
USES crt, SDL, SDL_VIDEO, SDL_TTF;

VAR
screen,fontface:pSDL_SURFACE;
loaded_font:pointer;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

if TTF_INIT=-1 then HALT(1);
loaded_font:=TTF_OPENFONT('C:\WINDOWS\fonts\arial.ttf',12);

readln;
SDL_FREESURFACE(screen);
SDL_FREESURFACE(fontface);
TTF_CLOSEFONT(loaded_font);
TTF_QUIT;
SDL_QUIT;
END.

So next we have to determine the colour of the letters and the messege itself. The colour is determined by a pSDL_COLOR record, which is of course kind of pointer. In pSDL_COLOR record there are three elements (actually four, but the forth is unused) which can be accessed by .r,.g and .b and determine as common the shares of red, green and blue colour. You will agree that writing a function for this can be senseful, especially if you have to handle many different colours. The fact that pSDL_COLOR is a pointer type we have to set up it by NEW command and free it finally by DISPOSE. This commands you should familiar with because they are usual Pascal commands.

PROGRAM chap5;
USES crt, SDL, SDL_VIDEO, SDL_TTF;

VAR
screen,fontface:pSDL_SURFACE;
loaded_font:pointer;
colour_font:pSDL_COLOR;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

if TTF_INIT=-1 then HALT;
loaded_font:=TTF_OPENFONT('C:\WINDOWS\fonts\arial.ttf',12);

NEW(colour_font);
colour_font^.r:=255; colour_font^.g:=0; colour_font^.b:=0;

readln;
DISPOSE(colour_font);
SDL_FREESURFACE(screen);
SDL_FREESURFACE(fontface);
TTF_CLOSEFONT(loaded_font);
TTF_QUIT;
SDL_QUIT;
END.

Now we use TTF_RENDERTEXT_SOLID which returns a pSDL_SURFACE. We return it to fontface. The parameters are the used font as pointer (loaded_font), the messege string and the colour as value of pSDL_COLOR (colour_font).

Finally we have to blit the fontface surface, on which now the messege is written, to the screen surface and update the screen surface.

PROGRAM chap5;
USES crt, SDL, SDL_VIDEO, SDL_TTF;

VAR
screen,fontface:pSDL_SURFACE;
loaded_font:pointer;
colour_font:pSDL_COLOR;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT;

if TTF_INIT=-1 then HALT;
loaded_font:=TTF_OPENFONT('C:\WINDOWS\fonts\arial.ttf',12);

NEW(colour_font);
colour_font^.r:=255; colour_font^.g:=0; colour_font^.b:=0;

fontface:=TTF_RENDERTEXT_SOLID(loaded_font,'HELLO WORLD',colour_font^);

SDL_BLITSURFACE(fontface,NIL,screen,NIL);
SDL_UPDATERECT(screen,0,0,0,0);

readln;
DISPOSE(colour_font);
SDL_FREESURFACE(screen);
SDL_FREESURFACE(fontface);
TTF_CLOSEFONT(loaded_font);
TTF_QUIT;
SDL_QUIT;
END.

Now you are able to write ;).

This file contains the source code: chap5.pas (right click and “save as”)
This file is the executable: chap5.exe (right click and “save as”)

[Downloads transferred from old website]

sdl_ttf.zip; FOR OUTDATED SDL4FP PACKAGE! Unit file for font support. (right click and “save as”)

Chapter 4: Drawing pixels (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

Okay. Maybe you think, why to learn how to display pictures first and then learning about the more basic feature to draw single pixels to the screen? – In chapter 3 you learned beside displaying a picture how common SDL programs are strctured. Furthermore this chapter will get a little bit longer because several things have to explained more detailed to impart a fully understanding. In chapter 3 that was not necessary.

So here we go. First of all we have to know about the meaning of pixels. The physical screen consists of many small units. Every unit consists itself of three different coloured lights. These colours are red, green and blue. If you mix them (additive) you can get every colour. For example if you mix red and green you receive yellow. For three colours that can be mixed with each other there are eight combinations possible which lead to different colours (RGB, RG, RB, R, GB, G, B, all lights off). Some of you may say RGB (white) and all lights off (black) are no colours. That is right but doesn’t matter here and to keep simpliness I will talk of colours even if I talk of black and white.

Did you get confused? Your screen definitvly has more than eight colours, doesn’t it? The reason is, your screen isn’t just able to put on or off lights. Besides it is in position to differ the intensities of the lights. The more intensity levels you have the more colours you can display. The case that you have eight colours as discussed before means that you just have one intensity level. If your screen is in 8 bit mode every pixel on the screen has the possibility to display 2 power 8 colours. That are 256 different colours. Every of the three lights has therefore a certain amount of different intensity levels. There are the red and the green light with eight intensity levels each and the blue light with four intensity levels. If you have 16 bit mode you have 2 power 16 and that are 65536 colours. Each light therefore must have the appropriate amount of intensity levels.

All the examples will be made in 8 bit mode. If you want to write directly to the screen surface it is possibly necessary that you lock it. We work in software mode (SDL_SWSURFACE) so we can leave locking the screen surface. The screen surface is a RECORD of many different data types. To read or write pixels of or to a surface there is a typ marker called “pixels” which is of pointer type. It points at some pixel of the surface. The location gets allocated to a pointer of WORD, namely “pixellocation” we define.

PROGRAM chap4;
USES crt, SDL, SDL_video;

VAR
screen:pSDL_SURFACE;
pixellocation:^WORD;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT(1);

pixellocation:=screen^.pixels;

readln;
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

It is unknown to us where to the surface it is pointing. This may not matter now; this we will treat later. Before we should allocate a colour to the pixel. Up to now we just have handed over the location to “pixellocation”. Yellow is the pixel colour we want to get. Red has to be 255, green has to be 255 and blue has to be 0 to get yellow. The function SDL_MAPRGB(pixel format, red, green, blue) is used to transform that input values into one longinteger (Uint32) code. The pixel format is given by the screen surface. We will use its pixel format by using screen^.format what contains the pixel format information of the screen surface. The calculated “colour code” is handed over to a new defined variable called “pixelcolor”.

So you have stored the location of the pixel to manipulate in variable pixellocation. You have stored the information of the colour you want to receive in pixelcolor. Eventually you have to allocate the pixel colour to the pointed pixel at the surface. That’s it. Of course we have to update the screen surface after the drawing.

PROGRAM chap4;
USES crt, SDL, SDL_video;

VAR
screen:pSDL_SURFACE;
pixellocation:^WORD;
pixelcolor:WORD;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT(1);

pixellocation:=screen^.pixels;
pixelcolor:=SDL_MAPRGB(screen^.format,255,255,0);
pixellocation^:=pixelcolor;

SDL_UPDATERECT(screen,0,0,0,0);
readln;
SDL_FREESURFACE(screen);
SDL_QUIT;
END.

If you look careful to the screen (when running program) you may see the pixel (left upper corner). After this success we want to see the pixel run along the screen! That will help you understand easily how the positioning of the pixel works, probably better as if I try to explain. We define a repeat-unitl loop what will delete old pixel (colour: black) and write a new one exaktly moved up by one pixel.

PROGRAM chap4;
USES crt, SDL, SDL_video;

VAR
screen:pSDL_SURFACE;
pixellocation:^WORD;
pixelcolor,i:WORD;

BEGIN
CLRSCR;
SDL_INIT(SDL_INIT_VIDEO);
screen:=SDL_SETVIDEOMODE(200,200,8,SDL_SWSURFACE);
if screen=nil then HALT(1);

i:=-1;
REPEAT
inc(i); IF i>39999 THEN i:=0;

pixellocation:=screen^.pixels+i;
pixelcolor:=SDL_MAPRGB(screen^.format,0,0,0);
pixellocation^:=pixelcolor;

pixellocation:=screen^.pixels+i+1;
pixelcolor:=SDL_MAPRGB(screen^.format,255,255,0);
pixellocation^:=pixelcolor;

SDL_UPDATERECT(screen,0,0,0,0);
delay(5);
UNTIL keypressed;

SDL_FREESURFACE(screen);
SDL_QUIT;
END.

So the position which is pointed by pixels pointer is set by adding to or substratcing from the position before. As can be seen in the program the pixel position is increased by one and so is the value of where screen^.pixels pointer is pointing at.

If you create a surface of width and height of 200 pixels as in the example the true surface can be a little bit wider. This means you have a window of width and height of 200 pixels displayed but there is an additional unvisible piece of surface. Maybe its width is 210, so the moving pixel in the last example would restart a few lines before end of window. To solve problems cause by this pitch to the surface you can read it out. The data type pitch will allow you to (e.g. screen^.pitch).

This file contains the source code: chap4.pas (right click and “save as”)
This file is the executable: chap4.exe (right click and “save as”)

Chapter 2: First steps using SDL (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

You should be slightly experienced in programming Freepascal. That means you should be familiar with the usual commands of Freepascal. If this is not the case you may have problems because this tutorial deals with the features of the usage of the SDL library.

Now let us begin. There are several units given that can be used. If you want to use SDL library you must include the unit “SDL”. It is needed to initialize any other component of the library. For example there are units called “SDL_audio”, “SDL_video”, “SDL_keyboard” and so on. You can draw conclusions on their meaning from their names. So let us start with the initialization of the SDL video system. The command needed to initialize any component is SDL_INIT(component);

PROGRAM test;
USES crt, SDL, SDL_video;

BEGIN

SDL_INIT(SDL_INIT_VIDEO);

END.

Instead of SDL_INIT_VIDEO you could initilize the respective component by using SDL_INIT_AUDIO, SDL_INIT_CDROM, SDL_INIT_JOYSTICK, SDL_INIT_TIMER, SDL_INIT_NOPARACHUTE, SDL_INIT_EVENTTHREAD, SDL_INIT_EVERYTHING. So if you want to use the features provided by the library for sound handling you should init it SDL_INIT_AUDIO. If you use SDL_INIT_EVERYTHING all subsystems are initialized.

There is another very important command: SDL_QUIT. Every program have to be closed by using this command. It cleans up your system! Never fotget it. This procedure ensures that all subsystems initilized get unloaded. There is a corresponding command to unload specific subsystems called SDL_QUITSUBSYSTEM(component).

PROGRAM test;
USES crt, SDL, SDL_video;

BEGIN
SDL_INIT(SDL_INIT_VIDEO);

{further code}

SDL_QUIT;
END.

Well, we have initilized the video subsystem and released it after that. Simple Directmedia Layer deserves its name, isn’t it?

Chapter 1: Introduction, installation and configuration (SDL4FP)

This is an SDL 1.2 chapter. SDL 1.2 is obsolete since it has been replaced by SDL 2.0. Unless you have good reasons to stay here you may prefer to go for the modern SDL 2.0 :-).

The introduction is short. SDL library gives you the ability to program powerful applications for many different operating systems (OS) only by learning one set of commands. The SDL library takes on the assignment to translate your commands to the specific OS commands. It’s especially meaningful to use the SDL library if you plan to develop games or similar software.

Now this Chapter concerns on the installation of all necessary software on your system for programming SDL applications with Freepascal under Windows XP (probably this will work for other windows systems as well; please report if you tried out).

First of all, we have to consider which software is needed. We need three different software packages. We need the Freepascal compiler of course. Furthermore we need the SDL library files and finally we need something what translates our pascal programs to the SDL library (written in C/C++). This will be taken on by a few units.

1) Download the latest stable Freepascal compiler (Version 2.0.0). You
get it here: http://www.freepascal.org/
2) Download the latest version of SDL4Freepascal (Version 1.2.0.0). You
get it here: http://sdl4fp.sourceforge.net/
3) Download the latest version of SDL runtime library (Version 1.2.8). You
get it here: http://www.libsdl.org/ (German readers may prefer: http://www.libsdl.de/)

Of course, if you have installed Freepascal already you haven’t to download it again and you can skip step 4.

4) Execute “fpc-2.0.0.i386-win32.exe” to install Freepascal. Let the self-installer create a shortcut on your desktop.
5) Extract “SDL-1.2.8-win32.zip” to get the SDL runtime library. This leads to two extracted files. There is a text file and the very important SDL.dll.
6) Copy those files (especially the SDL.dll!) to your
system32-folder! Usually you find it at “C:\WINDOWS\system32\”.
Don’t confuse it with the similar system-folder. (This works for
WinXP, probably for NT-series and Win2000 as well; if you use Win9x
or WinME you should copy it to system-folder instead of system32-folder)

If it for any reason isn’t possible to copy the files into this folder you later have to have that file into the same folder where the application is. Now you have installed Freepascal and the SDL runtime library on your system. Finally SDL4Freepascal have to be installed.

7) Extract “SDL4Freepascal-1.2.0.0.tar.gz” to get the units and some demo programs. There should be about 20 files and a folder “demos” which contains five more files.
8) Open the folder where you have installed Freepascal (e.g. C:\FPC\)
9) Open the folder “units” (e.g. C:\FPC\units\)
10) Create a new folder called “sdl” (e.g. C:\FPC\units\sdl\)
11) Copy the whole former extracted files (including the folder “demos”) from SDL4Freepascal into the sdl-Folder.

Now the compiler has to be told about where to find the new units.

12) Open the Freepascal IDE (for example by clicking the shortcut on desktop).
13) In the menue choose the following item “Options”. From “Options” choose “Directories…”. Now a window should pop up.
14) The last row is called “Unit directories”. There you should write in the full path to your SDL-units (e.g. C:\FPC\units\sdl). Leave the last backslash out.

Congratulations! You have configured your system for developing SDL applications with Freepascal! Now let’s check if it really was that easy…

15) Open the file “demo02.pp” in demos-folder (e.g. C:\FPC\units\sdl\demos\). Run it.

If you see some cool colourful red and blue lines you have done everything as it has to be done :)! Have fun with your configured system!

For those of you who try running the demo and get an abortion together with a messege saying “exitcode = 309”: You skipped step 6! Did you copy the SDL.dll to your system32- or system-folder respectively? If so and the error still occurs you should copy the SDL.dll into the folder where the demos are placed. Now it should work.

[Downloads transferred from old website]

SDL4Freepascal-1.2.0.0.tar.gz; OUTDATED: SDL4Free Pascal Version 1.2.0.0 (most recent)