User Tools

Site Tools


tutorial:basic

Device, timer and canvas

Introduction

This tutorial shows the basic steps required to create a Phoenix application

You can download the source for this tutorial here.

Prerequisites

Start with downloading and installing the 32bit version of Lazarus from the Lazarus downloads page.

The tutorials assumes the following directory structure

  • Tutorial folder
    • _Binary
      • This folder will contain the binary files
    • _Compiled
      • This folder will contain the compiled files
    • _Phoenix
      • Put the Phoenix source here
      • Source
    • 01_Basic
      • Source for tutorial 1
      • Main.pas
      • Tutorial01_Basic.dpr
      • Tutorial01_Basic.ico
      • Tutorial01_Basic.lpi
      • Tutorial01_Basic.res
    • 02_Images
      • Source for tutorial 2

You can download a Template project for lazarus that contains the above folders and a project with the correct paths.

Next download the latest Phoenix release from the download page and extract it into the phoenix folder above.

You will also need SDL.dll and FreeImage.dll. Download this from here and put them in the Binary folder of the tutorial

You can also compile the projects using the standardlone FreePascal compiler.

If you are using the standardlone freepascal compiler you can use the batch script below. This assumes you have installed it in C:\FPC\2.6.2\.

compile.bat
C:\FPC\2.6.2\bin\i386-win32\FPC "-FU..\_Compiled" "-FE..\_Binary\" "-Fi..\..\..\Source" "-Fu..\..\..\Source" "-Fu..\..\..\Source\Providers\" "-Fu..\..\..\Source\Headers\" Tutorial01_Basic.dpr
 
pause

The main unit

Open the Main.pas pascal unit that is included in the template and add the basic Phoenix includes.

For a full list of all units see the api reference.

Main.pas
unit Main;
 
interface
 
// This includes the phoenix configuration file
{$I phxConfig.inc}
 
uses SysUtils,
  // Basic phoenix types
  phxTypes,
  // Contains phoenix utility classes
  phxClasses,
  // Math functions
  phxMath,
  // Device
  phxDevice,
  // Contains the application framework
  phxApplication,
  // Used for loading and manipulating graphic images
  phxGraphics,
  // Contains the canvas class for rendering 2D primitives
  phxCanvas,
  // Texture classes
  phxTexture;
 
implementation
 
end.

Override the application class

The next step is to create our own instance of the TPHXApplication class that is contained in the phxApplication unit.

type TGame = class(TPHXApplication)
  private
  public
  end;

There is four public procedures in the TPHXApplication class that we need to override in our own class:

Init This function is called once on application startup, used for loading resources
Update This is called once every frame and should be used for updating the game loop
Render This is called once every frame and should be used for rendering
Shutdown This is called when the application exits, used for cleaning loaded resources

Add these procedures to your application

TGame = class(TPHXApplication)
  private
  public
    procedure Init; override;
    procedure Update; override;
    procedure Render; override;
    procedure Shutdown; override;
  end;

Create empty implementations for the functions.

procedure TGame.Init;
begin
end
 
procedure TGame.Update;
begin
end;
 
procedure TGame.Render;
begin
end;
 
procedure TGame.Shutdown;
begin
end;

The program file

This is the program file for the tutorial, this is included in the template and looks like this.

Tutorial01_Basic.dpr
program Tutorial01_Basic;
 
// Make shure we dont get a console window in freepascal
{$APPTYPE GUI}
 
// Include the resource file containing the application icon
{$R *.res}
 
uses
  Main;
 
var Game: TGame;
 
begin
  // Create the game instance and run it
  Game:= TGame.Create;
  Game.Run;
  Game.Free;
end.

Compile the program

Now compile the program by pressing Ctrl+F9. You should not get any compilation errors.

This will create the application file in the parent output folder. Note that if you run the program now it will not show a window and you wont be able to terminate the program without using the task manager.

Creating the device

The next step is to create the device that is used for rendering the scene. The first thing we have to do is to select a provider, in this demo we are using OpenGL3.1 with SDL as window manager that is located in the phxOpenGL_SDL.pas unit. Add this to the uses clause.

uses
  phxOpenGL_SDL;

This provider should work on windows, linux and MacOS. If you need to target another platform it is possible to create a custom renderer by implementing the IPHXDevice interface.

Now add a device instance variable to our application

TGame = class(TPHXApplication)
  private
    Device    : TPHXDevice;
  public
    procedure Init; override;
    procedure Update; override;
    procedure Render; override;
    procedure Shutdown; override;
  end;

And add code for creating the device

procedure TGame.Init;
begin
  // Creates the device with the device from phxOpenGL_SDL.pas
  Device:= TPHXDevice.Create;
  // This loads a new icon for the window
  Device.Window.Icon:= ContentPath + 'Phoenix.bmp';
  // Initialize the window with a width of 800 and a height of 600 pixels
  Device.Initialize('Phoenix Demo', 800, 600);
