Chapter 4a: Primitives, Image rotation/zooming, Framerate (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 :-).

In the previous chapter it was shown how to draw one pixel to the screen. Of course you could now develop routines to draw primitives from this single pixel manipulation but to make life easier someone (Andreas Schiffler) did this already for you. And furthermore the JEDI project already translated it for you to use it in Free Pascal :).

Maybe you remember the Turbo Pascal GRAPH unit which allowed to draw simple primitives like lines, squares, rectangles, circles, polygons and so on. Exactly this part is now fulfilled by the SDL_GFX unit in a SDL environment. So from now on you can also draw sprites directly to the surfaces and don’t have to draw them externally in a painting program. If you choose to draw sprites directly with this set of primitives or create them externally depends on your needs and preferences. Of course you can combine both features, load up an image first, then manipulate it further by the features shown in this chapter.

As an example you could imagine a game where you have game objects of the same type for each player which only differ by the same coloured elements. You now could create several object images with the possible different colours externally. However, if you want to provide 100 different colours you have to load up the object’s image 100 hundred times into your painting program, colour it, save it. You need 100 times the colour images space on hard disk. – With the provided functions you could just create ONE image of the units with a “wild card colour”, let’s say white. Now you just have to write a function which recognizes white areas on the image and colour it in 100 different colours, save it to hard disk (same space usage as first method) or in heap (no further hard disk space is needed!). Especially useful is the SDL_GFX unit if the white areas are of shape rectangle, circle, polygon or just a single pixel.

Before starting with SDL_GFX be aware that it is distributed by a third party developer, Andreas Schiffler. Unfortunately he is not distributing the pre-compiled shared library (DLL file) but instead he provides the source code only. So you are in need of compiling this file yourself or download the compiled SDL_gfx.dll file (zipped) (version 2.0.19) I compiled for you. The source code is written in C++ so you can’t use the Free Pascal compiler to do the compilation yourself. In the first part of this chapter I will deal with the compilation of your own DLL. The provided a pre-compiled SDL_gfx.dll (zipped) was compiled by me under 32 Bit Windows XP Professional on an AMD processor and usage might cause problems for 64 Bit systems and differing operating systems and processors. Furthermore it might be outdated, it’s version 2.0.19. In all these cases you should really consider to compile your own DLL file if the provided file isn’t working for you. If you use the pre-compiled DLL file you can skip the compilation procedure, just go on reading after the 15 step procedure for compilation below.

For compilation we need several things. We need a free C++ compiler to compile the DLL file from the source code. Of course we need the source code of SDL_GFX itself. Furthermore we need the SDL Development Library for Windows. The following table shows the names of the most recent files and their location.

Software Version Source Description
MinGW C++ Compiler 5.1.4 http://www.mingw.org/ The mainpage of the MinGW C++ Compiler, there look for “downloads” and get the most recent version, preferably with autoinstaller.
SDL_gfx-2.0.22.tar.gz 2.0.22 http://www.ferzkopp.net/ SDL_gfx C++ source code from Andreas Schiffler’s homepage. Look for “Software”, there for “SDL_gfx”.
SDL-devel-1.2.14-mingw32.tar.gz 1.2.14 http://www.libsdl.org/ SDL development library. Look for “SDL 1.2” in the menu, then for the development libraries.

1) First of all, get the MinGW C++ compiler installed. Make sure you check the g++ compiler, which is actually the C++ compiler we are looking for! The other compilers you can leave unchecked. See the picture below.

MinGW Install window

2) Extract the Development Library of SDL (SDL-devel-1.2.14-mingw32.tar.gz or newer).

3) Among other things there should be one folder called “lib” within the newly created folder of step 2. Copy the complete content of folder “lib” (3 files) into a folder also named “lib” in the MinGW directory. Make sure only to copy these three files, not the folder “lib” itself.

4) There is also a folder “include” in the extracted SDL Development Library folder. It contains one further folder called “SDL” (contains 34 files). This time copy this folder “SDL” as a whole into the “include” folder of the MinGW installation.

5) Now MinGW is fully prepared for the compiling of SDL_GFX.

6) Extract now the source code of SDL_GFX (SDL_gfx-2.0.22.tar.gz or newer).

7) Within the newly created folder you find a folder called “Other Builds”. Enter this folder. Within this folder you will find several zip files.

8) Extract file “mingw.zip”. This creates a new folder “mingw” and contains exact two files, “Makefile” and “README”.

9) Copy “Makefile” into the root folder of SDL_gfx.

10) Before using this makefile some changes have to be applied. The following script shows the first few lines of the makefile. The bold red printed parts have to be changed according to your needs. [REMARK: Now the lines are marked.]

CC = gcc
AR=ar rc
RANLIB=ranlib

prefix=c:/dev/local
bin_dir=$(prefix)/bin
include_dir=$(prefix)/include
lib_dir=$(prefix)/lib

CFLAGS = -O3 -march=athlon-xp -mmmx -msse -m3dnow -DBUILD_DLL -DWIN32 -Ic:/dev/local/include/SDL
LIBS = -Lc:/dev/local/lib -lSDL

OBJS = SDL_framerate.o SDL_gfxPrimitives.o SDL_imageFilter.o SDL_rotozoom.o

.
.
.
.

11) “c:/dev/local” has to be the path to the MinGW root folder [Line 5]. Remove flag “-DWIN32” [Line 10] and change the include flag/path to the corresponding (MinGW root folder)/include/SDL [Line 10, “-I(your path)/include/SDL”]. By the way, make sure to use slashes “/” instead of backslashes “\” to separate folders. Also give the library path as (MinGW root folder)/lib [Line 11, “-L(your path)/lib”]. Now save this makefile.

12) To compile the DLL file now, open the command window of Windows by using Start–>Run…, there type “cmd” and the n “OK”. A new “DOS-like” window will pop up.

12) Change the directory to the SDL_GFX root folder by using the DOS commands “cd (foldername)” and “cd..” to enter or leave a folder.

13) Now just give the full path to the MinGW make program located at “(MinGW root folder)\bin\mingw32-make”. Now press enter and see how your DLL file gets compiled.

14) If everything worked well you find a brand new SDL_gfx.dll in your SDL_GFX root folder.

15) Copy this file to your WINDOWS\system32 folder or to the folder where the application is located which is using SDL_GFX.

Now, since compilation is finished (or you skipped the compilation procedure) just a short hint about the licensing, SDL_GFX is licensed under the LGPL, which essentially means you can also use it in proprietary software.

Before proceeding make sure Free Pascal finds the SDL and SDL_GFX units (Options–>Directories…), however, if you installed a recent binary Free Pascal package you don’t have to care about this. Free Pascal then is already well configured to work with SDL and SDL_GFX.

Now we can proceed to the source code. Here is the full source code of the example program. It will rotate and at the same time zoom an image constantly and additionally draw some primitives to the screen.

PROGRAM chap4a;
USES SDL, SDL_GFX, CRT;

CONST
x_array:ARRAY[0..5] OF SINT16 = (50, 150, 250, 250, 150, 50);
y_array:ARRAY[0..5] OF SINT16 = (100, 50, 100, 200, 250, 200);

VAR
screen,original_image,modified_image:pSDL_SURFACE;
angle_value, zoom_value:DOUBLE;
framerate:pFPSMANAGER;
calc_width, calc_height:LONGINT;

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

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

NEW(modified_image);
angle_value:=0.0;
zoom_value:=0.0;

NEW(framerate);
SDL_INITFRAMERATE(framerate);
SDL_SETFRAMERATE(framerate, 30);

REPEAT
  angle_value:=angle_value+1.0;
  zoom_value:=zoom_value+0.05;
  IF angle_value>=359 THEN angle_value:=0.0;
  IF zoom_value>=2.0 THEN zoom_value:=0.0;

  ROTOZOOMSURFACESIZE(400, 400, angle_value, zoom_value, calc_width, calc_height);
  WRITELN('Width: ',calc_width,' Height: ',calc_height);
  modified_image:=ROTOZOOMSURFACE(original_image, angle_value, zoom_value, 1);

  CIRCLECOLOR(screen, 200, 200, 100, $FFFF00FF);
  FILLEDCIRCLECOLOR(screen, 200, 200, 50, $00FF00FF);
  ELLIPSECOLOR(screen, 200, 200, 175, 75, $00FFFFFF);
  FILLEDPIECOLOR(screen, 200, 200, 110, 10, 100, $FF0000FF);
  POLYGONCOLOR(screen, @x_array[0], @y_array[0], 6, $000000FF);
  BEZIERCOLOR(screen, @x_array[3], @y_array[3], 3, 2, $FFFFFFFF);


  SDL_BLITSURFACE(modified_image,NIL,screen,NIL);
  SDL_FLIP(screen);

  SDL_FRAMERATEDELAY(framerate);
UNTIL keypressed;

SDL_FREESURFACE(original_image);
SDL_FREESURFACE(modified_image);
SDL_FREESURFACE(screen);

DISPOSE(framerate);

SDL_QUIT;
END.

Now that you know the whole code, let’s discuss it step by step.

PROGRAM chap4a;
USES SDL, SDL_GFX, CRT;

CONST
x_array:ARRAY[0..5] OF SINT16 = (50, 150, 250, 250, 150, 50);
y_array:ARRAY[0..5] OF SINT16 = (100, 50, 100, 200, 250, 200);

VAR
screen,original_image,modified_image:pSDL_SURFACE;
angle_value, zoom_value:DOUBLE;
framerate:pFPSMANAGER;
calc_width, calc_height:LONGINT;

The program is called “chap4a” and uses the known units SDL and CRT (CRT for easy recognition of user pressing a key on the keyboard). Additionally the new unit SDL_GFX has to be included here. The latter unit provides the functionality described below.

There is a constant block defining two constant arrays “x_array” and “y_array” containing six elements of SINT16 (16 bit signed integer) corresponding to six x and y values. These will be needed later to define a polygon and a Bézier curve.

Three surface variables are defined. The “screen” variable represents the screen surface. The “original_image” surface stores an image, which then is manipulated (rotation and zooming) and the result is stored in the “modified_image” surface. The float number variables “angle_value” and “zoom_value” are storing a certain rotation angle and a zoom factor. Finally variable “framerate” is defined as a framerate manager variable pFPSMANAGER which is new and provided by SDL_GFX. This helpful tool is discussed in much detail later. Finally two variables “calc_width” and “calc_height” are defined and have to be of type LONGINT. They will store the estimated new size of the surface after rotation and zooming.

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

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

NEW(modified_image);
angle_value:=0.0;
zoom_value:=0.0;

The “screen” surface is initialized as known from previous chapters with 400 x 400 px. The “Free Pascal-meets-SDL” bitmap image from Chapter 3 is loaded to the surface variable “original_image”. For those who don’t remember the image, here it is again:

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

Notice, this image has 200 x 200 dimension. The “original_surface” surface will be the source for any manipulation. The second surface “modified_image” gets some space allocated and is ready for usage. However until now it stays empty. The rotation angle and the zoom factor are set to zero.

NEW(framerate);
SDL_INITFRAMERATE(framerate);
SDL_SETFRAMERATE(framerate, 30);

The framerate manager “framerate” gets some space and is initialized by PROCEDURE SDL_INITFRAMERATE(manager:PFPSmanager). Then the framerate is set in Hz (Hertz) by FUNCTION SDL_SETFRAMERATE(manager:PFPSmanager; rate:INTEGER):INTEGER which returns 0 on success and -1 if something is wrong. The default value is 30 Hz. It is also stored in flag FPS_DEFAULT. Additionally there are FPS_UPPER_LIMIT and FPS_LOWER_LIMIT which correspond to 200 and 1 Hz. Not shown in the example code is FUNCTION SDL_GETFRAMERATE(manager:PFPSMANAGER):INTEGER which will just return the set FPS value, however it will not return the real framerate. Even if the framerate dropped to 1 Hz it will return 30 Hz since this is the set value.

Well, some notes about the framerate: The framerate is usually a value indicating how many frames per second are drawn and shown at the screen. 30 Hz means there are 30 frames drawn to the screen within one second. Often the frequency if abbreviated by FPS meaning Frames Per Second, thus 30 FPS is the same as 30 Hz. If you perform many drawing operation or costly drawing operations (especially 3d applications know this) then it might be that the framerate drops because the system (processor and/or graphic hardware) isn’t capable of drawing fast enough to keep 30 frames per second.

