Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members

SpriteEngine.h

Go to the documentation of this file.
00001 /*********************************************************************************
00002  *
00003  * Razor! Engine - A modular C++ presentation engine
00004  *
00005  * $Id$
00006  *
00007  * Copyright (c) 2000 Tilo Christ. All Rights Reserved.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  **********************************************************************************/
00024 
00025 
00026 
00027 #ifndef SPRITE_ENGINE_H
00028 #define SPRITE_ENGINE_H
00029 
00030 #include <PalmOS.h>
00031 #include "Canvas.h"
00032 #include "SoundEngine.h"        // Needed for invocations of SoundEngine::timeTick()
00033 
00034 
00035 class SpriteGroup;
00036 
00037 
00038 /**
00039  * Sprite describes a single sprite, i.e. a movable graphical object
00040  * with a transparent background.
00041  */
00042 class Sprite
00043 {
00044     public:
00045 
00046     enum OptimizationMode
00047     {
00048         optNONE       = 0,
00049         optBUFFER     = 1,
00050         optNO_MASK    = 2
00051     };
00052 
00053     
00054     /**
00055      * Create a Sprite
00056      *
00057      * @param bitmapID the ID of the image bitmap in the resource database.
00058      * @param maskID the ID of the mask bitmap in the resource database.
00059      * @param hotSpotX the horizontal offset of the hotspot.
00060      * @param hotSpotY the vertical offset of the hotspot.
00061      * @param visible shall the sprite be visible?
00062      * @param optimizationMode which optimizations shall be applied?
00063      */
00064     Sprite(DmResID bitmapID, DmResID maskID = -1, Coord hotSpotX = 0, Coord hotSpotY = 0, Boolean visible = true, OptimizationMode optimizationMode = optNONE)
00065     {
00066         this->bitmapID = bitmapID;
00067         this->maskID = maskID;
00068         this->hotSpotX = hotSpotX;
00069         this->hotSpotY = hotSpotY;      
00070         this->visible = visible;
00071         this->optimizationMode = optimizationMode;
00072 
00073         move(0,0);
00074 
00075         switch(optimizationMode)
00076         {
00077         case optBUFFER:
00078             {
00079             WinHandle oldDrawH = WinGetDrawWindow();
00080             UInt16 error = errNone;
00081 
00082             {
00083                 // Paint sprite-bitmap to offscreen window
00084                 MemHandle resH = DmGetResource( bitmapRsc, bitmapID );
00085                 ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00086                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00087 
00088                 this->width = resP->width;
00089                 this->height = resP->height;
00090 
00091                 offScreenBitmap = WinCreateOffscreenWindow(resP->width, resP->height, screenFormat, &error);
00092                 WinSetDrawWindow(offScreenBitmap);
00093                 WinDrawBitmap (resP, 0,0);
00094 
00095                 MemPtrUnlock(resP);
00096                 DmReleaseResource( resH );
00097             }
00098 
00099             {
00100                 // Paint sprite-mask to offscreen window
00101                 MemHandle resH = DmGetResource( bitmapRsc, maskID );
00102                 ErrNonFatalDisplayIf( !resH, "Missing mask" );
00103                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00104 
00105                 offScreenMask = WinCreateOffscreenWindow(resP->width, resP->height, screenFormat, &error);
00106                 WinSetDrawWindow(offScreenMask);
00107                 WinDrawBitmap (resP, 0,0);
00108                 MemPtrUnlock(resP);
00109                 DmReleaseResource( resH );              
00110             }
00111 
00112             WinSetDrawWindow(oldDrawH);
00113             }           
00114             break;
00115         
00116         case optNONE:
00117         case optNO_MASK:
00118             // Lookup Bitmap resource
00119             MemHandle resH = DmGetResource( bitmapRsc, bitmapID );
00120             ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00121             BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00122 
00123             this->width = resP->width;
00124             this->height = resP->height;
00125 
00126             MemPtrUnlock(resP);
00127             DmReleaseResource( resH );
00128 
00129             offScreenBitmap = NULL;
00130             offScreenMask   = NULL;
00131             
00132             break;
00133         }
00134     }
00135     
00136     
00137     /**
00138      * Destroy the Sprite and deallocate all used resources.
00139      */
00140     ~Sprite()
00141     {
00142         if (offScreenBitmap != NULL)
00143         {
00144             WinDeleteWindow(offScreenBitmap, false);
00145         }
00146 
00147         if (offScreenMask != NULL)
00148         {
00149             WinDeleteWindow(offScreenMask, false);
00150         }
00151     }
00152 
00153 
00154     /**
00155      * Show the sprite during subsequent draws.
00156      */
00157     void show()
00158     {
00159         visible = true;
00160     }
00161 
00162 
00163     /**
00164      * Hide the sprite during subsequent draws.
00165      */
00166     void hide()
00167     {
00168         visible = false;
00169     }
00170 
00171 
00172     /**
00173      * Set the visibility of the sprite through a flag.
00174      *
00175      * @param visible shall the sprite be visible (true = shown / false = hidden)
00176      */
00177     Boolean setVisibility(Boolean visible)
00178     {
00179         Boolean oldVisible = visible;
00180         this->visible = visible;
00181         
00182         return oldVisible;
00183     }
00184 
00185 
00186     /**
00187      * Will the sprite be drawn during subsequent draws?
00188      */
00189     Boolean isVisible() const
00190     {
00191         return visible;
00192     }
00193 
00194 
00195     /**
00196      * Move the sprite (i.e. its hotspot) to the specified coordinates.
00197      */
00198     void move(Coord x, Coord y)
00199     {
00200         this->x = x;
00201         this->y = y;
00202     }
00203 
00204 
00205     /**
00206      * Draw the sprite at its current location.
00207      * Inquire the current draw window and allocate draw buffers as neccessary.
00208      *
00209      * @param bounds a pointer to a rectangle which will be filled with the screen space
00210      *        filled by the sprite, or NULL.
00211      */
00212     void draw(RectangleType *bounds = NULL) const
00213     {
00214         if (!visible)
00215         {
00216             if (bounds != NULL)
00217             {
00218                 bounds->topLeft.x = 0;
00219                 bounds->topLeft.y = 0;
00220                 bounds->extent.x = 0;
00221                 bounds->extent.y = 0;
00222             }
00223             
00224             return;
00225         }
00226         
00227     
00228         UInt16 error;
00229         
00230         WinHandle drawWindow = WinGetDrawWindow();
00231 
00232         switch(optimizationMode)
00233         {
00234         case optBUFFER:
00235         case optNO_MASK:
00236             quickDraw(drawWindow, NULL, bounds);
00237             
00238             break;
00239 
00240         case optNONE:
00241             WinHandle offScreenH = WinCreateOffscreenWindow(width, height, screenFormat, &error);
00242             WinSetDrawWindow(offScreenH);
00243             quickDraw(drawWindow, offScreenH, bounds);
00244             WinSetDrawWindow(drawWindow);
00245             WinDeleteWindow(offScreenH, false);
00246 
00247             break;
00248         }
00249     }
00250 
00251 
00252     /**
00253      * Get the screen space filled by the sprite.
00254      *
00255      * @param bounds a pointer to a rectangle which will be filled with the screen space
00256      *        filled by the sprite.
00257      */
00258     void getBounds(RectangleType *bounds) const
00259     {
00260         ErrNonFatalDisplayIf(bounds == NULL, "getBounds: bounds == NULL");
00261     
00262         bounds->topLeft.x = x - hotSpotX;
00263         bounds->topLeft.y = y - hotSpotY;
00264         bounds->extent.x = width;
00265         bounds->extent.y = height;
00266     }
00267 
00268 
00269 
00270     private:
00271 
00272     
00273     /**
00274      * Draw the sprite at its current location into the specified drawWindow 
00275      * and use the specified offScreen buffer for internal drawing operations.
00276      */
00277     void quickDraw(WinHandle drawWindow, WinHandle offScreenH, RectangleType *bounds) const
00278     {
00279         if (!visible)
00280         {
00281             if (bounds != NULL)
00282             {
00283                 bounds->topLeft.x = 0;
00284                 bounds->topLeft.y = 0;
00285                 bounds->extent.x = 0;
00286                 bounds->extent.y = 0;
00287             }
00288             
00289             return;
00290         }
00291         else
00292         {
00293             if (bounds != NULL)
00294                 getBounds(bounds);
00295         }   
00296 
00297         RectangleType size;
00298         size.topLeft.x = 0;
00299         size.topLeft.y = 0;
00300         size.extent.x = width;
00301         size.extent.y = height;         
00302         
00303         
00304         switch(optimizationMode)
00305         {
00306         case optBUFFER:
00307             // The fast drawing code...     
00308         
00309             WinCopyRectangle(offScreenMask, drawWindow, &size, x - hotSpotX, y - hotSpotY, winMask);
00310             SoundEngine::timeTick();
00311             WinCopyRectangle(offScreenBitmap, drawWindow, &size, x - hotSpotX, y - hotSpotY, winOverlay);
00312             SoundEngine::timeTick();
00313         
00314             break;  
00315 
00316         case optNONE:
00317             // The slow drawing code...
00318             {
00319                 // Paint sprite-mask to offscreen window
00320                 MemHandle resH = DmGetResource( bitmapRsc, maskID );
00321                 ErrNonFatalDisplayIf( !resH, "Missing mask" );
00322                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00323 
00324                 WinDrawBitmap (resP, 0,0);
00325 
00326                 MemPtrUnlock(resP);
00327                 DmReleaseResource( resH );              
00328 
00329                 WinCopyRectangle(offScreenH, drawWindow, &size, x - hotSpotX, y - hotSpotY, winMask);
00330     
00331                 SoundEngine::timeTick();
00332             }
00333             
00334             {
00335                 // Paint sprite-overlay over the masked-out area
00336                 MemHandle resH = DmGetResource( bitmapRsc, bitmapID );
00337                 ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00338                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00339 
00340                 WinDrawBitmap (resP, 0,0);
00341 
00342                 MemPtrUnlock(resP);
00343                 DmReleaseResource( resH );
00344 
00345                 WinCopyRectangle(offScreenH, drawWindow, &size, x - hotSpotX, y - hotSpotY, winOverlay);
00346 
00347                 SoundEngine::timeTick();    
00348             }
00349         
00350             break;
00351             
00352             
00353         case optNO_MASK:
00354             {
00355                 MemHandle resH = DmGetResource( bitmapRsc, bitmapID );
00356                 ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00357                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00358 
00359                 WinDrawBitmap (resP, x - hotSpotX, y - hotSpotY);
00360 
00361                 MemPtrUnlock(resP);
00362                 DmReleaseResource( resH );
00363 
00364                 SoundEngine::timeTick();    
00365             }   
00366         }
00367     }
00368     
00369 
00370     OptimizationMode getOptimizationMode() const
00371     {
00372         return optimizationMode;
00373     }
00374 
00375 
00376 
00377     DmResID bitmapID;
00378     DmResID maskID;
00379     Coord hotSpotX;
00380     Coord hotSpotY;
00381     Int16 width;
00382     Int16 height;
00383     Boolean visible;
00384     OptimizationMode optimizationMode;
00385 
00386     WinHandle offScreenBitmap;
00387     WinHandle offScreenMask;
00388     
00389     Coord x;
00390     Coord y;
00391 
00392 
00393     // Ain't it nice to have friends...
00394     friend class SpriteGroup;
00395 };
00396 
00397 
00398 
00399 /**
00400  * SpriteGroup assists in the management of a collection of sprites.
00401  */
00402 class SpriteGroup
00403 {
00404     public:
00405     
00406     
00407     /**
00408      * Create the SpriteGroup. The group may contain up to maxSprites Sprites.
00409      * @param maxSprites the maximum number of managed sprites
00410      */
00411     SpriteGroup(int maxSprites)
00412     {
00413         ErrNonFatalDisplayIf(maxSprites == 0, "maxSprites == 0");
00414         this->maxSprites = maxSprites;
00415         this->currSprites = 0;
00416         
00417         this->theSprites = new Sprite*[maxSprites];
00418 
00419         this->offscreenH = NULL;
00420         this->maxWidth = 0;
00421         this->maxHeight = 0;
00422         this->oldMaxWidth = -1;
00423         this->oldMaxHeight = -1;
00424         this->needBuffer = false;
00425     }
00426     
00427     
00428     /**
00429      * Destroy the SpriteGroup and deallocate all used resources.
00430      */
00431     ~SpriteGroup()
00432     {
00433         delete [] theSprites;
00434         
00435         if (offscreenH != NULL)
00436             WinDeleteWindow(offscreenH, false);
00437     }
00438 
00439 
00440     /**
00441      * Add a sprite to the group.
00442      *
00443      * @param sprite a reference to the sprite. Ownership of the sprite will remain
00444      *        with the caller, i.e. SpriteGroup will not destroy the sprite when the
00445      *        group is destroyed.
00446      */
00447     void addSprite(Sprite& sprite)
00448     {
00449         ErrNonFatalDisplayIf(currSprites == maxSprites, "SpriteGroup size exhausted");
00450 
00451         this->theSprites[currSprites] = &sprite;
00452 
00453         // Adjust size of drawing buffer if neccessary
00454         if (sprite.getOptimizationMode() == Sprite::optNONE)
00455         {
00456             RectangleType bounds;
00457             sprite.getBounds(&bounds);
00458 
00459             maxWidth  = max(bounds.extent.x, maxWidth);
00460             maxHeight = max(bounds.extent.y, maxHeight);
00461             
00462             needBuffer = true;
00463         }
00464 
00465         currSprites++;
00466     }
00467 
00468 
00469     /**
00470      * Draw all the sprites in the group.
00471      */
00472     void draw(RectangleType *bounds)
00473     {
00474         if (currSprites == 0)
00475             return;
00476 
00477         WinHandle drawWindow = WinGetDrawWindow();
00478         if (needBuffer)
00479         {
00480             if ((maxWidth != oldMaxWidth) || (maxHeight != oldMaxHeight))
00481             {
00482                 if (offscreenH != NULL)
00483                 {
00484                     WinDeleteWindow(offscreenH, false);
00485                     offscreenH = NULL;
00486                 }
00487             
00488                 oldMaxWidth = maxWidth;
00489                 oldMaxHeight = maxHeight;
00490             
00491                 UInt16 error;
00492                 offscreenH = WinCreateOffscreenWindow(maxWidth, maxHeight, screenFormat, &error);
00493             }
00494 
00495             WinSetDrawWindow(offscreenH);
00496         }
00497     
00498 
00499         RectangleType spriteBounds;
00500         for(int i = 0; i < currSprites; i++)
00501         {
00502             this->theSprites[i]->quickDraw(drawWindow, offscreenH, &spriteBounds);
00503             Canvas::uniteBounds(&spriteBounds, bounds, bounds);
00504         }
00505 
00506         if (needBuffer)
00507             WinSetDrawWindow(drawWindow);
00508     }
00509 
00510 
00511     private:
00512 
00513     int maxSprites;
00514     int currSprites;
00515     Sprite* *theSprites;
00516     
00517     WinHandle offscreenH;
00518     int maxWidth;
00519     int maxHeight;
00520     int oldMaxWidth;
00521     int oldMaxHeight;
00522     Boolean needBuffer;
00523 };
00524 
00525 
00526 
00527 #endif

Razor! Engine Developer's Guide. Copyright © by Tilo Christ. All Rights Reserved. Last updated: 4 Nov 2000