First steps

Unless you are really starved for knowledge, I strongly suggest you do not read the source code for stars.php as it will likely confuse you unnecessarily. Instead, create a new file (in the same place as stars.php if you are on Windows), and call it sdlfirst.php. Now, go and find a bitmap picture file from somewhere (file extension is .bmp). If you are using Windows, there are several to choose from in your Windows director - I chose "Gone Fishing.bmp". Put it into the same directory as your new script, and call it mypic.bmp. Finally, if you are on Windows, copy runstars.bat to runfirst.bat, and edit the batch file to this:

php.exe -q -f sdlfirst.php

Now we're all set to get to the code. The simplest SDL application we can make that does something requires quite a few functions - far too many to list in the chapter title. Here are the function prototypes for the first set of functions:

void phpSDL_Quit ( void )

int phpSDL_Init ( int flags)

array phpSDL_SetVideoMode ( int width, int height, int bpp, int flags)

int phpSDL_EventState ( int type, int state)

array phpSDL_LoadBMP ( string file)

int phpSDL_PollEvent ( array &event)

int phpSDL_BlitSurface ( array source, array source_rectangle, array destination, array destination_rectangle)

int phpSDL_Flip ( array screen)

void phpSDL_FreeSurface ( array surface)

With those functions we can create our first simple graphical "game" using this code:

<?php
    set_time_limit(0);
    dl("php_sdl.dll");
    register_shutdown_function("phpSDL_Quit");

    if (phpSDL_Init(SDL_INIT_VIDEO) < 0) exit;

    $video = phpSDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
    if(!$video) exit;

    for ( $i = 0; $i<SDL_NUMEVENTS; ++$i ) {
        if ( ($i != SDL_KEYDOWN) && ($i != SDL_QUIT) ) {
            phpSDL_EventState($i, SDL_IGNORE);
        }
    }

    $bmp = phpSDL_LoadBMP("mypic.bmp");

    while( phpSDL_PollEvent(NULL) == 0) {
        phpSDL_BlitSurface($bmp, NULL, $video, NULL);
        phpSDL_flip($video);
    }

    phpSDL_FreeSurface($bmp);
?>

Before I explain what it does, go ahead and run runfirst.bat - you should see your picture being displayed inside a window.

As you can see, your very first PHP SDL application is pretty basic, but it is not bad for just 24 lines. Now, time to explain how the script works. The first two lines start off by setting the time limit of the script to 0, which means "let it run forever". We do not usually call this in our CLI applications because the CLI SAPI defaults to this setting. However, as we're using someone else's php.exe, we cannot rely on it being the CLI SAPI version, so we make sure and set the time limit to infinite. Secondly we dl() the SDL extension. If you recall we renamed our php.ini file so as to avoid errors while using SDL, so we need to dynamically load our extensions as appropriate.

Once the PHP SDL extension is loaded, we use register_shutdown_function() to add phpSDL_Quit() to the list of functions to be called at shutdown. SDL is a very resource-heavy library and we need to be careful to always, always free up resources we assign within SDL. This function, phpSDL_Quit() tells the SDL library to close everything down and unload itself. This is the opposite of the phpSDL_Init() function that is called on the next line, which tells SDL to start up and initialise its video library. Note that phpSDL_Init() returns an error (an integer less than 0) if it failed to start up properly, and the scripts bails out immediately on error as it is simply not recoverable.

Moving on, the next line calls phpSDL_SetVideoMode(), which is what actually creates the window for displaying graphics. This takes four parameters, which are the width in pixels of the window to create, the height, the number of bits per pixel, and the flags to use. The number of bits per pixel (bpp) parameter is set to 0 in our example, which instructs SDL to use the bpp setting currently in use on the computer. Most machines use 32-bit graphics, but some use only 24-bit - unless you specifically want a certain number of bits (perhaps 8-bit is enough if you have limited graphics and want maximum speed), stick with 0. The flags are perhaps the most important thing in the call, and there are several available that you need to be aware of:

SDL_DOUBLEBUF

