Tutorial 1 Working with an Offscreen Buffer




Use the source Luke! Click here to download the tutorial.

In this tutorial we are going to create a viewport bitmap (our screen) and an offscreen bitmap. In real video games graphics cards use video (viewport memory) and an offscreen video memory (some complex games may use as many as three offscreen virtual screens to draw to). The idea is to draw the video game updates to the offscreen virtual memory and then flip the memory pointer to that memory when it is ready for display. In flash we don't have access to video card memory. So what we will do is create an offscreen flash bitmap. Update the offscreen bitmap and draw our sprites to that. When the drawing (rendering) is completed, we will copy the offscreen bitmap data to the viewport bitmap, which we have instructed to Flash is our active viewer bitmap (what the game player is seeing).

HaXe uses object oriented programming methods and they are incorporated in these examples. Because these are tutorials the object oriented concepts are lite. The purpose here is to make clear the video graphics concepts rather than OOP. When looking at the graphics code, keep in mind the art is from a SNES game rom. The SNES has a screen resolution of 256 x 224 for this particuliar game. The resolution for the viewport we will be setting up will then be 256 x 224. The background bitmap art is 256 x 192 pixels in size.

Loading the Background Art

All the art I am using in these examples are sprites ripped from the Gundam Wing Endless Duel SNES rom cartridge. I am grabbing the srites from the online resource
Game Sprite Archive. I refromatted most of the art here to PNG files. So right-click and download the art on this tutorial page. These are all formatted for use with HaXe and swfmill.


Double Buffering -Offscreen Buffers

Video game animation uses a double-buffering system to send updates to the screen. A double-buffering system uses an offscreen buffer and the video display memory. If we were to draw directly to the screen, we would see choppy updates because the eyes would detect the changes. Video game designers came up with a way to provide the illusion of smoother screen animation by using an offscreen buffer -a buffer not viewable by the user. In this scheme all updates are made to the offscreen buffer. When the animation updates for this frame are completed, the entire offscreen buffer is transferred to the screen display.

When working with double-buffering, typically, we are using video ram memory. In this example, we are using Flash so we don't have access to video memory. Flash uses bitmap objects. Flash bitmap objects currently reside in system memory and we setup a bitmap object to be used to display to the video card memory. For this example, we will use 2 bitmaps, _offscreen and _viewport. The _viewport bitmap object is our screen the player will see. The _offscreen bitmap object will be hidden from the user.

The figure below shows the steps our rendering program will take to draw our background bitmap object to the screen. This illustrates the step where the background bitmap object is loaded into memory. The _offscreen object is filled black, 0x000000, and the _viewport (the screen) is filled black, 0x000000. This is the first step of our drawing (rendering) to the screen.



The second step our rendering engine must copy the background bitmap pixels (bitmapdata) to the _offscreen bitmap. Remember all our rendering will take place here. We'll draw in layers. First the background bitmap and then our sprite bitmaps (in tutorial03 will do this). Right now we'll keep it simple and draw only the background bitmap. So now we have the background bitmap pixels copied to the _offscreen bitmap. We have not updated the _viewport bitmap yet.



In step 3, we have rendered the background bitmap completely to the _offscreen bitmap. And any sprite updates we want to render have completed. The frame of animation is now ready to be transferred to the _viewport bitmap which the user will see,

Some important numbers to keep in mind when looking at this example. The background bitmap is our background art, it is 256 pixels wide x 192 pixels high. The _offscreen bitmap, which is our hidden screen, is the same dimension as our _viewport bitmap (viewing screen). It is 256 pixels wide x 224 pixels tall. This is the SNES console screen resolution.



That's it for the rendering basics. Ready for some fun? Let's set up the project and play with double-buffering.

Step 1. Create your project directory

Let's take a quick look at my project workspace directory. I have 3 subdirectories, img, src and swf. Logically, all my png files are stored in the img subdirectory and my HaXe source in the src directory. The swfmill files are stored in directory swf.
Create a directory called Background. Then create the 3 directories, img, src and swf in the Background directory. Here is the snapshot of my project workspace Background directory.

mnorton@skynet:~/workspace/Background$ ls -lrt
total 48
drwxr-xr-x 2 mnorton mnorton 4096 2008-08-08 11:32 img
-rw-r--r-- 1 mnorton mnorton 107 2008-08-08 11:55 compile.hxml
drwxr-xr-x 2 mnorton mnorton 4096 2008-08-08 14:07 swf
drwxr-xr-x 2 mnorton mnorton 4096 2008-08-09 11:05 src
mnorton@skynet:~/workspace/Background$

Step 2. Copy the Art File to Background/img Directory

Just as you did with the Getting Started example on the home page. Right-click on the deathscythe_background.png file and select "Save Image as" to copy it to directory, Background/img.

Step 3. Create the swfmill xml source file

In this example I have the art downloaded into the img directory. The art needs to be compiled into a Shockwave Flash (swf) file for HaXe to read it. We are now going to create a swf file. The art will be read from the img directory and the swf file will be created in the the swf directory. To do this, we must first create a swf xml tag file for use by swfmill.

<movie width="320" height="240" framerate="12" version="9">
  <frame>
    <library>
      <bitmap id="BackgroundBitmap"
            import="img/deathscythe_background.png" />
    </library>
  </frame>
</movie>

Save this file as sprite_lng_lib.xml so we can compile it using the swfmill tool.
swfmill simple < xml file in > < swf file out >

swfmill simple sprite_png_lib.xml swf/sprite_png_lib.swf

Move the sprite_png_lib.swf to your swf directory.

Step 4. The HaXe Class for the SWF file

Now that we have a swf file with our backgorund art in it. We need to create a class for HaXe to read it into our code.All HaXe source code for these examples are in directory src. The class looks like this,


/*
  File: Swf_Resources.hx
  Date: 08/09/08
  Author: Michael Norton
  Description: bitmap classes for SWF art
  Copyright Michael J. Norton, Black Hole Computing.
    all rights reserved 2008
  Use how you wish FREELY - permission required for commercial use
*/
import flash.display.Bitmap;

class BackgroundBitmap extends Bitmap
{
    public function new()
    {
        super();
    }
}


Take note of the one-to-one correspondence of the class name, BackgroundBitmap in the haxe source and the bitmap id field, set to BackgroundBitmap in the file, sprite_png_lib.xml. This is how to associate the naming from the swf file to the haxe class file.

Step 5. The Gfx Class for Video

Let's look at the code for the Gfx class we use to handle all our viewport (screen) graphics updates.
The new operator (constructor) takes two arguments, screen width and screen height. Since we are pseudo emulating a SNES console, we will pass the screen resolution of 256 x 224, or new(256,224) to the object constructor. The constructor calls the function Gfx_setup_Viewport to create the console display. The constructor also creates an offscreen bitmap of the same size.

The new operator also sets the viewport as active bitmap for Flash. i.e., our console screen.

flash.Lib.current.addChild(_viewportBitmap);

When we draw sprites to the offscreen bitmap we will use the Gfx function, Gfx_copyPixels_to_Offscreen. Where you pass in the source bitmapdata, it's bounding rectangle and the destination point P(x,y) of the offscreen bitmap as arguments. This function will be one of the workhorses of our rendering.

The other function of interest is Gfx_copy_Offscreen_to_Viewport. This is where we envoke our pseudo page flip. In reality, we are copying the bitmapdata from the offscreen bitmap to the viewport bitmap. It's not really a page flip! Oh, the day Flash supports page flipping -watch out!!!

Here is the source listing for the Gfx (Video Graphics) class.


/*
  File: Gfx.hx
  Date: 08/09/08
  Author: Michael Norton
  Description: video graphics (gfx) blitting tools
                sets up viewport and offscreen bitmap objects
  Copyright Michael J. Norton, Black Hole Computing.
    all rights reserved 2008
  Use how you wish FREELY - permission required for commercial use
*/

import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Point;


class Gfx {

    private var _offscreenBitmap:Bitmap;
    private var _offscreenBitmapData:BitmapData;
    private var _viewportBitmap:Bitmap;
    private var _viewportBitmapData:BitmapData;
    private var _viewport_height : Int;
    private var _viewport_width : Int;

    public function new( width: Int, height : Int ){
        // create the offscreen buffer
        _offscreenBitmapData = new BitmapData(width, height,
                false, 0xffff00);
        _offscreenBitmap = new Bitmap(_offscreenBitmapData);

        // create the viewport buffer
        Gfx_setup_Viewport( width, height);

        // make the viewport active in Flash
        flash.Lib.current.addChild(_viewportBitmap);

    }

    // function setup_Viewport
    // define the dimension height x width in pixels
    // of the viewport.
    public function Gfx_setup_Viewport( width:Int, height:Int) {
        _viewport_height = height;
        _viewport_width = width;
        _viewportBitmapData = new BitmapData(width, height,
            false, 0x000000);
        _viewportBitmap = new Bitmap(_viewportBitmapData);
    }
    // END Gfx_setup_Viewport

