Selaa lähdekoodia

New factory-based timers.
Enables custom timer implementations.

woollybah 9 vuotta sitten
vanhempi
commit
ece2b3e489

+ 44 - 71
timer.mod/timer.bmx

@@ -1,20 +1,23 @@
 
-Strict
+SuperStrict
 
 Rem
 bbdoc: Events/Timers
 End Rem
 Module BRL.Timer
 
-ModuleInfo "Version: 1.03"
-ModuleInfo "Author: Simon Armstrong, Mark Sibly"
+ModuleInfo "Version: 1.04"
+ModuleInfo "Author: Simon Armstrong, Mark Sibly, Bruce A Henderson"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
-ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.04"
+ModuleInfo "History: New factory-based timer implementation."
 ModuleInfo "History: 1.03"
 ModuleInfo "History: Update to use Byte Ptr instead of int."
 
+Import BRL.Event
+
 Rem
 History:
 
@@ -28,75 +31,17 @@ Added check for Win32 timer firing after timeKillEvent
 Removed brl.standardio dependancy
 End Rem
 
-Import BRL.SystemDefault
-
-?Win32
-Import "timer.win32.c"
-?MacOS
-Import "timer.macos.m"
-?Linux
-Import "timer.linux.c"
-?
-
-Extern
-Function bbTimerStart:Byte Ptr( hertz#,timer:TTimer )
-Function bbTimerStop( handle:Byte Ptr,timer:TTimer )
-End Extern
-
-Function _TimerFired( timer:TTimer )
-	timer.Fire
-End Function
-
-Type TTimer
+Type TTimer Abstract
 
-	Method Ticks()
-		Return _ticks
-	End Method
+	Method Ticks:Int() Abstract
 	
-	Method Stop()
-		If Not _handle Return
-		bbTimerStop _handle,Self
-		_handle=0
-		_event=Null
-'		_cycle=Null
-	End Method
+	Method Stop() Abstract
 	
-	Method Fire()
-		If Not _handle Return
-		_ticks:+1
-		If _event
-			EmitEvent _event
-		Else
-			EmitEvent CreateEvent( EVENT_TIMERTICK,Self,_ticks )
-		EndIf
-	End Method
+	Method Fire() Abstract
 
-	Method Wait()
-		If Not _handle Return
-		Local n
-		Repeat
-			WaitSystem
-			n=_ticks-_wticks
-		Until n
-		_wticks:+n
-		Return n
-	End Method
+	Method Wait:Int() Abstract
 	
-	Function Create:TTimer( hertz#,event:TEvent=Null )
-		Local t:TTimer=New TTimer
-		Local handle:Byte Ptr=bbTimerStart( hertz,t )
-		If Not handle Return
-'		t._cycle=t
-		t._event=event
-		t._handle=handle
-		Return t
-	End Function
-
-	Field _ticks
-	Field _wticks
-	Field _cycle:TTimer	'no longer used...see history
-	Field _event:TEvent
-	Field _handle:Byte Ptr
+	Function Create:TTimer( hertz#,event:TEvent=Null ) Abstract
 
 End Type
 
@@ -112,14 +57,18 @@ If @event is Null, an event with an @id equal to EVENT_TIMERTICK and
 @source equal to the timer object will be emitted instead.
 End Rem
 Function CreateTimer:TTimer( hertz#,event:TEvent=Null )
-	Return TTimer.Create( hertz,event )
+	If timer_factories Then
+		Return timer_factories.Create(hertz, event)
+	Else
+		Throw "No Timer installed. Maybe Import BRL.TimerDefault ?"
+	End If
 End Function
 
 Rem
 bbdoc: Get timer tick counter
 returns: The number of times @timer has ticked over
 End Rem
-Function TimerTicks( timer:TTimer )
+Function TimerTicks:Int( timer:TTimer )
 	Return timer.Ticks()
 End Function
 
@@ -127,7 +76,7 @@ Rem
 bbdoc: Wait until a timer ticks
 returns: The number of ticks since the last call to #WaitTimer
 End Rem
-Function WaitTimer( timer:TTimer )
+Function WaitTimer:Int( timer:TTimer )
 	Return timer.Wait()
 End Function
 
@@ -138,3 +87,27 @@ End Rem
 Function StopTimer( timer:TTimer )
 	timer.Stop
 End Function
+
+Private
+
+Global timer_factories:TTimerFactory
+
+Public
+
+Type TTimerFactory
+	Field _succ:TTimerFactory
+	
+	Method New()
+		If _succ <> Null Then
+			Throw "Timer already installed : " + _succ.GetName()
+		End If
+		_succ=timer_factories
+		timer_factories=Self
+	End Method
+	
+	Method GetName:String() Abstract
+	
+	Method Create:TTimer(hertz#,event:TEvent=Null) Abstract
+		
+End Type
+

+ 83 - 0
timerdefault.mod/timer.linux.c

@@ -0,0 +1,83 @@
+
+//Oh the fun...no multiple timers in Linux (!) so we have to roll our own...
+//
+#include <brl.mod/blitz.mod/blitz.h>
+
+#include <pthread.h>
+
+typedef struct BBTimer{
+	pthread_t thread;
+	int status;
+	int puts;
+	int gets;
+	int start;
+	int period;
+	BBObject *bbTimer;
+}BBTimer;
+
+extern int bbMilliSecs();
+extern void bbDelay( int millis );
+
+extern void brl_timerdefault__TimerFired( BBObject *bbTimer );
+
+static void timerSyncOp( BBObject *user,int ret ){
+	BBTimer *timer=(BBTimer*)ret;
+
+	++timer->gets;	
+
+	switch( timer->status ){
+	case 1:
+		brl_timerdefault__TimerFired( timer->bbTimer );
+		break;
+	case 2:
+		if( timer->puts==timer->gets ){
+			BBRELEASE( timer->bbTimer );
+			free( timer );
+		}
+		break;
+	}
+}
+
+static void *timerProc( void *data ){
+	BBTimer *timer=(BBTimer*)data;
+	
+	int time=timer->start;
+	
+	while( timer->status==1 ){
+		time+=timer->period;
+
+		bbDelay( time-bbMilliSecs() );
+
+		++timer->puts;
+		bbSystemPostSyncOp( timerSyncOp,&bbNullObject,(int)timer );
+	}
+
+	bbSystemPostSyncOp( timerSyncOp,&bbNullObject,(int)timer );
+}
+
+BBTimer *bbTimerStart( float hertz,BBObject *bbTimer ){
+	BBTimer *timer;
+	int start=bbMilliSecs();
+	
+	timer=(BBTimer*)malloc( sizeof( BBTimer ) );
+	
+	timer->status=1;
+	timer->puts=1;
+	timer->gets=0;
+	timer->start=start;
+	timer->period=1000.0f/hertz;
+	timer->bbTimer=bbTimer;
+	
+	if( pthread_create( &timer->thread,0,(void*(*)(void*))timerProc,timer )<0 ){
+		free( timer );
+		return 0;
+	}
+	
+	BBRETAIN( timer->bbTimer );
+	
+	return timer;
+}
+
+void bbTimerStop( BBTimer *timer,BBObject *bbTimer ){
+	timer->status=2;
+}

+ 46 - 0
timerdefault.mod/timer.macos.m

@@ -0,0 +1,46 @@
+
+#import <Foundation/Foundation.h>
+
+#include <brl.mod/blitz.mod/blitz.h>
+
+void brl_timerdefault__TimerFired( void *data );
+
+@interface BBTimer : NSObject{
+	NSTimer *_timer;
+	void *_data;
+}
+-(id)initWithPeriod:(double)period data:(void*)data;
+-(void)stop;
+@end
+
+@implementation BBTimer
+-(id)initWithPeriod:(double)period data:(void*)data{
+	self=[super init];
+	_timer=[NSTimer scheduledTimerWithTimeInterval:period target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
+	_data=data;
+	return self;
+}
+-(void)stop{
+	[_timer invalidate];
+	_timer=0;
+}
+-(void)onTick:(NSTimer*)timer{
+	brl_timerdefault__TimerFired( _data );
+}
+@end
+
+BBTimer *bbTimerStart( float hertz,BBObject *bbTimer ){
+	BBTimer *timer=[[BBTimer alloc] initWithPeriod:1.0/hertz data:bbTimer];
+	if( !timer ) return 0;
+	
+	BBRETAIN( bbTimer );
+
+	return timer;
+}
+
+void bbTimerStop( BBTimer *timer,BBObject *bbTimer ){
+	[timer stop];
+	[timer release];
+
+	BBRELEASE( bbTimer );
+}

+ 49 - 0
timerdefault.mod/timer.win32.c

@@ -0,0 +1,49 @@
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdio.h>
+
+#include <brl.mod/systemdefault.mod/system.h>
+
+#define MAX_TIMERS 16
+
+void brl_timerdefault__TimerFired( BBObject *bbTimer );
+
+static int timers[MAX_TIMERS],n_timers;
+
+static void timerSyncOp( BBObject *bbTimer,int timer ){
+	int i;
+	for( i=0;i<n_timers && timer!=timers[i];++i ) {}
+	if( i<n_timers ) brl_timerdefault__TimerFired( bbTimer );
+}
+
+static void __stdcall timerProc( UINT timer,UINT msg,DWORD user,DWORD u1,DWORD u2 ){
+	bbSystemPostSyncOp( timerSyncOp,(BBObject*)user,timer );
+}
+
+void * bbTimerStart( float hertz,BBObject *bbTimer ){
+	int timer;
+	
+	if( n_timers==MAX_TIMERS ) return 0;
+	
+	timer=(int)timeSetEvent( 1000.0/hertz,0,timerProc,(DWORD)bbTimer,TIME_PERIODIC );
+	if( !timer ) return 0;
+	
+	BBRETAIN( bbTimer );
+	
+	timers[n_timers++]=timer;
+	return (void*)timer;
+}
+
+void bbTimerStop( void* t,BBObject *bbTimer ){
+	int i;
+	
+	int timer=(int)t;
+	for( i=0;i<n_timers && timer!=timers[i];++i ) {}
+	if( i==n_timers ) return;
+
+	timers[i]=timers[--n_timers];
+	timeKillEvent( timer );
+
+	BBRELEASE( bbTimer );
+}

+ 99 - 0
timerdefault.mod/timerdefault.bmx

@@ -0,0 +1,99 @@
+SuperStrict
+
+Rem
+bbdoc: Events/Timers
+End Rem
+Module BRL.TimerDefault
+
+ModuleInfo "Version: 1.00"
+ModuleInfo "Author: Simon Armstrong, Mark Sibly, Bruce A Henderson"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Blitz Research Ltd"
+
+ModuleInfo "History: 1.00"
+ModuleInfo "History: Default/System Timer implementation."
+
+Import BRL.Timer
+Import BRL.SystemDefault
+
+?Win32
+Import "timer.win32.c"
+?MacOS
+Import "timer.macos.m"
+?Linux
+Import "timer.linux.c"
+?
+
+Extern
+Function bbTimerStart:Byte Ptr( hertz#,timer:TTimer )
+Function bbTimerStop( handle:Byte Ptr,timer:TTimer )
+End Extern
+
+Function _TimerFired( timer:TTimer ) { nomangle }
+	timer.Fire
+End Function
+
+Type TDefaultTimer Extends TTimer
+
+	Method Ticks:Int()
+		Return _ticks
+	End Method
+	
+	Method Stop()
+		If Not _handle Return
+		bbTimerStop _handle,Self
+		_handle=0
+		_event=Null
+	End Method
+	
+	Method Fire()
+		If Not _handle Return
+		_ticks:+1
+		If _event
+			EmitEvent _event
+		Else
+			EmitEvent CreateEvent( EVENT_TIMERTICK,Self,_ticks )
+		EndIf
+	End Method
+
+	Method Wait:Int()
+		If Not _handle Return 0
+		Local n:Int
+		Repeat
+			WaitSystem
+			n=_ticks-_wticks
+		Until n
+		_wticks:+n
+		Return n
+	End Method
+	
+	Function Create:TTimer( hertz#,event:TEvent=Null )
+		Local t:TDefaultTimer =New TDefaultTimer
+		Local handle:Byte Ptr=bbTimerStart( hertz,t )
+		If Not handle Return Null
+		t._event=event
+		t._handle=handle
+		Return t
+	End Function
+
+	Field _ticks:Int
+	Field _wticks:Int
+	'Field _cycle:TTimer	'no longer used...see history
+	Field _event:TEvent
+	Field _handle:Byte Ptr
+
+End Type
+
+Type TDefaultTimerFactory Extends TTimerFactory
+	
+	Method GetName:String()
+		Return "DefaultTimer"
+	End Method
+	
+	Method Create:TTimer(hertz#,event:TEvent=Null)
+		Return TDefaultTimer.Create( hertz,event )
+	End Method
+		
+End Type
+
+New TDefaultTimerFactory