end;

When you only have one provider included the TPHXDevice.Create function will use this provider. If you have more then one provider you will need to specify which provider to use with one of the overloaded constructors.

There are overloaded methods for the TPHXDevice.Initalize function for showing the window in fullscreen and setting other options.

We also have to update the device each frame and free it when the application shuts down.

procedure TGame.Update;
begin
  Device.Update;
end;
 
procedure TGame.Shutdown;
begin
  Device.Free;
end;

In the render function we must first clear the back buffer (off-screen) then flip the front and back buffer to show the scene we are creating.

procedure TGame.Render;
begin
  // Clear the off-screen buffer
  Device.Clear;
  // Flip the buffers to show the image
  Device.Flip;
end;

Now we have a window with a blue background color, the next step is to initialize a canvas for rendering 2D primitives.

Creating the timer

The timer is used to measure the time of each frame for frame rate independent movement as well as calculating the current FPS and the elapsed time of the game.

Add the timer variable to the game class.

TGame = class(TPHXApplication)
  private
    Device  : TPHXDevice;
    Timer   : TPHXTimer;
  public
    procedure Init; override;
    procedure Update; override;
    procedure Render; override;
    procedure Shutdown; override;
  end;

Create the timer in the Init procedure when the timer is created it will be automatically Reset so if you have long loading times you want to create the timer last.

procedure TGame.Init;
begin
  ...
  // Create the timer
  Timer:= TPHXTimer.Create;
end; 

Also call the TPHXTimer.Update method from the game update method .

procedure TGame.Update;
begin
  // Update the device
  Device.Update;
  // Update the timer
  Timer.Update;
end;

Creating the canvas

The canvas class is used for rendering 2D primitives, it contains a pixel and vertex shader for textured or colored primitives the canvas is created using a factory function in the device, but first we must create a instance variable for it.

TGame = class(TPHXApplication)
  private
    Device    : TPHXDevice;
    Canvas    : TPHXCanvas;
  public
    procedure Init; override;
    procedure Update; override;
    procedure Render; override;
    procedure Shutdown; override;
  end;

Add the code for creating the canvas in the Init procedure, dont forget to free it in the Shutdown procedure.

  // Create the canvas using the device factory function
  Canvas:= Device.CreateCanvas;

Now we can draw a rectangle by calling the Canvas.Rectangle function. This function adds the primitives required for drawing the rectangle to the internal buffer in the canvas. To show this to the screen we must call the Canvas.Flush procedure before flipping the device.

procedure TGame.Render;
begin
  // Clear the back buffer
  Device.Clear;
 
  // Draw a rectangle
  Canvas.Rectangle(100, 100, 200, 200);
  // Flush the canvas
  Canvas.Flush;
 
  // Flip the front and back buffers to show the scene
  Device.Flip;
end;

Now you should see this

Colors

To change the color of a primitive we can change the color property of the canvas, the next rendered primitive will be in that color.

  // Change the color to white
  Canvas.Color:= clrWhite;
  // Draw a rectangle
  Canvas.Rectangle(100, 100, 200, 200);
  // Change the color to red
  Canvas.Color:= clrRed;
  // Draw a rectangle
  Canvas.Rectangle(300, 100, 400, 200);

Textures

For this part you will need to download this texture and save it as mud.png in the binary folder.

The next step is to add a texture to our rectangles. To do this we first have to declare a texture variable:

  Texture: TPHXTexture;

We also need to provide a texture loading library, for instance the (FreeImage) loader. Note that you must copy FreeImage.dll to your output directory.

uses
  ...
  phxGraphics_FreeImage;

There are texture loaders for Vampyre and SDL_Image included in phoenix as standard.

It is also possible to create your own texture loader by overriding the TPHXGraphicFiler class. See one of the included loaders for an example on how to do it.

Then we have to create the texture and load it from our texture file.

  // Create the texture using the device factory function
  Texture:= Device.CreateTexture;
  // Load the texture from a file
  Texture.LoadTexture('mud.png');

Note that the LoadFromFile is used to load a texture that is saved in the built in texture format and LoadTexture is used to import external textures using the texture filers.

Now we can assign this texture to the canvas and then draw a rectangle using it.

  // Change back to white color
  Canvas.Color:= clrWhite;
  // Bind the texture
  Canvas.Texture:= Texture;
  // Draw a filled rectangle
  Canvas.FilledRectangle(100, 300, 200, 400);
  // Remove the texture
  Canvas.Texture:= nil;

Note that changing the texture for the canvas will flush all buffered verticies, to improve performance sort your draw calls using the texture.

You can also use the TPHXTextureList class to manage textures, by using this you dont have to free individual textures.

Back to tutorial index

tutorial/basic.txt · Last modified: 2013/08/17 11:33 by amnoxx