So what about the framerate manager, how does it help? In simple programs the SDL_DELAY(delay in milli seconds) function is used to control the framerate if placed in the rendering loop (the loop which flips the scene to the screen surface). Assuming you set is to 33, so SDL_DELAY(33) it means every 33 ms one frame is drawn, this means approximately 30 frames are drawn within one second! Thus the framerate is 30 Hz here as well. However this only applies if you assume that the drawing itself doesn’t need time, which is a good approximation for simple applications and simple scenes. When drawing more complex scenes the drawing itself will take some milli seconds or even more time, the SDL_DELAY function will just add its delay time, so this leads to a remarkable delay. In contrast a framerate manager recognizes that the framerate dropped and will skip the delay time to keep the framerate at 30 Hz (or whatever value is set). Additionally the framerate manager is keeping the actual framerate more accurately at the framerate, in the contrary SDL_DELAY is quite inaccurate.

REPEAT
  angle_value:=angle_value+1.0;
  zoom_value:=zoom_value+0.05;
  IF angle_value>=359 THEN angle_value:=0.0;
  IF zoom_value>=2.0 THEN zoom_value:=0.0;

  ROTOZOOMSURFACESIZE(400, 400, angle_value, zoom_value, calc_width, calc_height);
  WRITELN('Width: ',calc_width,' Height: ',calc_height);
  modified_image:=ROTOZOOMSURFACE(original_image, angle_value, zoom_value, 1);

Now the rendering loop is entered. Every cycle the rotation angle is increased by 1.0 degree. Also the zoom factor is increased by 0.05 every cycle. A zoom factor of 1.0 means no change of the picture. Values smaller than 1.0 mean shrinkage of the image, values larger than 1.0 mean enlargement of the image. A value of 0.5 and 2.0 mean half the size and double the size of the original image respectively. The two IF clauses ensure that the value of “angle_value” is restored to 0 (equals 360) degree (no rotation), if the image is rotated by 259 degree. If the image got zoomed to twice its original size, “zoom_value” gets restored to 0.0.

PROCEDURE ROTOZOOMSURFACESIZE(width:INTEGER; height:INTEGER; angle:DOUBLE; zoom:DOUBLE; VAR dstwidth:INTEGER; VAR dstheight:INTEGER) calculates the new surface size after rotation and zooming. The first two parameters are the width and height of the initial surface (in our example the image/surface has 200 x 200 dimension). The next two parameters expect the rotation and zoom values (in our example they are stored in “rotation_angle” and “zoom_angle”). The last two parameters store the return values. The results will be returned to “calc_width” and “calc_height” in our example. They are written to the screen. Now one of the most amazing functions of the SDL_GFX unit is introduced. It allows the rotation and zooming of an image. In FUNCTION ROTOZOOMSURFACE(src:pSDL_SURFACE; angle:DOUBLE; zoom:DOUBLE; smooth:INTEGER):pSDL_SURFACE you give the source surface first, which is the surface with the original image in our case, then the angle and zoom factor which we discussed right before and finally if antialiasing should be performed. Antialiasing means to smooth edges. 0 means no antialiasing, 1 means antialiasing, well, also two flags you could use, SMOOTHING_OFF and SMOOTHING_ON. (However I experienced that antialiasing didn’t work out even though a 32 bit surface is used which is necessary to perform antialiasing as the author stated.)

