175 lines
4.0 KiB
C#
175 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using System.Threading;
|
|
using System.Diagnostics;
|
|
|
|
using org.budnhead.graphics;
|
|
using org.budnhead.tools;
|
|
|
|
using OpenTK.Graphics;
|
|
|
|
namespace org.budnhead.core
|
|
{
|
|
public delegate void UpdateDelegate(float elapsed);
|
|
|
|
public static class Engine
|
|
{
|
|
/** Objects of the Game World **/
|
|
|
|
|
|
/** Engine management stuff **/
|
|
private static Object engineLock = new object();
|
|
private static Boolean initialized = false;
|
|
|
|
private static readonly float tickTimeSpan = (1.0f / Stopwatch.Frequency);
|
|
private static readonly float tickTimeSpanMS = (1000.0f / Stopwatch.Frequency);
|
|
private static long lastWorldUpdateTick;
|
|
private static ConsumerProducerLock
|
|
consumerProducerLock = new ConsumerProducerLock();
|
|
internal static List<SceneWindow>
|
|
sceneWindows = new List<SceneWindow>();
|
|
private static JobThreader sceneWindowJobs;
|
|
|
|
private static Thread updateThread = new Thread(updateWorldThread);
|
|
|
|
public static event UpdateDelegate
|
|
BeforeUpdate,
|
|
AfterUpdate;
|
|
|
|
private static Boolean exiting;
|
|
private static Object syncGraphicsStartup = new object();
|
|
|
|
private static float targetUpdatePeriod = 100;
|
|
|
|
public static SceneWindow[] SceneWindows {
|
|
get { lock (sceneWindows) { return sceneWindows.ToArray(); } }
|
|
}
|
|
|
|
public static float TargetUpdatePeriod {
|
|
get { return targetUpdatePeriod; }
|
|
set { targetUpdatePeriod = value; }
|
|
}
|
|
|
|
public static float TargetUpdateFrequency {
|
|
get { return targetUpdatePeriod == 0 ? 0 : 1.0f / targetUpdatePeriod; }
|
|
set { targetUpdatePeriod = value == 0 ? 0 : 1.0f / value; }
|
|
}
|
|
|
|
public static Boolean ShouldContinue {
|
|
get { lock(engineLock) { return !Engine.exiting; } }
|
|
}
|
|
|
|
public static void Shutdown(){
|
|
lock (engineLock){
|
|
exiting = true;
|
|
}
|
|
}
|
|
|
|
public static void Initialize(){
|
|
InitializeGraphics();
|
|
InitializeUpdateThread();
|
|
}
|
|
|
|
public static void InitializeUpdateThread(){
|
|
}
|
|
|
|
public static void InitializeGraphics(){
|
|
GraphicsContext.ShareContexts = true;
|
|
|
|
sceneWindowJobs = new JobThreader();
|
|
|
|
SceneWindow primaryWindow = new SceneWindow();
|
|
primaryWindow.MakeCurrent();
|
|
|
|
initialized = GlobalDefaults.initialize();
|
|
}
|
|
|
|
public static void run(){
|
|
updateThread.Start();
|
|
|
|
sceneWindowsThread();
|
|
}
|
|
|
|
|
|
private static void updateWorld(float elapsed){
|
|
consumerProducerLock.ProducerEnter();
|
|
|
|
if (BeforeUpdate!=null){
|
|
BeforeUpdate(elapsed);
|
|
}
|
|
|
|
Actor.updateActors(elapsed);
|
|
|
|
if (AfterUpdate!=null){
|
|
AfterUpdate(elapsed);
|
|
}
|
|
|
|
consumerProducerLock.producerExclusive();
|
|
|
|
cycleBufferedValues();
|
|
|
|
consumerProducerLock.ProducerExit();
|
|
}
|
|
|
|
public static bool cycleBufferedValues(){
|
|
BufferedValueInstance<object>.cycle();
|
|
return true;
|
|
}
|
|
|
|
public static void ConsumerEnter(){
|
|
consumerProducerLock.ConsumerEnter();
|
|
}
|
|
public static void ConsumerExit(){
|
|
consumerProducerLock.ConsumerExit();
|
|
}
|
|
|
|
|
|
public static SceneWindow createSceneWindow(){
|
|
return sceneWindowJobs.execute(delegate { return new SceneWindow(); });
|
|
}
|
|
|
|
static void sceneWindowsThread(){
|
|
|
|
while (Engine.ShouldContinue){
|
|
sceneWindowJobs.execute();
|
|
|
|
lock(Engine.sceneWindows){
|
|
foreach (SceneWindow sceneWindow in Engine.sceneWindows.ToArray()){
|
|
if (sceneWindow.Visible){
|
|
sceneWindow.ProcessEvents();
|
|
}
|
|
}
|
|
|
|
foreach (SceneWindow sceneWindow in Engine.sceneWindows.ToArray()){
|
|
sceneWindow.paint();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void updateWorldThread(){
|
|
|
|
long lastWorldUpdateTick = Stopwatch.GetTimestamp();
|
|
float elapsed = 0;
|
|
float update_needs;
|
|
|
|
while (Engine.ShouldContinue){
|
|
long ticks = Stopwatch.GetTimestamp();
|
|
elapsed = tickTimeSpan * (ticks - lastWorldUpdateTick);
|
|
|
|
updateWorld(elapsed);
|
|
|
|
update_needs = tickTimeSpanMS * (Stopwatch.GetTimestamp() - ticks);
|
|
|
|
lastWorldUpdateTick = ticks;
|
|
|
|
if (update_needs < targetUpdatePeriod){
|
|
Thread.Sleep( (int)(targetUpdatePeriod - update_needs) );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|