00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 00021 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"
00033
00034
00035 class SpriteGroup;
00036
00037 00038 00039 00040 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 00056 00057 00058 00059 00060 00061 00062 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
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
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
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 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 00156
00157 void show()
00158 {
00159 visible = true;
00160 }
00161
00162 00163 00164 00165
00166 void hide()
00167 {
00168 visible = false;
00169 }
00170
00171 00172 00173 00174 00175 00176
00177 Boolean setVisibility(Boolean visible)
00178 {
00179 Boolean oldVisible = visible;
00180 this->visible = visible;
00181
00182 return oldVisible;
00183 }
00184
00185 00186 00187 00188
00189 Boolean isVisible() const
00190 {
00191 return visible;
00192 }
00193
00194 00195 00196 00197
00198 void move(Coord x, Coord y)
00199 {
00200 this->x = x;
00201 this->y = y;
00202 }
00203
00204 00205 00206 00207 00208 00209 00210 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 00254 00255 00256 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 00275 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
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
00318 {
00319
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
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
00394 friend class SpriteGroup;
00395 };
00396
00397
00398 00399 00400 00401
00402 class SpriteGroup
00403 {
00404 public:
00405
00406 00407 00408 00409 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 00430
00431 ~SpriteGroup()
00432 {
00433 delete [] theSprites;
00434
00435 if (offscreenH != NULL)
00436 WinDeleteWindow(offscreenH, false);
00437 }
00438
00439 00440 00441 00442 00443 00444 00445 00446
00447 void addSprite(Sprite& sprite)
00448 {
00449 ErrNonFatalDisplayIf(currSprites == maxSprites, "SpriteGroup size exhausted");
00450
00451 this->theSprites[currSprites] = &sprite;
00452
00453
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 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