News | Articles | Libraries | Developer Tools | Books | Forum Links | Search   
Sections:
 

Programming DieselEngine 1. Close up and personal with DieselEngine, Using DieselGraphics

By Jani Immonen, November 12, 2001.
CTO, Co-Founder www.inmarsoftware.com
Print version

Introduction

DieselEngine is a software development kit by Inmar Software Ltd. It is multi platform SDK that allows producing real-time 2D and 3D graphics, along with input mapping and sound engine with 3D sound. DieselEngine SDK is free for non-commercial use, and its demo version downloadable at: www.inmarsoftware.com. Demo version contains all features that licensed version, and works equally well when following this set of articles.

I'm planning to write several articles. At this point I have something like this in my mind:

  • Article 1, Close up and personal with DieselEngine, Using DieselGraphics:
    • Creating DieselEngine application
    • Using basic 2D services
    • Some OS event handling
  • Article 2, Using Diesel3D:
    • Creating Diesel3D application
    • Using CDiesel3DDevice class
    • Loading, updating and rendering 3D scenarios with CDiesel3DScene class
  • Article 3, Simplifying input with DieselInput:
    • Using DieselInput for input device mapping
    • Using advanced features like button timestamps and delays
  • Article 4, Making it sing, using DieselSound:
    • Creating DieselSoundEngine object
    • Loading sounds and sound playback
    • Controlling sound playback
    • Streaming sounds
    • 3D sound

This is only the preliminary information and might change whatever comes along.

Some articles depend on each other. For example Article 2, Using Diesel3D requires knowledge of basic DieselGraphics services. I try to make articles about input and sound as independent as possible, but I might use some references to previous articles.

I hope to provide some internal information about engine, and try to use it as efficiently as possible. But in sake of simplicity I won't give much attention of error handling etc. so this is not an article of good programming practices, it is article of how to use DieselEngine SDK. You should also go thru every example application bundled with SDK, there is so much information commented on source code.

What I'm expecting from reader?

I expect basic knowledge of C++ programming, by basic knowledge I mean classes, deriving classes and virtual functions. If these areas of C++ programming are not in good shape, following these articles might be difficult.

Also I expect that developing environments are already set. If you can compile the DieselEngine SDK example programs, everything is fine, if not see DieselEngine SDK documentation for details how to set up the developing environments.

OK, that's enough for preface, let's get close up and personal with DieselEngine.

Creating DieselEngine application by using application wizards

In this article we are going to create DieselEngine application for PocketPC, and we use SDK version 1.04. If you are using older release of SDK, please update. Although we create PocketPC application, all information provided applies equally to other supported platforms, and if not it is clearly stated. We'll be using the Microsoft eMbedded Visual C++ 3.0. I'll call it EVC from now on.

At first I though of that we should create new application from scratch, but second though: why would we do that? DieselEngine SDK has these very handy application wizards to do the job. For good tutorial of how to use Diesel Application Wizards, see SDK documentation. But, I'll walk you thru now.

  • Select file->new... from EVC menu
  • You should see 'Diesel Application Wizard' at projects list box. If it is not there, refer to SDK documentation about how to install Diesel Application Wizards
  • Type in your project name and location, just as any new project with EVC
  • You should see following screen:
    Step 1 of 6
  • Type in your main application class name. This class will be derived from IDieselApplication class and performs as main application object. Every DieselEngine application using graphics MUST have one and only one IDieselApplication derived object, although there are many ways of using the derived object. In this article we'll use the way it is designed for, IDieselApplication object will use internal loop for updating the display. In this article we use name CFirstDieselApp, but you can use whatever you like.
  • Application title is text that application shows on window title and taskbar depending of platform.
  • Source comments: You should select the 'A Lot of please!' option unless you are familiar with DieselEngine. Wizard then generates comments that explain almost every function call with parameter explanation.
  • Click 'Next >', you should see following screen:
    Step 2 of 6
  • In this screen you can select the IDieselApplication virtual functions to override. You don't have to select any of them, but generally you'll need some of them later. Select the 'void OnKeyDown(DWORD dwKey)' function and press 'Next >' Step 3 of 6
  • In this screen we'll select the application type whatever it will be windowed or full screen application. All these settings can be changed later from source code. Select the 'Fullscreen application' with default resolution. Press 'Next >' Step 4 of 6
  • In this step we can add Diesel3D to application, we don't want it now, so de-select the 'Use Diesel3D' check box.
  • We don't care about two remaining steps for now, so press 'Finish' to create the application.

You'll notice that wizard created one class called CFirstDieselApp and also created the Main.cpp file that contains the WinMain function. In addition the 'resource.h' is created to contain application icon.

Now make sure that 'Active WCE Platform' combo box says 'PocketPC' (in WCE it is by default H/PC Pro 2.11).

Open the 'FirstDieselApp.h' file and notice that wizard generated some functions even that you didn't select them from virtual functions step of wizard. These are: OnInitDone, OnExit and OnFlip.

Exploring the generated functions

DE_RETVAL OnInitDone()

This function is very important. The IDieselApplication object calls this virtual function when it has finished all initialisation of display device and internal surfaces etc. This is the best place to allocate your own resources such as surfaces etc. You also have possibility to terminate application by returning something else than DE_OK, for example if application runs out of memory while allocation resources. The return value returned by OnInitDone function is passed thru as return value to Startup function, which resides in 'Main.cpp' file.

void OnExit()

This is the counterpart to OnInitDone function and is called by IDieselApplication when it is just about to release all internal structures and the display device. This is the best place to release all your application resources.

void OnFlip

This is your application main loop. The OnFlip function is called by IDieselApplication just before it draw contents of back buffer to device screen. Go to the 'FirstDieselApp.cpp' file and see the implementation of this function. The first line in function is m_srfBack.Fill(0, NULL). The m_srfBack is CDieselSurface object and is IDieselApplication class member.

The m_srfBack member is essential part of engine. Whatever you draw into the m_srfBack will be copied to screen after OnFlip returns.

What is CDieselSurface object?

Well, on PocketPC platform surface is just a rectangular block of memory owned by CDieselSurface object. Surface has lots of manipulation functions to copy and produce effects to surfaces.

All functions that copy surface to another (one way or another) are called Blitting functions. Surface object supports several formats: 8 bit palettized, 16 bit 555, 16 bit 565 and 32 bit full color surfaces. The 24 bit surface is not supported, and some effects do nothing with 8 bit surfaces. Surface do not support format conversions, so when using any of blitting functions, surfaces must be in same format. Fortunately there is handy format called eDE_COMPATIBLE, which creates surface to same format as application back buffer object. Surface object has automatic clipping, which can be disabled by setting DE_BLTNOCLIP flag to blitting functions.

The one blitting function which is used the most is the CDieselSurface::BltFast function:

CDieselSurface::BltFast

To those who have used the Microsoft DirectX, this is very familiar, actually one design goals was to make DieselEngine very accessible to programmers who know DirectX. Along the way you'll notice a lot of similarities, and similarities won't stop there:when building DieselEngine application for Desktop PC, CDieselSurface has function: GetDirectDrawSurface() which returns pointer to actual IDirectDrawSurface interface. But this is article of PocketPC development, so we'll not go into it any further. On PocketPC builds GetDirectDrawSurface() always returns NULL (well, there is no DirectDrawSurface, is there?).

The BltFast function copies surface to another. It also supports some effects like color keying, flipping, mirroring and HalfAlpha, which is quite fast version of true alpha blending, producing 50% transparent surface copy. BltFast flags:

  • DE_BLTSRCCOLORKEY
    The blitting operation uses color keying, where pixels of defined color will not be copied to target surface. Color key must be set with CDieselSurface::SetColorKey or CDieselSurface::SetAutoColorKey() function before using this flag.
  • DE_BLTNOCLIP
    Disables automatic clipping, use this when you know that surface will always be fully visible. But a word of caution: Application will most likely crash if you try to copy the surface outside target area.
  • DE_BLTFLIPX and DE_BLTFLIPY
    Mirror the surface in x or y direction
  • DE_BLTHALFALPHA
    Does the copy operation with 50% transparency. This is quite efficient ways of using alpha blended blitting, and definitely faster than 'real' alpha blend.

All these flags can be used separately or combined with bitwise OR | operator.

The BltFast cannot stretch or shrink the surfaces, for that there is a function called Blt:

CDieselSurface::Blt

This function is extended version of BltFast function. It can stretch or shrink the surface while copying it to another. This function also supports the same flags as the BltFast counterpart, and in addition the flag DE_BLTQUALITYSTRETCH that interpolates the neighbouring colours while stretching or shrinking the surface. The quality stretch is not meant to use in real time.

There are a lot more blitting functions available such as BltRotate, AlphaBlend and BltEffect but will get into those later. Also there are functions that operate to surface itself, for example: GradientFill, FadeRGB and Fill.

Ok, there was some background about surfaces, now lets do something with our brand new generated application.

Adding you own functionality to application

Now you have the generated application framework, and basically you can compile and execute it if you want, but don't do it just yet. One quite important thing is missing. The application has no way of terminating and will require reset of PocketPC device to shut it down! If you followed the instructions on using the wizard you should have function called OnKeyDown in your application class. Add the following code to function:

void CFirstDieselApp::OnKeyDown(DWORD dwKey) { // TODO: Add your handler code here... if (dwKey == VK_RETURN) { Shutdown(); } }

Note, there is some WIN32 specific code, the key code (VK_RETURN) will not be the same with upcoming EPOC release. But anyway, now whenever any button is pressed, the OnKeyDown function is called. The parameter dwKey tells the virtual key code of pressed button. Every PocketPC should have VK_RETURN automatically mapped, for example on Compaq iPaq device it is button in center of directional control button.

Now, when button is pressed we call IDieselApplication::Shutdown function. This function starts to release all internal resources, and in some point calls the virtual OnExit function as described earlier. After that the IDieselApplication::Run function at Main.cpp returns, and application exits the WinMain.

Now we have way of exiting the application, so compile and execute it, although it is a bit boring application:just black screen with nothing on it, but bear with me, we'll add some action shortly.

Many times the first thing we need is way to draw text to screen. CDieselSurface class has means to draw on it with windows GDI functions with GetDC and ReleaseDC functions, but access to GDI is provided only for image loading etc. and is definitely not real time. Fortunate again, DieselGraphics has class called CDieselWriter that can draw text to screen quite efficiently.

Now, go to the 'FirstDieselApp.h' file and add new member object to CFirstDieselApp class. First add the include statement of DieselWriter:

#include <DieselWriter.h>

Then add the member object to header:

protected: CDieselWriter m_Writer;

Now open the 'FirstDieselApp.cpp' file and go to the OnInitDone function. Add following code inside.

res = m_Writer.Startup(NULL, 0, 12); f (res != DE_OK) { // failed to start writer object return res; }

Here, we start the writer object. First parameter is pointer to CDieselSurface object to use as font surface. We set it to NULL, which forces writer object to create internal 'default' font surface. You may give pointer to your own surface, which contains image of all 256 ANSI characters ordered into the 8x8 grid. More info about font surfaces is found in SDK documentations.

Second parameter is additional pixels between each character when writing the text. Using negative value makes strings more 'solid' and positive more 'fragmented' (don't know if those are good words to describe it). Experiment different values to see how it works.

Third parameter is length of 'space' characters in pixels. We'll use 12 here.

Next go to the OnExit function and add code:

m_Writer.Shutdown();

Which shuts down the writer object. Most DieselEngine objects use Startup/Shutdown semantics on object creation and destruction, but some (like CDieselSurface) uses Create/Release. It is safe for all DieselEngine objects to call Shutdown or Release multiple times.

Now the writer object is ready for writing text. Add code to OnFlip function:

m_Writer.WriteText(0, 0, &m_srfBack, "Hello World! from\nDieselEngine application.", DE_BLTSRCCOLORKEY);

Note that WriteText function supports all BltFast flags as last parameter. It can also use some basic formatting on string like '\n' and '\t'.

Ok, compile and execute again to see the results.

Loading images to CDieselSurface object

CDieselSurface can load images from files, Diesel Media Packs and from application resource. The formats supported natively are windows bitmaps (BMP), JPEG compressed images (JPG) and gif images (GIF). Now lets load an image!

Create an image, sized 240x320 and save it as jpg or gif. This example uses file called 'diesel.jpg'. Copy the file to same folder on your PocketPC device where example application exe is. By default EVC uses '\Windows\Start Menu'.

Now add some code to CFirstDieselApp header:

CDieselSurface m_srfImage;

Add code to OnInitDone function:

TCHAR filename[MAX_PATH]; BuildFilepath(filename, _T("\\diesel.jpg")); res = m_srfImage.Load(filename, NULL); if (res != DE_OK) { // failed to load image... return res; }

Here we use IDieselApplication function BuildFilepath. That function is made to simplify the creation of file name string. Most platforms handle file systems differently, so this function builds right kind of string pointing to file. It can also use subfolders, but they are always relative to application executable location. See SDK documentation for more information.

Then we use surfaces Load function to load the image. First parameter is file name string, second is pointer to SDE_SURFACEDESC structure. We set it to NULL, which creates the surface that will be compatible with application back buffer and has same dimensions as image we are loading. We could fill up the structure and pass it to Load function to force surface to load to different size than original, but now NULL is fine.

Other image loading functions work basically the same. If you wish, try to load a jpg image from application resource with LoadFromResource function instead of Load

And just as with writer object, add some code to OnExit function:

m_srfImage.Release();

This frees memory allocated for surface.

Next we need to be able to see the surface. Add code to OnFlip function:

m_srfBack.BltFast(0, 0, &m_srfImage, NULL, 0);

Add this code before the WriteText function call, so blitting the image won't override the text we write. In above code we are saying "Blit into the m_srfBack surface to coordinates 0x0. Use m_srfImage as source surface, and use entire area of source surface when blitting. No additional operations needed". I hope first three parameters need no additional explaining, but fourth is pointer to rectangle that defines the source area used when blitting. This makes possible to copy only portions of source surface. The last parameter is blitting flags described earlier. Just go ahead and experiment with blitting flags.

Now you can remove the line m_srfBack.Fill(0, NULL) from OnFlip function. There is no point of filling the back buffer surface when we are filling it completely with image.

Now, execute application again, and you should see something like this (with your own image of course):

Hello world

Creating surface object from scratch

Now we know how to load image into the surface, lets create an empty surface by hand. Loading image to surface effectively creates the surface, but now we create it manually. Add code to CFirstDieselApp class header:

CDieselSurface m_srfEmpty; //not very good name though, surface won't be empty for long:

Then go into the OnInitDone and add:

SDE_SURFACEDESC desc; desc.iWidth = 64; desc.iHeight = 64; desc.eFormat = eDE_COMPATIBLE; desc.dwFlags = 0; res = m_srfEmpty.Create(desc); if (res != DE_OK) { // failed to create image... return res; } m_srfEmpty.Fill(0x00ff0000, NULL);

First thing to do when creating surface is to fill the SDE_SURFACEDESC structure. Here we create surface, which is 64 pixels wide, and 64 pixels height (you should always try to use square, powers of 2 sized surfaces. Trust me, it pays off later). The surface format is set to eDE_COMPATIBLE that creates surface that is same format as application back buffer.

The dwFlags member of structure may contain one of the following flags:

  • DE_SYSTEMMEMORY
    Forces surface to system memory. This flag has no meaning on PocketPC devices, where surfaces are always in system memory
  • DE_TEXTURE
    Surface will be used as texture with CDiesel3DDevice object. More about that on another article.

Ok, 0 for dwFlags is fine for now. After calling the Create function we call function called Fill. Fill takes colour value as first parameter, just note that it is in format independed form (XXRRGGBB). Second parameter is pointer to rectangle, which specifies area to fill, or NULL to fill entire surface.

Remember to add releasing code to OnExit function, just like you did with m_srfImage object.

Now, unlike the member name m_srfEmpty, surface is no longer empty. It is full of red color. Let's draw it to screen, go to OnFlip function and add following code:

m_srfBack.BltFast(0, 0, &m_srfEmpty, NULL, DE_BLTHALFALPHA);

We use the half alpha flag to show it off. Execute the app and you should see something like this:

Hello world with half-alpha

Here we go, our nice little red surface drawn with alpha blending. Next we'll do something more radical:surface rotation:

For surface rotation we'll use surface object just created, just add code to OnFlip:

static float fAngle = 0.0f; m_srfBack.BltRotate( m_srfBack.GetWidth() / 2, m_srfBack.GetHeight() / 2, &m_srfEmpty, fAngle, 64, DE_BLTHALFALPHA ); fAngle += PI * m_fFrameTime;

Again we are using half alpha, just to show that BltRotate supports it also. Now lets go thru what happens here.

First two parameters are coordinates where into the rotated image will be drawn. These coordinates mean middle point of rotated blit, not the upper left corner as other blitting functions.

Third parameter is pointer to source surface. Fourth parameter is rotation angle in radians.

Fifth parameter is radius of rotated image. This parameter makes it possible to simultaneously rotate and stretch / shrink the image. Because of internal implementation of BltRotate function, there is no extra cost for size change.

Sixth and the last parameter is same old blitting flags used with other blitting functions.

The next line after BltRotate is interesting. It uses the IDieselApplication internal timing services to make fAngle increase PI (defined in DieselMath.h, included automatically) radians per second independed of application frame rate. Many DieselEngine classes use this same variable to time the operations. Anything you multiply with this value will be translated to units per second. As conclusion m_fFrameTime member if time value it took for last frame to draw, in seconds. For example if application is running at 15 frames per second, the m_fFrameTime is approx. 0.066.

Execute the app to see results. Ok I admit it is little bit boring, but rotated surface could contain something else, like any image loaded from file.

Using color keyed blitting

Color keying is something that almost every graphics application needs. In DieselEngine, color keying is made as easy as possible. Lets create yet another surface, go to header and add new member:

CDieselSurface m_srfColorKey;

Create the surface with same parameters as you did with m_srfEmpty, and then fill it with following code:

m_srfColorKey.Fill(0x000000ff, NULL); RECT rect = {0, 0, 16, 16 }; m_srfColorKey.Fill(0x0000ff00, &rect);

What we do here is fill the entire surface to blue, and then fill the 16x16 sized upper left corner with green. Next we set up the color keying:

m_srfColorKey.SetAutoColorKey();

I like the SetAutoColorKey function in particular. It reads the pixel color value from given coordinate, and sets it as transparent color for color keying. Function has default parameters (0, 0), so usually you don't have to set the parameters to function. There is also another function called SetColorKey, which takes actual transparent color value as parameter. That function is little bit more involved, because it needs surface format depended color value. Of course there is no problem if transparent color is black (0) or white (0x00ffffff).

Now, don't forget to add surface release into OnExit function. Now everything is set up, lets draw the color-keyed surface:

static float fX = 0.0f; static float fSpeed = 50.0f; // moving 50 pixels per second m_srfBack.BltFast((int)fX, 150, &m_srfColorKey, NULL, DE_BLTSRCCOLORKEY); fX += fSpeed * m_fFrameTime; if (fX > m_srfBack.GetWidth() - m_srfColorKey.GetWidth()) { fX = (float)(m_srfBack.GetWidth() - m_srfColorKey.GetWidth()); fSpeed = -fSpeed; } else if (fX < 0.0f) { fX = 0.0f; fSpeed = -fSpeed; }

Add above code just before the rotation code. That way color keyed surface moves nicely under the alpha blended and rotated surface. If you change the DE_BLTSRCCOLORKEY to 0, you'll see the green upper left corner of surface.

Here is a screenshot of final step:
Hello world with rotation

Source code this far

OK, here is source codes this far.

The Main.cpp file:

/*--------------------------------------------------------- Main.cpp source file Created by Diesel Application Wizard v:1.0 (c) 2000-2001 Inmar Software Ltd. Date: 7.11.2001 FirstDieselApp Application Winmain function and DieselEngine Initialization ---------------------------------------------------------*/ #include "FirstDieselApp.h" #include "resource.h" CFirstDieselApp theApp; // Application 'main' function int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, TCHAR *pCmdLine, int nCmdShow) { // Initialize DieselEngine { DE_RETVAL res = DE_OK; // set the application title. this text shows // on application main window and windows taskbar theApp.SetAppTitle(_T("First DieselEngine Application")); // Set Application resource IDs here // First parameter: menu resource identifier // Second parameter: icon resource identifier // Third parameter: acceleration resource identifier theApp.SetResources(0, IDI_APPICON, 0); // initialize the display mode structure // if engine is initialized to windowed mode // 'iRefresh' and 'iBPP' members of structure // has no meaning. This is also true with // 'single' displaymode devices such as // PocketPC SDE_DISPLAYMODE mode; mode.iWidth = 240; mode.iHeight = 320; mode.iRefresh = 0; mode.iBPP = 16; DWORD dwStartupFlags = 0; // Startup the engine. If derived class OnInitDone // function failed, return value is passed here // First parameter: The display device identifier // Use IDieselApplication 'GetDisplayDevices' // function to retreive all installed devices // Second parameter: The display mode to set if fullscreen, // or the application window size // Third parameter: Combination of the following flags: // DE_WINDOWED - start at windowed mode // DE_WINDOWLOCKED - application window cannot be resized // DE_FORCEHARDWARE - (DirectX specific) starts the engine // only if hardware display device is found // ( this flags is usually only for debugging) // DE_FORCESOFTWARE - (DirectX specific) starts engine // without hardware support // ( this flags is usually only for debugging) res = theApp.Startup(NULL, &mode, dwStartupFlags); if (res != DE_OK) { // failed to start application // even the OnInitDone function returned // error, or internal structures failed // to initialize. return 0; } } // start pumping messages // DieselApplication function 'Run' returns // the last message from window message pump int ret = 0; ret = theApp.Run(); return ret; } The CFirstDieselApp class header ////////////////////////////////////////////////////////////// // FirstDieselApp.h: interface for the CFirstDieselApp class. // Date: 7.11.2001 // // Created by Diesel Application Wizard v:1.0 // (c) 2000-2001 Inmar Software Ltd. // ////////////////////////////////////////////////////////////// #ifndef __FIRSTDIESELAPP_H__ #define __FIRSTDIESELAPP_H__ #include <Diesel.h> #include <DieselGraphics.h> #include <DieselWriter.h> class CFirstDieselApp : public IDieselApplication { public: // construction & destruction CFirstDieselApp(); virtual ~CFirstDieselApp(); // pure virtual function override void OnFlip(); // Overrided virtual functions DE_RETVAL OnInitDone(); void OnExit(); void OnKeyDown(DWORD dwKey); protected: CDieselWriter m_Writer; CDieselSurface m_srfImage; CDieselSurface m_srfEmpty; CDieselSurface m_srfColorKey; }; #endif // ifndef __FIRSTDIESELAPP_H__ The CFirstDieselApp class cpp file: // FirstDieselApp.cpp: implementation of the CFirstDieselApp class. // // Created by Diesel Application Wizard v:1.0 // (c) 2000-2001 Inmar Software Ltd. // /////////////////////////////////////////////////////////////////// #include "FirstDieselApp.h" /////////////////////////////////////////////////////////////////// // Construction/Destruction /////////////////////////////////////////////////////////////////// CFirstDieselApp::CFirstDieselApp() { } CFirstDieselApp::~CFirstDieselApp() { } // OnInitDone() // Called by DieselEngine, when all initialization is done // if return value is FAILED, engine will clean up and close // return value of this function is passed to 'Startup' function // called at main.cpp DE_RETVAL CFirstDieselApp::OnInitDone() { DE_RETVAL res = DE_OK; res = m_Writer.Startup(NULL, 0, 12); if (res != DE_OK) { // failed to start writer object return res; } TCHAR filename[MAX_PATH]; BuildFilepath(filename, _T("\\diesel.jpg")); res = m_srfImage.Load(filename, NULL); if (res != DE_OK) { // failed to load image... return res; } SDE_SURFACEDESC desc; desc.iWidth = 64; desc.iHeight = 64; desc.eFormat = eDE_COMPATIBLE; desc.dwFlags = 0; res = m_srfEmpty.Create(desc); if (res != DE_OK) { // failed to create image... return res; } m_srfEmpty.Fill(0x00ff0000, NULL); res = m_srfColorKey.Create(desc); if (res != DE_OK) { // failed to create surface return res; } m_srfColorKey.Fill(0x000000ff, NULL); RECT rect = {0, 0, 16, 16 }; m_srfColorKey.Fill(0x0000ff00, &rect); m_srfColorKey.SetAutoColorKey(); return DE_OK; } // OnExit() // Called by DieselEngine, just before it cleans up // this is good place to clean up your resources void CFirstDieselApp::OnExit() { m_srfColorKey.Release(); m_srfEmpty.Release(); m_srfImage.Release(); m_Writer.Shutdown(); } //////////////////////////////////////////////////////////////// // Updating //////////////////////////////////////////////////////////////// // OnFlip() // Application main loop void CFirstDieselApp::OnFlip() { m_srfBack.BltFast(0, 0, &m_srfImage, NULL, 0); m_Writer.WriteText(0, 0, &m_srfBack, "Hello World! from\nDieselEngine application.", DE_BLTSRCCOLORKEY); m_srfBack.BltFast(0, 0, &m_srfEmpty, NULL, DE_BLTHALFALPHA); static float fX = 0.0f; static float fSpeed = 50.0f; // moving 50 pixels per second m_srfBack.BltFast((int)fX, 150, &m_srfColorKey, NULL, DE_BLTSRCCOLORKEY); fX += fSpeed * m_fFrameTime; if (fX > m_srfBack.GetWidth() - m_srfColorKey.GetWidth()) { fX = (float)(m_srfBack.GetWidth() - m_srfColorKey.GetWidth()); fSpeed = -fSpeed; } else if (fX < 0.0f) { fX = 0.0f; fSpeed = -fSpeed; } static float fAngle = 0.0f; m_srfBack.BltRotate( m_srfBack.GetWidth() / 2, m_srfBack.GetHeight() / 2, &m_srfEmpty, fAngle, m_srfEmpty.GetWidth(), DE_BLTHALFALPHA ); fAngle += PI * m_fFrameTime; // m_fFrameTime member is time elapsed since last frame in seconds // so, if m_fFrameTime is 0.05, application is running on 20 fps // use the 'GetFps' function to retreive the current frames per second // m_fFrameTime is used as multiplier everywhere when timing is needed // it is best to use m_fFrameTime to all timing issues. Therefore // it is easy to slow down or accelerate the whole application. // m_dwTimeGetTimeVal is a value returned by timeGetTime() windows // function. } ////////////////////////////////////////////////////////////////////// // Overrided Message handlers ////////////////////////////////////////////////////////////////////// void CFirstDieselApp::OnKeyDown(DWORD dwKey) { // TODO: Add your handler code here... if (dwKey == VK_RETURN) { Shutdown(); } }

Additional DieselGraphics features

CDieselSurface class has a lot more features than I showed here. One very handy feature is automatic sub-frame system, which simplifies drawing animated sprites when all animation frames are stored in one surface. There are also more blitting functions, like Fade, AlphaBlend and their RGB counterparts. I won't go into details here, now you should have enough information to experiment with them by yourself. Remember, the DieselEngine SDK example programs are the best reference for DieselEngine programming, and SDK documentation also contains lots of useful information.

DieselGraphics has higher-level classes, like sprites and particle systems, and they all are basically build on top of IDieselApplication and CDieselSurface operations. For now sprites and particle systems are out of this articles scope, but if you would like to have an article specialising into them, please let me know.

That's it for now, Next time we're going to Startup the CDiesel3DDevice object, and you'll notice that using 3D graphics has never been easier.

Related resources:

Discuss

Discuss this article. Here you can write your comments and read comments of other developers.
Rate this article:     Poor Excellent    
 12345 
© 2001-2005 Pocket PC Developer Network, a division of Spb Software House