This instructs SDL to make all drawing writes to a special, invisible screen (known as the back buffer), then, when you are finished with a frame, you flip the live frame with the invisible frame to update. This is only available if you also use SDL_HWSURFACE. It is generally best to use SDL_DOUBLEBUF if you can, as it makes drawing much smoother.

SDL_FULLSCREEN

This asks SDL to make its window full screen as opposed to in a moveable window. You may find that mixing SDL_FULLSCREEN with SDL_DOUBLEBUF causes flicking, and you need to remove SDL_DOUBLEBUF.

SDL_HWSURFACE

This asks SDL to create the drawing surface in video memory. This is very fast.

SDL_NOFRAME

you use this without SDL_FULLSCREEN, the window that is created will have no border to it. This flag is implicit in SDL_FULLSCREEN.

SDL_OPENGL

This gives you a drawing surface capable for use with OpenGL.

SDL_SWSURFACE

This creates the drawing surface in system memory as opposed to video memory. Not as fast, but better for older machines.

If successful, phpSDL_SetVideoMode() returns the drawing surface that is your main window. If not, you get "false" back and you cannot continue, so our script checks the return value and again exits immediately if it has no valid drawing surface.

The next loop comes courtesy of stars.php, and basically sets up SDL to ignore all events except a key being pressed or the application being told to exit, e.g. by clicking close from the title bar. This is not the most elegant solution to handling events, but it is simple and solves our needs for now.

Calling phpSDL_LoadBMP() loads the Windows bitmap file specified in its only parameter and returns the loaded surface ready for use.

Then we come to the main "game" loop, with game being used in the loosest sense as our application is not exactly any fun yet. The condition in the loop is that phpSDL_PollEvent() returns false - that not events have come in. The NULL being passed in is there because if you actually want to handle the event you can pass a variable in there and SDL will fill it in with information about the event, such as what the event actually was. Right now, though, we've disabled all events except ones that mean "I want to quit", so we do not care what event has come in. As a result, we just call phpSDL_PollEvent() - if there are any events waiting to be processed this will return non-zero. This means our loop will continue whizzing round until we hit a keyboard button or exit, as planned.

The loop itself contains just two functions, phpSDL_BlitSurface() and phpSDL_Flip(), which draw our bitmap surface onto the main window surface then flip the buffers respectively. The first of these, phpSDL_BlitSurface(), takes four parameters, which are the surface you want to copy, an array containing the area you want to copy out of that surface, the surface you want to copy onto, and the area you want to copy the surface to. If you supply NULL to parameter two, the entire surface is copied, and if you supply NULL to parameter four, the surface is copied to the top-left hand corner of the destination surface - co-ordinates (0,0).

Secondly, we flip the main drawing surface using phpSDL_Flip() and passing in the return value from phpSDL_SetVideoMode(). Just to make sure this is quite clear, the call to phpSDL_BlitSurface() drew the picture onto the back buffer, and therefore was not visible on the main screen. When we call phpSDL_Flip(), the back buffer becomes the front buffer (visible) and the old front buffer becomes the new back buffer. Drawing then takes place on the new back buffer, then it is flipped again, etc, etc.

The last thing the script does is call phpSDL_FreeSurface(), which frees up the memory allocated to our bitmap. You should never, ever rely on PHP to clean up PHP SDL code for you - always call phpSDL_FreeSurface() on any surfaces you create. There is one and only one exception to this, and that is the primary surface that gets returned by phpSDL_SetVideoMode() - this is automatically freed for you when phpSDL_Quit() is called.

As we registered phpSDL_Quit as a shutdown function, when the script exits from the loop (perhaps a key was pressed, etc), phpSDL_Quit() is called automatically, thus freeing the primary drawing surface, and we're done.

 

Want to learn PHP 7?

Hacking with PHP has been fully updated for PHP 7, and is now available as a downloadable PDF. Get over 1200 pages of hands-on PHP learning today!

If this was helpful, please take a moment to tell others about Hacking with PHP by tweeting about it!

Next chapter: Moving our sprite >>

Previous chapter: Getting it to work

Jump to:

 

Home: Table of Contents

Copyright ©2015 Paul Hudson. Follow me: @twostraws.