Tag Archives: sdl 2.0 tutorial

OpenGL Logo

SDL 2.0 meets modern OpenGL

Good news, Chapter 10 has been released right now! You ever wondered what to do if you would like to create 3d graphics for a game or application? – Well, you go for modern OpenGL. And SDL 2.0 is probably the best and most convenient way to go for modern OpenGL nowadays, even professionals typically use SDL as powerful assistant for their OpenGL applications.  Learn more about the strong relationship between SDL and OpenGL in Chapter 10. – And learn how it’s done, of course ;-).

Chapter 3 got a short explanation now on how to copy the source code of a chapter. In the SDL 1.2 chapters the source code  was shipped for each chapter as Pascal file. Nowadays it is much more convenient to grab the source code (or just the desired parts) by copying it directly from the chapter’s source code boxes (in the browser) and paste it whereever it is needed.

The transfer of the old website has been finished. Nearly the complete content is in some way or another transfered to the new page. For example, all tutorial pages (even the old ones) are still available. Some downloads are integrated at the corresponding tutorial pages now, so they are not lost. Some pages are gone, these are Downloads, Tables and Links. These pages are of no benefit anymore since their information are now provided at the corresponding place instead of separate pages. Nevertheless, links trying to access these pages are redirected to the main page to prevent broken links.

No One’s Space got greenlit. This means that this Free Pascal/SDL game will be available in Steam for purchase soon. It demonstrates the power of Free Pascal and SDL.

Small update of some subdomain settings. Subdomain links work again.

Chapter 10 – SDL and modern OpenGL 3.0+

This chapter will introduce you on how to combine the SDL library with the famous Open Graphics Library (OpenGL).

What is OpenGL?

OpenGL is the first choice when it comes to platform independent 2d and 3d graphics programming. The emphasis is on graphics programming only though!

Why and when to combine SDL and OpenGL?

SDL is an excellent choice if you need platform independent 2d graphics. OpenGL is capable of 2d graphics, too, but why using the more complicated library if you could use the easy to use SDL library? – And by the way, underneath SDL is actually using OpenGL (or similar libraries depending upon the system) to achieve its hardware accelerated 2d graphics.

However, if your project needs 3d graphics, which isn’t covered by SDL, you can set up your system for this quite easy with SDL. The setup of an OpenGL environment is very easy and platform independent with SDL. Without SDL you would’ve to write different code to set up OpenGL for each operating system. In fact, even professional developers use SDL to set up their OpenGL applications.

Furthermore, since OpenGL is a pure graphics library, any other task is further done by SDL (e.g. keyboard handling, sound,…).

At this point I’d like to quote Klaus Vor der Landwehr (professional developer) from Turtle-Games, who described the relation of SDL and OpenGL in a very clear way.

Although the graphics are often in the foreground, it is for me as a game programmer only one aspect of many with which I have to deal. And the graphics do not even require the most work. OpenAL for example costs much more time and effort if you want to build a 3D sound channel management. And there are many other interfaces. Here is a list of categories in which SDL has been a great help:

  • multiple displays
  • window management
  • Event handling
  • keyboard
  • mouse
  • joystick
  • game controller
  • force feedback
  • threads
  • timers

… for Windows, Mac and Linux.

Source: Pascal Game Development Community.

What exactly is modern OpenGL?

As of version 2.0 of OpenGL, the so-called fixed pipeline has been replaced by a programmable pipeline (modern OpenGL). In general, the pipeline makes your input data appear on the screen in a hardware accelerated manner by using your graphics card. For the fixed pipeline it was easy to draw something to the screen but, as the name suggests, it was quite fixed and unflexible. The programmable pipeline which is controlled by a newly introduced shader (script) language is far more flexible, though, the ease is gone :-D.

Anyway, some people refer to OpenGL version 3.0 and up as modern OpenGL. This is because a lot of typical functionality was deprecated as of this version. The backwards compatibility is gone.

In this chapter I will demonstrate how to use SDL 3.0 and up to set up a modern OpenGL environment using some basic shaders. I based the description heavily on an excellent C++ tutorial over at opengl-tutorial.org and their second chapter. You may look for further OpenGL stuff there or have a look at this WikiBook OpenGL Introduction (C++). I’m not aware of OpenGL tutorials for Free Pascal or Delphi treating modern OpenGL (let me know if you know).

OpenGL Pascal units (headers)

Similar to SDL 2.0, you need specific units which translate and connect your code to the OpenGL library. There is a native OpenGL unit GL which covers the main functionality of OpenGL. Additionally for modern OpenGL you need the unit GLext which covers the functionality up to OpenGL version 4.0. These units are shipped right along with the Free Pascal compiler.

In case you are interested in support of OpenGL version 4.4, you should look into the dglOpenGL.pas. This unit is not shipped natively along with the Free Pascal compiler.

Let the fun begin

Let’s have a look at the code:

Wow that is a lot of code. What you will get is this:

Result for chapter 10

The background will change slowly from green to blue. And you will get this:

Command result for chapter 10

The vendor, OpenGL version and shader version information will be different according to your system. Also, if your system doen’t support the needed OpenGL version you’ll not have “success” but rather “failure” after the compiling and linking processes. Additional information may be shown then.

The program is called “chap10_SDL2” for obvious reason.

Additionally to the SDL2 unit we load the native FPC units Classes (for TStringList support), SysUtils (for PChar functions) and GL and GLext for OpenGL support.

Thre are three constants declared. The first two are defined as the filenames of the so-called shader source files.  Basically they are simple text files which contain a script. More about shaders and the script later. The third is an array of nine GLfloat values. GLfloat is the OpenGL float variable type which in fact is translated as Pascal’s Single type. In short, these nine values describe three points in 3d space which, if connected, form a triangle. More about this later.

The first variable “sdlWindow1” is well known from previous chapters. Any variable to follow is new though. Most of them are related to OpenGL.

“sdlGLContext1” is of type TSDL_GLContext needed to create a so-called OpenGL context. In fact, this variable type is provided by SDL and a key type to set up an OpenGL conext in a simple and cross-platform manner.

The variable “i” is a simple Word variable for counting purposes.

OpenGL’s Integers and Strings

Most of the following variables are either of type GLuint or of type PGLchar. The last variable is an dynamic array of GLchars. Their specific meaning will be discussed later but GLuint is the OpenGL unsigned integer type (no negative values) which translates to Pascal’s Cardinal/Longword type. Text handling in OpenGL works by null-terminated strings of type PGLchar which translate to Pascal’s PChar. GLchar translates to Char then, obviously.

At this point you may wonder why as for SDL the null-terminated strings are used instead of simple strings (see Chapter 7 for the PAnsiChar variable type discussion). The answer again is that OpenGL is based upon C which handles strings this way. PChar equals PAnsiChar by the way.

The remaining variables “ShaderCode” of type TStringList will be used to handle the shader text files. “compilationResult” and “InfoLogLength” are of GLint type. In contrast to GLuint they allow for negative values.

First SDL2 is initilized as known. “sdlWindow1” is created as known by SDL_CreateWindow. Be careful though, in order to work with OpenGL the flag SDL_WINDOW_OPENGL has to be set!

SDL 2.0 and the OpenGL context

An OpenGL context is kind of an abstract name. It doesn’t represents just a window, even though it is created from a SDL2 window, but rather it contains everything (including the window information) that is related to this OpenGL context. The OpenGL context is therefore kind of “broader” than just a window, that is why it is called context rather than just a OpenGL window.