There are some accompied functions not demonstrated in the example code which should be mentioned now. FUNCTION ZOOMSURFACE(src:pSDL_SURFACE; zoomx:DOUBLE; zoomy:DOUBLE; smooth:INTEGER):pSDL_SURFACE zooms only without rotation but zooming in x direction and y direction can be set independently. FUNCTION ROTOZOOMSURFACEXY(src:pSDL_SURFACE; angle:DOUBLE; zoomx:DOUBLE; zoomy:DOUBLE; smooth:INTEGER):pSDL_SURFACE is the same function as before but with rotation additionally. For both of these functions also corresponding procedures exist which return the size of the newly created surfaces. Thay are PROCEDURE ZOOMSURFACESIZE(width:INTEGER; height:INTEGER; zoomx:DOUBLE; zoomy:DOUBLE; VAR dstwidth:INTEGER; VAR dstheight:INTEGER) and PROCEDURE ROTOZOOMSURFACEXYSIZE(width:INTEGER; height:INTEGER; angle:DOUBLE; zoomx:DOUBLE; zoomy:DOUBLE; VAR dstwidth:INTEGER; VAR dstheight:INTEGER). They work the very same way as demonstrated in the example code.

It is very important to keep in mind that every manipulating procedure (rotation and zooming) is distorting the image information. So the number of manipulations should be keep as small as possible. In the example every cycle of the loop the original image gets manipulated exactly two times. It gets rotated once and zoomed once. Instead of this you could also implement a recursive solution, namely rotating the original image in the first cycle by one degree, take the resulting image and rotate it in the second cycle again by one degree, and so on. Let’s check for the result after 25 cycles, in fact both methods rotated the image by 25 degree, but well, the quality is remarkable different. And this neglecting the zooming which has an even worse impact on quality if implemented recursively. The following drawing will illustrate what the results will look like. On the left the rotation of the original image by 25 degree once, on the right the rotation of the same image 25 times by one degree.

Results of different rotation implementations
Left: Rotation once by 25 degree; Right: 25 Rotations by one degree

The loss of information with each cycle will add up for each manipulation leading to ugly results like the right one. Compare this to the left image where no loss of information is noticable.

CIRCLECOLOR(screen, 200, 200, 100, $FFFF00FF);
  FILLEDCIRCLECOLOR(screen, 200, 200, 50, $00FF00FF);
  ELLIPSECOLOR(screen, 200, 200, 175, 75, $00FFFFFF);
  FILLEDPIECOLOR(screen, 200, 200, 110, 10, 100, $FF0000FF);
  POLYGONCOLOR(screen, @x_array[0], @y_array[0], 6, $000000FF);
  BEZIERCOLOR(screen, @x_array[3], @y_array[3], 3, 2, $FFFFFFFF);

As promised SDL_GFX is able to draw a lot of primitives. The primitives shown in the example code are just a few of them. The principle of implementing them is demonstrated anyway. The table below gives the complete list of primitives you can use. Most of the functions are intuitive, so a circle is defined by its position (x/y values), its radius r and its colour. The same applies for a filled circle. An ellipse is defined by its position (x/y values), its horizontal and vertical axes rx and ry, and its colour.

Especially polygon and Bézier curve calls may be not so intuitive. The polygon function is function POLYGONCOLOR(dst:pSDL_SURFACE; const vx:pSINT16; const vy:pSINT16; n:INTEGER; color:UINT32):INTEGER and the Bézier curve function is function BEZIERCOLOR(dst:pSDL_SURFACE; const vx:pSINT16; const vy :pSINT16; n:INTEGER; s:INTEGER; color:UINT32):INTEGER. As for all the other functions you define the surface first onto which you would like to draw these primitives. The next parameters expect a pointer (pSINT16) to an array of x values of type SINT16 (16 bit unsigned integer) and an array of y values of the same type. This is achieved by the @ operator at the first and fourth element of the arrays respectivly. These vectors were defined initially in the constant block, you should remember. The next parameter n is the number of points the polygon has or the number of reference points the Bézier curve has. If the arrays contain six elements, n should be six as well. Since in the case of the Bézier curve only the last three elements are of interest (at least in our example), n has to be three and the resulting curve is of order four (quadratic Bézier curve). The s value defines the smoothness of the curve. The higher s the higher the smoothness.

Some general information about these primitive functions: All functions presented here have the same suffix …COLOR. This means that the last parameter expects the colour you desire in hexadecimal form, $RRGGBBAA. The hexadecimal digit 00 corresponds to decimal digit 0, and hexadecimal digit FF corresponds to decimal digit 255. All of these function are accompanied by a function with the suffix …RGBA instead of …COLOR. Here, all parameters are the same except from the colour parameter, instead of ONE colour code in hexadecimal form, you enter four parameters r, g, b, a (red, green, blue, alpha/transparency). For example instead of $FF0000FF you put 255, 0, 0, 255. All functions return 0 as INTEGER value on success.

