1 /******************************************************************* 2 * 3 * DESCRIPTION: Daemon code - things that need to be updated on a 4 * per-frame basis provided they are "active" 5 * AUTHOR: David Malcolm 6 * 7 * HISTORY: 8 * 9 *******************************************************************/ 10 11 /* Includes ********************************************************/ 12 #include "3dc.h" 13 #include "daemon.h" 14 15 #include "inline.h" 16 17 #if SupportCallbackHooks 18 #include "scrobj.hpp" 19 #endif 20 21 #define UseLocalAssert Yes 22 #include "ourasert.h" 23 24 /* Constants *******************************************************/ 25 #define UseRealFrameTime Yes 26 27 /* Imported function prototypes ************************************/ 28 29 /* Imported data ***************************************************/ 30 #ifdef __cplusplus 31 extern "C" 32 { 33 #endif 34 #if 0 35 extern OurBool DaveDebugOn; 36 extern FDIEXTENSIONTAG FDIET_Dummy; 37 extern IFEXTENSIONTAG IFET_Dummy; 38 extern FDIQUAD FDIQuad_WholeScreen; 39 extern FDIPOS FDIPos_Origin; 40 #endif 41 #ifdef __cplusplus 42 }; 43 #endif 44 45 46 /* Internal function prototypes ************************************/ 47 48 /* Exported globals ************************************************/ 49 /*static*/ int Daemon :: DaemonTimeScale = ONE_FIXED; 50 51 #if !IndividualTiming 52 /*static*/ int Daemon :: FixP_Time = 0; 53 #endif 54 55 /* Internal globals ************************************************/ 56 // static 57 Daemon* Daemon :: p666_FirstActive = NULL; 58 // static 59 Daemon* Daemon :: p666_Iteration_Current = NULL; 60 // static 61 Daemon* Daemon :: p666_Iteration_Next = NULL; 62 63 /* Exported function definitions ***********************************/ 64 #if SupportCallbackHooks 65 // class CallbackHook CallbackHook(Daemon * p666_New,void * pUser_New)66CallbackHook :: CallbackHook 67 ( 68 Daemon* p666_New, 69 void* pUser_New 70 ) 71 { 72 if ( p666_New -> pFirstHook ) 73 { 74 GLOBALASSERT( p666_New -> pFirstHook -> pPrvHook == NULL); 75 p666_New -> pFirstHook -> pPrvHook = this; 76 } 77 78 pNxtHook = p666_New -> pFirstHook; 79 80 p666_New -> pFirstHook = this; 81 82 pPrvHook = NULL; 83 84 p666_Val = p666_New; 85 pUser_Val = pUser_New; 86 } 87 ~CallbackHook()88CallbackHook :: ~CallbackHook() 89 { 90 // Remove from list: 91 if ( pPrvHook ) 92 { 93 #if debug 94 if ( p666_Val ) 95 { 96 GLOBALASSERT( this != p666_Val -> pFirstHook ); 97 } 98 #endif 99 pPrvHook -> pNxtHook = pNxtHook; 100 } 101 else 102 { 103 if ( p666_Val ) 104 { 105 // this was it's daemon's first callback: 106 GLOBALASSERT( this == p666_Val -> pFirstHook ); 107 p666_Val -> pFirstHook = pNxtHook; 108 } 109 } 110 111 if ( pNxtHook ) 112 { 113 pNxtHook -> pPrvHook = pPrvHook; 114 } 115 116 } 117 #endif // SupportCallbackHooks 118 119 // class Daemon Daemon(OurBool fActive)120Daemon :: Daemon 121 ( 122 OurBool fActive 123 ) 124 { 125 #if SupportCallbackHooks 126 pFirstHook= NULL; 127 #endif 128 129 fIsActive_Val = No; 130 131 if (fActive) 132 { 133 Start(); 134 } 135 else 136 { 137 p666_NextActive = NULL; 138 p666_PrevActive = NULL; 139 } 140 } 141 ~Daemon()142Daemon :: ~Daemon() 143 { 144 if (fIsActive_Val) 145 { 146 Stop(); 147 } 148 149 if ( p666_Iteration_Current == this ) 150 { 151 // Then this daemon is being processed for Activity(); 152 // Set the static iteration ptr to NULL to signify it has been deleted 153 // so that callback hooks don't get called 154 p666_Iteration_Current = NULL; 155 } 156 157 #if SupportCallbackHooks 158 // remove from screen objects lists of attached daemons 159 while ( pFirstHook ) 160 { 161 pFirstHook -> p666_Val = NULL; 162 163 pFirstHook = pFirstHook -> pNxtHook; 164 } 165 #endif 166 } 167 168 Start(void)169void Daemon :: Start(void) 170 { 171 if (!fIsActive_Val) 172 { 173 // Insert at front of active 666 list 174 p666_PrevActive = NULL; 175 p666_NextActive = p666_FirstActive; 176 177 if (p666_FirstActive) 178 { 179 p666_FirstActive -> p666_PrevActive = this; 180 } 181 182 p666_FirstActive = this; 183 184 fIsActive_Val = Yes; 185 } 186 } 187 Stop(void)188void Daemon :: Stop(void) 189 { 190 if (fIsActive_Val) 191 { 192 // Remove from active 666 list 193 { 194 // Check against the iteration in the Maintain() static function: 195 { 196 if ( p666_Iteration_Next == this ) 197 { 198 // then this is due the next daemon to have its Activity() called; 199 // advance the static iteration ptr to this daemon's next 200 p666_Iteration_Next = p666_NextActive; 201 } 202 } 203 204 if ( p666_PrevActive ) 205 { 206 GLOBALASSERT( p666_PrevActive -> fIsActive_Val ); 207 208 p666_PrevActive -> p666_NextActive = p666_NextActive; 209 } 210 211 if ( p666_NextActive ) 212 { 213 GLOBALASSERT( p666_NextActive -> fIsActive_Val ); 214 215 p666_NextActive -> p666_PrevActive = p666_PrevActive; 216 } 217 218 if (p666_FirstActive == this) 219 { 220 p666_FirstActive = p666_NextActive; 221 } 222 } 223 224 fIsActive_Val = No; 225 } 226 } 227 SetActive(OurBool fActive)228void Daemon :: SetActive(OurBool fActive) 229 { 230 if (fActive) 231 { 232 Start(); 233 } 234 else 235 { 236 Stop(); 237 } 238 } 239 bActive(void) const240OurBool Daemon :: bActive(void) const 241 { 242 return fIsActive_Val; 243 } 244 245 #if SupportCallbackHooks ForceHookActivity(void)246void Daemon :: ForceHookActivity(void) 247 { 248 // a way to call the OnActivity() method for all attached hooks 249 250 CallbackHook* pCallbackHook = pFirstHook; 251 while ( pCallbackHook ) 252 { 253 CallbackHook* pCallbackHook_Nxt = pCallbackHook -> pNxtHook; 254 255 pCallbackHook -> OnActivity(); 256 257 pCallbackHook = pCallbackHook_Nxt; 258 } 259 260 } 261 #endif // SupportCallbackHooks 262 263 #if 0 264 void Daemon :: LinkScreenObject 265 ( 266 ScreenObject& ScrObj 267 ) 268 { 269 UNWRITTEN(); 270 } 271 272 void Daemon :: UnlinkScreenObject 273 ( 274 ScreenObject& ScrObj 275 ) 276 { 277 UNWRITTEN(); 278 } 279 #endif 280 281 // static Maintain(int FixP_Time_ToUse)282void Daemon :: Maintain(int FixP_Time_ToUse) 283 { 284 GLOBALASSERT( NULL == p666_Iteration_Current ); 285 GLOBALASSERT( NULL == p666_Iteration_Next ); 286 287 #if DaemonDiagnostics 288 ProfileStart(); 289 #endif 290 291 p666_Iteration_Current = p666_FirstActive; 292 293 FixP_Time = FixP_Time_ToUse; 294 295 while ( p666_Iteration_Current ) 296 { 297 p666_Iteration_Next = p666_Iteration_Current -> p666_NextActive; 298 299 { 300 #if DaemonNaming && DaemonDiagnostics 301 char* tempDebugName = p666_Iteration_Current -> GetDebugName(); 302 // in case it gets deleted during the loop 303 304 ProfileStart(); 305 #endif 306 307 #if SupportCallbackHooks 308 if 309 ( 310 p666_Iteration_Current -> Activity(FixP_Time) 311 ) 312 { 313 if ( p666_Iteration_Current ) 314 { 315 // run the OnActivity() method for all the callback hooks attached to this daemon 316 CallbackHook* pCallbackHook = p666_Iteration_Current -> pFirstHook; 317 while ( pCallbackHook ) 318 { 319 CallbackHook* pCallbackHook_Nxt = pCallbackHook -> pNxtHook; 320 321 pCallbackHook -> OnActivity(); 322 323 pCallbackHook = pCallbackHook_Nxt; 324 } 325 } 326 // else the iterating daemon got deleted during the call to Activity() 327 } 328 #else 329 { 330 #if IndividualTiming 331 { 332 p666_Iteration_Current -> Activity(FixP_Time); 333 } 334 #else 335 { 336 p666_Iteration_Current -> Activity(); 337 } 338 #endif 339 } 340 #endif 341 342 #if DaemonNaming && DaemonDiagnostics 343 ProfileStop 344 ( 345 tempDebugName 346 ); 347 #endif 348 349 } 350 /* 351 Advance to the next in the iteration. 352 This will be either the next ptr of the current as stored above, 353 or one further along the list (since the pNext one itself might 354 have got deleted during the call to Activity) 355 */ 356 p666_Iteration_Current = p666_Iteration_Next; 357 } 358 359 #if DaemonDiagnostics 360 361 ProfileStop("Daemon :: Maintain()"); 362 363 #if CountActiveDaemons 364 textprint("Num active daemons:%i\n",GetNumActive()); 365 #endif 366 367 #endif // #if DaemonDiagnostics 368 369 } 370 DAEMON_Init(void)371void DAEMON_Init(void) 372 { 373 } 374 375 extern "C" { 376 #if UseRealFrameTime 377 extern int RealFrameTime; 378 #else 379 extern int NormalFrameTime; 380 #endif 381 } 382 DAEMON_Maintain(void)383void DAEMON_Maintain(void) 384 { 385 #if 0 386 textprint("DAEMON_Maintain() called\n"); 387 #endif 388 389 #if 0 390 textprint("RealFrameTime=%i\n",RealFrameTime); 391 #endif 392 393 int DaemonFrameTime = 394 ( 395 #if UseRealFrameTime 396 RealFrameTime 397 #else 398 NormalFrameTime 399 #endif 400 ); 401 402 { 403 if (Daemon :: DaemonTimeScale!=ONE_FIXED) 404 { 405 DaemonFrameTime = MUL_FIXED(DaemonFrameTime,Daemon :: DaemonTimeScale); 406 } 407 408 } 409 410 /* cap DaemonFrameTime if frame rate is really low */ 411 if (DaemonFrameTime>32768) DaemonFrameTime=32768; 412 413 Daemon :: Maintain 414 ( 415 DaemonFrameTime 416 ); 417 } 418 419 420 /* Internal function definitions ***********************************/ 421