GapiDraw from a DirectDraw developers perspective
Johan Sanneblad (johan.sanneblad@home.se), March 28, 2002.
Summary
GapiDraw is designed to be as similar to DirectDraw as possible, but at the same time
being as easy to use and as optimized as possible for handheld devices. This page presents
some common tasks in DirectDraw, and how they are implemented in GapiDraw.
What You Need
Opening the display device
A display is to a computer nothing more than a memory area containing bytes representing pixels.
To write directly to this area, both DirectDraw and GapiDraw requires you to create a
specialized surface called a primary surface. Drawing to this primary surface directly
affects what is visible on screen.
The first step to create a primary surface is to open the display and set a display mode.
The following steps are the minimum required number of steps to do so using DirectDraw.
DirectDraw
LPDIRECTDRAW lpDD;
HRESULT ddrval;
// Create the main Direct Draw object
ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
if(ddrval != DD_OK)
{
return(false);
}
// Set Cooperative level to allow Direct Draw to run full screen
ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if(ddrval != DD_OK)
{
lpDD->Release();
return(false);
}
// Set display mode to 320x240x16
ddrval = lpDD->SetDisplayMode(320, 240, 16);
if(ddrval != DD_OK)
{
lpDD->Release();
return(false);
}
With GapiDraw things are much easier. Since surfaces are objects instead of COM
interfaces, they never have to be manually released. The following GapiDraw example
opens the display device and sets the default display mode with just one command.
GapiDraw
CGapiDisplay display;
HRESULT gdrval;
// Open display in standard Pocket PC 240x320x16 mode
gdrval = display.OpenDisplay(hwnd, GDOPENDISPLAY_FULLSCREEN);
if(gdrval != GD_OK)
{
return(false);
}
Retreiving the primary surface and back buffer
Using Direct Draw, you manually have to request the main Direct Draw object to create a
special surface for you, the primary surface, which can be used to draw directly to
the display. The reason only one surface interface is used for both memory surfaces
and displays in Direct Draw can easily be explained with the lack of subclassing in the
old COM model being used. The following example creates a primary surface and retrieves
its back buffer using Direct Draw.
DirectDraw
LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface
LPDIRECTDRAWSURFACE lpDDSBack; // DirectDraw back surface
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
HRESULT ddrval;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
// Create the primary surface
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
if(ddrval != DD_OK)
{
lpDD->Release();
return(false);
}
// Get the back buffer
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
if(ddrval != DD_OK)
{
lpDDSPrimary->Release();
lpDD->Release();
return(false);
}
Again, using GapiDraw things are much easier. The CGapiDisplay object automatically
becomes the primary surface once CGapiSurface::OpenDisplay has been called. Since
CGapiDisplay is a subclass of CGapiSurface, all blit and drawing operations are already
available. To get the backbuffer from the CGapiDisplay, this is done as in the
following code sample.
GapiDraw
CGapiSurface backbuffer; // GapiDraw back surface
HRESULT gdrval;
// Get the back buffer
gdrval = display.GetBackBuffer(&backbuffer);
if(gdrval != GD_OK)
{
return(false);
}
Flipping and losing surfaces
Surfaces in DirectDraw are usually stored in video memory and may actually be
overwritten at any time (in case the user switched applications or started another
one using GDI). This means that each operation to a surface can fail at any time
as well, simply because the surface data was overwritten. So all operations using
Direct Draw must check every time if the surface was lost, and then manually restore
and re-create the surface from scratch. The following example illustrates this.
DirectDraw
ddrval = lpDDSBack->Blt(&rcRectDest, lpDDSMySurf, &rcRectSrc, DDBLT_WAIT, NULL);
if(ddrval == DDERR_SURFACELOST)
{
// The surface was overwritten, and you must now restore
// and re-create all your surfaces manually.
}
ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);
if(ddrval == DDERR_SURFACELOST)
{
// The surface was overwritten, and you must now restore
// and re-create all your surfaces manually.
}
Since Pocket PCs do not use video memory, all surface data is stored in physical
RAM memory and is copied to the display area only when CGapiDisplay::Flip is
called. If the Pocket PC device uses a buffered access to the display area it
is possible for the Pocket PC to move the location of its back buffer. No devices
have yet been reported to do this, but it is always best to plan ahead. To capture
a lost back buffer in GapiDraw you use the following code.
GapiDraw
// Surfaces in normal operations cannot be lost
gdrval = backbuffer.Blt(&rcRectDest, &mysurf, &rcRectSrc, 0, NULL);
gdrval = display.Flip();
if(gdrval == GDERR_BACKBUFFERLOST)
{
// The display buffer area has moved, just get an updated back buffer
display.GetBackBuffer(&backbuffer);
}
Summing up
What has been mentioned above are the major differences between GapiDraw and Direct
Draw. Other features such as blits, color keys, rectangle coordinates etc. are
identical. GapiDraw also contains a huge amount of extra features not available in
Direct Draw, such as advanced blit effects, zooming while rotating, loading bitmap
images from file or memory, drawing tools, collision masks, surface intersections,
thread timers, bitmapped font support, and much more.
Notes
The Direct Draw examples on this page was taken from the excellent Direct Draw
Programming tutorial by Lan Mader, available online at gamedev.net.
Related resources:
-
http://www.pocketpcdn.com/sections/gapi.html
Section: GAPI
-
http://www.pocketpcdn.com/articles/gapidraw2.html
Article: Creating a new project with GapiDraw
-
http://www.pocketpcdn.com/libraries/gapidraw.html
Library: GapiDraw
-
http://www.pocketpcdn.com/libraries/stgapibuffer.html
Library: STGapiBuffer
-
http://www.pocketpcdn.com/libraries/easyce.html
Library: EasyCE
-
http://www.pocketpcdn.com/libraries/gapiemulation.html
Library: GAPI for Emulator
-
http://www.pocketpcdn.com/libraries/pocketgl.html
Library: Pocket GL (iPAQ and Cassiopeia)
-
http://www.pocketpcdn.com/libraries/gapitools.html
Library: GapiTools
-
http://www.pocketpcdn.com/libraries/aspritece.html
Control: ASpriteCE Game Control
-
http://www.pocketpcdn.com/articles/gapibuffer.html
Article: Drawing images and other graphics with GAPI
-
http://www.pocketpcdn.com/articles/dieselengine2.html
Article: Programming DieselEngine 2. Using Diesel3D
-
http://www.pocketpcdn.com/articles/dieselengine1.html
Article: Programming DieselEngine 1. Close up and personal with DieselEngine, Using DieselGraphics
- http://www.microsoft.com/mobile/developer/technicalarticles/gameapi.asp
Article: Getting Started with the Game API
- http://www.microsoft.com/mobile/developer/technicalarticles/gapi.asp
Article: Here Comes GAPI!
- http://pocketmatrix.com/phantom/tutorial1.htm
Article: PocketPC Advanced Graphics & Games Programming Tutorial. Part 1 - Getting started with EasyCE
- http://pocketmatrix.com/phantom/tutorial2.htm
Article: Pocket PC Advanced Graphics & Games Programming Tutorial. Part 2 - Advanced tricks with pixels
- http://pocketmatrix.com/phantom/tutorial3.htm
Article: Pocket PC Advanced Graphics & Games Programming Tutorial. Part 3 - Pixel warps and displacement tables
- http://pocketmatrix.com/phantom/tutorial4.htm
Article: Pocket PC Advanced Graphics & Games Programming Tutorial. Part 4 - Buffers, pointers and sprites
- http://pocketmatrix.com/phantom/tutorial5.htm
Article: Pocket PC Advanced Graphics & Games Programming Tutorial. Part 5 - Rotozooming and fixed point arithmetic
- http://www.pocket-g.com/prx/sprite.html
Article: Sprite
- http://www.pocket-g.com/prx/animation.html
Article: Animation
- http://www.pocket-g.com/prx/timer.html
Article: Timer call back
- http://www.pocket-g.com/prx/bckgnd.html
Article: Scrolling background
- http://www.pocket-g.com/prx/collision.html
Article: Object collision
- http://www.pocket-g.com/prx/offscreen.html
Article: Off-screen technique