The function to create an OpenGL context from a SDL2 window is:

function SDL_GL_CreateContext(window: PSDL_Window): TSDL_GLContext

So, it is simple as that, just use the SDL2 window as argument and voila, you’ll get a OpenGL context, platform-independent. That is why everybody loves SDL2 to work with OpenGL. Note that the returned Context isn’t a pointer but an actual instance. So to error check against nil you need to refer to the instance’s addresse by the @ operator.

OpenGL version check and initialization

The nested if-then-statements check if at least version 3.0 of OpenGL is installed. If so, the highest available version is loaded. If not, the program is stopped and returns a text message.

If your hardware doen’t support OpenGL 3.0 or higher you should try to update your graphics driver. There is a good chance that you are able to use OpenGL 3.0 or higher then. Anyway, if the upgrade doesn’t work out or you wouldn’t want to update, you may have a look into the JEDI-SDL Chapter about OpenGL, there the old OpenGL is treated (although that chapter treats SDL 1.2, it shouldn’t be too hard to make it work with SDL 2.0 with minor changes).

Next there are three text messages printed out. These present the Vendor, the OpenGL version and the Shading language version. To get them in a readable form you need to transform the constants into strings by function glGetString. Let’s have a look at the command window again:

Command result for chapter 10

Have a look at the first three lines and you see what it could look like.

Vertex Array Object and Vertex Buffer Object

If you are new to OpenGL,  OpenGL as kind of machine with many switches. Each switch

Briefly, a Vertex Array Object (VAO) is a specific OpenGL object which contains important settings (e.g. format of vertex data) and references to other objects, including Vertex Buffer Objects (VBO). Notice, it doesn’t store the object’s data (content) itself, it just stores the reference to these objects.

The Vertex Buffer Object (VBO) contains the actual data (content). In the example case these are three vertices, each described by three float point values in cartesian space.

OpenGL Object name or ID

Because it is important to understand, in contrast to SDL where objects usually are directly submitted to a function by its pointer reference, in OpenGL you have a so-called OpenGL Object name, which actually is an integer value of GLuint type. Therefore ID is a suitable name, too. Let’s see how this works:

The VAO is created by function glGenVertexArrays( number of VAO names, pointer to VAO names array ). The first parameter determines how many VAO names I’d like to create. We just need 1. The second parameter asks for a pointer to an array of VAO names. Since VAO names are just simple GLuints, it is a simple array of GLuints. Anyway, since we just need one, a pointer to a simple GLuint variable will be suitable, too. In our case that is “VertexArrayID”. To bind (“activate”) the corresponding VAO to the OpenGL context, the function glBindVertexArray( name of VAO ) is used. The argument is the name of the VAO we just created in “VertexArrayID”.

Similar to the VAO, the VBO is created by function glGenBuffers( number of VBO names, pointer to VBO names array ). Again, we just need 1 VBO whose name should be returned to “triangleVBO”. This variable just stores an ID (object name) of GLuint type.

From the naming of “triangleVBO” it is clear to us what we intent here (representing a triangle by three vertices), anyway, how should OpenGL know? – We explain the meaning of this buffer object to OpenGL by using glBindBuffer ( target, VBO name ). There are numerous options as target but GL_VERTEX_BUFFER is the right choice here.

The actual VBO is created by glBufferData( target, size of object’s data store in bytes, pointer to data to be copied into VBO, expected usage ). This functions takes four arguments. The target is GL_VERTEX_BUFFER again. The size of the VBO’s data store in bytes is determined by Pascal’s SizeOf function applied to “triangleData”. The “triangleData” constant also holds the data to be copied into the VBO, so its pointer is suitable as the third argument. Since we are not going to change the data a lot, we should use GL_STATIC_DRAW as fourth argument.

