Improved documentation. Split On*** event methods between On***Internal and On***, to protect user's from forgetting to call base.On*** (no need to call that now). Improved Resize event handling (goes through OnUpdateFrameInternal now, removes duplicate events).
This commit is contained in:
parent
7c159bc2df
commit
8138033b2a
1 changed files with 255 additions and 80 deletions
|
@ -16,27 +16,51 @@ using OpenTK.OpenGL;
|
|||
|
||||
namespace OpenTK
|
||||
{
|
||||
/// <summary>
|
||||
/// The GameWindow class contains cross-platform methods to create and render on an OpenGL window, handle input and load resources.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// GameWindow contains several events you can hook or override to add your custom logic:
|
||||
/// <list>
|
||||
/// <item>OnLoad: Occurs after creating the OpenGL context, but before entering the main loop. Override to load resources.</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>OnRenderFrame: Occurs at the specified frame render rate. Override to add your rendering code.</item>
|
||||
/// </list>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public class GameWindow : OpenTK.Platform.IGameWindow
|
||||
{
|
||||
#region --- Fields ---
|
||||
|
||||
private INativeGLWindow glWindow;
|
||||
private ResizeEventArgs resizeEventArgs = new ResizeEventArgs();
|
||||
private DisplayMode mode;
|
||||
INativeGLWindow glWindow;
|
||||
DisplayMode mode;
|
||||
|
||||
private InputDriver driver;
|
||||
ResizeEventArgs resizeEventArgs = new ResizeEventArgs();
|
||||
|
||||
private bool isExiting;
|
||||
private bool disposed;
|
||||
bool isExiting;
|
||||
bool disposed;
|
||||
|
||||
private double updateTime, renderTime, eventTime, frameTime;
|
||||
double updateTime, renderTime, eventTime, frameTime;
|
||||
|
||||
int width, height;
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Internal Fields ---
|
||||
|
||||
bool MustResize
|
||||
{
|
||||
get { return glWindow.Width != this.Width || glWindow.Height != this.Height; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Contructors ---
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new GameWindow, using a safe DisplayMode.
|
||||
/// Constructs a new GameWindow. Call CreateWindow() to open a render window.
|
||||
/// </summary>
|
||||
public GameWindow()
|
||||
{
|
||||
|
@ -58,11 +82,31 @@ namespace OpenTK
|
|||
throw new PlatformNotSupportedException("Your platform is not supported currently. Please, refer to http://opentk.sourceforge.net for more information.");
|
||||
}
|
||||
|
||||
glWindow.Resize += new ResizeEvent(glWindow_Resize);
|
||||
glWindow.Create += new CreateEvent(glWindow_CreateInputDriver);
|
||||
//glWindow.Resize += new ResizeEvent(glWindow_Resize);
|
||||
glWindow.Destroy += new DestroyEvent(glWindow_Destroy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new GameWindow, and opens a render window with the specified DisplayMode.
|
||||
/// </summary>
|
||||
/// <param name="mode">The DisplayMode of the GameWindow.</param>
|
||||
public GameWindow(DisplayMode mode)
|
||||
: this()
|
||||
{
|
||||
CreateWindow(mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new GameWindow with the specified title, and opens a render window with the specified DisplayMode.
|
||||
/// </summary>
|
||||
/// <param name="mode">The DisplayMode of the GameWindow.</param>
|
||||
/// <param name="title">The Title of the GameWindow.</param>
|
||||
public GameWindow(DisplayMode mode, string title)
|
||||
: this()
|
||||
{
|
||||
CreateWindow(mode, title);
|
||||
}
|
||||
|
||||
void glWindow_Destroy(object sender, EventArgs e)
|
||||
{
|
||||
Debug.Print("GameWindow destruction imminent.");
|
||||
|
@ -72,38 +116,45 @@ namespace OpenTK
|
|||
//this.Dispose();
|
||||
}
|
||||
|
||||
void glWindow_CreateInputDriver(object sender, EventArgs e)
|
||||
{
|
||||
//glWindow.Context.MakeCurrent();
|
||||
|
||||
if (driver == null)
|
||||
driver = new InputDriver(this.WindowInfo);
|
||||
glWindow.Create -= glWindow_CreateInputDriver;
|
||||
|
||||
this.OnCreate(e);
|
||||
}
|
||||
|
||||
void glWindow_Resize(object sender, ResizeEventArgs e)
|
||||
{
|
||||
this.OnResize(e);
|
||||
this.OnResizeInternal(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Internal Properties ---
|
||||
#region --- Functions ---
|
||||
|
||||
#region public IList<OpenTK.Input.IInputDevice> Input
|
||||
#region public void CreateWindow(DisplayMode mode, string title)
|
||||
|
||||
internal InputDriver InputDriver
|
||||
/// <summary>
|
||||
/// Creates a render window for the calling GameWindow, with the specified DisplayMode and Title.
|
||||
/// </summary>
|
||||
/// <param name="mode">The DisplayMode of the render window.</param>
|
||||
/// <param name="title">The Title of the render window.</param>
|
||||
/// <remarks>
|
||||
/// It is an error to call this function when a render window already exists.
|
||||
/// <para>Call DestroyWindow to close the render window.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ApplicationException">Occurs when a render window already exists.</exception>
|
||||
public void CreateWindow(DisplayMode mode, string title)
|
||||
{
|
||||
get
|
||||
if (!Exists)
|
||||
{
|
||||
if (driver == null && !this.IsExiting)
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("WARNING: Accessed null InputDriver - creating new. This may indicate a prorgamming error.");
|
||||
driver = new InputDriver(this.WindowInfo);
|
||||
glWindow.CreateWindow(mode);
|
||||
this.Title = title;
|
||||
}
|
||||
return driver;
|
||||
catch (ApplicationException expt)
|
||||
{
|
||||
Debug.Print(expt.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ApplicationException("A render window already exists for this GameWindow.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +229,7 @@ namespace OpenTK
|
|||
#region public bool Exists
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a render window has been exists.
|
||||
/// Gets a value indicating whether a render window exists.
|
||||
/// </summary>
|
||||
public bool Exists
|
||||
{
|
||||
|
@ -187,6 +238,44 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public string Text
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the GameWindow title.
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return glWindow.Title;
|
||||
}
|
||||
set
|
||||
{
|
||||
glWindow.Title = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public bool Visible
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the GameWindow is visible.
|
||||
/// </summary>
|
||||
public bool Visible
|
||||
{
|
||||
get
|
||||
{
|
||||
return glWindow.Visible;
|
||||
}
|
||||
set
|
||||
{
|
||||
glWindow.Visible = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public IWindowInfo WindowInfo
|
||||
|
||||
public IWindowInfo WindowInfo
|
||||
|
@ -196,13 +285,31 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public IInputDriver InputDriver
|
||||
|
||||
/// <summary>
|
||||
/// Gets an interface to the InputDriver used to obtain Keyboard, Mouse and Joystick input.
|
||||
/// </summary>
|
||||
public IInputDriver InputDriver
|
||||
{
|
||||
get
|
||||
{
|
||||
return glWindow.InputDriver;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public void CreateWindow(DisplayMode mode)
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new render window. The Create event is raised after the window creation
|
||||
/// is complete, to allow resource initalisation.
|
||||
/// Creates a render window for the calling GameWindow.
|
||||
/// </summary>
|
||||
/// <param name="mode">The DisplayMode of the render window.</param>
|
||||
/// <remarks>
|
||||
/// It is an error to call this function when a render window already exists.
|
||||
/// <para>Call DestroyWindow to close the render window.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ApplicationException">Occurs when a render window already exists.</exception>
|
||||
public void CreateWindow(DisplayMode mode)
|
||||
{
|
||||
|
@ -217,11 +324,10 @@ namespace OpenTK
|
|||
Debug.Print(expt.ToString());
|
||||
throw;
|
||||
}
|
||||
//OpenTK.OpenGL.GL.LoadAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ApplicationException("A render window already exists");
|
||||
throw new ApplicationException("A render window already exists for this GameWindow.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,12 +446,13 @@ namespace OpenTK
|
|||
public virtual void Run(double updateFrequency, double renderFrequency)
|
||||
{
|
||||
this.OnLoad(EventArgs.Empty);
|
||||
resizeEventArgs.Width = this.Width;
|
||||
resizeEventArgs.Height = this.Height;
|
||||
this.OnResize(resizeEventArgs);
|
||||
|
||||
Debug.Print("Entering main loop");
|
||||
|
||||
//resizeEventArgs.Width = this.Width;
|
||||
//resizeEventArgs.Height = this.Height;
|
||||
//this.OnResize(resizeEventArgs);
|
||||
|
||||
Stopwatch watch = new Stopwatch();
|
||||
UpdateFrameEventArgs updateArgs = new UpdateFrameEventArgs();
|
||||
RenderFrameEventArgs renderArgs = new RenderFrameEventArgs();
|
||||
|
@ -383,7 +490,7 @@ namespace OpenTK
|
|||
while (next_update <= 0.0)
|
||||
{
|
||||
updateArgs.Time += watch.Elapsed.TotalSeconds;
|
||||
this.OnUpdateFrame(updateArgs);
|
||||
this.OnUpdateFrameInternal(updateArgs);
|
||||
if (update_target == 0.0)
|
||||
break;
|
||||
next_update += update_target;
|
||||
|
@ -395,7 +502,7 @@ namespace OpenTK
|
|||
if (next_render <= 0.0)
|
||||
{
|
||||
renderArgs.Time += time;
|
||||
this.OnRenderFrame(renderArgs);
|
||||
this.OnRenderFrameInternal(renderArgs);
|
||||
next_render += render_target;
|
||||
}
|
||||
renderTime = watch.Elapsed.TotalSeconds - time;
|
||||
|
@ -435,23 +542,20 @@ namespace OpenTK
|
|||
/// </remarks>
|
||||
public void ProcessEvents()
|
||||
{
|
||||
if (driver != null)
|
||||
driver.Poll();
|
||||
if (!isExiting)
|
||||
InputDriver.Poll();
|
||||
glWindow.ProcessEvents();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public virtual void OnRenderFrame(RenderFrameEventArgs e)
|
||||
#region OnRenderFrame(RenderFrameEventArgs e)
|
||||
|
||||
/// <summary>
|
||||
/// Raises the RenderFrame event. Override in derived classes to render a frame.
|
||||
/// Raises the RenderFrame event, and calls the public function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If overriden, the base.OnRenderFrame() function should be called, to ensure
|
||||
/// listeners are notified of RenderFrame events.
|
||||
/// </remarks>
|
||||
public virtual void OnRenderFrame(RenderFrameEventArgs e)
|
||||
/// <param name="e"></param>
|
||||
private void OnRenderFrameInternal(RenderFrameEventArgs e)
|
||||
{
|
||||
if (!this.Exists && !this.IsExiting)
|
||||
{
|
||||
|
@ -461,6 +565,20 @@ namespace OpenTK
|
|||
}
|
||||
if (RenderFrame != null)
|
||||
RenderFrame(this, e);
|
||||
|
||||
// Call the user's override.
|
||||
OnRenderFrame(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in derived classes to render a frame.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains information necessary for frame rendering.</param>
|
||||
/// <remarks>
|
||||
/// The base implementation (base.OnRenderFrame) is empty, there is no need to call it.
|
||||
/// </remarks>
|
||||
public virtual void OnRenderFrame(RenderFrameEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -470,16 +588,9 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public virtual void OnUpdateFrame(UpdateFrameEventArgs e)
|
||||
#region OnUpdateFrame(UpdateFrameEventArgs e)
|
||||
|
||||
/// <summary>
|
||||
/// Raises the UpdateFrame event. Override in derived classes to update a frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If overriden, the base.OnUpdateFrame() function should be called, to ensure
|
||||
/// listeners are notified of UpdateFrame events.
|
||||
/// </remarks>
|
||||
public virtual void OnUpdateFrame(UpdateFrameEventArgs e)
|
||||
private void OnUpdateFrameInternal(UpdateFrameEventArgs e)
|
||||
{
|
||||
if (!this.Exists && !this.IsExiting)
|
||||
{
|
||||
|
@ -487,8 +598,31 @@ namespace OpenTK
|
|||
mode = new DisplayMode(640, 480);
|
||||
this.CreateWindow(mode);
|
||||
}
|
||||
|
||||
if (MustResize)
|
||||
{
|
||||
resizeEventArgs.Width = glWindow.Width;
|
||||
resizeEventArgs.Height = glWindow.Height;
|
||||
OnResizeInternal(resizeEventArgs);
|
||||
}
|
||||
|
||||
if (UpdateFrame != null)
|
||||
{
|
||||
UpdateFrame(this, e);
|
||||
}
|
||||
|
||||
OnUpdateFrame(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in derived classes to update a frame.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains information necessary for frame updating.</param>
|
||||
/// <remarks>
|
||||
/// The base implementation (base.OnUpdateFrame) is empty, there is no need to call it.
|
||||
/// </remarks>
|
||||
public virtual void OnUpdateFrame(UpdateFrameEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -498,26 +632,35 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public virtual void OnLoad(EventArgs e)
|
||||
#region OnLoad(EventArgs e)
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Load event. Override to load resources that should
|
||||
/// be maintained for the lifetime of the application.
|
||||
/// Occurs after establishing an OpenGL context, but before entering the main loop.
|
||||
/// </summary>
|
||||
public virtual void OnLoad(EventArgs e)
|
||||
public event LoadEvent Load;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Load event, and calls the user's OnLoad override.
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
private void OnLoadInternal(EventArgs e)
|
||||
{
|
||||
Debug.Print("Firing GameWindow.Load event.");
|
||||
if (this.Load != null)
|
||||
{
|
||||
this.Load(this, e);
|
||||
}
|
||||
|
||||
OnLoad(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after the GameWindow has been created, but before
|
||||
/// entering the main loop.
|
||||
/// Occurs after establishing an OpenGL context, but before entering the main loop.
|
||||
/// Override to load resources that should be maintained for the lifetime of the application.
|
||||
/// </summary>
|
||||
public event LoadEvent Load;
|
||||
/// <param name="e">Not used.</param>
|
||||
public virtual void OnLoad(EventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -550,16 +693,37 @@ namespace OpenTK
|
|||
|
||||
#endregion
|
||||
|
||||
#region public IList<Keyboard> Keyboard
|
||||
#region public Keyboard Keyboard
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available Keyboard devices.
|
||||
/// Gets the primary Keyboard device, or null if no Keyboard exists.
|
||||
/// </summary>
|
||||
public IList<Keyboard> Keyboard
|
||||
public KeyboardDevice Keyboard
|
||||
{
|
||||
get
|
||||
{
|
||||
return InputDriver.Keyboard;
|
||||
if (InputDriver.Keyboard.Count > 0)
|
||||
return InputDriver.Keyboard[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public Mouse Mouse
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary Mouse device, or null if no Mouse exists.
|
||||
/// </summary>
|
||||
public MouseDevice Mouse
|
||||
{
|
||||
get
|
||||
{
|
||||
if (InputDriver.Mouse.Count > 0)
|
||||
return InputDriver.Mouse[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,7 +740,7 @@ namespace OpenTK
|
|||
/// </summary>
|
||||
public int Width
|
||||
{
|
||||
get { return glWindow.Width; }
|
||||
get { return width; }
|
||||
set
|
||||
{
|
||||
if (value == this.Width)
|
||||
|
@ -603,7 +767,7 @@ namespace OpenTK
|
|||
/// </summary>
|
||||
public int Height
|
||||
{
|
||||
get { return glWindow.Height; }
|
||||
get { return height; }
|
||||
set
|
||||
{
|
||||
if (value == this.Height)
|
||||
|
@ -629,17 +793,34 @@ namespace OpenTK
|
|||
|
||||
#region public event ResizeEvent Resize;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the GameWindow is resized. Derived classes should override the OnResize method for better performance.
|
||||
/// </summary>
|
||||
public event ResizeEvent Resize;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Resize event.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains the new Width and Height of the window.</param>
|
||||
protected virtual void OnResize(ResizeEventArgs e)
|
||||
/// <param name="e">Contains information about the Resize event.</param>
|
||||
private void OnResizeInternal(ResizeEventArgs e)
|
||||
{
|
||||
Debug.Print("Firing GameWindow.Resize event: {0}.", e.ToString());
|
||||
|
||||
this.width = e.Width;
|
||||
this.height = e.Height;
|
||||
|
||||
if (this.Resize != null)
|
||||
this.Resize(this, e);
|
||||
|
||||
OnResize(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in derived classes to respond to the Resize events.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains information about the Resize event.</param>
|
||||
protected virtual void OnResize(ResizeEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -698,12 +879,6 @@ namespace OpenTK
|
|||
|
||||
if (manual)
|
||||
{
|
||||
if (driver != null)
|
||||
{
|
||||
driver.Dispose();
|
||||
driver = null;
|
||||
}
|
||||
|
||||
if (glWindow != null)
|
||||
{
|
||||
glWindow.Dispose();
|
||||
|
|
Loading…
Reference in a new issue