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)66 CallbackHook :: 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()88 CallbackHook :: ~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)120 Daemon :: 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()142 Daemon :: ~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)169 void 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)188 void 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)228 void Daemon :: SetActive(OurBool fActive)
229 {
230 	if (fActive)
231 	{
232 		Start();
233 	}
234 	else
235 	{
236 		Stop();
237 	}
238 }
239 
bActive(void) const240 OurBool Daemon :: bActive(void) const
241 {
242 	return fIsActive_Val;
243 }
244 
245 #if SupportCallbackHooks
ForceHookActivity(void)246 void 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)282 void 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)371 void 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)383 void 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