If you are a newcomer to OpenGL, don’t worry if you are confused the first time. Most people are. And now it may even get worse :-(.

Shaders and OpenGL Shading Language

When starting with modern OpenGL the so-called Shaders are talked about a lot. Shaders are scripts written in a C-like script language called OpenGL Shading Language (GLSL). These scripts are compiled at runtime and influence the way how the graphics data is processed at certain steps in the so-called rendering pipeline of OpenGL. In fact, you can create rather complex and special effects with shaders without even changing one line of code of your source code.

Vertex Shader and Fragment Shader

There are two Shaders that are crucial and have to be set up to work with modern OpenGL. They are called  Vertex Shader and Fragment Shader. There are more Shaders not covered here, though. Each type of Shader influences different aspects of the rendering.

The Vertex Shader is the first Shader program executed in the rendering pipeline. Every vertex is “put through” the Vertex Shader program and processed accordingly, hence the name. Often this Shader is used to perform transformation operations. The Shader script used in this tutorial is shown next:

This GLSL source code is saved into a file VertexShader.txt and located in the same directory as the source code of this chapter’s example source code. I’m not going to explain this GLSL code in detail here, but a detailed explanation is found over at opengl-tutorial.org Chapter 2 where I got this Shader code from, by the way.

The Frgament Shader is the last Shader program executed in the renderin pipeline. The so-called rasterization process produces fragments. Every fragment is “put through” the Fragment Shader program and processed accordingly. The Shader script used for the Fragment Shader is:

This code is in file FragmentShader.txt and located in the same directory as the VertexShader.txt. The detailed explanation is found over at opengl-tutorial.org Chapter 2 again. Anyway, you’ll notice that there is a “color” variable (three component vector). As you see, it sets the (red,green,blue) values for the fragments to (1,0,0) which means red should be the result, red = 100%, green and blue = 0%. You may play around with these values.

Both Shaders are created by function glCreateShader( Shader type ). It returns the reference (or name) as GLuint as seen before for the VAO and VBO. We store them in the VertexShaderID and FragmenShaderID, respecitvely.

The next part is about loading the source code from the two Shader files (VertexShader.txt, FragmentShader.txt) and converting them to be used with OpenGL. First a “ShaderCode” variable of TStringList type is created. Its LoadFromFile method let us load the file contents into the variable conveniently. First for the Vertex Shader, whose file name is stored in constant “VertexShaderFile”. The variable “VertexShaderCode” is of type PGLchar, which is the way OpenGL handles strings. Since PGLchar is of type PChar anyway, the method GetText is perfectly suitable here to convert the source code string into a null-terminated array of chars. Finally, there is a simple check if the PGLchars are empty (nil), which shouldn’t be the case if the source code is pointed to as expected.

Exactly the same is done for the FragmentShader and the source code associated with “FragmentShaderCode”.

Finally, the dummy variable “ShaderCode” is free’d.

To associate the source code we stored in “VertexSourceCode” to “VertexShaderID” of GLuint type, the function glShaderSource( Shader reference, number of array elements, pointer to array of source code PGLchars, pointer to array of lengths ). The Vertex Shader reference is stored in “VertexShaderID” which is the first argument. We just have one source code, so the second argument is 1. The source code is stored VertexShaderCode, and its pointer is addressed by @VertexShaderCode as the third argument. As seen before, since we just have one element here, it is not necessary to have really an array. The fourth parameter allows for some length specification, but if set to nil it expects null-terminated arrays of chars.

The compilation is straight forward done by glCompileShader( Shader reference ). It is really advised to to error checking here, that is why it is shown how to do that. The function glGetShaderiv( Shader reference, object parameter, pointer of correct type for return value ) is used to request information about objects. First we like to know if the compilation was successful. The Shader reference is stored in “VertexShaderID”, the object parameter is GL_COMPILE_STATUS. This will return a GLint value, which can be interpreted as GL_FALSE or GL_TRUE. The result is stored in “compilationResult” by using its pointer (@compilationResult) as argument.

Right after that we request the length of the information log by GL_INFO_LOG_LENGTH. It will be greater than 0 if some information were logged (probably an error occured on compilation then). The result is returned to “InfoLogLength” by its pointer @InfoLogLength.

If an error occurs, “compilationResult” is GL_FALSE. In this case “failure” along with more specific information is printed out. I’m not going into detail here, since this shouldn’t happen. Otherwise (and that should be the case), “success” is printed out.

The very same way the Fragment Shader is compiled and checked.

The shaders have to be attached and linked by a Shader program. A Shader program is created by glCreateProgram(). The parenthesis are important here. It returns an reference of GLuint type which is stored in ProgramID.

The Shaders are attached to this Shader program by glAttacheShader( Program reference, Shader reference ). The program is linked by glLinkProgram( Program reference ). The reference for the Shader program is “ProgramID”. The references for the Shaders are “VertexShaderID” and “FragmentShaderID”, respectively.

By complete analogy to the error checking for the Shader compilation, the Shader program linking is checked. Anyway, instead of GL_COMPILE_STATUS, GL_LINK_STATUS is used.

The for-loop counts from 0 to 400. Within each cycle it first changes the background color by glClearColor( red, green, blue, alpha ). Red and alpha are constant, green and blue are varied each cycle dependend upon variable i. This makes the background slowly changing from green to blue, feel free to play around with the rgba values. To actually clear the color buffer glClear( buffer ) with GL_COLOR_BUFFER_BIT as argument is used.

glUseProgram( Shader program reference ) is used to apply the Shader program to the rendering state. “ProgramID” is the Shader program reference in the example code.

glEnableVertexAttribArray( array index ) is used in order to make the attribute array available for rendering by glDrawArrays. The index is 0 here. The “triangleVBO” is bound by glBindBuffer( target, buffer ) to the GL_BUFFER_ARRAY target to change attribute data of said VBO. Latter is done by glVertexAttribPointer( index, size, type, normalized, stride, offset of first component ) with the given arguments. Hence, the index is 0, 3 components per generic vertex attribute, each of float point type (thus, GL_FLOAT), not normalized (thus GL_FALSE), no strides between vertex attributes, no offset for the first component.

The rendering is done by glDrawArrays( type of primitive, starting index, number of elements ). The type of primitive is a triangle, hence GL_TRIANGLES is the first argument. We start at the very beginning, so index is 0. We have 3 sequential elements (vertices).

glDisableVertexAttribArray( array index ) is the counter function to glEnableVertexAttribArray( array index ), obviously. It disables the vertex attribute array.

SDL_Delay delays the loop by 20 milliseconds.

The procedure

procedure SDL_GL_SwapWindow(window: PSDL_Window)

is used to actually display the rendering result to the the window “sdlWindow1”. Keep in mind that this window has to be initialized as an OpenGL window. This procedure is comparable to SDL’s SDL_RenderPresent.

After i matching 400, the for-loop is left.

For the clean up, the shaders have to be detached from the shader program by glDetachShader( program, shader ). After that they can be deleted by glDeleteShader( shader ), and the program by glDeleteProgram( program ).

The shader script PChars are disposed by StrDispose( PChar ).

The VBO and the vertex array have to be free’d by glDeleteBuffers( number of buffer objects, pointer to array of buffers ) and glDeleteVertexArrays( number of VAOs, pointer to array of VAOs ) respectively. The first parameter is the number of objects to be deleted, which is 1 in both our cases.

To resolve the OpenGL context

procedure SDL_GL_DeleteContext(context: TSDL_GLContext)

is used.

The SDL Window is destroyed as known. Finally SDL is shut down as known by SDL_Quit.

← Chapter 9 | Chapter 11 (not existent yet) →










Chapter 9 application preview

New Chapter 9 about Music and Sound

The new Chapter 9: Music and Sound has been released. It demonstrates how to use the SDL_mixer 2.0 to load music and sound files to use them in your applications.

I was surprised to find that there have been made many important updates to Tim Blume’s SDL 2.0 units since the latest release (version 1.72). This means for everybody who relies on these units, update to the latest master branch release (later than version 1.72)!

Download ZIP button
IMPORTANT: Get the latest master branch release! Download Link

Otherwise you will struggle to get some important sdl features. E.g. key code constants and the code of the new Chapter 9 won’t work. I adapted Chapter 8 about event handling.

An interesting new header translation project was mentioned to me which allows for dynamic loading of SDL 2.0. Check out Chapter 1 to read more about this project by Imants Gulis.

Many smaller updates have been performed, too. Also the color scheme has been updated since it was stated that the contrast of the former color scheme has been too weak. You may also have noticed the amazing new fractal title background image :-)!

Important hint: The Free Pascal compiler got a new stable release on 25th November of 2015, version 3.0.0. Don’t forget to update your favourite compiler :-)!

Chapter 9 – Music and Sound

ATTENTION: You need the most recent Pascal translations by Tim Blume  for this chapter to work properly. Version 1.72 of Tim Blume’s Pascal translations will not work! Check step 2) in Chapter 2 for details.

This chapter will introduce you on how to load music and sounds since these are key features of every game and many applications.

SDL_mixer 2.0 for easy music and sound support

Although SDL 2.0 supports music and sound handling natively, there is an easier way to play music and sound files. The official unit SDL_mixer 2.0 (unit’s name SDL2_mixer) has been created exactly for this purpose and is maintained by the same authors (Sam Lantinga, Stephane Peter, Ryan Gordon) as SDL 2.0 itself. The Pascal translation is fortunately available, too in Tim Blume’s header translations.

Supported music and sound file formats in SDL 2.0

According to the official SDL2_mixer documentation the following music and sound formats are supported:

  • WAVE/RIFF (.wav)
  • AIFF (.aiff)
  • VOC (.voc)
  • MOD (.mod .xm .s3m .669 .it .med and more) requiring libmikmod on system
  • MIDI (.mid) using timidity or native midi hardware
  • OggVorbis (.ogg) requiring ogg/vorbis libraries on system
  • MP3 (.mp3) requiring SMPEG or MAD library on system
  • FLAC (.flac) requiring the FLAC library on system

You’ll need these files:

File name
SDL2_mixer dynamic link library
SDL2_mixer-2.0.1-win32-x86.zip (32-bit Windows)
SDL2_mixer-2.0.1-win32-x64.zip (64-bit Windows)
This is the corresponding dynamic link library file for the unit for Windows. Note: Mac OS X and Linux versions are also available.
dial.wav sound file dial.wav
A simple telephone dial sound. Source: pdsounds. License: Public domain.
In my mind.ogg music file In my mind.ogg
In my mind.ogg
A nice music sample. Source/Creator: First. License: CC BY-ND 3.0.

You should extract the zip-file and get several files. These are four license text files and a readme text file, furthermore you have eight dll files including the important SDL2_mixer.dll. The other dll files are necessary to play the different sound and music formats. Copy all the files to the Windows system32-folder (or the corresponding place). If you forget this and run the examples below you will get an error with exitcode = 309.

Now that you are prepared, let’s have an overview of the code.

When running this program, you’ll get two windows. A simple SDL 2.0 window without any content (white) and the title “Music and Sound window” and a console window showing a simple menu (list) of possible actions to play around with the music and sound. Keep in mind that the focus has to be on the SDL 2.0 window for the key recognition to work.

Chapter 9 application preview

Let’s start with the first part of the code.

The program is called “chap9_SDL2”. It uses the SDL2 and the new SDL2_mixer unit.

We’re going to use event handling as discussed in Chapter 8 to check what keys have been pressed. Consequently we need a variable “sdlWindow1” for the SDL 2.0 application window (for the focus) and an event variable “sdlEvent”.

The pointer variable “music” is of the new type PMix_Music and points at the loaded music file data later. The “sound” pointer variable is of type PMix_Chunk and points at the loaded sound file data later. Note: Each song is referenced by an own PMix_Music pointer and each sound effect (e.g. explosions, shots, …) is referenced by an own PMix_Chunk pointer.

What is the difference between music and sound?

Music is associated with PMix_Music pointers and sounds are associated with PMix_Chunk pointers, but why distinguish them at all? – Well, it is convenient to have them separated since they have rather different properties. Music is usually several minutes long, sounds are usually just a few seconds short. It is usually just one song played at a time, sounds need to mix up if necessary. For music it usually doesn’t plays a role if it is sligthly delayed to when it should start, for sounds a larger delay usually means a strange feeling for the player. So, for music there is exactly one channel reserved where the music is played. For sounds eight sound channels are available to make it possible for them to mix up. Now let’s get back to the code.

The variable “exitloop” is a boolean variable to determine when the main loop of the program should be exited.

The program is initialized by SDL_Init as known. Note though that not only SDL_INIT_VIDEO but additionally SDL_INIT_AUDIO is set. They are combined by the or operator (not the and operator :-)!).  The window is set up afterwards by SDL_CreateWindow as known.

To initialize SDL2_mixer the function

function Mix_OpenAudio(frequency: Integer; format: UInt16; channels: Integer; chunksize: Integer): Integer

has to be called. It requests four parameters. These are the frequency, the audio format, the channels (mono or audio) and the chunksize. All these parameters are of Integer type. Function Mix_OpenAudio returns 0 on success and -1 on errors.

The frequency in Hertz (1/s) usually is 22050 Hz or MIX_DEFAULT_FREQUENCY in games but double as high for CD quality sound (44100 Hz). The higher the frequency, the more CPU power is needed.

Next we have to define the audio format. It determines how the audio data is stored. MIX_DEFAULT_FORMAT equals AUDIO_S16SYS. Different values are given in the following list (from official SDL2_mixer documentation):

  • Format constant name Description
  • AUDIO_U8 Unsigned 8-bit samples
  • AUDIO_S8 Signed 8-bit samples
  • AUDIO_U16LSB Unsigned 16-bit samples, in little-endian byte order
  • AUDIO_S16LSB Signed 16-bit samples, in little-endian byte order
  • AUDIO_U16MSB Unsigned 16-bit samples, in big-endian byte order
  • AUDIO_S16MSB Signed 16-bit samples, in big-endian byte order
  • AUDIO_U16 same as AUDIO_U16LSB (for backwards compatability probably)
  • AUDIO_S16 same as AUDIO_S16LSB (for backwards compatability probably)
  • AUDIO_U16SYS Unsigned 16-bit samples, in system byte order
  • AUDIO_S16SYS Signed 16-bit samples, in system byte order

Then we decide for a sound channel type, which means either stereo or mono. For stereo sound we choose 2 and for mono we choose 1 as value. MIX_DEFAULT_CHANNELS equals stereo output.

Finally the chunksize has to be set, where 4096 bytes per sample is a good and default value. Too low values may lead to skipping samples. Too high values may lead to delayed playing.

Loading music and sounds from files in SDL 2.0

We will load the music by

function Mix_LoadMUS(_file: PAnsiChar): PMix_Music.

_file can be the absolute path. If the Pascal file and the music file are in the same folder the file name is sufficient (as shown in the example). If the loading was unsuccessful, the function returns nil. The volume can be set by

function Mix_VolumeMusic(volume: Integer): Integer.

The volume can be set between 0 (silence) to 128 (maximum volume). The latter equals MIX_MAX_VOLUME. By the way, if you set -1 as argument, the return value corresponds to the set volume.

Quite similar sound files are loaded by

function Mix_LoadWAV(_file: PAnsiChar): PMix_Chunk.

Although the function’s name doesn’t indicate this, use this function to load the sound files of any format (Wave, Aiff, Riff, Ogg, Voc), not only for .wav sound files. It return nil on error. There is alittle difference when setting the volume by

function Mix_VolumeChunk(chunk: PMix_Chunk; volume: Integer): Integer.

Instead of just setting a general volume, the volume is bound to a certain sound. In the example case the sound is in variable “sound”. Just to mention it here, there is a third possibility, to set the volume for a certain channel:

function Mix_Volume(channel: Integer; volume: Integer): Integer.

This can be quite handy, anyway, channels are discussed a little bit later below. If your argument is -1 the average volume will be returned.

Here nothing new can be found. The menu is printed out and some memory is allocated to the event pointer. Let’s proceed.

Playing, pausing, resuming music and sounds

The main application loop is entered and should be left if variable “exitloop” is true.

As known from previous Chapter 8 about event handling, we firstly poll for events by SDL_PollEvent() and enter a further loop. Secondly, if there are events found waiting to be processed, we check by a case statement what exact key has been pressed.

For each key a different music or sound related function is used to do something. Let’s discuss them now in detail. We start with the functions used for keys 1-4:

function Mix_PlayMusic(music: PMix_Music; loops: Integer): Integer

procedure Mix_PauseMusic

procedure Mix_ResumeMusic

procedure Mix_RewindMusic

Mix_PlayMusic plays music. The first argument is the music itself which we previously got from the example .ogg music file and associated with the “music” pointer of PMix_Music type. The second argument determines how often the music is played. Additionally -1 means infinite repetition. This function returns 0 on success and -1 on error.

The meaning of the three procedures Mix_PauseMusic, Mix_ResumeMusic and Mix_RewindMusic ist obvious from their names. They are used to pause, resume (if paused before) and rewind the played music.

The analogous function and procedures for sound channels are shown now:

function Mix_PlayChannel(channel: Integer; chunk: PMix_Chunk; loops: Integer): Integer

procedure Mix_Pause(channel: Integer)

procedure Mix_Resume(channel: Integer)

As you can see the function Mix_PlayChannel has three parameters. The first parameter asks for a channel with which the sound should be associated. SDL2_mixer provides eight sound channels. Usually you should use -1 which means the first free channel will be used to play the sound. Anyway, you could specifiy a certain channel here if you like. The second parameter asks for a sound pointer of PMix_Chunk type. The  third parameter is the same as for music, -1 means an infinite loop. Attention though for specific repetitions. The value for loops is increased by 1. So, if you want a sound to be played once, you need the argument to be 0. The return value corresponds to the sound channel the sound is played on, it is -1 on error.

The procedures Mix_Pause and Mix_Resume are self-explanatory. Use them to pause or resume a certain channel, which is the argument. If the argument is -1 (as in the example code) you pause or resume all channels. By the way, you may have noticed that there is not a rewind analogue, because sounds are not expected to be rewound.

Fading and distance effects

Important to know about effects like fading. They are performed on the fly to your data, so the more effects you use, the more computational power they require. It is important to unregister effects you don’t need anymore.

These are the four fade functions triggered by the next keys (A-F):

function Mix_FadeInMusic(music: PMix_Music; loops: Integer; ms: Integer): Integer

function Mix_FadeOutMusic(ms: Integer): Integer

function Mix_FadeInChannel(channel: Integer; chunk: PMix_Chunk; loops: Integer; ms: Integer): Integer

function Mix_FadeOutChannel(which: Integer; ms: Integer): Integer

The function Mix_FadeInMusic works the very same way as Mix_PlayMusic above, but there is a further parameter which allows for a fade in effect in milliseconds. 3000 milliseconds equals 3 seconds. It returns 0 on success and -1 on error.

Mix_FadeOutMusic fades out the playing music within the given time in milliseconds in the moment the function is called (hence the key is pressed in the example program). Attention, it returns 1 on success and 0 on error.

Quite similar the functions Mix_FadeInChannel and Mix_FadeOutChannel work. Instead of the music pointer, the sound pointer has to be given. Additionally the channel has to be given. By the way, also here the number of times the sound is played is increased by 1, so if you want to play a sound with fade in effect once, the argument has to be 0. Both functions return 0 on success and -1 on error.

The functions triggered by the keys G-M are:

function Mix_SetPanning(channel: Integer; left: UInt8; right: UInt8): Integer

For setting the panning you need the channel to which panning should be applied and the volume values which may vary from 0 (quiet) to 255 (loudest). For a consistent panning effect you may substract the left value from the right value (left: volume, right: 255-volume). To unregister this effect, you should set both values to 255, which is recommended to be done if you don’t need panning anymore. The function returns 0 on errors.

function Mix_SetDistance(channel: Integer; distance: UInt8): Integer

The higher the distance the quieter the sound appears. The value can range between 0 (near) and 255 (far). If distance is set to 0 the effect is unregistered. It returns 0 on errors.

function Mix_SetPosition(channel: Integer; angle: SInt16; distance: UInt8): Integer

This function adjusts volumes according to an angle and a distance value, hence it combines the effects of the two functions discussed before for panning and distance. The distance value works the same way as discussed for Mix_SetDistance. Angle of 0 (degree) means in front of you, 90 means directly to the right, 180 means directly behind, 270 means directly to the left.

Finally, if the SDLK_ESCAPE has been pressed, the loop stopping variable “exitloop” is set to true, which will stop the main loop.

Within the main loop a short delay of 5 milliseconds is used to prevent the application from running an empty loop no events are waiting.

The clean up means freeing sdlEvent, and use the procedures Mix_FreeMusic and Mix_FreeChunk to free the music and sound data.

procedure Mix_FreeMusic(music: PMix_Music)

procedure Mix_FreeChunk(chunk: PMix_Chunk)

The arguments have to be the music and sound pointer respectively.

SDL_mixer 2.0 has to be closed by

procedure Mix_CloseAudio.

Finally SDL 2.0 and the application are shut down as known.

← previous Chapter | Chapter 10 →

10 Years Anniversary of FreePascal-meets-SDL.net

Happy New Year! 10 Years Free Pascal meets SDL!

Hi all,

right on time for the 1st January 2016, I finished the first part of the major update of www.FreePascal-meets-SDL.net. That’s an excellent start of the new year, isn’t it? 🙂

At the same time I’m happy and proud to announce that www.FreePascal-meets-SDL.net exists for ten years now! It has been originally established on 20th July 2005 and got 34,000+ views by now. It helped a lot of people to get familiar with Free Pascal and SDL or SDL2 and got a lot of positive responses.

I would like to thank all of you readers and supporters for your responses and encouragement in the past ten years, since I’m sure, without this, www.FreePascal-meets-SDL.net wouldn’t exist anymore today. A special thanks goes to Cybermonkey (developer of the amazing SDL based  EGSL Engine) who made many helpful and encouraging comments and to the whole Pascal Game Development Community where a fruitful affiliation has been established for many years.

For the new year and the ten years anniversary I decided to improve the website’s design since the old design is classic yet outdated in many ways, not only from an aesthetic point of view. I would like to allow for more interactivity, e.g. allow for comments directly to a certain tutorial page. Additionally the site is mobile-friendly now. Also I stopped using third-party forum software or a third-party visitor counter, which was suitable back in 2005. Just to name a few aspects, expect even more improvements and changes to come. At the moment the forum is gone completely, anyway, I’m not decided yet, if I re-introduce an own forum again.

All the seven chapters of the SDL 2.0 Tutorial have been corrected and extended and a completely new chapter consisting of two parts has been added. Step by step I will update the content (e.g. SDL 1.2 Tutorial) for the new design. Until I’m finished with transferring and making up the content, there is a link “Old Website” in the menu which will link to the old Website. So you can still access all the old resources.

The download area will be gone for now, since all downloads there are just related to the SDL 1.2 Tutorial and furthermore it would be more convenient to have them directly within the chapter page that is related to them. The tables section is also gone for now, no need for having them anymore.

And now have fun exploring the new site and functionality. By the way, you should be able to log-in via several social media services (e.g. Twitter), so you are not in need to create a new account.


Chapter 1 – Introduction

The introduction is short.

What is SDL or rather SDL2?

SDL abbreviates Simple Direct Media Layer. In August 2013 the official successor of original SDL (SDL 1.2) has been released, simply called SDL 2.0 (or SDL2). It is a library to develop powerful applications for many different operating systems (platforms) by learning only one set of commands. This is called cross-platform development. The following platforms are officially supported by SDL2:

  • Windows
  • Mac OS X
  • Linux
  • iOS
  • Android.

Internally the SDL library layer translates your commands to the platform specific commands, which is reflected by the followig diagram.

SDL2 Layers Diagram
Image by Adriatikus at English Wikipedia [Public domain], Wikimedia
SDL2 Layer Diagram
It’s especially meaningful to use the SDL library if you plan to develop games or need fast paced rendering. Jump and run-, Role-playing-, Real time/turn based strategy-, side-scrolling-, arcade-, board-, card-, simulation-, multi-user dungeon-, puzzle-, shooter-, network games and so on are possible, and any combination of these ;-).


The SDL 2.0 library, as well as the units for translation, are licensed under the zlib license. This license grants a high degree of freedom. So even closed-source, commercial applications and games are possible with SDL 2.0 and Free Pascal. As a sidenote, you are free to choose the MPL license for the units, if you like.

How to get SDL2 for Free Pascal or Object Pascal?

There are several SDL 2.0 units out there (see comparison and discussion here) which translate SDL 2.0 to Pascal, since originally it has been written in C. Over time it turned out that Tim Blume’s SDL 2.0 units are the best choice to use if you like to get into SDL 2.0 development in Free Pascal or Object Pascal.

A detailed installation instruction to set your system up for SDL 2.0 development under Pascal is found in Chapter 2 for Windows or Linux. If you did install SDL 2.0 for Free Pascal or Object Pascal already, proceed to Chapter 3.

Chapter 2 (Windows) → | Chapter 2 (Linux) → | Chapter 3 →

Chapter 2 – Installation and Configuration

What is covered, what not?

  • installation guide for SDL 2.0 under Microsoft Windows
  • installation of Free Pascal Compiler (FPC)
  • installation of Free Pascal IDE and Lazarus IDE
  • installation of SDL 2.0
  • configuration of FP IDE and Lazarus IDE to work with SDL 2.0
  • after this you are ready to code awesome SDL 2.0 stuff 🙂

Free Pascal IDE or Lazarus IDE