In many cases there are further accompanied functions with the prefix aa. This means the very same function with the same parameter list but the result is antialiased. For many functions furthermore the prefix filled is possible as shown for the circle in the example code. Also here the parameter list is completely the same but the resulting primitive is filled with the given colour.

SDL_BLITSURFACE(modified_image,NIL,screen,NIL); SDL_FLIP(screen); SDL_FRAMERATEDELAY(framerate); UNTIL keypressed;

Primitive Definition Description
Of all functions two types exist: …Color and …RGBA. They are in fact equal and differ only in the way you put in the colour information. For …Color functions there is the color:Uint32 argument where you put in the colour code in hexadecimal form, e.g. $FF0000FF for red without transparency. For …RGBA functions there are four arguments r:Uint8; g:Uint8; b:Uint8; a:Uint8 where you enter 255; 0; 0; 255 for red without transparency.
Functions with the prefix aa are equal to the functions without this prefix but are printing antialiased primitives. Functions with the prefix filled are equal to the functions without this prefix but the enclosed area of the primitive is filled with the given colour. Antialiased primitives are never filled and vice versa.
All functions return 0 as INTEGER on success.
Pixel (Dot) function pixelColor( dst : PSDL_Surface; x : Sint16; y : Sint16; color : Uint32 ) : integer Draws one pixel at position (x/y) in the given colour.
function pixelRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Line function hlineColor( dst : PSDL_Surface; x1: Sint16; x2 : Sint16; y : Sint16; color : Uint32 ) : integer Draws a horizontal line from x1 to x2 at height y in the given colour.
function hlineRGBA( dst : PSDL_Surface; x1: Sint16; x2 : Sint16; y : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function vlineColor( dst : PSDL_Surface; x : Sint16; y1 : Sint16; y2 : Sint16; color : Uint32 ) : integer Draws a vertical line at position x from y1 to y2 in the given colour.
function vlineRGBA( dst : PSDL_Surface; x : Sint16; y1 : Sint16; y2 : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function lineColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; color : Uint32 ) : integer Draws a free line from position (x1/y1) to (x2/y2) in the given colour.
function lineRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16;
x2 : Sint16; y2 : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function aalineColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; color : Uint32 ) : integer
function aalineRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16;
x2 : Sint16; y2 : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Rectangle (Box) function rectangleColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; color : Uint32 ) : integer Draws a rectangle from position (x1/y1) to (x2/y2) in the given colour.
function rectangleRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16;
x2 : Sint16; y2 : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function boxColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; color : Uint32 ) : integer
function boxRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16;
y2 : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Circle function circleColor( dst : PSDL_Surface; x : Sint16; y : Sint16; r : Sint16; color : Uint32 ) : integer Draws a circle with the center at position (x/y) and the radius r in the given colour.
function circleRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16; rad : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function aacircleColor( dst : PSDL_Surface; x : Sint16; y : Sint16; r : Sint16; color : Uint32 ) : integer
function aacircleRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16;
rad : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function filledCircleColor( dst : PSDL_Surface; x : Sint16; y : Sint16; r : Sint16; color : Uint32 ) : integer
function filledCircleRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16;
rad : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Pie function pieColor( dst : PSDL_Surface; x : Sint16; y : Sint16; rad : Sint16;
start : Sint16; finish : Sint16; color : Uint32 ) : integer
Draws a pie chart with the pie’s edge being at position (x/y) with the radius rad. “start” and “finish” define the arc length of the pie in degree. If “start” is 0 then the pie starts at the right (east) side of a circle. To start at the top, “start” should be 270 or -90. If “start” is 0 and “finish” is 90, you get one quarter of a circle.
function pieRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16; rad : Sint16;
start : Sint16; finish : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function filledPieColor( dst : PSDL_Surface; x : Sint16; y : Sint16; rad : Sint16;
start : Sint16; finish : Sint16; color : Uint32 ) : integer
function filledPieRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16; rad : Sint16;
start : Sint16; finish : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Ellipse function ellipseColor( dst : PSDL_Surface; x : Sint16; y : Sint16; rx : Sint16; ry : Sint16; color : Uint32 ) : integer Draws an ellipse with its center at position (x/y) and the two radii rx and ry for its horizontal and vertical axes in the given colour.
function ellipseRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16;
rx : Sint16; ry : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function aaellipseColor( dst : PSDL_Surface; xc : Sint16; yc : Sint16; rx : Sint16; ry : Sint16; color : Uint32 ) : integer
function aaellipseRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16;
rx : Sint16; ry : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function filledEllipseColor( dst : PSDL_Surface; x : Sint16; y : Sint16; rx : Sint16; ry : Sint16; color : Uint32 ) : integer
function filledEllipseRGBA( dst : PSDL_Surface; x : Sint16; y : Sint16;
rx : Sint16; ry : Sint16; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Polygon function trigonColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16; color : Uint32 ) : integer Draws a trigon with its edges at (x1/y1), (x2/y2) and (x3/y3) in the given colour.
function trigonRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16;
r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function aatrigonColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16; color : Uint32 ) : integer
function aatrigonRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16;
r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function filledTrigonColor( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16; color : Uint32 ) : integer
function filledTrigonRGBA( dst : PSDL_Surface; x1 : Sint16; y1 : Sint16; x2 : Sint16; y2 : Sint16; x3 : Sint16; y3 : Sint16;
r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function polygonColor( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16; n : integer; color : Uint32 ) : integer Draws a polygon with x values from array of SINT16 in vx. y values are from array of SINT16 in vy. n is the number of edges/points the polygon has.
function polygonRGBA( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16;
n : integer; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function aapolygonColor( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16; n : integer; color : Uint32 ) : integer
function aapolygonRGBA( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16;
n : integer; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
function filledPolygonColor( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16; n : integer; color : Uint32 ) : integer
function filledPolygonRGBA( dst : PSDL_Surface; const vx : PSint16;
const vy : PSint16; n : integer; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer
Bézier curve function bezierColor( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16; n : integer; s : integer; color : Uint32 ) : integer Draws a Bézier curve of any order. n is the number of points, well n+1 is the order of the curve then. The x and y values are from arrays of SINT16. The higher value s the smoother the curve gets. s should be 2 at least.
function bezierRGBA( dst : PSDL_Surface; const vx : PSint16; const vy : PSint16;
n : integer; s : integer; r : Uint8; g : Uint8; b : Uint8; a : Uint8 ) : integer

 

  SDL_BLITSURFACE(modified_image,NIL,screen,NIL);
  SDL_FLIP(screen);

  SDL_FRAMERATEDELAY(framerate);
UNTIL keypressed;

Nothing really new here. The “modified_image” surface with the rotated, zoomed image and the primitives is blitted to the screen surface. The result is flipped to the screen. Then the extensivly discussed framerate manager decides by procedure SDL_FRAMERATEDELAY(manager:PFPSMANAGER) how long actually to wait until the loop is repeated. This procedure replaces the common SDL_DELAY command. The loop is stopped when the user presses any key.

SDL_FREESURFACE(original_image);
SDL_FREESURFACE(modified_image);
SDL_FREESURFACE(screen);

DISPOSE(framerate);

SDL_QUIT;
END.

Finally all the used surfaces are free’d and the framerate manager is disposed. SDL is quit and the program finished.

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

The final result should look and behave like this: The image fpsdl.bmp is rotated and zoomed continouisly and some primitives (circle, filled circle, ellipse, pie, hexagon, Bézier curve) are drawn onto the image. If you use the pre-compiled exe file make sure to have the image copied to c:\.

Result of JEDI-SDL Chapter 4a

[Downloads transferred from old website]

SDL_gfx.dll; The pre-compiled SDL_gfx.dll (Version 2.0.19) for chapter 4a.

SDL_gfx-2.0.19.tar.gz; For license reasons here you can download the source code to compile the SDL_gfx.dll for chapter 4a. However, the most recent version for compilation you will find on the authour’s page.

Leave a Reply

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