From 6b3d358abd242bcd11d1ef61d0927c62da1753e0 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 26 Sep 2007 11:50:44 +0000 Subject: [PATCH] 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). --- Source/OpenTK/GameWindow.cs | 335 +++++++++++++++++++++++++++--------- 1 file changed, 255 insertions(+), 80 deletions(-) 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();