Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

spritemanager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           spritemanager.cpp  -  description
00003                              -------------------
00004     begin                : Fri Mar 7 2003
00005     copyright            : (C) 2003 by Tyler Montbriand
00006     email                : tsm@accesscomm.ca
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 #include <string.h>
00018 #include <stdlib.h>
00019 #include "spritemanager.h"
00020 #include "ticktimer.h"
00021 #include "spriteloader.h"
00022 
00029 
00034 int SpriteManager::Event(int code, void *data1, void *data2)
00035 { return(0); }
00036 
00041 void SpriteManager::Handler(SDL_Event *event)
00042 { }
00043 
00048 void SpriteManager::Idle()
00049 { }
00050 
00051 
00056 SpriteManager::SpriteManager(Uint16 w, Uint16 h, Uint8 depth, Uint32 vflags)
00057 {
00058   flag=SM_TOTALREDRAW|SM_OWNBG;  
00059 
00060   lock=SDL_CreateMutex();
00061 
00062   if(!SDL_WasInit(SDL_INIT_VIDEO))
00063     if(SDL_InitSubSystem(SDL_INIT_VIDEO)<0)
00064     {
00065       fprintf(stderr,"Warning, couldn't initialize SDL video\n");
00066     }
00067 
00068   if(vflags&SDL_DOUBLEBUF)
00069   {
00070     fprintf(stderr,"SDL_DOUBLEBUF flag detected, using fullscreen flips\n");
00071     flag|=SM_DOUBLEBUF;
00072   }
00073 
00074   screen=SDL_SetVideoMode(w,h,depth,SDL_ANYFORMAT|vflags);
00075 
00076   if(screen==NULL)
00077   {
00078     fprintf(stderr,"SpriteManager::SpriteManager(%d,%d,%d,%d)\n",w,h,depth,vflags);
00079     fprintf(stderr,"Warning - can't set video mode!\n");
00080   }
00081 
00082   bg=SDL_DisplayFormat(screen);
00083 
00084   if(bg==NULL)
00085   {
00086     fprintf(stderr,"Error - can't create background!\n");
00087   }
00088 }
00089 
00093 void SpriteManager::DrawOnBG(SDL_Surface *src, SDL_Rect *srcrect, SDL_Rect *destrect)
00094 {
00095   Lock();
00096 
00097   SDL_BlitSurface(src,srcrect,bg,destrect);
00098 
00099   flag|=SM_TOTALREDRAW;
00100 
00101   Unlock();
00102 }
00103 
00107 void SpriteManager::SendEvent(int code, void *data1, void *data2)
00108 {
00109   Sprite *spr=sprites.Head();
00110 
00111   while(spr!=NULL)
00112   {
00113     spr->Event(code,data1,data2);
00114     spr=spr->next;
00115   }
00116 }
00117 
00125 SMRun_Return SpriteManager::Run(Sint32 frametick, Sint32 gametick)
00126 {
00127   TickTimer frame,game;
00128   bool drawn=false;
00129 
00130   flag|=SM_RUNNING;
00131   frame.Reset();
00132   game.Reset();
00133 
00134   if((frametick<=0)||(gametick<=0))
00135     return(SMRUN_TIMESTEP);
00136 
00137   while(flag&SM_RUNNING)
00138   {
00139     SDL_Event event;
00140     while(SDL_PollEvent(&event))
00141       switch(event.type)
00142       {
00143       case SDL_QUIT:  /* Break the game loop on SDL_QUIT  */
00144         flag&=~SM_RUNNING;
00145         break;
00146 
00147       case SDL_USEREVENT:
00148         /* Pass SDL_USEREVENTs along to the virtual Event function  */
00149         if(!Event(event.user.code,event.user.data1,event.user.data2))
00150         {
00151           /* If Event() returns zero, pass the event to every sprite  */
00152           SendEvent(event.user.code, event.user.data1, event.user.data2);
00153         }
00154         break;
00155 
00156       default:  /* Pass any other events onto the virtual handler function */
00157         Handler(&event);
00158         break;
00159       }
00160 
00161     if(game>=gametick)
00162     { /* If we can't process game ticks fast enough
00163          to keep up with realtime, we've got ourselves
00164          an infinite loop here..  need max_iterations
00165          to break out, in worst case scenario.        */
00166       int max_iterations=(game/gametick)*2;
00167       int iterations=0;
00168       drawn=false;
00169       
00170       while(game>=gametick)
00171       { 
00172         if(iterations>max_iterations) /* Can't keep up with the timer! */
00173           return(SMRUN_TIMESTEP);
00174         
00175         if(!Paused()) Move(gametick);
00176         
00177         game-=gametick;
00178         iterations++;
00179       }
00180     }
00181     else if(frame>=frametick)
00182     {
00183       if(!drawn)
00184       {
00185         drawn=true;
00186         Draw();
00187         Update();
00188         Preserve();
00189       }      
00190       frame-=frametick;
00191     }
00192     else
00193     {
00194       Idle();
00195       SDL_Delay(10);
00196     }
00197   }
00198   
00199   return(SMRUN_OK);
00200 }
00201 
00209 SMRun_Return SpriteManager::Run(Sint32 frametick)
00210 {
00211   TickTimer timer;
00212   flag|=SM_RUNNING;  
00213 
00214   if(frametick<=0)
00215     return(SMRUN_TIMESTEP);
00216 
00217   timer.Reset();
00218   /* Run the event loop until SDL_QUIT or enter/return keypress */
00219   while(flag&SM_RUNNING)
00220   {
00221     SDL_Event event;
00222 
00223     while(SDL_PollEvent(&event))/* SDL event loop */
00224     switch(event.type)
00225     {
00226     case SDL_QUIT:  /* Break the game loop on SDL_QUIT  */
00227       flag&=~SM_RUNNING;
00228       break;
00229 
00230     case SDL_USEREVENT:
00231       /* Pass SDL_USEREVENTs along to the virtual Event function  */
00232       if(!Event(event.user.code,event.user.data1,event.user.data2))
00233       {
00234         /* If Event() returns zero, pass the event to every sprite  */
00235         SendEvent(event.user.code, event.user.data1, event.user.data2);
00236       }
00237       break;
00238 
00239     default:  /* Pass any other events onto the virtual handler function */
00240       Handler(&event);
00241       break;
00242     }
00243 
00244     /* If the screen needs updating */
00245     if(timer>=frametick)
00246     {
00247       Draw();
00248       Update();
00249 
00250       if(!Paused()) /* Don't call Move() while paused */
00251       {
00252         Preserve();
00253         while(timer>=frametick)
00254         {        
00255           Move(frametick);
00256           timer-=frametick;
00257         }
00258       }
00259     }
00260     else  /* Screen doesn't need updating */
00261     {
00262       Idle();         /* Call the virtual Idle handler  */
00263       SDL_Delay(10);  /* give time to other processes */
00264     }
00265   }
00266 
00267   return(SMRUN_OK);
00268 }
00269 
00274 void SpriteManager::Preserve()
00275 {
00276   Sprite *spr=sprites.Head();
00277 
00278   while(spr!=NULL)
00279   {
00280     spr->Preserve();
00281     spr=spr->next;
00282   }
00283 }
00284 
00289 SpriteManager::SpriteManager(Uint16 flags,SDL_Surface *screenin,
00290                              const char *bgnd)
00291  :rects(MAX_RECTS)
00292 {
00293   flag=flags|SM_TOTALREDRAW|SM_OWNBG;
00294 
00295   lock=SDL_CreateMutex();
00296 
00297   if(screenin==NULL)
00298   {
00299     screen=SDL_GetVideoSurface();
00300     if(screen==NULL)
00301     {
00302       fprintf(stderr,"Couldn't get video surface!\n");
00303           exit(1);
00304     }
00305 
00306     if(bgnd==NULL)
00307     {
00308       bg=SDL_DisplayFormat(screen);
00309     }
00310     else
00311     {
00312       bg=LoadConvertBMP(bgnd);
00313     }
00314   }
00315   else
00316   {
00317     screen=screenin;
00318 
00319     if(bgnd==NULL)
00320     {
00321       bg=SDL_DisplayFormat(screen);
00322     }
00323     else
00324     {
00325       bg=LoadConvertBMP(bgnd);
00326     }
00327   }
00328 }
00329 
00333 bool SpriteManager::AddSprite(Sprite *spr)
00334 {
00335   bool retval;
00336 
00337   Lock();
00338   retval=sprites.Insert(spr);
00339   Unlock();
00340 
00341   return(retval);
00342 }
00343 
00347 bool SpriteManager::RemoveSprite(Sprite *spr)
00348 {
00349   bool retval;
00350 
00351   Lock();
00352   retval=sprites.Extract(spr);
00353   Unlock();
00354 
00355   return(retval);
00356 }
00357 
00361 void SpriteManager::Draw()
00362 {
00363   /* Redraw whole screen */
00364   if(flag&(SM_TOTALREDRAW|SM_DOUBLEBUF))
00365   {
00366     flag&=~SM_TOTALREDRAW;      /* Turn off total-redraw flag */
00367     SimpleBlit();               /* Draw */
00368   }
00369   else
00370   {
00371     QuadBlit();
00372   }
00373 }
00374 
00378 void SpriteManager::Move(Sint32 dtick)
00379 {
00380   Sprite *spr=NULL;
00381 
00382   Lock(); /* Lock the mutex to prevent simultaneous access  */
00383 
00384   spr=sprites.Head();
00385   while(spr!=NULL)
00386   {
00387     if(spr->Expired())
00388     {
00389       spr=spr->next;
00390       continue;
00391     }
00392     else if(spr->New())
00393     { /*  If the sprite's new, clear the Wait flag
00394           so it will be drawn next frame.           */
00395       spr->ClearFlags(SPRITE_WAIT);
00396       /*  Set the MOVED flag so it will be checked for
00397           collisions against all sprites at least once. */
00398       spr->SetFlags(SPRITE_MOVED);
00399     }
00400     
00401     spr->Update(dtick);     /* Call the virtual update function */
00402 
00403     spr=spr->next;  /* Proceed to next sprite in list */
00404   }
00405 
00406   spr=sprites.Head();
00407   while(spr!=NULL)  /* Loop through every sprite in list  */
00408   {    
00409     Sprite *spr2=spr->next; /* Get next sprite in list  */
00410 
00411     if(spr->Expired())
00412     {
00413       /* Ignore collisions with dead sprites */
00414     }    
00415     else if(spr->Moved())  /* Test against moving and unmoving sprites */
00416     {
00417 
00418       while(spr2!=NULL) /* Loop through portion of list after spr */
00419       {
00420         if(spr2->Expired())
00421         {
00422           /* Ignore collisions with expired sprites */
00423         }
00424         else if(spr->CanCollide(spr2)) /* If the sprites collide */
00425         {
00426           /* Call their virtual collision handler functions */
00427           spr->OnCollide(  spr2,spr2->GetColIndex() );
00428           spr2->OnCollide( spr , spr->GetColIndex() );
00429         }
00430 
00431         spr2=spr2->next;  /* Advance to next sprite in inner loop */
00432       }
00433     }
00434     else /* Only test against moving sprites */
00435     {
00436       while(spr2!=NULL) /* Loop through portion of list after spr */
00437       {
00438         if(spr2->Expired())
00439         {
00440           /* Ignore collisions with expired sprites */
00441         }
00442         else if(spr2->Moved())
00443           if(spr->CanCollide(spr2)) /* If the sprites collide */
00444           {
00445             /* Call their virtual collision handler functions */
00446             spr->OnCollide(  spr2,spr2->GetColIndex() );
00447             spr2->OnCollide( spr , spr->GetColIndex() );
00448           }
00449 
00450 
00451         spr2=spr2->next;  /* Advance to next sprite in inner loop */
00452       }      
00453     }
00454 
00455     spr=spr->next;      /* Advance to next sprite in outer loop */
00456   }
00457 
00458   Unlock(); /*  Unlock the mutex to allow access to the manager */
00459 }
00460 
00461 
00462 
00468 SDL_Surface *SpriteManager::CheckOutBG()
00469 {
00470   Lock();
00471   return(bg);
00472 }
00476 bool SpriteManager::CheckInBG(SDL_Surface *bg_in)
00477 {
00478   if(bg_in==bg)
00479   {
00480     Unlock();
00481     return(true);
00482   }
00483   else
00484   {
00485     return(false);
00486   }
00487 }
00488 
00489 
00490 
00494 SpriteManager::~SpriteManager()
00495 {
00496   Lock(); /* Lock mutex to prevent simultaneous access  */
00497 
00498   /* If the background is freeable */
00499   if((flag&SM_OWNBG)&&(bg!=NULL))
00500   {
00501     SDL_FreeSurface(bg);  /* Free the background surface */
00502   }
00503   
00504   SDL_DestroyMutex(lock); /* Destroy the mutex itself */
00505 }

Generated on Sat Oct 11 13:19:26 2003 for Spritelib by doxygen 1.3.4