User Tools

Site Tools


====== Device, timer and canvas ====== [[tutorial:index|Tutorial index]] ==== 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 * {{:content:folder.png?nolink|}} Tutorial folder * {{:content:folder.png?nolink|}} _Binary * //This folder will contain the binary files// * {{:content:folder.png?nolink|}} _Compiled * // This folder will contain the compiled files // * {{:content:folder.png?nolink|}} _Phoenix * // Put the Phoenix source here // * {{:content:folder.png?nolink|}} Source * {{:content:folder.png?nolink|}} 01_Basic * // Source for tutorial 1 // * {{:content:file.png?nolink|}} Main.pas * {{:content:file.png?nolink|}} Tutorial01_Basic.dpr * {{:content:file.png?nolink|}} Tutorial01_Basic.ico * {{:content:file.png?nolink|}} Tutorial01_Basic.lpi * {{:content:file.png?nolink|}} Tutorial01_Basic.res * {{:content:folder.png?nolink|}} 02_Images * // Source for tutorial 2 // You can download a {{:tutorial:downloads:template.7z|Template}} project for lazarus that contains the above folders and a project with the correct paths. Next download the latest Phoenix release from [[:start#downloads|the download page]] and extract it into the phoenix folder above. You will also need SDL.dll and FreeImage.dll. Download this from {{:tutorial:downloads:template-files.7z|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\//. <file batch 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 </file> ==== 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]]. <file pascal Main.pas> unit Main; interface // This includes the phoenix configuration file {$I} 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. </file> ==== Override the application class ==== The next step is to create our own instance of the TPHXApplication class that is contained in the [[|phxApplication]] unit. <code pascal> type TGame = class(TPHXApplication) private public end; </code> 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 <code pascal> TGame = class(TPHXApplication) private public procedure Init; override; procedure Update; override; procedure Render; override; procedure Shutdown; override; end; </code> Create empty implementations for the functions. <code pascal> procedure TGame.Init; begin end procedure TGame.Update; begin end; procedure TGame.Render; begin end; procedure TGame.Shutdown; begin end; </code> ==== The program file ==== This is the program file for the tutorial, this is included in the template and looks like this. <file pascal 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. </file> ==== 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. <code pascal> uses phxOpenGL_SDL; </code> 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 <code pascal> TGame = class(TPHXApplication) private Device : TPHXDevice; public procedure Init; override; procedure Update; override; procedure Render; override; procedure Shutdown; override; end; </code> And add code for creating the device <code pascal> 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; </code> 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. <code pascal> procedure TGame.Update; begin Device.Update; end; procedure TGame.Shutdown; begin Device.Free; end; </code> 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. <code pascal> procedure TGame.Render; begin // Clear the off-screen buffer Device.Clear; // Flip the buffers to show the image Device.Flip; end; </code> Now we have a window with a blue background color, the next step is to initialize a canvas for rendering 2D primitives. {{tutorial:basic-empty.png?direct&200|}} ==== 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. <code pascal> TGame = class(TPHXApplication) private Device : TPHXDevice; Timer : TPHXTimer; public procedure Init; override; procedure Update; override; procedure Render; override; procedure Shutdown; override; end; </code> 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. <code pascal> procedure TGame.Init; begin ... // Create the timer Timer:= TPHXTimer.Create; end; </code> Also call the [[|TPHXTimer.Update]] method from the game update method . <code pascal> procedure TGame.Update; begin // Update the device Device.Update; // Update the timer Timer.Update; end; </code> ==== 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. <code pascal> TGame = class(TPHXApplication) private Device : TPHXDevice; Canvas : TPHXCanvas; public procedure Init; override; procedure Update; override; procedure Render; override; procedure Shutdown; override; end; </code> Add the code for creating the canvas in the Init procedure, dont forget to free it in the Shutdown procedure. <code pascal> // Create the canvas using the device factory function Canvas:= Device.CreateCanvas; </code> 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. <code pascal> 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; </code> Now you should see this {{:tutorial:basic-rectangle.png?direct&200|}} ==== 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. <code pascal> // 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); </code> {{:tutorial:basic-colors.png?direct&200|}} ==== Textures ==== For this part you will need to download this texture and save it as **mud.png** in the binary folder. {{:tutorial:resources:mud.png?direct&100|}} The next step is to add a texture to our rectangles. To do this we first have to declare a texture variable: <code pascal> Texture: TPHXTexture; </code> 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. <code pascal> uses ... phxGraphics_FreeImage; </code> 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. <code pascal> // Create the texture using the device factory function Texture:= Device.CreateTexture; // Load the texture from a file Texture.LoadTexture('mud.png'); </code> 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. <code pascal> // 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; </code> Note that changing the texture for the canvas will flush all buffered verticies, to improve performance sort your draw calls using the texture. {{:tutorial:basic-texture.png?direct&200|}} You can also use the [[|TPHXTextureList]] class to manage textures, by using this you dont have to free individual textures. [[tutorial:index|Back to tutorial index]]

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