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

SpriteEngine.cpp

Go to the documentation of this file.
00001 /*********************************************************************************
00002  *
00003  * Razor! Engine - A modular C++ presentation engine
00004  *
00005  * $Id: SpriteEngine.cpp,v 1.1.1.1 2000/12/09 09:28:40 christ Exp $
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 #include "SpriteEngine.h"
00028 #include "SoundEngine.h"        // Needed for invocations of SoundEngine::timeTick()
00029 
00030 
00031 AnimFrames::AnimFrames(UInt16 numFrames, DmResID bitmapID, DmResID maskID, Coord hotSpotX, Coord hotSpotY, OptimizationMode optimizationMode)
00032 {
00033     this->numFrames = numFrames;
00034     this->bitmapID  = bitmapID;
00035     this->maskID    = maskID;
00036     this->hotSpotX  = hotSpotX;
00037     this->hotSpotY  = hotSpotY;     
00038     this->optimizationMode = optimizationMode;
00039 
00040     // Determine width/height
00041     MemHandle resH = DmGetResource( bitmapRsc, bitmapID );
00042     ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00043     BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00044 
00045     this->width  = resP->width;
00046     this->height = resP->height;
00047 
00048     MemPtrUnlock(resP);
00049     DmReleaseResource( resH );
00050 
00051 
00052     /////////////////////////////
00053     // Prepare optimized images
00054     /////////////////////////////
00055     frameDescriptors = new FrameDescriptor[numFrames];
00056     
00057         
00058     switch(optimizationMode)
00059     {
00060     case AnimFrames::optBUFFER:
00061         {
00062         WinHandle oldDrawH = WinGetDrawWindow();
00063         UInt16 error = errNone;
00064 
00065         for (int frameIdx = 0; frameIdx < numFrames; frameIdx++)
00066         {
00067             {
00068                 // Paint sprite-bitmap to offscreen window
00069                 MemHandle resH = DmGetResource( bitmapRsc, bitmapID + frameIdx);
00070                 ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00071                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00072 
00073                 frameDescriptors[frameIdx].offScreenBitmap = WinCreateOffscreenWindow(resP->width, resP->height, screenFormat, &error);
00074                 WinSetDrawWindow(frameDescriptors[frameIdx].offScreenBitmap);
00075                 WinDrawBitmap (resP, 0,0);
00076 
00077                 MemPtrUnlock(resP);
00078                 DmReleaseResource( resH );
00079             }
00080 
00081             {
00082                 // Paint sprite-mask to offscreen window
00083                 MemHandle resH = DmGetResource( bitmapRsc, maskID + frameIdx);
00084                 ErrNonFatalDisplayIf( !resH, "Missing mask" );
00085                 BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00086 
00087                 frameDescriptors[frameIdx].offScreenMask = WinCreateOffscreenWindow(resP->width, resP->height, screenFormat, &error);
00088                 WinSetDrawWindow(frameDescriptors[frameIdx].offScreenMask);
00089                 WinDrawBitmap (resP, 0,0);
00090                 MemPtrUnlock(resP);
00091                 DmReleaseResource( resH );              
00092             }
00093         }
00094 
00095         WinSetDrawWindow(oldDrawH);
00096         }           
00097         break;
00098         
00099     case AnimFrames::optNONE:
00100     case AnimFrames::optNO_MASK:
00101         for (int frameIdx = 0; frameIdx < numFrames; frameIdx++)
00102         {
00103             frameDescriptors[frameIdx].offScreenBitmap = NULL;
00104             frameDescriptors[frameIdx].offScreenMask   = NULL;
00105         }       
00106         break;
00107     }
00108 }
00109 
00110 
00111 AnimFrames::~AnimFrames()
00112 {
00113     for (int frameIdx = 0; frameIdx < numFrames; frameIdx++)
00114     {
00115         if (frameDescriptors[frameIdx].offScreenBitmap != NULL)
00116         {
00117             WinDeleteWindow(frameDescriptors[frameIdx].offScreenBitmap, false);
00118         }
00119 
00120         if (frameDescriptors[frameIdx].offScreenMask != NULL)
00121         {
00122             WinDeleteWindow(frameDescriptors[frameIdx].offScreenMask, false);
00123         }
00124     }
00125 
00126     delete[] frameDescriptors;
00127 }
00128 
00129 
00130 void AnimFrames::getBounds(Coord x, Coord y, RectangleType *bounds) const
00131 {
00132     ErrNonFatalDisplayIf(bounds == NULL, "getBounds: bounds == NULL");
00133     
00134     bounds->topLeft.x = x - hotSpotX;
00135     bounds->topLeft.y = y - hotSpotY;
00136     bounds->extent.x = width;
00137     bounds->extent.y = height;
00138 }
00139 
00140 
00141 void AnimFrames::draw(UInt16 index, Coord x, Coord y, RectangleType *bounds) const
00142 {
00143     UInt16 error;
00144         
00145     WinHandle drawWindow = WinGetDrawWindow();
00146 
00147     switch(optimizationMode)
00148     {
00149     case AnimFrames::optBUFFER:
00150     case AnimFrames::optNO_MASK:
00151         quickDraw(index, x, y, drawWindow, NULL, bounds);
00152             
00153         break;
00154 
00155     case AnimFrames::optNONE:
00156         WinHandle offScreenH = WinCreateOffscreenWindow(width, height, screenFormat, &error);
00157         WinSetDrawWindow(offScreenH);
00158         quickDraw(index, x, y, drawWindow, offScreenH, bounds);
00159         WinSetDrawWindow(drawWindow);
00160         WinDeleteWindow(offScreenH, false);
00161 
00162         break;
00163     }
00164 }
00165 
00166 
00167 void AnimFrames::quickDraw(UInt16 index, Coord x, Coord y, WinHandle drawWindow, WinHandle offScreenH, RectangleType *bounds) const
00168 {
00169     if (bounds != NULL)
00170         getBounds(x, y, bounds);
00171 
00172     RectangleType size;
00173     size.topLeft.x = 0;
00174     size.topLeft.y = 0;
00175     size.extent.x = width;
00176     size.extent.y = height;         
00177         
00178         
00179     switch(optimizationMode)
00180     {
00181     case AnimFrames::optBUFFER:
00182         // The fast drawing code...     
00183         
00184         WinCopyRectangle(frameDescriptors[index].offScreenMask, drawWindow, &size, x - hotSpotX, y - hotSpotY, winMask);
00185         SoundEngine::timeTick();
00186         WinCopyRectangle(frameDescriptors[index].offScreenBitmap, drawWindow, &size, x - hotSpotX, y - hotSpotY, winOverlay);
00187         SoundEngine::timeTick();
00188         
00189         break;  
00190 
00191     case AnimFrames::optNONE:
00192         // The slow drawing code...
00193         {
00194             // Paint sprite-mask to offscreen window
00195             MemHandle resH = DmGetResource( bitmapRsc, maskID + index);
00196             ErrNonFatalDisplayIf( !resH, "Missing mask" );
00197             BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00198 
00199             WinDrawBitmap (resP, 0,0);
00200 
00201             MemPtrUnlock(resP);
00202             DmReleaseResource( resH );              
00203 
00204             WinCopyRectangle(offScreenH, drawWindow, &size, x - hotSpotX, y - hotSpotY, winMask);
00205     
00206             SoundEngine::timeTick();
00207         }
00208             
00209         {
00210             // Paint sprite-overlay over the masked-out area
00211             MemHandle resH = DmGetResource( bitmapRsc, bitmapID + index);
00212             ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00213             BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00214 
00215             WinDrawBitmap (resP, 0,0);
00216 
00217             MemPtrUnlock(resP);
00218             DmReleaseResource( resH );
00219 
00220             WinCopyRectangle(offScreenH, drawWindow, &size, x - hotSpotX, y - hotSpotY, winOverlay);
00221 
00222             SoundEngine::timeTick();    
00223         }
00224         
00225         break;
00226             
00227             
00228     case AnimFrames::optNO_MASK:
00229         {
00230             MemHandle resH = DmGetResource( bitmapRsc, bitmapID + index);
00231             ErrNonFatalDisplayIf( !resH, "Missing bitmap" );
00232             BitmapType* resP = (BitmapPtr)MemHandleLock(resH);
00233 
00234             WinDrawBitmap (resP, x - hotSpotX, y - hotSpotY);
00235 
00236             MemPtrUnlock(resP);
00237             DmReleaseResource( resH );
00238 
00239             SoundEngine::timeTick();    
00240         }   
00241     }
00242 }
00243 
00244 
00245 AnimFrames::OptimizationMode AnimFrames::getOptimizationMode() const
00246 {
00247     return optimizationMode;
00248 }
00249 
00250 
00251 
00252 
00253 Sprite::Sprite(DmResID bitmapID, DmResID maskID, Coord hotSpotX, Coord hotSpotY, Boolean visible, AnimFrames::OptimizationMode optimizationMode)
00254 {
00255     animFrames = new AnimFrames(1, bitmapID, maskID, hotSpotX, hotSpotY, optimizationMode);
00256     ownsAnimFrames = true;
00257 
00258     this->visible  = visible;
00259     move(0,0);
00260     setFrame(0);
00261 }
00262     
00263 
00264 Sprite::Sprite(AnimFrames& animFrames, Boolean visible)
00265 {
00266     this->animFrames = &animFrames;
00267     ownsAnimFrames = false;
00268     
00269     this->visible = visible;
00270     move(0,0);
00271     setFrame(0);
00272 }
00273     
00274 
00275 Sprite::~Sprite()
00276 {
00277     if (ownsAnimFrames)
00278         delete animFrames;
00279 }
00280 
00281 
00282 void Sprite::show()
00283 {
00284     visible = true;
00285 }
00286 
00287 
00288 void Sprite::hide()
00289 {
00290     visible = false;
00291 }
00292 
00293 
00294 Boolean Sprite::setVisibility(Boolean visible)
00295 {
00296     Boolean oldVisible = visible;
00297     this->visible = visible;
00298         
00299     return oldVisible;
00300 }
00301 
00302 
00303 Boolean Sprite::isVisible() const
00304 {
00305     return visible;
00306 }
00307 
00308 
00309 void Sprite::setFrame(UInt16 frameIndex)
00310 {
00311     this->frameIndex = frameIndex;
00312 }
00313 
00314 
00315 void Sprite::move(Coord x, Coord y)
00316 {
00317     this->x = x;
00318     this->y = y;
00319 }
00320 
00321 
00322 void Sprite::draw(RectangleType *bounds) const
00323 {
00324     if (!visible)
00325     {
00326         if (bounds != NULL)
00327         {
00328             bounds->topLeft.x = 0;
00329             bounds->topLeft.y = 0;
00330             bounds->extent.x = 0;
00331             bounds->extent.y = 0;
00332         }
00333             
00334         return;
00335     }
00336 
00337     animFrames->draw(frameIndex, x, y, bounds);
00338 }
00339 
00340 
00341 void Sprite::getBounds(RectangleType *bounds) const
00342 {
00343     animFrames->getBounds(x, y, bounds);
00344 }
00345 
00346 
00347 void Sprite::quickDraw(WinHandle drawWindow, WinHandle offScreenH, RectangleType *bounds) const
00348 {
00349     if (!visible)
00350     {
00351         if (bounds != NULL)
00352         {
00353             bounds->topLeft.x = 0;
00354             bounds->topLeft.y = 0;
00355             bounds->extent.x = 0;
00356             bounds->extent.y = 0;
00357         }
00358             
00359         return;
00360     }
00361 
00362 
00363     animFrames->quickDraw(frameIndex, x, y, drawWindow, offScreenH, bounds);
00364 }
00365     
00366 
00367 AnimFrames::OptimizationMode Sprite::getOptimizationMode() const
00368 {
00369     return animFrames->getOptimizationMode();
00370 }
00371 
00372 
00373 
00374 SpriteGroup::SpriteGroup(int maxSprites)
00375 {
00376     ErrNonFatalDisplayIf(maxSprites == 0, "maxSprites == 0");
00377     this->maxSprites = maxSprites;
00378     this->currSprites = 0;
00379     
00380     this->theSprites = new Sprite*[maxSprites];
00381 
00382     this->offscreenH = NULL;
00383     this->maxWidth = 0;
00384     this->maxHeight = 0;
00385     this->oldMaxWidth = -1;
00386     this->oldMaxHeight = -1;
00387     this->needBuffer = false;
00388 }
00389     
00390     
00391 SpriteGroup::~SpriteGroup()
00392 {
00393     delete [] theSprites;
00394         
00395     if (offscreenH != NULL)
00396         WinDeleteWindow(offscreenH, false);
00397 }
00398 
00399 
00400 void SpriteGroup::addSprite(Sprite& sprite)
00401 {
00402     ErrNonFatalDisplayIf(currSprites == maxSprites, "SpriteGroup size exhausted");
00403 
00404     this->theSprites[currSprites] = &sprite;
00405 
00406     // Adjust size of drawing buffer if neccessary
00407     if (sprite.getOptimizationMode() == AnimFrames::optNONE)
00408     {
00409         RectangleType bounds;
00410         sprite.getBounds(&bounds);
00411 
00412         maxWidth  = max(bounds.extent.x, maxWidth);
00413         maxHeight = max(bounds.extent.y, maxHeight);
00414             
00415         needBuffer = true;
00416     }
00417 
00418     currSprites++;
00419 }
00420 
00421 
00422 void SpriteGroup::draw(RectangleType *bounds)
00423 {
00424     if (currSprites == 0)
00425         return;
00426 
00427     WinHandle drawWindow = WinGetDrawWindow();
00428     if (needBuffer)
00429     {
00430         if ((maxWidth != oldMaxWidth) || (maxHeight != oldMaxHeight))
00431         {
00432             if (offscreenH != NULL)
00433             {
00434                 WinDeleteWindow(offscreenH, false);
00435                 offscreenH = NULL;
00436             }
00437             
00438             oldMaxWidth = maxWidth;
00439             oldMaxHeight = maxHeight;
00440             
00441             UInt16 error;
00442             offscreenH = WinCreateOffscreenWindow(maxWidth, maxHeight, screenFormat, &error);
00443         }
00444 
00445         WinSetDrawWindow(offscreenH);
00446     }
00447     
00448 
00449     RectangleType spriteBounds;
00450     for(int i = 0; i < currSprites; i++)
00451     {
00452         this->theSprites[i]->quickDraw(drawWindow, offscreenH, &spriteBounds);
00453         Canvas::uniteBounds(&spriteBounds, bounds, bounds);
00454     }
00455 
00456     if (needBuffer)
00457         WinSetDrawWindow(drawWindow);
00458 }

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