Skip to content

Instantly share code, notes, and snippets.

@ncannasse
Created March 6, 2016 16:09
Show Gist options
  • Save ncannasse/8048e759daa6cea3ce8c to your computer and use it in GitHub Desktop.
Save ncannasse/8048e759daa6cea3ce8c to your computer and use it in GitHub Desktop.
version 2, adds delay()
package haxe;
class MainEvent {
var f : Void -> Void;
var prev : MainEvent;
var next : MainEvent;
public var nextRun(default,null) : Float;
public var priority(default,null) : Int;
function new(f,p) {
this.f = f;
this.priority = p;
}
/**
Delay the execution of the event for the given time, in seconds.
If t is null, the event will be run at tick() time.
**/
public function delay( t : Null<Float> ) {
nextRun = t == null ? null : haxe.Timer.stamp() + t;
}
/**
Call the event. Will do nothing is the event has been stopped.
**/
public inline function call() {
if( f != null ) f();
}
/**
Stop the event from firing anymore.
**/
public inline function stop() {
f = null;
delay = null;
if( prev == null )
@:privateAccess MainLoop.pending = next;
else
prev.next = next;
if( next != null )
next.prev = prev;
}
}
class MainLoop {
static var pending : MainEvent = null;
static var sleepMutex : sys.vm.Mutex;
/**
Add a pending event to be run into the main loop.
**/
public static function add( f : Void -> Void, priority = 0 ) : MainEvent @:privateAccess {
var e = new MainEvent(f,priority);
var head = pending;
if( head == null ) {
pending = e;
return e;
}
var prev = null;
while( head != null && head.priority > priority ) {
prev = head;
head = head.next;
}
if( prev == null ) {
e.next = head;
head.prev = e;
pending = e;
} else {
var n = prev.next;
if( n != null ) n.prev = e;
e.next = n;
prev.next = e;
e.prev = prev;
}
return e;
}
/**
Wakeup a sleeping run()
**/
public static function wakeup() {
if( sleepMutex != null ) sleepMutex.release();
}
/**
Run the pending events. Return the time for next event.
**/
static function tick() {
// TODO : it will be necessary to reorder the events based on nextRun before
// processing them so they get run in correct order. this can be done in MainEvent.delay() as well but might
// cause ordering issues since we're processing events here
var e = pending;
var now = haxe.Timer.stamp();
var wait = 1e9;
while( e != null ) {
var next = e.next;
if( e.nextRun == null ) {
wait = 0;
e.call();
} else {
var wt = e.nextRun - now;
if( wt <= 0 ) {
wait = 0;
e.call();
} else if( wait > wt )
wait = wt;
}
e = next;
}
return wait;
}
/**
Start the main loop. Depending on the platform, this can return immediately or will only return when the application exits.
**/
public static function run() @:privateAccess {
#if js
tick();
var window : Dynamic = js.Browser.window;
var rqf : Dynamic = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
rqf(run);
#elseif flash
flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) tick());
#else
while( true ) {
var e = pending;
if( e == null ) break;
var nextTick = tick();
if( nextTick > 0 ) {
if( sleepMutex == null ) sleepMutex = new sys.vm.Mutex();
sleepMutex.tryAcquire(nextTick); // wait until nextTick or wakeup() call
}
}
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment