Programming animation on Series 60 can be seen from two perspectives: using an animation DLL framework, or using client-side application code. Dedicated animation classes are provided as part of the platform and can be used to create a DLL to perform the animation inside a server. However, this approach is not suitable in all cases. Performing animation "client-side" (in application code) is at times preferable.

When all of the images that comprise the animation have been predetermined, then it is relatively simple to employ the DLL animation architecture. The CAknBitmapAnimation provides support for this. A bitmap animation DLL is provided as part of Series 60, and access to it is wrapped up inside CAknBitmapAnimation .

If the image to be displayed can dynamically change during program execution, then a client-side approach is best. An example of using an Animation Server might be the repeated animation of a corporate logo, while a client code example could be displaying the collision of objects in a game. Client-side animation uses double buffering to ensure that the animation does not suffer from flicker during redraws, and it requires an understanding of Active Objects.

The Animation Architecture

Employing the animation architecture directly can be quite complex, requiring the implementation of a specific DLL for each desired animation. The main advantage of this approach is that the animation is able to run within the thread of the Window Server. As this is a high-priority thread, performance benefits are guaranteed . Client-side approaches must use Active Objects, which will not enjoy the priority advantages afforded by the thread of the Window Server.

The provided animation classes use a Client/Server mechanism in order to animate, with the client and server being wrapped up inside the DLL. The client in this case should not be confused with the alternative "client-side" approach.

Animation clients should derive from the RAnim class and are used to pass the Animation Server relevant information, such as the number of frames per second. Deriving from RAnimDLL provides the DLL interface. On the server side, CAnim -derived classes must be implemented to perform the animation, with CAnimDLL being used for the DLL interface.

Implementing your own animation DLL is beyond the scope of this chapter, however the SDK documentation provides an in-depth explanation of the key animation classes and how to use them. An example can also be found in the directory \Series60Ex\Animation in the root of your SDK.

In truth, there is no real need to implement a DLL for animating bitmaps, as the CAknBitmapAnimation class (as used in the Animation example) provides an interface to an animation DLL ”you need only provide it with some images and attribute data.

The simplest way to use the CAknBitmapAnimation class is to define its relevant parts inside a resource file and then initialize the class with this data. Three essential resources are needed to construct an animation: the bitmap animation data ( BMPANIM_DATA ), an array of bitmap frames ( ARRAY ), and the individual bitmap frames themselves (BMPANIM_FRAME ). Table 11-10 lists the elements of the STRUCT definitions from the Avkon.rh file. ARRAY is ignored, as it is generic and not specific to animation as such. Resource files are covered in more detail in Chapter 5.

Table 11-10. Animation Resource Components


Element Type

Element Name





Delay between frames.



Three playmodes ” see \epoc32\include\avkon.hrh in the root directory of your SDK:

Play ” play once.

Cycle ” repeat from the first frame to the last.

Bounce ” play the first frame to the last and then back down to the first, repeatedly.



Causes the animation to flash, or not, while playing.



The .mbm file containing the animation frame.



Reference to the ARRAY resource of BMPANIM_FRAME definitions.



Reference to the background frame definitions.




Time that frame is displayed for.


posx x

x coordinate of top left of frame.


posy y

Y coordinate of top left of frame.



ID (from the .mbg file) of the desired bitmap from the .mbm file for this frame.



ID (from the .mbg file) of the desired masking bitmap from .mbm file for this frame.

The following resource structures show part of the concrete implementation from the Animation example. However, it should be noted that all elements do not have to be assigned values for the resource to be valid:

 RESOURCE BMPANIM_DATA r_animation_example_data    {    frameinterval = 50;    playmode = EAknBitmapAnimationPlayModeBounce;    flash = 0;    bmpfile = ANIMATION_BMPFILE_NAME;    frames = r_animation_example_array ;    } RESOURCE ARRAY r_animation_example_array    {    items =       {       BMPANIM_FRAME          {          time = 200;          bmpid = EMbmAnimationDisplayimageframe1;          },       ...       BMPANIM_FRAME          {          time = 1000;          bmpid = EMbmAnimationDisplaytextframe;          }       };    } 