    // function copy_Offscreen_to_Viewport
    // copy the _offscreenBitmapData to the _viewportBitmapData
    // ..updates the screen..
    public function Gfx_copy_Offscreen_to_Viewport() {

        var srcRect = new Rectangle(0,0,256,192);
        var dstPt = new Point(0,0);

       // copy the offscreen bitmap data to the viewport bitmap data
        _viewportBitmapData.copyPixels( _offscreenBitmapData,
            srcRect, dstPt);
    } // END copy_Offscreen_to_Viewport

    // function copyPixels_to_Offscreen
    //
    public function Gfx_copyPixels_to_Offscreen( bitmapdata:BitmapData,
        srcRect:Rectangle, dstPt:Point ) {

        _offscreenBitmapData.copyPixels(bitmapdata, srcRect, dstPt );
    }
    // END Gfx_copyPixels_to_Offscreen
}
// END class Gfx



Step 6. The Main Driver Class

We can now take a look at the Main class was pulls this entire tutorial together. Right off the bat you will notice that the Main constructor calls the Gfx constructor. We pass in as arguments the SNES screen resolution for 256 x 224 pixels.

The member function Render does all the work for us in this example. 1st we create the background bitmap object (bitmapdata from the swf resource file) and then we copy this to the offscreen bitmap. And finally, the offscreen is copied to the viewport where it is displayed.


/*
  File: Main.hx
  Date: 08/09/08
  Author: Michael Norton
  Description: Main classes driver for Tutorial 1
  http://www.employees.org/~mnorton/haxe/HaXe.html
  Copyright Michael J. Norton, Black Hole Computing.
    all rights reserved 2008
  Use how you wish FREELY - permission required for commercial use
*/

import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Point;

import Swf_Resources; // load src/Swf_Resources.hx
import Gfx; // load src/Gfx.hx


class Main {

    private var _offscreenBitmap:Bitmap;
    private var _offscreenBitmapData:BitmapData;
    private var _viewportBitmap:Bitmap;
    private var _viewportBitmapData:BitmapData;
    private var background_Bitmap:BackgroundBitmap;
    private var gfx: Gfx;


    public function new(){
        // create a viewport with SNES console
        // resolution dimensions of 256 x 224 pixels
        gfx = new Gfx(256,224);
    }

    // function Render
    // used for composing the animation
    // Step 1. draw the background bitmap to the offscreen bitmap
    // Step 2. draw the offscreen bitmap to the viewport (user screen)
    public function Render() {


        // create a background object (the background art)
        var background_Bitmap = new BackgroundBitmap();

        // copy the background bitmap to the offscreen
        // compose all animation on the offscreen bitmap
        // and then drw it to the viewport (Flash on the browser)
        var srcRect = new Rectangle(0,0,256,192);
        var dstPt = new Point(0,0);
        gfx.Gfx_copyPixels_to_Offscreen( background_Bitmap.bitmapData,
                srcRect, dstPt );

        // update the viewport
        gfx.Gfx_copy_Offscreen_to_Viewport();
    }
    // END Render


    // main driver code
    public static function main(){
        var screen = new Main();
        screen.Render();

    }

}



Step 7. Compile the code

Create the following file and name it compile.hxml qnd save it in your Background directory.

-swf Tutorial01.swf
-swf-version 9
-swf-lib swf/sprite_png_lib.swf
-cp src
-swf-header 256:224:30
-main Main

Compile the code using the HaXe compiler syntax.

haxe compile.hxml

If you like living old school, you just use the HaXe command line arguments as well.

haxe -swf Tutorial01.swf -swf-version 9 -swf-lib swf/sprite_png_lib.swf -cp src -swf-header 256:224:30 -main Main

Step 8. Run the code.

Look for the file, Tutorial.swf in your Background directory. This is the Flash binary that the HaXe compiler created. Open this file in your browser to execute. The hyperlink below provides a pre-compiled swf file I made for this tutorial. Here's your chance to try out the shockwave file. This is the tutorial I created so you can see what it does. Nothing fancy. Just demonstrates how to setup an offscreen bitmap and draw to the offscreen.

Tutorial01.html

Get the Code

Download the HaXe source to the respective directories.

src/Swf_Resources.hx
src/Gfx.hx
src/Main.hx

Download the swf files to the respective directories.

swf/prite_png_lib.xml
swf/sprite_png_lib.swf

To compile, use this command line syntax for HaXe.

haxe -swf Tutorial01.swf -swf-version 9 -swf-lib swf/sprite_png_lib.swf -cp src -swf-header 256:224:30 -main Main

Under Construction...

Coming soon, Tutorial02 Scrolling Background and HaXe Timers

Scroll Demo
Return to Home Page

Send comments to: mnorton wecare net