IDE stands for integrated development environment. Although you could write your programs in a simple text editor, an IDE makes your life much easier. For example, it highlights keywords, makes it easier for you to set up the compiler, and much more. Now let’s have a look at these two IDEs:

You may notice that the native Free Pascal IDE (left) looks old, but it is shipped right along with the Free Pascal Compiler. In contrast to that the Lazarus IDE (right) looks up-to-date, but requires it to be installed additionally. My advise is nonetheless, use the Lazarus IDE.

The Free Pascal Compiler (FPC)

We need three different software packages. First of all we need the stand-alone Free Pascal Compiler or Lazaruse IDE (which already has a copy of the Free Pascal Compiler included). If you are not sure, I recommend to go with the Lazarus IDE package.

SDL Library and SDL 2.0 units

Additionaly we need the original SDL library files (.dll files). And finally we need units that connect our SDL 2.0 code written in Free Pascal to the SDL library files. The latter will be done by Tim Blume’s SDL 2.0 units.

This table provides all information and sources you need with respect to installation steps 1) – 3). Keep in mind, you have to download either the Lazarus IDE or the stand-alone Free Pascal Compiler, not both.

approx. Size [MB]
Source link
Details and remarks
Lazarus IDE (has FPC included)
1.4.4 or later
Linux and Mac OS X versions are here: http://www.lazarus-ide.org (see Downloads).
Free Pascal Compiler (stand-alone)
3.0.0 or later
Windows 32 bit version
Windows 64 bit version (needs 32 bit version)
If you need the Linux, Mac OS X or other versions, check them out here: http://www.FreePascal.org (see Download).
Tim Blume's SDL 2.0 units
1.72* (see remark)
On the right upper side is a button saying Download ZIP. Click on this button for the download of the latest release. *Better go with the latest availabe version (not version 1.72!) since some important bugfixes have been made lately.
SDL 2.0 dynamic link library
SDL 2.0 > Download > Choose the download suitable for your system.

Download Lazarus or the stand-alone Free Pascal Compiler (FPC)

If you have Free Pascal or the Lazarus IDE installed already, you can skip the steps 1a) and 1b).

1a) For Lazarus IDE: Download the latest version of the Lazarus IDE. It has the Free Pascal Compiler accompanied. Remark: As of today (12/02/2016) the bundle doesn’t provide the most recent Free Pascal Compiler (3.0.0) but the version before (2.6.4). The tutorial examples will work with both versions though.

1b) For Free Pascal IDE: 32 bit Windows: Download the latest stable Free Pascal compiler, version 3.0.0 or higher. 64 bit Windows: You have two choices, 1) Simple way: Go with the 32 bit version of Free Pascal. (Recommended), 2) Install the 64 bit version of Free Pascal on top of the 32 bit version of Free Pascal. In this case you need both files. Hence, you need to download both Free Pascal installers shown above.

Download SDL 2.0 and Header translation

2) Download the latest version of Tim Blume’s SDL 2.0 units, better go with the latest branch (master branch), and do not use version 1.72 since it contains some bugs. Click on “Clone or download” and then on “Download ZIP” (see arrows in image below) of the page and make sure that Branch: master (not v1.72!) is chosen at the left side (see arrow in image below). This is important for any operating system: Windows, Linux, Mac OS X.

Download SDL2 units on GitHub
Choose the master branch (1), click on “Clone or download” (2) and click on Download ZIP (3).

3) Download the latest version of SDL 2.0 runtime library, version 2.0.4 or higher.

Install Lazarus or the Free Pascal Compiler

4a) For Lazarus: 32 and 64 bit Windows: Execute lazarus-1.4.4-fpc-2.6.4-win32.exe  to install Lazarus for a 32 bit or 64 bit Windows system and follow the self-installer. Let the self-installer create a shortcut on your desktop.

4b) For Free Pascal IDE: 32 and 64 bit Windows: Execute fpc-2.6.4.i386-win32.exe  to install Free Pascal for a 32 bit or 64 bit Windows system. Let the self-installer create a shortcut on your desktop. Don’t modify any checked options during installation process. The default path is: C:\FPC\[Compiler version]\. [Compiler version] should be 3.0.0 or higher numbers. 64 bit Windows only: After you installed the 32 bit Free Pascal, you may execute fpc-3.0.0.i386-win32.cross.x86_64-win64.exe optionally to add the 64 bit version on top.

Install SDL 2.0 and Header translation

5) Extract SDL2-2.0.4-win32-x86.zip or SDL2-2.0.4-win32-x64.zip to get the SDL runtime library. This leads to two extracted files. There is a text file and the very important SDL2.dll.

6) 32bit Windows: Copy those files (especially the SDL2.dll!) to your system32-folder, C:\WINDOWS\system32\. 64bit Windows:  Copy those 64bit files to your system32-folder (!), C:\WINDOWS\system32\, Windows is expecting you to do this. Do not use the SysWoW64-folder (Hint: 32 bit files on 64 bit Windows go here).

If it is not possible to copy the files into this folder (or you are unsure about its location) alternativly you can copy the SDL2.dll right into the same folder where the SDL 2.0 application (.exe) is located. That is because SDL 2.0 first  looks for the SDL2.dll in the folder from which it is executed and if it isn’t found there, in the corresponding system folder! Anyway, if it isn’t found anywhere, the program will raise an error.

Now you have installed Free Pascal and the SDL runtime library on your system. Finally Tim Blume’s SDL 2.0 units have to be installed.

7a) For Lazarus IDE: Extract the Pascal-SDL-2-Headers-master.zip. The Free Pascal Compiler is located in a subfolder called “fpc”. I suggest to copy all the files to a folder with full path C:\Lazarus\fpc\[Compiler Version]\units\SDL2\. [Compiler version] should be 2.6.4 or higher numbers. Skip step 7b).

7b) For Free Pascal IDE: Extract the Pascal-SDL-2-Headers-master.zip. I suggest to copy all the files to a folder with full path C:\FPC\[Compiler Version]\units\SDL2\. [Compiler version] should be 3.0.0 or higher numbers. All later chapters will assume you installed to this path.

Configuring the Lazarus IDE

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

8) Open the Free Pascal IDE (for example by clicking the shortcut on desktop).

Lazarus IDE Desktop Icon

9) In Lazarus the path to external units has to be set for each project. Create a project if no project is set up (Project > New Project …). In the menue choose the following item Project > Project Options …. Now a window should pop up.

10) Under “Compiler Options” choose “Paths” (see red mark). Choose the three dots button (see red mark on the right side) for the “Other units files (-Fu)” field (red mark). This makes the “Path Editor” pop up. In the area “Search paths:”, click on the yellow folder symbol in the right bottom corner. Choose the path to your SDL-units (e.g. C:\Lazarus\2.6.4\units\SDL2). Make sure the path leads to the folder, where the sdl2.pas file is located! This file contains all the basic features of SDL 2.0.

Lazarus IDE Include Paths

Confirm by clicking “OK” until all windows are closed. Your Lazarus IDE is now set up for SDL 2.0 application development :-)!

Configuring the Free Pascal IDE (skip if you use Lazarus)

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

8) Open the Free Pascal IDE (for example by clicking the shortcut on desktop).

Free Pascal IDE Desktop Icon

9) In the menue choose the following item Options > Directories…. Now a window should pop up.

10) The first tab whitin this new window is called “Units”. Here you add the full path to your SDL-units (e.g. C:\FPC\3.0.0\units\SDL2) right below the other paths. Leave the last backslash out. Make sure the path leads to the folder, where the sdl2.pas file is located! This file contains all the basic features of SDL 2.0.

SDL2 directories
Since the screenshot is old, the compiler version has been 2.6.2, which is reflected in the shown pathes. It should be 3.0.0 or higher numbers for you.

Confirm by clicking “OK”.


Congratulations! You have configured your system for developing SDL 2.0 applications with the Lazarus IDE or the Free Pascal IDE! Simple, isn’t it? 🙂

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

← Chapter 1 | Chapter 3 →

Chapter 3 – First Steps

Last updated on November 10th, 2018

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.

How to get the source code of examples?

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

Diagram how to get source code
Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
  1. Hover into the source code box with your mouse cursor, a grey mini menu will show up at the top.
  2. Click on the button “Toggle Plain Code” (or just double click into the source code box anywhere). The source code box turns black and white.
  3. Copy the full source code (or parts of it) into your compiler’s IDE or a simple text file.

To reverse the effect, just again hover into the box and click “Toggle Plain Code” again. The source code is displayed as originally. Feel free to try it out further below, there is a source code box :-).

The SDL2 unit and the first application

Let’s start now. The most important rule to get ready for SDL 2.0 in your Pascal programs is:

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.

It will return 0 on success and a negative error code on failure. You may wonder about the variable types SInt32 and UInt32 in the SDL_Init function declaration. Such integer types (which we will see in other chapters again) originate from the original C-language SDL 2.0 code. For an easier translation to Free Pascal they were kept. The S and U mean “signed” (negative values possible) and “unsigned” (values greater or equal zero only), the Int stands for “integer” and the number stands for the bit value. So UInt32 is an 32 bit unsigned integer (which corresponds to Free Pascal’s longword).

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

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. The table shows an overview of all the possible flags and their meaning:

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.

Of course you are allowed to combine several components 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


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

Quitting your programs

Every SDL program has to be closed by

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

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.

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

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 to keep code examples short. I will mention the error values to be expected though.

You should know that there is a function called

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:

The flags for the message box could be:


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.

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, isn’t it?

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

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

What is this page about?

This page is made to help you to start with the SDL and/or SDL2 (Simple Directmedia Layer) library under Free Pascal (or other Pascal dialects) and to acquaint yourself with SDL’s concepts and commands.

Be aware though that my tutorials gives just a brief overview and introduction to the SDL and SDL2 library and are far from being all-embracing.

The tutorials aim at Pascal programmers knowing the basic concepts (loops, functions, pointers) of Pascal and now like to progress to SDL and/or SDL2.

Drawing Primitives

Last updated on May 10th, 2020

Displaying of textures as discussed in previous chapters are sometimes accompanied by drawing operations. For some applications and games drawing operations are even essential, e.g. you need to draw buttons of dynamic dimension in your application. Discussion of a more detailed case is found right after the code example.

Supported Primitives: Points, Lines, Rectangles

SDL2 supports natively the drawing of

  • Points
  • Lines
  • Rectangles (outline only)
  • Filled Rectangles.

Drawing in SDL 2.0

Now lets jump right into the code:

Wow, that looks like a big load of new functions, but I promise, drawing in SDL2 is very simple. What the executed program will look like is shown in the following screenshot.

Result screenshot for chapter 5

Now, let’s have a closer look to the first lines of code.

The program is called “Chapter5_SDL2”. We will need a counter variable “i” of native Pascal type integer later. We need a window and a renderer and call them “sdlWindow1” and “sdlRenderer” as known from the previous chapters. Next we declare a variable “sdlRect1” which is of type TSDL_Rect. The same is true for “sdlPoints” which is an array of 500 elements of type TSDL_Point.

Nothing new here, we initilize SDL2, create a window with 500 pixels width and 500 pixels height and associate the renderer with this window.

Colours, alpha value and RGB(A) notation in SDL 2.0

Now we have something new here, SDL_SetRenderDrawColor() sets a colour for drawing operations, just as if you choose for a pencil colour to draw something. This function doesn’t draw anything though. It returns 0 on success and the negative error code on failure.

SDL_SetRenderDrawColor(renderer: PSDL_Renderer; r: UInt8; g: UInt8; b: UInt8; a: UInt8): SInt32

First you need to set the renderer for which this drawing colour is meant. After that you have to set the colours red, green, blue and the alpha value. They can range from 0 to 255 (integer values only). Think in terms of 255 being 100% and 0 being 0% of that colour or the alpha value. As a start let’s neglect the alpha value.

If you like to have a red colour, you need to set the value for the red colour high, e.g. 100%, the maximum value is 255, and since you don’t want to mix in green and blue, they get the minimum value of 0 (hence 0%). Setting up red therefore corresponds to 255/0/0 in terms of r/g/b. For comparision, 0/255/0 will lead to green, 255/255/255 is white and 0/0/0 is black, and so on. In the example code we used 0/255/255 which leads to cyan (mixing up green and blue additively). With these three values you can generate every colour possible.

So what is the meaning of the alpha value then? Well, it determines the transparency. 255 means fully opaque and 0 means full transparency. This is very important for blend effects in computer graphics and will be demonstrated later on in the code. By the way, instead of 255 you could use SDL_ALPHA_OPAQUE. If you count the alpha value also as colour variation you have 4.29 billion different possibilities.

Setting up a background in SDL2

The function SDL_RenderClear() is for clearing the screen with the drawing colour. As argument you just need to tell the renderer. It is simple as that :-). Since we set the drawing colour to cyan before, the screen will be cleared with a cyan colour.

SDL_RenderClear(renderer: PSDL_Renderer): SInt32

This function will return 0 on success and a negative error code on failure. The cleared screen will be shown for one second by SDL_RenderPresent() and SDL_Delay(). These two procedures are known from the previous chapter.

Drawing Lines and Points in SDL2

Now we change the drawing colour by SDL_SetRenderDrawColor() to red and use SDL_RenderDrawLine() to draw a simple line.

SDL_RenderDrawLine(renderer: PSDL_Renderer; x1: SInt32; y1: SInt32; x2: SInt32; y2: SInt32): SInt32

Again you need the renderer, which is “sdlRenderer” in our case. After that you specify the x/y coordinates where the line should begin and then the x/y coordinates where the line should end. Remember that the origin 0/0 is at the top left corner of the window. The coordinates 10/10 mean to start at the point ten pixels to the right and ten pixel to the bottom relative to the origin. Thus, the coordinates 490/490 for the second point will lead to a diagonal line across the window. This diagonal line will be 10 pixels short with respect to the window edge. This function returns 0 on success and a negative error code on failure.

After that again we ask to render this line to the screen by SDL_RenderPresent() and wait one second by SDL_Delay().

Now we change the colour to black and draw some points by the function SDL_RenderDrawPoint(). It is nearly identical to SDL_RenderDrawLine() but instead of four coordinates you need just two coordinates where the point should be drawn.

SDL_RenderDrawPoint(renderer: PSDL_Renderer; x: SInt32; y: SInt32): SInt32

This function returns 0 on success and the negative error code on failure.

I thought it would be nice to have more than just one point to be drawn, so the function is used in a for-loop to draw altogether 48 points. Here we need the counter variable “i”. Maybe you can guess from the code where the points are and how they are arranged, if not, just run the code ;-). Finally the result is rendered to the screen by SDL_RenderPresent() and the program waits one second by SDL_Delay().

Let’s proceed to the next chunk of code now.

The drawing colour is set to green by SDL_SetRenderDrawColor() and the rectangle is drawn by SDL_RenderDrawRect().

SDL_RenderDrawRect(renderer: PSDL_Renderer; rect: PSDL_Rect): SInt32

It requires the renderer, which is “sdlRenderer” for us and a PSDL_Rect , thus we use the @ operator for the declared rectangle of TSDL_Rect type to get its pointer value. This function returns 0 on success and the negative error code on failure. Notice, we neither render the result to the screen now nor do we delay here. Anyway, we want a second rectangle! 🙂

We change the rectangles x/y coordinates for the second rectangle but keep its width and height. What we are looking for is a filled rectangle that has some transparency. Until now we always used 255 (opaque) as alpha value. We set the colour to draw the second rectangle to blue by SDL_SetRenderDrawColor(). Notice that the fourth value is 128 (half-transparent) instead of 255 (opaque). So everything behind the blue rectangle, e.g. the cyan background, should therefore shine through. To generate a filled rectangle SDL_RenderFillRect() is used:

SDL_RenderFillRect(renderer: PSDL_Renderer; rect: PSDL_Rect): SInt32

The renderer and the rectangle of type PSDL_Rect are the parameters of this function. So we use “sdlRenderer” and “sdlRect1” (with the @ operator) again to draw the rectangle. This function returns 0 on success and the negative error code on failure.

The Blend Mode in SDL 2.0

But to be honest, even if you change the alpha value it will be opaque. This is because the blend mode is set to SDL_BLENDMODE_NONE by default. We need to change this to be able to use the alpha value as desired. SDL_SetRenderDrawBlendMode() is what we are looking for:

SDL_SetRenderDrawBlendMode(renderer: PSDL_Renderer; blendMode: TSDL_BlendMode): SInt32

First the renderer for which the blend mode has to be set is chosen. In our case it is “sdlRenderer” again. Then there are four blend modes available. Their description is taken from the official SDL2 Wiki.

    • no blending
    • dstRGBA = srcRGBA
    • alpha blending
    • dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
    • dstA = srcA + (dstA * (1-srcA))
    • additive blending
    • dstRGB = (srcRGB * srcA) + dstRGB
    • dstA = dstA
    • color modulate
    • dstRGB = srcRGB * dstRGB
    • dstA = dstA

We are looking for alpha blending, so we use SDL_BLENDMODE_BLEND as argument for the blend mode. This function returns 0 on success and the negative error code on failure.

After doing so the result is rendered to the screen by SDL_RenderPresent() and shown for one second by SDL_Delay(). Both rectangles, the green one and the half-transparent blue one appear at the same time.

Spread Points Randomly using PSDL_Point

Randomize is a Free Pascal procedure (from system unit) to initilize the random number generator. Imagine this as shaking the dice.

Let’s have a look at TSDL_Point. It is just a record of this structure:

As expected, the TSDL_Point record has two values, the x/y coordinates of the point. Notice how PSDL_Point is just a pointer to it. Free Pascal’s Random() function generates random numbers between 0 and the number which is used as argument substracted by one. So we generate 500 times a random x and y value between 0 and 499 and save them into the 500 SDL_Point records.

A grey colour is set by SDL_SetRenderDrawColor() for the points. To draw the points in the array “sdlPoints” we use SDL_RenderDrawPoints().

SDL_RenderDrawPoints(renderer: PSDL_Renderer; points: PSDL_Point; count: SInt32): SInt32

This function returns 0 on success and the negative error code on failure. First you need to set the renderer, then just a pointer to an array of TSDL_Point (returned by simply passing the array’s name) and finally the number of points. The latter should be consistent with the array. So, if your array has 500 elements, the count should be 500 at maximum. Notice how we are not using a loop here to draw all 500 points by calling a certain function 500 times. Instead we just pass an array of points once. This way we save a lot of time at runtime, especially if you think of a real application where even more points have to be drawn. There are similar functions for lines, rectangles and filled rectangles. They are not used in the example but it may be interesting to know, so here they are:

SDL_RenderDrawLines(renderer: PSDL_Renderer; points: PSDL_Point; count: SInt32): SInt32

SDL_RenderDrawRects(renderer: PSDL_Renderer; rects: PSDL_Rect; count: SInt32): SInt32

SDL_RenderFillRects(renderer: PSDL_Renderer; rects: PSDL_Rect; count: SInt32): SInt32

As a hint, try replacing SDL_RenderDrawPoints by SDL_RenderDrawLines, and changing the count to 499. You will be rewarded with a beautiful pattern. 🙂

Finally all the memory reserved for points, the rectangle, the renderer and the window is free’d and SDL2 shut down by SDL_Quit.

Congratulations, you just finished this chapter :-).

You may read

  • Trouble: Using Array of PSDL_Point
  • Case: Drawing for Dynamic Colouring
  • Understanding Colours in Computer Graphics

below, or you may directly skip to the next chapter .

← previous Chapter | next Chapter →

Trouble: Using Array of PSDL_Point

To put your array in the heap, you would want to use an array of PSDL_Point instead of an array of TSDL_Point. For some reason it doesn’t seem to work well with the SDL_RenderDrawPoints() function. This means, instead of, let’s say 500 points just a quarter of all points (125 in the example) is shown unless you specifiy the count as being four times greater (2000 in the example). The reason behind this, is not clear to me.

Case: Drawing for Dynamic Colouring

SDL2 drawing and images diagram

As an example when drawing can be very helpful, think of the following situation. You create a game, let’s say a racing game. There are different players. Of course, each player’s car has to have a different colour. There are generally two ways to achieve this:

1) You create several images with differently coloured cars and store them on your harddrive.

This is perfectly okay if you have a small number of cars (and colours) to be chosen. But what if you want the player to choose from a large variety of colours, 100 colours or more, or what if you want to let the player to choose the colour of his car by himself? Notice, in case of 16 bit colouring that means 65536 possibilities after all! Would you want to create that many images? In case of 32 bit colouring you have fantastic 4.29 billion colours!! Amazing, but you will never be able to create so many images in just one human being’s life. Furthermore, this would take up a lot of hard drive memory (4.29 billion times the file size of the car image) for just a simple car racing game. Look at the following image. It contains the discussed method from left to the middle. On the right to the middle is the solution :-).

Instead of having each car coloured as an image file, why not using just one image file of a car without colouring? It is kind of a template. Now you can easily ask the player what colour he prefers (and he may pick from 4.29 billion colours if necessary), and then you simply colour the car on the fly. This is the second way:

2) You create one template image on your harddrive and colour it during runtime of the program.

This is just one example where drawing is very helpful.

Understanding Colours in Computer Graphics

The colour is composed of four components, RGBA, that is red, green, blue and the alpha value. The physical screen consists of many small units. Every unit itself consists of three different coloured lights. These colours are red, green and blue. If you mix them up, you can get every other colour. These colours are mixed up additively. For example if you mix red and green you get 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). If you mix red, green and blue (all lights on, RGB), you get white, and if all lights are off, you get black. Some may say, white and black are no colours at all. Well, 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.

Your screen definitvly has more than eight colours, doesn’t it? The reason is, your screen isn’t just able to switch lights on or off. Besides it is able 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, on or off. 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 light intensity levels. If you have 16 bit mode you have 2 power 16 and that are 65536 colours. Each light therefore has the appropriate amount of intensity levels. Since we prefer 32 bit mode, we have 4.29 billion different colours!