GameWindow.Exit() now throws an exception that is caught inside GameWindow.Run() to signal end of execution. Simplifies code and removes some ugly conditionals.
This commit is contained in:
parent
1fa4641781
commit
11015a9fc7
1 changed files with 118 additions and 104 deletions
|
@ -105,6 +105,7 @@ namespace OpenTK
|
||||||
glWindow.Destroy += new DestroyEvent(glWindow_Destroy);
|
glWindow.Destroy += new DestroyEvent(glWindow_Destroy);
|
||||||
|
|
||||||
CreateWindow(mode, title);
|
CreateWindow(mode, title);
|
||||||
|
this.vsync = VSyncMode.Adaptive;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glWindow_Destroy(object sender, EventArgs e)
|
void glWindow_Destroy(object sender, EventArgs e)
|
||||||
|
@ -433,121 +434,134 @@ namespace OpenTK
|
||||||
/// <param name="frames_per_second">The frequency of RenderFrame events.</param>
|
/// <param name="frames_per_second">The frequency of RenderFrame events.</param>
|
||||||
public void Run(double updates_per_second, double frames_per_second)
|
public void Run(double updates_per_second, double frames_per_second)
|
||||||
{
|
{
|
||||||
if (updates_per_second < 0.0 || updates_per_second > 200.0)
|
try
|
||||||
throw new ArgumentOutOfRangeException("updates_per_second", updates_per_second, "Parameter should be inside the range [0.0, 200.0]");
|
|
||||||
if (frames_per_second < 0.0 || frames_per_second > 200.0)
|
|
||||||
throw new ArgumentOutOfRangeException("frames_per_second", frames_per_second, "Parameter should be inside the range [0.0, 200.0]");
|
|
||||||
|
|
||||||
TargetUpdateFrequency = updates_per_second;
|
|
||||||
TargetRenderFrequency = frames_per_second;
|
|
||||||
|
|
||||||
Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch();
|
|
||||||
double time, next_render = 0.0, next_update = 0.0, update_time_counter = 0.0;
|
|
||||||
int num_updates = 0;
|
|
||||||
UpdateFrameEventArgs update_args = new UpdateFrameEventArgs();
|
|
||||||
RenderFrameEventArgs render_args = new RenderFrameEventArgs();
|
|
||||||
|
|
||||||
double sleep_granularity; // In seconds.
|
|
||||||
|
|
||||||
//GC.Collect(2);
|
|
||||||
//GC.WaitForPendingFinalizers();
|
|
||||||
//GC.Collect(2);
|
|
||||||
|
|
||||||
// Find the minimum granularity of the Thread.Sleep() function.
|
|
||||||
// TODO: Disabled - see comment on Thread.Sleep() problems below.
|
|
||||||
//update_watch.Start();
|
|
||||||
//const int test_times = 5;
|
|
||||||
//for (int i = test_times; --i > 0; )
|
|
||||||
// Thread.Sleep(1);
|
|
||||||
//update_watch.Stop();
|
|
||||||
//sleep_granularity = System.Math.Round(1000.0 * update_watch.Elapsed.TotalSeconds / test_times, MidpointRounding.AwayFromZero) / 1000.0;
|
|
||||||
//update_watch.Reset(); // We don't want to affect the first UpdateFrame!
|
|
||||||
|
|
||||||
OnLoadInternal(EventArgs.Empty);
|
|
||||||
|
|
||||||
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
|
|
||||||
|
|
||||||
while (!isExiting)
|
|
||||||
{
|
{
|
||||||
// Process events
|
if (updates_per_second < 0.0 || updates_per_second > 200.0)
|
||||||
ProcessEvents();
|
throw new ArgumentOutOfRangeException("updates_per_second", updates_per_second, "Parameter should be inside the range [0.0, 200.0]");
|
||||||
|
if (frames_per_second < 0.0 || frames_per_second > 200.0)
|
||||||
|
throw new ArgumentOutOfRangeException("frames_per_second", frames_per_second, "Parameter should be inside the range [0.0, 200.0]");
|
||||||
|
|
||||||
if (isExiting)
|
TargetUpdateFrequency = updates_per_second;
|
||||||
break;
|
TargetRenderFrequency = frames_per_second;
|
||||||
|
|
||||||
// Raise UpdateFrame events
|
Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch();
|
||||||
time = update_watch.Elapsed.TotalSeconds;
|
double time, next_render = 0.0, next_update = 0.0, update_time_counter = 0.0;
|
||||||
if (time > 1.0)
|
int num_updates = 0;
|
||||||
time = 1.0;
|
UpdateFrameEventArgs update_args = new UpdateFrameEventArgs();
|
||||||
while (next_update - time <= 0.0)
|
RenderFrameEventArgs render_args = new RenderFrameEventArgs();
|
||||||
|
|
||||||
|
double sleep_granularity; // In seconds.
|
||||||
|
|
||||||
|
//GC.Collect(2);
|
||||||
|
//GC.WaitForPendingFinalizers();
|
||||||
|
//GC.Collect(2);
|
||||||
|
|
||||||
|
// Find the minimum granularity of the Thread.Sleep() function.
|
||||||
|
// TODO: Disabled - see comment on Thread.Sleep() problems below.
|
||||||
|
//update_watch.Start();
|
||||||
|
//const int test_times = 5;
|
||||||
|
//for (int i = test_times; --i > 0; )
|
||||||
|
// Thread.Sleep(1);
|
||||||
|
//update_watch.Stop();
|
||||||
|
//sleep_granularity = System.Math.Round(1000.0 * update_watch.Elapsed.TotalSeconds / test_times, MidpointRounding.AwayFromZero) / 1000.0;
|
||||||
|
//update_watch.Reset(); // We don't want to affect the first UpdateFrame!
|
||||||
|
|
||||||
|
OnLoadInternal(EventArgs.Empty);
|
||||||
|
|
||||||
|
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
|
||||||
|
|
||||||
|
while (!isExiting)
|
||||||
{
|
{
|
||||||
next_update = next_update - time + TargetUpdatePeriod;
|
// Process events
|
||||||
|
ProcessEvents();
|
||||||
update_time_counter += time;
|
|
||||||
++num_updates;
|
|
||||||
|
|
||||||
update_watch.Reset();
|
|
||||||
update_watch.Start();
|
|
||||||
|
|
||||||
update_args.Time = time;
|
|
||||||
OnUpdateFrameInternal(update_args);
|
|
||||||
|
|
||||||
if (TargetUpdateFrequency == 0.0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
// Raise UpdateFrame events
|
||||||
time = update_watch.Elapsed.TotalSeconds;
|
time = update_watch.Elapsed.TotalSeconds;
|
||||||
next_update -= time;
|
if (time > 1.0)
|
||||||
update_time_counter += time;
|
time = 1.0;
|
||||||
|
while (next_update - time <= 0.0)
|
||||||
|
{
|
||||||
|
next_update = next_update - time + TargetUpdatePeriod;
|
||||||
|
|
||||||
// Allow up to 10 frames to be dropped.
|
update_time_counter += time;
|
||||||
// Prevent the application from hanging with very high update frequencies.
|
++num_updates;
|
||||||
if (num_updates >= 10)
|
|
||||||
break;
|
update_watch.Reset();
|
||||||
|
update_watch.Start();
|
||||||
|
|
||||||
|
update_args.Time = time;
|
||||||
|
OnUpdateFrameInternal(update_args);
|
||||||
|
|
||||||
|
if (TargetUpdateFrequency == 0.0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
time = update_watch.Elapsed.TotalSeconds;
|
||||||
|
next_update -= time;
|
||||||
|
update_time_counter += time;
|
||||||
|
|
||||||
|
// Allow up to 10 frames to be dropped.
|
||||||
|
// Prevent the application from hanging with very high update frequencies.
|
||||||
|
if (num_updates >= 10)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (num_updates > 0)
|
||||||
|
{
|
||||||
|
update_period = update_time_counter / (double)num_updates;
|
||||||
|
num_updates = 0;
|
||||||
|
update_time_counter = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise RenderFrame event
|
||||||
|
time = render_watch.Elapsed.TotalSeconds;
|
||||||
|
if (time > 1.0)
|
||||||
|
time = 1.0;
|
||||||
|
double time_left = next_render - time;
|
||||||
|
if (VSync == VSyncMode.Adaptive)
|
||||||
|
{
|
||||||
|
// Check if we have enough time for a vsync
|
||||||
|
if (time_left <= 0.5 * TargetRenderFrequency)
|
||||||
|
Context.VSync = false;
|
||||||
|
else
|
||||||
|
Context.VSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_left <= 0.0)
|
||||||
|
{
|
||||||
|
next_render = time_left + TargetRenderPeriod;
|
||||||
|
render_watch.Reset();
|
||||||
|
render_watch.Start();
|
||||||
|
|
||||||
|
render_period = render_args.Time = time;
|
||||||
|
render_args.ScaleFactor = RenderPeriod / UpdatePeriod;
|
||||||
|
OnRenderFrameInternal(render_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yield CPU time, if the Thread.Sleep() granularity allows it.
|
||||||
|
// TODO: Disabled because it does not work reliably enough on all systems.
|
||||||
|
// Enable vsync as a workaround.
|
||||||
|
//if (AllowSleep && next_render > sleep_granularity && next_update > sleep_granularity)
|
||||||
|
//{
|
||||||
|
// Thread.Sleep((int)(1000.0 * System.Math.Min(next_render - sleep_granularity, next_update - sleep_granularity)));
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
if (num_updates > 0)
|
|
||||||
{
|
|
||||||
update_period = update_time_counter / (double)num_updates;
|
|
||||||
num_updates = 0;
|
|
||||||
update_time_counter = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raise RenderFrame events
|
|
||||||
if (isExiting)
|
|
||||||
break;
|
|
||||||
|
|
||||||
time = render_watch.Elapsed.TotalSeconds;
|
|
||||||
if (time > 1.0)
|
|
||||||
time = 1.0;
|
|
||||||
if (next_render - time <= 0.0)
|
|
||||||
{
|
|
||||||
next_render = next_render - time + TargetRenderPeriod;
|
|
||||||
render_watch.Reset();
|
|
||||||
render_watch.Start();
|
|
||||||
|
|
||||||
render_period = render_args.Time = time;
|
|
||||||
render_args.ScaleFactor = RenderPeriod / UpdatePeriod;
|
|
||||||
OnRenderFrameInternal(render_args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yield CPU time, if the Thread.Sleep() granularity allows it.
|
|
||||||
// TODO: Disabled because it does not work reliably enough on all systems.
|
|
||||||
// Enable vsync as a workaround.
|
|
||||||
//if (AllowSleep && next_render > sleep_granularity && next_update > sleep_granularity)
|
|
||||||
//{
|
|
||||||
// Thread.Sleep((int)(1000.0 * System.Math.Min(next_render - sleep_granularity, next_update - sleep_granularity)));
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
catch (GameWindowExitException e)
|
||||||
Thread.CurrentThread.Priority = ThreadPriority.Normal;
|
|
||||||
|
|
||||||
OnUnloadInternal(EventArgs.Empty);
|
|
||||||
|
|
||||||
if (this.Exists)
|
|
||||||
{
|
{
|
||||||
glWindow.DestroyWindow();
|
|
||||||
while (this.Exists)
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.Priority = ThreadPriority.Normal;
|
||||||
|
|
||||||
|
OnUnloadInternal(EventArgs.Empty);
|
||||||
|
|
||||||
|
if (this.Exists)
|
||||||
{
|
{
|
||||||
this.ProcessEvents();
|
glWindow.DestroyWindow();
|
||||||
|
while (this.Exists)
|
||||||
|
{
|
||||||
|
this.ProcessEvents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue