[SDK Documentation] [Getting started]


Creating a new project

This document has been updated for use with GapiDraw 4.0 or later.
Last updated on October 5, 2008.



GapiDraw is all about providing you with the tools you need to focus on mobile content instead of spending time investigating in how to optimize raster graphics on a vast diversity of mobile devices! It should be easy and fun to create advanced and good looking mobile applications, and we believe we have the tools to help you achieve this!

Many of the advanced technologies developed in GapiDraw were developed as research projects, and have resulted in awards, numerous M. Sc exams and even a Ph.D thesis. We believe we have the best platform available for creating advanced applications for Windows Mobile devices, and we hope you will like it too!


Getting Started

We always base all our applications around the Minimal sample application, and we recommend that you do so too. GapiDraw supports Embedded Visual C++ 4.0, Visual Studio 2005 and Visual Studio 2008, and depending on what tool you have the steps to complete some of the tasks in this tutorial might differ slightly.

Begin by opening the Minimal project in the folder:

Replace vs2008-mobile with vs2005-mobile if you are using Visual Studio 2005, or evc4 if you are using Embedded Visual C++.


The Minimal Project

The Minimal project is based on two files: myapplication.cpp and myapplication.h. These two files represent the realization of the class CMyApplication, which is a subclass to a class named CGapiApplication. If you look at the basic flow on top of myapplication.cpp it looks approximately like the following:

	return GapiDrawMain(hInst);

int GapiDrawMain(HINSTANCE hInst)
	::ZeroMemory(&config, sizeof(GDAPPCONFIG));

	config.hInstance           = hInst;
	config.pAppTitle           = _T("Minimal application");
	config.dwWindowIcon        = IDI_APP;
	config.dwDisplayFlags      = 0;
	config.dwMaxFPS            = 30; // Maximum 30 updates per second
	config.dwDisplayFlags      = GDDISPLAY_FULLSCREEN;
	// Create the CGapiApplication subclass
	CMyApplication* pMyApp = new CMyApplication(config);
	// Start the main loop
	HRESULT hr = -1;
	if (pMyApp)
		hr = pMyApp->Run();
		delete pMyApp;
	// Exit application
	return hr;

The three basic steps to run a GapiDraw application as can be seen above are:

  1. Create a configuration structure: GDAPPCONFIG
  2. Create a new subclass of CGapiApplication and send the GDAPPCONFIG in the constructor
  3. Call CGapiApplication::Run to start the application

Normally you don't have to change this code. But you might want to change the configuration parameters, to make your application run in windowed mode or fullscreen mode, or to use a quarter size display backbuffer.


Exploring Minimal

The basic minimal project doesn't do so much. It shows some text and a button bar in the top right corner. It is recommended that you scroll through myapplication.cpp to review the various operations and how the application is structured. There are only 13 operations in CMyApplication, and 9 of these does not have any code in them. So it should be fairly straightforward to see what is required to start a new application.

The Minimal sample application


Adding an image to Minimal

It is recommended that you use BMP or PNG images as resources, since GapiDraw features highly optimized and very low memory overhead readers of these formats. For simplicity we will use an image from another sample application to demonstrate how images can be drawn by GapiDraw.

Copy the image Samples\win32\Simple\common\res\ipaq.png to Breakout\common\res


Define a CGapiSurface class called m_pIpaqSurface in myapplication.h:

// myapplication.h
// Attributes
	CGapiSurface* m_pIpaqSurface;


Implement it in the constructor of myapplication.cpp.

// myapplication.cpp
CMyApplication::CMyApplication(const GDAPPCONFIG& config) : CGapiApplication(config)
	m_pIpaqSurface = new CGapiSurface(GetGlobal());

Notice that the global CGapiDraw object is passed to the CGapiSurface constructor, this is so that all surfaces are aware of changes in the display that might happen. The easiest way to retrieve the global CGapiDraw object is either by using the GetGlobal() method as seen below, or by using the m_pGapiDraw member variable directly from CGapiApplication.


Destroy the surface in the destructor of myapplication.cpp:

// myapplication.cpp
	delete m_pIpaqSurface;


We now have a CGapiSurface object instantiated. We can now load a PNG image from either file or resource to this object. In this example we will include the PNG in the executable, and then load it as a resource to the CGapiSurface. So the first step is to include the PNG image in the executable.

In Visual Studio, click the "Resource View" and right-click "Minimal.rc". Choose "Add Resource" and then "Import". Browse to Minimal\common\res and pick the file ipaq.png. In Embedded Visual C++ 4.0 you will get the question in what category you want to import the image. Choose PNG and click OK. In Visual Studio 2008 the image will by default be added to the PNG resource category.

Browse to the image in the Resource View (it should be located under Minimal.rc\PNG\ in the Resource View) and it should be named something like IDB_PNG2. Mark it and rename it to IDB_IPAQ. You might also want to change the search path to the image to be a relative search path instead of an absolute path, if you later want to move the project to a different location. We have now included a PNG image in our executable, so let's create a new surface from this image!


Creating a Surface

To create the surface, add the following code to CreateVidMemSurfaces. This is the typical location to load images in GapiDraw.

// myapplication.cpp
HRESULT CMyApplication::CreateVidMemSurfaces(CGapiSurface* pBackBuffer, HINSTANCE hInstance)
	// Create ipaq surface
	m_pIpaqSurface->CreateSurface(0, hInstance, IDB_IPAQ, _T("PNG"));

Notice that we do not specify any particular flags to CreateSurface, which means that GapiDraw by default will try to store the images in video memory if available. We also forward the instance handle, and specify what our image resource is called (IDB_IPAQ) and where it is stored ("PNG"). The reason _T is used to prefix the string is for cross-platform compatibility between Unicode and non-Unicode platforms, and is standard practice in Win32 development.

We also specify a color key on the surface, which means that when we later copy the image to the display we do not want to copy the pixels that are purple (RGB(255,0,255)).


Copying the Image to the Display

While it appears that we do copy images to the display, we don't actuallty draw images directly to the display, we draw them to the backbuffer. GapiDraw will then several times each second copy the contents of this backbuffer to the display. To draw our iPaq surface to the backbuffer, copy the following code to ProcessNextFrame in myapplication.cpp:

// myapplication.cpp
HRESULT CMyApplication::ProcessNextFrame(CGapiSurface* pBackBuffer, DWORD dwFlags)
	// Clear the back buffer
	pBackBuffer->FillRect(NULL, RGB(128, 128, 128), 0, NULL);
	// Draw the ipaq
	pBackBuffer->BltFast(0, 0, m_pIpaqSurface, NULL, GDBLTFAST_KEYSRC, NULL);

We choose to copy our ipaq surface to the back buffer at destination coordinates 0,0. We also choose to key the colors in the source surface that match our previously set purple color key value.

If we now run our application again it should look as follows:

The Minimal sample application with an iPaq shown behind the text

We hope this small tutorial helped you get up to speed with GapiDraw, and you can now go on to explore the advanced features of GapiDraw such as gradients, rotation and text drawing with customized fonts. Or why not head over to our Breakout tutorial and learn how to create a complete game based on the Minimal sample application!