diff --git a/Source/OpenTK/GameWindow.cs b/Source/OpenTK/GameWindow.cs
index 8eae67d7..b3d2fffa 100644
--- a/Source/OpenTK/GameWindow.cs
+++ b/Source/OpenTK/GameWindow.cs
@@ -16,27 +16,51 @@ using OpenTK.OpenGL;
namespace OpenTK
{
+ ///
+ /// The GameWindow class contains cross-platform methods to create and render on an OpenGL window, handle input and load resources.
+ ///
+ ///
+ /// GameWindow contains several events you can hook or override to add your custom logic:
+ ///
+ /// - OnLoad: Occurs after creating the OpenGL context, but before entering the main loop. Override to load resources.
+ /// - OnResize: Occurs whenever GameWindow is resized. You should update the OpenGL Viewport and Projection Matrix here.
+ /// - OnUpdateFrame: Occurs at the specified logic update rate. Override to add your game logic.
+ /// - OnRenderFrame: Occurs at the specified frame render rate. Override to add your rendering code.
+ ///
+ /// 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.
+ ///
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 ---
///
- /// Constructs a new GameWindow, using a safe DisplayMode.
+ /// Constructs a new GameWindow. Call CreateWindow() to open a render window.
///
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);
}
+ ///
+ /// Constructs a new GameWindow, and opens a render window with the specified DisplayMode.
+ ///
+ /// The DisplayMode of the GameWindow.
+ public GameWindow(DisplayMode mode)
+ : this()
+ {
+ CreateWindow(mode);
+ }
+
+ ///
+ /// Constructs a new GameWindow with the specified title, and opens a render window with the specified DisplayMode.
+ ///
+ /// The DisplayMode of the GameWindow.
+ /// The Title of the GameWindow.
+ 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 Input
+ #region public void CreateWindow(DisplayMode mode, string title)
- internal InputDriver InputDriver
+ ///
+ /// Creates a render window for the calling GameWindow, with the specified DisplayMode and Title.
+ ///
+ /// The DisplayMode of the render window.
+ /// The Title of the render window.
+ ///
+ /// It is an error to call this function when a render window already exists.
+ /// Call DestroyWindow to close the render window.
+ ///
+ /// Occurs when a render window already exists.
+ 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
///
- /// Gets a value indicating whether a render window has been exists.
+ /// Gets a value indicating whether a render window exists.
///
public bool Exists
{
@@ -187,6 +238,44 @@ namespace OpenTK
#endregion
+ #region public string Text
+
+ ///
+ /// Gets or sets the GameWindow title.
+ ///
+ public string Title
+ {
+ get
+ {
+ return glWindow.Title;
+ }
+ set
+ {
+ glWindow.Title = value;
+ }
+ }
+
+ #endregion
+
+ #region public bool Visible
+
+ ///
+ /// Gets or sets a value indicating whether the GameWindow is visible.
+ ///
+ 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
+
+ ///
+ /// Gets an interface to the InputDriver used to obtain Keyboard, Mouse and Joystick input.
+ ///
+ public IInputDriver InputDriver
+ {
+ get
+ {
+ return glWindow.InputDriver;
+ }
+ }
+
+ #endregion
+
#region public void CreateWindow(DisplayMode mode)
///
- /// 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.
///
/// The DisplayMode of the render window.
+ ///
+ /// It is an error to call this function when a render window already exists.
+ /// Call DestroyWindow to close the render window.
+ ///
/// Occurs when a render window already exists.
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
///
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)
///
- /// Raises the RenderFrame event. Override in derived classes to render a frame.
+ /// Raises the RenderFrame event, and calls the public function.
///
- ///
- /// If overriden, the base.OnRenderFrame() function should be called, to ensure
- /// listeners are notified of RenderFrame events.
- ///
- public virtual void OnRenderFrame(RenderFrameEventArgs e)
+ ///
+ 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);
+ }
+
+ ///
+ /// Override in derived classes to render a frame.
+ ///
+ /// Contains information necessary for frame rendering.
+ ///
+ /// The base implementation (base.OnRenderFrame) is empty, there is no need to call it.
+ ///
+ public virtual void OnRenderFrame(RenderFrameEventArgs e)
+ {
}
///
@@ -470,16 +588,9 @@ namespace OpenTK
#endregion
- #region public virtual void OnUpdateFrame(UpdateFrameEventArgs e)
+ #region OnUpdateFrame(UpdateFrameEventArgs e)
- ///
- /// Raises the UpdateFrame event. Override in derived classes to update a frame.
- ///
- ///
- /// If overriden, the base.OnUpdateFrame() function should be called, to ensure
- /// listeners are notified of UpdateFrame events.
- ///
- 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);
+ }
+
+ ///
+ /// Override in derived classes to update a frame.
+ ///
+ /// Contains information necessary for frame updating.
+ ///
+ /// The base implementation (base.OnUpdateFrame) is empty, there is no need to call it.
+ ///
+ public virtual void OnUpdateFrame(UpdateFrameEventArgs e)
+ {
}
///
@@ -498,26 +632,35 @@ namespace OpenTK
#endregion
- #region public virtual void OnLoad(EventArgs e)
+ #region OnLoad(EventArgs e)
///
- /// 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.
///
- public virtual void OnLoad(EventArgs e)
+ public event LoadEvent Load;
+
+ ///
+ /// Raises the Load event, and calls the user's OnLoad override.
+ ///
+ ///
+ private void OnLoadInternal(EventArgs e)
{
- Debug.Print("Firing GameWindow.Load event.");
if (this.Load != null)
{
this.Load(this, e);
}
+
+ OnLoad(e);
}
///
- /// 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.
///
- public event LoadEvent Load;
+ /// Not used.
+ public virtual void OnLoad(EventArgs e)
+ {
+ }
#endregion
@@ -550,16 +693,37 @@ namespace OpenTK
#endregion
- #region public IList Keyboard
+ #region public Keyboard Keyboard
///
- /// Gets the list of available Keyboard devices.
+ /// Gets the primary Keyboard device, or null if no Keyboard exists.
///
- public IList 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
+
+ ///
+ /// Gets the primary Mouse device, or null if no Mouse exists.
+ ///
+ public MouseDevice Mouse
+ {
+ get
+ {
+ if (InputDriver.Mouse.Count > 0)
+ return InputDriver.Mouse[0];
+ else
+ return null;
}
}
@@ -576,7 +740,7 @@ namespace OpenTK
///
public int Width
{
- get { return glWindow.Width; }
+ get { return width; }
set
{
if (value == this.Width)
@@ -603,7 +767,7 @@ namespace OpenTK
///
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;
+ ///
+ /// Occurs when the GameWindow is resized. Derived classes should override the OnResize method for better performance.
+ ///
public event ResizeEvent Resize;
///
/// Raises the Resize event.
///
- /// Contains the new Width and Height of the window.
- protected virtual void OnResize(ResizeEventArgs e)
+ /// Contains information about the Resize event.
+ 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);
+ }
+
+ ///
+ /// Override in derived classes to respond to the Resize events.
+ ///
+ /// Contains information about the Resize event.
+ 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();