The animation control can be fully constructed via the resource and started as shown here:

[View full width]
[View full width]
// instantiate CAknBitmapAnimation iAnimation = CAknBitmapAnimation::NewL(); TResourceReader reader; iCoeEnv->CreateResourceReaderLC(reader, R_ANIMATION_EXAMPLE_DATA); // map resource to resource reader // provide animation control with animation data iAnimation->ConstructFromResourceL(reader); // animation control needs a window iAnimation->SetContainerWindowL(*this); iAnimation->StartAnimationL(); // start animation CleanupStack::PopAndDestroy(); // resource reader created

Initially the CAknBitmapAnimation object is created. However, it does not contain any data relating to the animation itself ”as the animation has been defined in a resource file, you need to read in the resource, and this is achieved by creating a TResourceReader object pointing to the animation resource.

The CAknBitmapAnimation::ConstructFromResourceL() can then be used to provide the animation data to the animation control. A window to draw to is required by the animation control, and this is assigned through the SetContainerWindowL() function in the Animation example application.

Should you choose to write your own CAknBitmapAnimation -derived class, then there is also the option of the animation control being "window-owning" by calling the CreateWindowL() function. The animation can be started and stopped by using the StartAnimationL() and CancelAnimation() methods , respectively.

Practical use of CAknBitmapAnimation can be found throughout Series 60, as it is employed by numerous user interface controls, such as CAknNoteControl and CAknQueryControl .

Off-Screen Bitmaps and Double Buffering

Often, when programming animations, you do not have a set of predefined bitmaps, and you have to construct each animation frame in code. Before you can display the new frame on the screen, you need to clear the previous one. If you are using the system graphics context, clearing and then constructing each frame, then there is a high probability that the resulting animation will flicker. This is a common problem on all computing platforms, because screens are continually refreshed, and a refresh may take place while the frame has been cleared, or is currently being constructed.

In order to overcome this, the technique of double buffering is employed ”creating a bitmap within memory and using it to "build up" the next animation frame off screen. Then, when it is fully "prepared," it is quickly drawn to the screen in one go. The three key areas of graphics devices, graphics contexts and bitmaps are interwoven in order to implement double buffering on Series 60.

Recalling earlier discussions relating to graphics devices, the "device" being drawn to here is an in-memory bitmap. An ideal choice for this class is the CFbsBitmapDevice , which enables a bitmap managed by the Font and Bitmap Server to act as a graphics device. Consequently, this requires an associated bitmap to be provided. The bitmap device also has to provide client code with its graphics context using the CreateContext() function. Note that the CDoubleBufferedArea class is not part of Series 60 and has been written for illustration purposes as part of this text.

 void CDoubleBufferedArea::ConstructL(TSize aSize, TDisplayMode aDisplayMode)    {    // Constructing off-screen play area:    // create in memory/offscreen bitmap    iAreaBitmap = new (ELeave) CFbsBitmap();    // set size and display mode of bitmap    iAreaBitmap->Create(aSize, aDisplayMode);    // create bitmap device    iAreaBitmapDevice = CFbsBitmapDevice::NewL(iAreaBitmap);    // create graphics context for drawing to bitmap}    iAreaBitmapDevice->CreateContext(iAreaBitmapContext);    } 

Now, using the graphics context of the bitmap device, it is possible to perform all of the graphics operations illustrated throughout this chapter, such as rendering shapes , text and bitmaps. However, rather than being drawn to the screen, they are now being drawn to the bitmap in memory:

 iDoubleBufferedArea->GetDoubleBufferedAreaContext().Clear(); TRgb colorBlack = AKN_LAF_COLOR(KColorBlack); iDoubleBufferedArea->GetDoubleBufferedAreaContext().SetBrushColor(colorBlack); iDoubleBufferedArea->GetDoubleBufferedAreaContext().DrawRect(Rect()); ... 

As a final step, you blit the off-screen bitmap using the screen's graphics context:

 ... gc.BitBlt(TPoint(0,0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap())); ... 

There is now no danger of drawing to the screen while the next frame is still being "prepared," as this has all taken place in memory.

The Client-Side Approach to Animation

If you want to perform double-buffered animation within application code, a dedicated drawing function and timing mechanism are essential. In the ClientAnimation example, as with all of the other examples, drawing takes place within a CCoeControl -derived class.

Potentially, CCoeControl::DrawNow() could be repeatedly called via a timing mechanism. This would in turn call CCoeControl::Draw() , within which the animation code would be implemented. However, the motivation for providing a separate dedicated drawing function is that if you choose not to use a CCoeControl in your own implementation, the example is still relevant.

 void CClientAnimationContainer::DrawFrame()    {    Window().Invalidate(Rect());    ActivateGc();    Window().BeginRedraw(Rect());    DrawToDoubleBufferedArea();    CWindowGc& gc = SystemGc();    gc.BitBlt(TPoint(0, 0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap()));    Window().EndRedraw();    DeactivateGc();    } 

When using your own draw function instead of the CCoeControl::Draw() function, some extra housekeeping operations are required. Recalling that the Window Server redraws invalid regions of windows , the area to be drawn to must be invalidated before redrawing can begin. Following this, the system graphics context has to be activated so that an object exists, with which drawing can actually take place.

Before drawing commences, the Window Server is informed that an attempt is being made to draw to a portion of the screen by calling the RWindow::BeginRedraw() function. This has the effect of setting the Window Server to clip drawing to the area passed into BeginRedraw() . Drawing can now take place as normal, remembering that in this example drawing takes place to the off-screen bitmap. The off-screen bitmap is then drawn to the screen. Before deactivating the graphics context, RWindow::EndRedraw() is called to inform the Window Server it can clean up objects it created for the redraw process.

If ActivateGc() has been called and is called again, without a previous call to DeActivateGc() , a panic will occur.

In order to perform animation you need to repeatedly call the redraw function, and for this a timer is necessary. The most suitable and easy to use timer, for this task, is the CPeriodic timer:

[View full width]
[View full width]
// function definition from CPeriodic class in e32base.h IMPORT_C void Start(TTimeIntervalMicroSeconds32 aDelay, TTimeIntervalMicroSeconds32 anInterval, TCallBack aCallBack);

Upon starting the timer, a callback function and two time intervals are passed in. The first time interval is the delay from the calling of the CPeriodic::Start() function to the calling of the callback function for the first time:

[View full width]
[View full width]
// function use in ClientAnimation example application iTimer->Start(0, KAnimFrameTime, TCallBack(CClientAnimationContainer::AnimationCallback, this));

The timer will then repeatedly invoke the callback function with a delay of the second interval specified, until it is stopped ”calling the CPeriodic::Cancel() function stops the timer. By making the callback call your redraw function, animation occurs:

 // Callback function used to call DrawFrame() TInt CClientAnimationContainer::AnimationCallback(TAny* aPtr)    {    ((CClientAnimationContainer*)aPtr)->DrawFrame();    // returning 1 ensures the callback function    // is repeatedly called    return 1;    } 

Note that there are numerous ways to implement the timing mechanism, not just by using CPeriodic . An alternative approach might be to derive from CTimer and in the overridden RunL() function perform the necessary drawing. This alternative approach is used in the subsequent Direct Screen Access example game, Skiing .

CPeriodic is itself derived from CTimer . More traditional approaches, such as using a while loop with a time checking and waiting mechanism, are greatly discouraged. The Series 60 View Server has been designed to detect and terminate unresponsive applications. Animating via a while loop, even for a relatively short period of time, will result in the View Server considering your application to be unresponsive , causing it to panic and close your application. By using the system timing classes outlined, which are Active Objects, you avoid this problem.

Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139 © 2008-2017.
If you may any questions please contact us: