mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-12 15:35:29 +00:00
Big update: added timing information. Improved update and render frequency limiting algorithms (they extremely accurate now!) Added VSync property and VSyncMode enum. Adaptive VSync not available yet.
This commit is contained in:
parent
e932f8e162
commit
fa395a5325
|
@ -23,6 +23,7 @@ namespace OpenTK
|
||||||
/// GameWindow contains several events you can hook or override to add your custom logic:
|
/// GameWindow contains several events you can hook or override to add your custom logic:
|
||||||
/// <list>
|
/// <list>
|
||||||
/// <item>OnLoad: Occurs after creating the OpenGL context, but before entering the main loop. Override to load resources.</item>
|
/// <item>OnLoad: Occurs after creating the OpenGL context, but before entering the main loop. Override to load resources.</item>
|
||||||
|
/// <item>OnUnload: Occurs after exiting the main loop, but before deleting the OpenGL context. Override to unload resources.</item>
|
||||||
/// <item>OnResize: Occurs whenever GameWindow is resized. You should update the OpenGL Viewport and Projection Matrix here.</item>
|
/// <item>OnResize: Occurs whenever GameWindow is resized. You should update the OpenGL Viewport and Projection Matrix here.</item>
|
||||||
/// <item>OnUpdateFrame: Occurs at the specified logic update rate. Override to add your game logic.</item>
|
/// <item>OnUpdateFrame: Occurs at the specified logic update rate. Override to add your game logic.</item>
|
||||||
/// <item>OnRenderFrame: Occurs at the specified frame render rate. Override to add your rendering code.</item>
|
/// <item>OnRenderFrame: Occurs at the specified frame render rate. Override to add your rendering code.</item>
|
||||||
|
@ -30,7 +31,7 @@ namespace OpenTK
|
||||||
/// Call the Run() method to start the application's main loop. Run(double, double) takes two parameters that
|
/// Call the Run() method to start the application's main loop. Run(double, double) takes two parameters that
|
||||||
/// specify the logic update rate, and the render update rate.
|
/// specify the logic update rate, and the render update rate.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class GameWindow : IGameWindow
|
public class GameWindow : INativeGLWindow
|
||||||
{
|
{
|
||||||
#region --- Fields ---
|
#region --- Fields ---
|
||||||
|
|
||||||
|
@ -42,13 +43,18 @@ namespace OpenTK
|
||||||
bool isExiting;
|
bool isExiting;
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
|
||||||
double updateTime, renderTime, eventTime, frameTime;
|
double update_period, render_period;
|
||||||
|
double target_update_period, target_render_period, target_render_period_doubled;
|
||||||
|
// TODO: Implement these:
|
||||||
|
double update_time, render_time, event_time;
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
|
VSyncMode vsync;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region --- Internal Fields ---
|
#region --- Internal Properties ---
|
||||||
|
|
||||||
bool MustResize
|
bool MustResize
|
||||||
{
|
{
|
||||||
|
@ -403,7 +409,7 @@ namespace OpenTK
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region --- IGameWindow Members ---
|
#region --- GameWindow Methods ---
|
||||||
|
|
||||||
#region void Run()
|
#region void Run()
|
||||||
|
|
||||||
|
@ -426,6 +432,7 @@ namespace OpenTK
|
||||||
Run(updateFrequency, 0.0);
|
Run(updateFrequency, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the default game loop on GameWindow at the specified update and render frequency.
|
/// Runs the default game loop on GameWindow at the specified update and render frequency.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -452,25 +459,30 @@ namespace OpenTK
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual void Run(double updateFrequency, double renderFrequency)
|
public virtual void Run(double updateFrequency, double renderFrequency)
|
||||||
{
|
{
|
||||||
this.OnLoad(EventArgs.Empty);
|
|
||||||
|
|
||||||
// Setup timer
|
// Setup timer
|
||||||
Stopwatch watch = new Stopwatch();
|
Stopwatch watch = new Stopwatch();
|
||||||
UpdateFrameEventArgs updateArgs = new UpdateFrameEventArgs();
|
UpdateFrameEventArgs updateArgs = new UpdateFrameEventArgs();
|
||||||
RenderFrameEventArgs renderArgs = new RenderFrameEventArgs();
|
RenderFrameEventArgs renderArgs = new RenderFrameEventArgs();
|
||||||
|
|
||||||
// Setup update and render rates. If updateFrequency or renderFrequency <= 0.0, use full throttle for that frequency.
|
// Setup update and render rates. If updateFrequency or renderFrequency <= 0.0, use full throttle for that frequency.
|
||||||
double update_target = 0.0, render_target = 0.0, next_update = 0.0, next_render = 0.0;
|
double next_update = 0.0, next_render = 0.0;
|
||||||
double time, total_time;
|
double start_time;
|
||||||
|
|
||||||
|
double update_watch = 0.0, render_watch = 0.0;
|
||||||
|
int num_updates = 1;
|
||||||
|
double t0 = 0.0, t1 = 0.0, t2 = 0.0, t3 = 0.0;
|
||||||
|
|
||||||
if (updateFrequency > 0.0)
|
if (updateFrequency > 0.0)
|
||||||
{
|
{
|
||||||
next_update = update_target = 1.0 / updateFrequency;
|
next_update = updateTimeTarget = 1.0 / updateFrequency;
|
||||||
}
|
}
|
||||||
if (renderFrequency > 0.0)
|
if (renderFrequency > 0.0)
|
||||||
{
|
{
|
||||||
next_render = render_target = 1.0 / renderFrequency;
|
next_render = renderTimeTarget = 1.0 / renderFrequency;
|
||||||
}
|
}
|
||||||
|
renderTargetDoubled = renderTimeTarget * 2.0;
|
||||||
|
|
||||||
|
this.OnLoad(EventArgs.Empty);
|
||||||
|
|
||||||
// Enter main loop:
|
// Enter main loop:
|
||||||
// (1) Update total frame time (capped at 0.1 sec)
|
// (1) Update total frame time (capped at 0.1 sec)
|
||||||
|
@ -484,52 +496,207 @@ namespace OpenTK
|
||||||
Debug.Print("Entering main loop.");
|
Debug.Print("Entering main loop.");
|
||||||
while (this.Exists && !IsExiting)
|
while (this.Exists && !IsExiting)
|
||||||
{
|
{
|
||||||
// Update total frame time.
|
|
||||||
total_time = frameTime = watch.Elapsed.TotalSeconds;
|
|
||||||
if (total_time > 0.1)
|
|
||||||
total_time = 0.1;
|
|
||||||
updateArgs.Time = renderArgs.Time = total_time;
|
|
||||||
|
|
||||||
watch.Reset();
|
watch.Reset();
|
||||||
watch.Start();
|
watch.Start();
|
||||||
|
|
||||||
// Process events and update event_time
|
//frameTime = watch.Elapsed.TotalSeconds;
|
||||||
time = watch.Elapsed.TotalSeconds;
|
/*
|
||||||
|
// Adaptive VSync control:
|
||||||
|
bool disable_vsync = VSync == VSyncMode.Adaptive && Context.VSync && renderTime > renderTargetDoubled;
|
||||||
|
bool enable_vsync = VSync == VSyncMode.Adaptive && !Context.VSync && renderTime <= renderTargetDoubled;
|
||||||
|
if (disable_vsync)
|
||||||
|
{
|
||||||
|
//Debug.Print("Disabled vsync");
|
||||||
|
Title = "Off";
|
||||||
|
Context.VSync = false;
|
||||||
|
}
|
||||||
|
else if (enable_vsync)
|
||||||
|
{
|
||||||
|
//Debug.Print("Enabled vsync");
|
||||||
|
Title = "On";
|
||||||
|
Context.VSync = true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
t0 = watch.Elapsed.TotalSeconds;
|
||||||
|
// Process events and update eventTime
|
||||||
|
eventTime = t2 + t3 + t0; // t2 and t3 come from the previous run through the loop.
|
||||||
this.ProcessEvents();
|
this.ProcessEvents();
|
||||||
eventTime = watch.Elapsed.TotalSeconds - time;
|
|
||||||
|
|
||||||
if (!IsExiting)
|
if (!IsExiting)
|
||||||
{
|
{
|
||||||
// Raise UpdateFrame event(s) and update update_time.
|
// --- UpdateFrame ---
|
||||||
time = watch.Elapsed.TotalSeconds;
|
// Raise the necessary amount of UpdateFrame events to keep
|
||||||
next_update -= (total_time + time);
|
// the UpdateFrame rate constant. If the user didn't set an
|
||||||
while (next_update <= 0.0)
|
// UpdateFrame rate, raise only one event.
|
||||||
{
|
|
||||||
updateArgs.Time += watch.Elapsed.TotalSeconds;
|
|
||||||
this.OnUpdateFrameInternal(updateArgs);
|
|
||||||
if (update_target == 0.0)
|
|
||||||
break;
|
|
||||||
next_update += update_target;
|
|
||||||
}
|
|
||||||
updateTime = watch.Elapsed.TotalSeconds - time;
|
|
||||||
|
|
||||||
|
t1 = watch.Elapsed.TotalSeconds - t0;
|
||||||
|
|
||||||
|
start_time = t3 + t0 + t1; // t3 come from the previous run through the loop.
|
||||||
|
update_watch += start_time;
|
||||||
|
if (num_updates > 0)
|
||||||
|
{
|
||||||
|
updateTime = update_watch / (double)num_updates;
|
||||||
|
num_updates = 0;
|
||||||
|
update_watch = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_update -= start_time;
|
||||||
|
updateArgs.Time = update_watch;
|
||||||
|
if (next_update <= 0.0)
|
||||||
|
{
|
||||||
|
//updateArgs.Time += watch.Elapsed.TotalSeconds;
|
||||||
|
double prev_update = watch.Elapsed.TotalSeconds;
|
||||||
|
this.OnUpdateFrameInternal(updateArgs);
|
||||||
|
updateArgs.Time = watch.Elapsed.TotalSeconds - prev_update;
|
||||||
|
|
||||||
|
++num_updates;
|
||||||
|
|
||||||
|
// Schedule next update
|
||||||
|
//if (updateTimeTarget != 0.0)
|
||||||
|
{
|
||||||
|
next_update += updateTimeTarget;
|
||||||
|
next_update -= (watch.Elapsed.TotalSeconds - start_time);
|
||||||
|
}
|
||||||
|
//else
|
||||||
|
// break; // User didn't request a fixed UpdateFrame rate.
|
||||||
|
}
|
||||||
|
// --------------------
|
||||||
|
t2 = watch.Elapsed.TotalSeconds - t1;
|
||||||
|
// --- Render Frame ---
|
||||||
// Raise RenderFrame event and update render_time.
|
// Raise RenderFrame event and update render_time.
|
||||||
time = watch.Elapsed.TotalSeconds;
|
|
||||||
next_render -= (total_time + time);
|
start_time = t0 + t1 + t2;
|
||||||
|
render_watch += start_time;
|
||||||
|
next_render -= start_time;
|
||||||
if (next_render <= 0.0)
|
if (next_render <= 0.0)
|
||||||
{
|
{
|
||||||
renderArgs.Time += time;
|
// Update framerate counters
|
||||||
|
renderTime = renderArgs.Time = render_watch;
|
||||||
|
render_watch = 0.0;
|
||||||
|
|
||||||
this.OnRenderFrameInternal(renderArgs);
|
this.OnRenderFrameInternal(renderArgs);
|
||||||
next_render += render_target;
|
|
||||||
|
next_render += renderTimeTarget;
|
||||||
|
next_render -= (watch.Elapsed.TotalSeconds - start_time);
|
||||||
}
|
}
|
||||||
renderTime = watch.Elapsed.TotalSeconds - time;
|
|
||||||
|
// --------------------
|
||||||
|
|
||||||
// If there is any CPU time left, and we are not running full-throttle, Sleep() to lower CPU usage.
|
// If there is any CPU time left, and we are not running full-throttle, Sleep() to lower CPU usage.
|
||||||
if (renderTime < render_target && updateTime < update_target)
|
/*
|
||||||
|
if (renderTime < renderTimeTarget && updateTime < updateTimeTarget)
|
||||||
{
|
{
|
||||||
Thread.Sleep((int)(1000.0 * System.Math.Min(
|
int sleep_time = (int)System.Math.Truncate(1000.0 * System.Math.Min(renderTimeTarget - renderTime - eventTime,
|
||||||
render_target - renderTime, update_target - updateTime)));
|
updateTimeTarget - updateTime - eventTime));
|
||||||
|
if (sleep_time < 0)
|
||||||
|
sleep_time = 0;
|
||||||
|
Thread.Sleep(sleep_time);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
loop_time_clock = watch.Elapsed.TotalSeconds;
|
||||||
|
if (loop_time_clock > 0.05)
|
||||||
|
loop_time_clock = 0.05;
|
||||||
|
render_time_clock += loop_time_clock;
|
||||||
|
update_time_clock += loop_time_clock;
|
||||||
|
*/
|
||||||
|
//if (loop_time_clock > 0.1)
|
||||||
|
// loop_time_clock = 0.1;
|
||||||
|
|
||||||
|
t3 = watch.Elapsed.TotalSeconds - t2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnUnloadInternal(EventArgs.Empty);
|
||||||
|
|
||||||
|
if (this.Exists)
|
||||||
|
{
|
||||||
|
glWindow.DestroyWindow();
|
||||||
|
while (this.Exists)
|
||||||
|
{
|
||||||
|
this.ProcessEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
public void Run(double updates_per_second, double frames_per_second)
|
||||||
|
{
|
||||||
|
if (updates_per_second < 0.0 || updates_per_second > 200.0)
|
||||||
|
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();
|
||||||
|
|
||||||
|
GC.Collect(2);
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
GC.Collect(2);
|
||||||
|
|
||||||
|
OnLoadInternal(EventArgs.Empty);
|
||||||
|
|
||||||
|
while (!isExiting)
|
||||||
|
{
|
||||||
|
// Events
|
||||||
|
ProcessEvents();
|
||||||
|
|
||||||
|
if (isExiting)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Updates
|
||||||
|
time = update_watch.Elapsed.TotalSeconds;
|
||||||
|
if (time > 0.1)
|
||||||
|
time = 0.1;
|
||||||
|
while (next_update - time <= 0.0)
|
||||||
|
{
|
||||||
|
next_update = next_update - time + TargetUpdatePeriod;
|
||||||
|
|
||||||
|
update_time_counter += time;
|
||||||
|
++num_updates;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (num_updates > 0)
|
||||||
|
{
|
||||||
|
update_period = update_time_counter / (double)num_updates;
|
||||||
|
num_updates = 0;
|
||||||
|
update_time_counter = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame
|
||||||
|
if (isExiting)
|
||||||
|
break;
|
||||||
|
|
||||||
|
time = render_watch.Elapsed.TotalSeconds;
|
||||||
|
if (time > 0.1)
|
||||||
|
time = 0.1;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,8 +729,8 @@ namespace OpenTK
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void ProcessEvents()
|
public void ProcessEvents()
|
||||||
{
|
{
|
||||||
if (!isExiting)
|
//if (!isExiting)
|
||||||
InputDriver.Poll();
|
// InputDriver.Poll();
|
||||||
glWindow.ProcessEvents();
|
glWindow.ProcessEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +781,7 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
if (!this.Exists && !this.IsExiting)
|
if (!this.Exists && !this.IsExiting)
|
||||||
{
|
{
|
||||||
Debug.Print("WARNING: UpdateFrame event raised, without a valid render window. This may indicate a programming error. Creating render window.");
|
Debug.Print("WARNING: UpdateFrame event raised without a valid render window. This may indicate a programming error. Creating render window.");
|
||||||
mode = new DisplayMode(640, 480);
|
mode = new DisplayMode(640, 480);
|
||||||
this.CreateWindow(mode);
|
this.CreateWindow(mode);
|
||||||
}
|
}
|
||||||
|
@ -721,20 +888,6 @@ namespace OpenTK
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region public void SwapBuffers()
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Swaps the front and back buffer, presenting the rendered scene to the user.
|
|
||||||
/// Only useful in double- or triple-buffered formats.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Calling this function is equivalent to calling Context.SwapBuffers()</remarks>
|
|
||||||
public void SwapBuffers()
|
|
||||||
{
|
|
||||||
Context.SwapBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region public bool IsExiting
|
#region public bool IsExiting
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -786,6 +939,241 @@ namespace OpenTK
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region public VSyncMode VSync
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the VSyncMode.
|
||||||
|
/// </summary>
|
||||||
|
public VSyncMode VSync
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return vsync;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == VSyncMode.Off)
|
||||||
|
Context.VSync = false;
|
||||||
|
else if (value == VSyncMode.On)
|
||||||
|
Context.VSync = true;
|
||||||
|
|
||||||
|
vsync = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public void SwapBuffers()
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Swaps the front and back buffer, presenting the rendered scene to the user.
|
||||||
|
/// Only useful in double- or triple-buffered formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Calling this function is equivalent to calling Context.SwapBuffers()</remarks>
|
||||||
|
public void SwapBuffers()
|
||||||
|
{
|
||||||
|
Context.SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region --- GameWindow Timing ---
|
||||||
|
|
||||||
|
|
||||||
|
#region public double TargetRenderPeriod
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target render period in seconds.
|
||||||
|
/// </summary>
|
||||||
|
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
|
/// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public double TargetRenderPeriod
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return target_render_period;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0.005)
|
||||||
|
{
|
||||||
|
target_render_period = target_render_period_doubled = 0.0;
|
||||||
|
}
|
||||||
|
else if (value <= 1.0)
|
||||||
|
{
|
||||||
|
target_render_period = value;
|
||||||
|
target_render_period_doubled = 2.0 * target_render_period;
|
||||||
|
}
|
||||||
|
else Debug.Print("Target render period clamped to 1.0 seconds.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double TargetRenderFrequency
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target render frequency in Herz.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
|
/// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public double TargetRenderFrequency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (TargetRenderPeriod == 0.0)
|
||||||
|
return 0.0;
|
||||||
|
return 1.0 / TargetRenderPeriod;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 1.0)
|
||||||
|
{
|
||||||
|
TargetRenderPeriod = 0.0;
|
||||||
|
}
|
||||||
|
else if (value <= 200.0)
|
||||||
|
{
|
||||||
|
TargetRenderPeriod = 1.0 / value;
|
||||||
|
}
|
||||||
|
else Debug.Print("Target render frequency clamped to 200.0Hz.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double TargetUpdatePeriod
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target update period in seconds.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
|
/// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public double TargetUpdatePeriod
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return target_update_period;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0.005)
|
||||||
|
{
|
||||||
|
target_update_period = 0.0;
|
||||||
|
}
|
||||||
|
else if (value <= 1.0)
|
||||||
|
{
|
||||||
|
target_update_period = value;
|
||||||
|
}
|
||||||
|
else Debug.Print("Target update period clamped to 1.0 seconds.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double TargetUpdateFrequency
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target update frequency in Herz.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
|
||||||
|
/// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public double TargetUpdateFrequency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (TargetUpdatePeriod == 0.0)
|
||||||
|
return 0.0;
|
||||||
|
return 1.0 / TargetUpdatePeriod;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 1.0)
|
||||||
|
{
|
||||||
|
TargetUpdatePeriod = 0.0;
|
||||||
|
}
|
||||||
|
else if (value <= 200.0)
|
||||||
|
{
|
||||||
|
TargetUpdatePeriod = 1.0 / value;
|
||||||
|
}
|
||||||
|
else Debug.Print("Target update frequency clamped to 200.0Hz.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double RenderFrequency
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual frequency of RenderFrame events in Herz (i.e. FPS or Frames Per Second).
|
||||||
|
/// </summary>
|
||||||
|
public double RenderFrequency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (render_period == 0.0)
|
||||||
|
return 1.0;
|
||||||
|
return 1.0 / render_period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double RenderPeriod
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the period of RenderFrame events in seconds.
|
||||||
|
/// </summary>
|
||||||
|
public double RenderPeriod
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return render_period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double UpdateFrequency
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the frequency of UpdateFrame events in Herz.
|
||||||
|
/// </summary>
|
||||||
|
public double UpdateFrequency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (update_period == 0.0)
|
||||||
|
return 1.0;
|
||||||
|
return 1.0 / update_period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public double UpdatePeriod
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the period of UpdateFrame events in seconds.
|
||||||
|
/// </summary>
|
||||||
|
public double UpdatePeriod
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return update_period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region --- IResizable Members ---
|
#region --- IResizable Members ---
|
||||||
|
@ -963,6 +1351,36 @@ namespace OpenTK
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region public enum VSyncMode
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the available VSync modes.
|
||||||
|
/// </summary>
|
||||||
|
public enum VSyncMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Vsync disabled.
|
||||||
|
/// </summary>
|
||||||
|
Off = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// VSync enabled.
|
||||||
|
/// </summary>
|
||||||
|
On,
|
||||||
|
/// <summary>
|
||||||
|
/// VSync enabled, but automatically disabled if framerate falls below a specified limit.
|
||||||
|
/// </summary>
|
||||||
|
Adaptive
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region --- GameWindow Events ---
|
||||||
|
|
||||||
|
public delegate void UpdateFrameEvent(GameWindow sender, UpdateFrameEventArgs e);
|
||||||
|
public delegate void RenderFrameEvent(GameWindow sender, RenderFrameEventArgs e);
|
||||||
|
public delegate void LoadEvent(GameWindow sender, EventArgs e);
|
||||||
|
public delegate void UnloadEvent(GameWindow sender, EventArgs e);
|
||||||
|
|
||||||
public class UpdateFrameEventArgs : EventArgs
|
public class UpdateFrameEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
private double time;
|
private double time;
|
||||||
|
@ -980,6 +1398,7 @@ namespace OpenTK
|
||||||
public class RenderFrameEventArgs : EventArgs
|
public class RenderFrameEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
private double time;
|
private double time;
|
||||||
|
private double scale_factor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Time elapsed between frame updates, in seconds.
|
/// Gets the Time elapsed between frame updates, in seconds.
|
||||||
|
@ -989,5 +1408,22 @@ namespace OpenTK
|
||||||
get { return time; }
|
get { return time; }
|
||||||
internal set { time = value; }
|
internal set { time = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double ScaleFactor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return scale_factor;
|
||||||
}
|
}
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
if (value != 0.0 && !Double.IsNaN(value))
|
||||||
|
scale_factor = value;
|
||||||
|
else
|
||||||
|
scale_factor = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue