First Steps

Last updated on November 21st, 2021

For this tutorial it is presumed, that you are familiar with procedures, functions, loops, pointers and usual commands of Free Pascal or its dialects. If this is not the case you may face problems because this tutorial deals with the features and usage of the SDL 2.0 library and will not explain basic concepts of Pascal programming. For a quick refresh on some Pascal basics, have a look into this (good) article Modern Object Pascal Introduction For Programmers by Michalis Kamburelis.

You can easily copy the example source code directly from the source code box for each chapter.

The SDL2 unit and the first application

program FirstSteps;

uses SDL2;

begin

  //initilization of video subsystem
  if SDL_Init(SDL_INIT_VIDEO) < 0 then Exit;

    {your SDL2 application/game}

  //shutting down video subsystem
  SDL_Quit;

end. 

That’s it, your first SDL2 program. You may copy the code directly in your environment and run it. It should work without any errors if everything is set up correctly. The most important rule to get ready for SDL 2.0 in your Pascal programs is obviously:

Always include the SDL2 unit in the uses clause.

The SDL2 unit is the heart of every SDL 2.0 application! If you do so, you are perfectly prepared to start coding.

The different features of SDL 2.0 (screen/video handling, audio handling, keyboard handling, and so on) have to be initilized individually using this function:

function SDL_Init(flags: TSDL_Init): cint.

It will return 0 on success and a negative error code on failure. The return value is of integer type cint. What this means, we will discuss later.

In the first example we initialize the SDL 2.0 video subsystem for screen handling by using the flag SDL_INIT_VIDEO. Instead of SDL_INIT_VIDEO you could initilize the respective subsystem by using SDL_INIT_AUDIO for audio subsystem, SDL_EVENTS for event subsystem, and so on. What subssystem you need to initialize depends on what you want to do. The table shows an overview of all the possible flags and their meaning:

FlagDescription
SDL_INIT_TIMERInitilizes timer subsystem for handling of time related events.
SDL_INIT_AUDIOInitilizes audio subsystem for playing music or sound effects.
SDL_INIT_VIDEOInitilizes video subsystem for drawing/showing/manipulating of graphics, textures and screen, usually the most important subsystem.
SDL_INIT_JOYSTICKInitilizes joystick subsystem for handling of joysticks.
SDL_INIT_HAPTICInitilizes haptic (force feedback) subsystem.
SDL_INIT_GAMECONTROLLERInitilizes game controller subsystem.
SDL_INIT_EVENTSInitilizes events subsystem for handling of mouse or keyboard input.
SDL_INIT_EVERYTHINGInitilizes all the subsystems above.
SDL_INIT_NOPARACHUTEIgnores fatal signals. In SDL2 this is set by default and it isn’t possible to change this state. The explanation is given in the official migration guide I will cite here:There’s no SDL parachute anymore. What 1.2 called SDL_INIT_NOPARACHUTE is a default and only state now. This would cause problems if something other than the main thread crashed, and it would interfere with apps setting up their own signal/exception handlers. On the downside, some platforms don’t clean up fullscreen video well when crashing. You should install your own crash handler, or call SDL_Quit() in an atexit() function or whatnot if this is a concern. Note that on Unix platforms, SDL still catches SIGINT and maps it to an SDL_QUIT event.
List of subsystem flags.

Of course you are allowed to combine several subsystem flags by OR, 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

function SDL_InitSubSystem(flags: TSDL_Init): cint

respectivly. Again 0 ist returned on success and the negativ error code in case of failure.

The flag SDL_INIT_EVERYTING will initialize all subsystems. Use this if you are unsure on what subsystem you should use, although it will need a little bit more resources.

Quitting your programs

Every SDL program has to be closed by

procedure 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

procedure SDL_QuitSubSystem(flags: TSDL_Init).

You are allowed to quit two or more subsystems by this function by using OR operator. It is advised to always quit SDL 2.0 applications by SDL_Quit even if you quit all of them individually by SDL_QuitSubSystem before.

Try the example program. You will not see much but if you didn’t get an error message you are successful. Before proceeding, let’s have a quick look into error handling.

C variable types

You may wonder about the return value cint in the SDL_Init function declaration. This and other similar types (which we will see in other chapters again) originate from the original C-language in which SDL2 has been written. cint simply means a C integer variable. Similar to a Pascal integer, a C integer can be different in memory size depending on your system and that is why it is important to know exactly with which variable types you are working. Further examples: cuint8 is a C unsigned integer of 8 bit size, cint32 is a C signed integer of 32 bit size, cfloat is a C float point variable, and so on.

In Free Pascal they are correctly translated to the corresponding Pascal variable type by the ctypes unit. In Delphi this is done by a ctypes.inc file shipped with the units.

As a beginner working with the units, you don’t have to be too concerned with these details, but now you know why these variable types have these names.

SDL 2.0 functions and errors

Every SDL 2.0 function returns an error value for you to check if the function runs properly at runtime. The values returned are of integer or pointer type. There is no general rule what values correspond to which status. In SDL 2.0 usually an integer value of 0 means “function runs/ran succesfully”, values lower than 0 correspond to a status “function couldn’t be run, something is wrong”. For pointers nil means error and any non-nil pointer means success. However, in most cases I won’t do error checking in the examples to keep the code short. I will mention the error values to be expected though.

You should know that there is a function called

SDL_GetError: PAnsiChar

which translates the last error received into a message (of type PAnsiChar) that can be read out and printed to the screen by any function that can handle strings as well (e.g. the Pascal’s common write() function). Since SDL 2.0 is written in C originally, the PAnsiChar type is used in contrast to the String type (which is more common among Pascal programmers for message storage and handling).

A quick way to return the error message is to use the SDL2 message box feature:

function SDL_ShowSimpleMessageBox(flags: TSDL_MessageBoxFlags; title: PAnsiChar; _message: PAnsiChar; window: PSDL_Window): cint

The flags for the message box could be:

  • SDL_MESSAGEBOX_ERROR
  • SDL_MESSAGEBOX_WARNING
  • SDL_MESSAGEBOX_INFORMATION
  • SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT
  • SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT

While the flags indicate the reason for the message box, the title and the message argument are used to set a box title and a message. The window argument can be set to the nil pointer.

The following short code snippet demonstrates a convenient way of using the box for showing error messages in the case of SDL2 initialization as done above.

//initilization of video subsystem
if SDL_Init(SDL_INIT_VIDEO) < 0 then 
begin
  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 'Error Box',  SDL_GetError, nil);
  Exit;
end;

Well, we have initilized the video subsystem and released it afterwards, and we learned about showing error messages in a simple message box. Simple Directmedia Layer deserves its name, doesn’t it?

Only if you agree, you may proceed to the next chapter ;-)!

← Chapter 2 (Windows) | ← Chapter 2 (Linux) | next Chapter →

7 thoughts on “First Steps

  1. Hello. It can’t work on Ubuntu 16.04 🙁
    All libraries installed. It’s compiled, but crashed with error:
    Runtime error 200 at $00007F859C697634
    $00007F859C697634

    I tried another version of Tim Blume’s SDL2 units (1.62-master) and this error repeated.

    1. I’m confused, did you use the example code as is shown in the chapter (above)?

      Runtime error 200 means “division by zero”.

        1. I cannot confirm this behavior. I tried it again on Linux Mint (x64, Ubuntu based).

          Do you use Lazarus as IDE? If so, try to start a completely new project (Simple Program).
          1) Then run the code (basically an empty Pascal program). Does it work?
          2) Add SDL2 to the uses clause and add the appropriate path to the project’s unit path. Run it. Does it work?
          3) Add the sample code again. Run it. Does it work?

          1. This error very strange. It compiles, but crashed after run program.
            I completely reinstall fpc + lazarus + libsdl2*. It works. Yet.
            Thank you for your lessons, Matthias.

Leave a Reply

Your email address will not be published. Required fields are marked *