From: jpbruyere Date: Wed, 11 Jan 2017 15:21:45 +0000 (+0100) Subject: first test with 3d interface X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=51a188ce9bc23e7c302d8fa5258d329c00328106;p=jp%2Fcrow.git first test with 3d interface --- diff --git a/Templates/CheckBox.template b/Templates/CheckBox.template index 070f8e2e..a9a62a4a 100755 --- a/Templates/CheckBox.template +++ b/Templates/CheckBox.template @@ -2,5 +2,5 @@ - \ No newline at end of file diff --git a/Tests/BasicTests.cs b/Tests/BasicTests.cs index 22007eb8..761775b9 100644 --- a/Tests/BasicTests.cs +++ b/Tests/BasicTests.cs @@ -10,7 +10,7 @@ using System.Diagnostics; namespace Tests { - class BasicTests : OpenTKGameWindow + class BasicTests : CrowWindow3D { public BasicTests () : base(800, 600,"test: press to toogle test files") diff --git a/Tests/CrowWindow.cs b/Tests/CrowWindow.cs new file mode 100644 index 00000000..a4261c98 --- /dev/null +++ b/Tests/CrowWindow.cs @@ -0,0 +1,356 @@ +// +// OpenTKGameWindow.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Threading; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using System.Collections.Generic; + +namespace Crow +{ + public class CrowWindow : GameWindow, IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + if (ValueChanged != null) + ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + public Interface CrowInterface; + + #region FPS + int frameCpt = 0; + int _fps = 0; + + public int fps { + get { return _fps; } + set { + if (_fps == value) + return; + + _fps = value; + + if (_fps > fpsMax) { + fpsMax = _fps; + ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax)); + } else if (_fps < fpsMin) { + fpsMin = _fps; + ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin)); + } + if (frameCpt % 3 == 0) + ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); + #if MEASURE_TIME + foreach (PerformanceMeasure m in PerfMeasures) + m.NotifyChanges(); + #endif + } + } + + public int fpsMin = int.MaxValue; + public int fpsMax = 0; + + void resetFps () + { + fpsMin = int.MaxValue; + fpsMax = 0; + _fps = 0; + } + public string update = ""; + public string drawing = ""; + public string layouting = ""; + public string clipping = ""; + #if MEASURE_TIME + public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10); + #endif + + #endregion + + #region ctor + public CrowWindow(int _width = 800, int _height = 600, string _title="Crow", + int colors = 32, int depth = 24, int stencil = 0, int samples = 1, + int major=3, int minor=3) + : this(_width, _height, new OpenTK.Graphics.GraphicsMode(colors, depth, stencil, samples), + _title,GameWindowFlags.Default,DisplayDevice.Default, + major,minor,OpenTK.Graphics.GraphicsContextFlags.Default) + { + } + public CrowWindow (int width, int height, OpenTK.Graphics.GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags) + : base(width,height,mode,title,options,device,major,minor,flags) + { + CrowInterface = new Interface (); + + #if MEASURE_TIME + PerfMeasures = new List ( + new PerformanceMeasure[] { + this.CrowInterface.updateMeasure, + this.CrowInterface.layoutingMeasure, + this.CrowInterface.clippingMeasure, + this.CrowInterface.drawingMeasure, + this.glDrawMeasure + } + ); + #endif + + Thread t = new Thread (interfaceThread); + t.IsBackground = true; + t.Start (); + } + + #endregion + + #if MEASURE_TIME + public List PerfMeasures; + #endif + + void interfaceThread() + { + CrowInterface.Quit += Quit; + CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; + while (CrowInterface.ClientRectangle.Size.Width == 0) + Thread.Sleep (5); + + while (true) { + CrowInterface.Update (); + //Thread.Sleep (1); + } + } + + public void Quit (object sender, EventArgs e) + { + this.Exit (); + } + void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e) + { + this.Cursor = new MouseCursor( + (int)e.NewCursor.Xhot, + (int)e.NewCursor.Yhot, + (int)e.NewCursor.Width, + (int)e.NewCursor.Height, + e.NewCursor.data); + } + + #region Events + //those events are raised only if mouse isn't in a graphic object + public event EventHandler MouseWheelChanged; + public event EventHandler MouseButtonUp; + public event EventHandler MouseButtonDown; + public event EventHandler MouseClick; + public event EventHandler MouseMove; + public event EventHandler KeyboardKeyDown; + public event EventHandler KeyboardKeyUp; + + #endregion + + #region graphic context + public int texID; + public Shader shader; + public vaoMesh quad; + public Matrix4 projection; + + /// Create the texture for the interface redering + void createContext() + { + if (GL.IsTexture(texID)) + GL.DeleteTexture (texID); + GL.GenTextures(1, out texID); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, texID); + + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, + ClientRectangle.Width, ClientRectangle.Height, 0, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.bmp); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + + GL.BindTexture(TextureTarget.Texture2D, 0); + } + /// Rendering of the interface + void OpenGLDraw() + { + #if MEASURE_TIME + glDrawMeasure.StartCycle(); + #endif + bool blend, depthTest; + GL.GetBoolean (GetPName.Blend, out blend); + GL.GetBoolean (GetPName.DepthTest, out depthTest); + GL.Enable (EnableCap.Blend); + GL.Disable (EnableCap.DepthTest); + + shader.Enable (); + shader.SetMVP (projection); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, texID); + if (Monitor.TryEnter(CrowInterface.RenderMutex)) { + if (CrowInterface.IsDirty) { + GL.TexSubImage2D (TextureTarget.Texture2D, 0, + CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top, + CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.dirtyBmp); + CrowInterface.IsDirty = false; + } + Monitor.Exit (CrowInterface.RenderMutex); + } + quad.Render (BeginMode.TriangleStrip); + GL.BindTexture(TextureTarget.Texture2D, 0); + + if (!blend) + GL.Disable (EnableCap.Blend); + if (depthTest) + GL.Enable (EnableCap.DepthTest); + #if MEASURE_TIME + glDrawMeasure.StopCycle(); + #endif + } + #endregion + + /// Override this method for your OpenGL rendering calls + public virtual void OnRender(FrameEventArgs e) + { + } + /// Override this method to customize clear method between frames + public virtual void GLClear() + { + GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit); + } + + #region Game win overrides + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + this.KeyPress += new EventHandler(OpenTKGameWindow_KeyPress); + Keyboard.KeyDown += new EventHandler(Keyboard_KeyDown); + Keyboard.KeyUp += new EventHandler(Keyboard_KeyUp); + Mouse.WheelChanged += new EventHandler(Mouse_WheelChanged); + Mouse.ButtonDown += new EventHandler(Mouse_ButtonDown); + Mouse.ButtonUp += new EventHandler(Mouse_ButtonUp); + Mouse.Move += new EventHandler(Mouse_Move); + + GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + #if DEBUG + Console.WriteLine("\n\n*************************************"); + Console.WriteLine("GL version: " + GL.GetString (StringName.Version)); + Console.WriteLine("GL vendor: " + GL.GetString (StringName.Vendor)); + Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion)); + Console.WriteLine("*************************************\n"); + #endif + + projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1); + + shader = new Shader (); + quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); + } + + protected override void OnUpdateFrame(FrameEventArgs e) + { + base.OnUpdateFrame(e); + fps = (int)RenderFrequency; + + + if (frameCpt > 500) { + resetFps (); + frameCpt = 0; +// #if DEBUG +// GC.Collect(); +// GC.WaitForPendingFinalizers(); +// NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); +// #endif + } + frameCpt++; + } + protected override void OnRenderFrame(FrameEventArgs e) + { + GLClear (); + + base.OnRenderFrame(e); + + OnRender (e); + OpenGLDraw (); + + SwapBuffers (); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize (e); + CrowInterface.ProcessResize( + new Rectangle( + 0, + 0, + this.ClientRectangle.Width, + this.ClientRectangle.Height)); + createContext (); + GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); + } + #endregion + + #region Mouse Handling + void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){ + for (int i = 0; i < MouseState.MaxButtons; i++) { + if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i)) + e.EnableBit (i); + } + } + void Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) + { + if (!CrowInterface.ProcessMouseMove (otk_e.X, otk_e.Y)) + MouseMove.Raise (sender, otk_e); + } + void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + if (!CrowInterface.ProcessMouseButtonUp ((int)otk_e.Button)) + MouseButtonUp.Raise (sender, otk_e); + } + void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + if (!CrowInterface.ProcessMouseButtonDown ((int)otk_e.Button)) + MouseButtonDown.Raise (sender, otk_e); + } + void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) + { + if (!CrowInterface.ProcessMouseWheelChanged (otk_e.DeltaPrecise)) + MouseWheelChanged.Raise (sender, otk_e); + } + #endregion + + #region keyboard Handling + void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (!CrowInterface.ProcessKeyDown((int)otk_e.Key)) + KeyboardKeyDown.Raise (this, otk_e); + } + void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (!CrowInterface.ProcessKeyUp((int)otk_e.Key)) + KeyboardKeyUp.Raise (this, otk_e); + } + void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) + { + CrowInterface.ProcessKeyPress (e.KeyChar); + } + #endregion + } +} diff --git a/Tests/CrowWindow3D.cs b/Tests/CrowWindow3D.cs new file mode 100644 index 00000000..1209c4b9 --- /dev/null +++ b/Tests/CrowWindow3D.cs @@ -0,0 +1,488 @@ +// +// OpenTKGameWindow.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Threading; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using System.Collections.Generic; + +namespace Crow +{ + public class CrowWindow3D : GameWindow, IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + if (ValueChanged != null) + ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + public Interface CrowInterface; + + #region FPS + int frameCpt = 0; + int _fps = 0; + + public int fps { + get { return _fps; } + set { + if (_fps == value) + return; + + _fps = value; + + if (_fps > fpsMax) { + fpsMax = _fps; + ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax)); + } else if (_fps < fpsMin) { + fpsMin = _fps; + ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin)); + } + if (frameCpt % 3 == 0) + ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); + #if MEASURE_TIME + foreach (PerformanceMeasure m in PerfMeasures) + m.NotifyChanges(); + #endif + } + } + + public int fpsMin = int.MaxValue; + public int fpsMax = 0; + + void resetFps () + { + fpsMin = int.MaxValue; + fpsMax = 0; + _fps = 0; + } + public string update = ""; + public string drawing = ""; + public string layouting = ""; + public string clipping = ""; + #if MEASURE_TIME + public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10); + #endif + + #endregion + + #region ctor + public CrowWindow3D(int _width = 800, int _height = 600, string _title="Crow", + int colors = 32, int depth = 24, int stencil = 0, int samples = 1, + int major=3, int minor=3) + : this(_width, _height, new OpenTK.Graphics.GraphicsMode(colors, depth, stencil, samples), + _title,GameWindowFlags.Default,DisplayDevice.Default, + major,minor,OpenTK.Graphics.GraphicsContextFlags.Default) + { + } + public CrowWindow3D (int width, int height, OpenTK.Graphics.GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags) + : base(width,height,mode,title,options,device,major,minor,flags) + { + CrowInterface = new Interface (); + + #if MEASURE_TIME + PerfMeasures = new List ( + new PerformanceMeasure[] { + this.CrowInterface.updateMeasure, + this.CrowInterface.layoutingMeasure, + this.CrowInterface.clippingMeasure, + this.CrowInterface.drawingMeasure, + this.glDrawMeasure + } + ); + #endif + + Thread t = new Thread (interfaceThread); + t.IsBackground = true; + t.Start (); + } + + #endregion + + #if MEASURE_TIME + public List PerfMeasures; + #endif + + void interfaceThread() + { + CrowInterface.Quit += Quit; + CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; + while (CrowInterface.ClientRectangle.Size.Width == 0) + Thread.Sleep (5); + + while (true) { + CrowInterface.Update (); + //Thread.Sleep (1); + } + } + + public void Quit (object sender, EventArgs e) + { + this.Exit (); + } + void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e) + { + this.Cursor = new MouseCursor( + (int)e.NewCursor.Xhot, + (int)e.NewCursor.Yhot, + (int)e.NewCursor.Width, + (int)e.NewCursor.Height, + e.NewCursor.data); + } + + #region Events + //those events are raised only if mouse isn't in a graphic object + public event EventHandler MouseWheelChanged; + public event EventHandler MouseButtonUp; + public event EventHandler MouseButtonDown; + public event EventHandler MouseClick; + public event EventHandler MouseMove; + public event EventHandler KeyboardKeyDown; + public event EventHandler KeyboardKeyUp; + + #endregion + + #region graphic context + public int texID; + public Shader shader; + public vaoMesh quad; + public Matrix4 projection; + + void initGL(){ + GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); + shader = new Shader (); + quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); + } + /// Create the texture for the interface redering + void createContext() + { + if (GL.IsTexture(texID)) + GL.DeleteTexture (texID); + GL.GenTextures(1, out texID); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, texID); + + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, + ClientRectangle.Width, ClientRectangle.Height, 0, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.bmp); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + + GL.BindTexture(TextureTarget.Texture2D, 0); + } + /// Rendering of the interface + void OpenGLDraw() + { + #if MEASURE_TIME + glDrawMeasure.StartCycle(); + #endif + bool blend, depthTest; + GL.GetBoolean (GetPName.Blend, out blend); + GL.GetBoolean (GetPName.DepthTest, out depthTest); + GL.Enable (EnableCap.Blend); + GL.Disable (EnableCap.DepthTest); + + shader.Enable (); + shader.SetMVP (modelview * projection); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, texID); + if (Monitor.TryEnter(CrowInterface.RenderMutex)) { + if (CrowInterface.IsDirty) { + GL.TexSubImage2D (TextureTarget.Texture2D, 0, + CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top, + CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.dirtyBmp); + CrowInterface.IsDirty = false; + } + Monitor.Exit (CrowInterface.RenderMutex); + } + quad.Render (BeginMode.TriangleStrip); + GL.BindTexture(TextureTarget.Texture2D, 0); + + if (!blend) + GL.Disable (EnableCap.Blend); + if (depthTest) + GL.Enable (EnableCap.DepthTest); + #if MEASURE_TIME + glDrawMeasure.StopCycle(); + #endif + } + #endregion + + /// Override this method for your OpenGL rendering calls + public virtual void OnRender(FrameEventArgs e) + { + } + /// Override this method to customize clear method between frames + public virtual void GLClear() + { + GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit); + } + + #region Game win overrides + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + this.KeyPress += new EventHandler(OpenTKGameWindow_KeyPress); + Keyboard.KeyDown += new EventHandler(Keyboard_KeyDown); + Keyboard.KeyUp += new EventHandler(Keyboard_KeyUp); + Mouse.WheelChanged += new EventHandler(Mouse_WheelChanged); + Mouse.ButtonDown += new EventHandler(Mouse_ButtonDown); + Mouse.ButtonUp += new EventHandler(Mouse_ButtonUp); + Mouse.Move += new EventHandler(Mouse_Move); + + #if DEBUG + Console.WriteLine("\n\n*************************************"); + Console.WriteLine("GL version: " + GL.GetString (StringName.Version)); + Console.WriteLine("GL vendor: " + GL.GetString (StringName.Vendor)); + Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion)); + Console.WriteLine("*************************************\n"); + #endif + + initGL (); + } + + protected override void OnUpdateFrame(FrameEventArgs e) + { + base.OnUpdateFrame(e); + fps = (int)RenderFrequency; + + + if (frameCpt > 500) { + resetFps (); + frameCpt = 0; +// #if DEBUG +// GC.Collect(); +// GC.WaitForPendingFinalizers(); +// NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); +// #endif + } + frameCpt++; + } + protected override void OnRenderFrame(FrameEventArgs e) + { + GLClear (); + + base.OnRenderFrame(e); + + OnRender (e); + OpenGLDraw (); + + SwapBuffers (); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize (e); + CrowInterface.ProcessResize( + new Rectangle( + 0, + 0, + this.ClientRectangle.Width, + this.ClientRectangle.Height)); + createContext (); + UpdateViewMatrix (); + } + #endregion + int[] viewport = new int[4]; + #region Mouse Handling + void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){ + for (int i = 0; i < MouseState.MaxButtons; i++) { + if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i)) + e.EnableBit (i); + } + } + public static Matrix4 modelview; + public static Matrix4 orthoMat//full screen quad rendering + = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1); + Vector3 vEyeTarget = new Vector3(0f, 0f, 0f); + Vector3 vEye; + Vector3 vLookInit = Vector3.Normalize(new Vector3(0.0f, 0.0f, 1.0f)); + Vector3 vLook; // Camera vLook Vector + float zFar = 300.0f; + float zNear = 0.001f; + float fovY = (float)Math.PI / 4; + float eyeDist = 1.2f; + float MoveSpeed = 0.02f; + float RotationSpeed = 0.005f; + float ZoomSpeed = 0.22f; + float viewZangle, viewXangle; + + public Vector4 vLight = new Vector4 (0.5f, 0.5f, -1f, 0f); + + Point mousePosition; + + void updateMousePosition(OpenTK.Input.MouseMoveEventArgs otk_e) + { + Vector3 vMouse = UnProject(ref projection, ref modelview, viewport, new Vector2 (otk_e.X, otk_e.Y)).Xyz; + Vector3 vMouseRay = Vector3.Normalize(vMouse - vEye); + float a = vEye.Z / vMouseRay.Z; + vMouse = vEye - vMouseRay * a; + mousePosition = new Point ((int)Math.Truncate ((vMouse.X + 0.5f) * viewport [2]), + viewport [3] - (int)Math.Truncate ((vMouse.Y + 0.5f) * viewport [3])); + } + + void Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) + { + updateMousePosition (otk_e); + + if (mousePosition.X.IsInBetween (0, ClientRectangle.Width) & mousePosition.Y.IsInBetween (0, ClientRectangle.Height) + &!(Keyboard[OpenTK.Input.Key.ShiftLeft])) { + if (CrowInterface.ProcessMouseMove (mousePosition.X, mousePosition.Y)) + return; + } + if (otk_e.XDelta != 0 || otk_e.YDelta != 0) + { + if (otk_e.Mouse.MiddleButton == OpenTK.Input.ButtonState.Pressed) { + viewZangle -= (float)otk_e.XDelta * RotationSpeed; + viewXangle -= (float)otk_e.YDelta * RotationSpeed; +// if (viewXangle < - 0.75f) +// viewXangle = -0.75f; +// else if (viewXangle > MathHelper.PiOver4) +// viewXangle = MathHelper.PiOver4; + UpdateViewMatrix (); + }else if (otk_e.Mouse.LeftButton == OpenTK.Input.ButtonState.Pressed) { + return; + }else if (otk_e.Mouse.RightButton == OpenTK.Input.ButtonState.Pressed) { + Vector2 v2Look = vLook.Xz.Normalized (); + Vector2 disp = v2Look.PerpendicularLeft * otk_e.XDelta * MoveSpeed + + v2Look * otk_e.YDelta * MoveSpeed; + vEyeTarget += new Vector3 (disp.X, disp.Y, 0); + UpdateViewMatrix(); + } + //System.Diagnostics.Debug.WriteLine ("vMouse={0} newPos={1}", vMouse, newPos); + } + MouseMove.Raise (sender, otk_e); + } + + void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + if (mousePosition.X.IsInBetween (0, ClientRectangle.Width) & mousePosition.Y.IsInBetween (0, ClientRectangle.Height) + &!(Keyboard[OpenTK.Input.Key.ShiftLeft])) { + if (CrowInterface.ProcessMouseButtonUp ((int)otk_e.Button)) + return; + } + MouseButtonUp.Raise (sender, otk_e); + } + void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + if (mousePosition.X.IsInBetween (0, ClientRectangle.Width) & mousePosition.Y.IsInBetween (0, ClientRectangle.Height) + &!(Keyboard[OpenTK.Input.Key.ShiftLeft])) { + if (CrowInterface.ProcessMouseButtonDown ((int)otk_e.Button)) + return; + } + MouseButtonDown.Raise (sender, otk_e); + } + void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) + { + if (mousePosition.X.IsInBetween (0, ClientRectangle.Width) & mousePosition.Y.IsInBetween (0, ClientRectangle.Height) + &!(Keyboard[OpenTK.Input.Key.ShiftLeft])) { + if (CrowInterface.ProcessMouseWheelChanged (otk_e.DeltaPrecise)) + return; + } + float speed = ZoomSpeed; + if (Keyboard[OpenTK.Input.Key.ControlLeft]) + speed *= 20.0f; + + eyeDist -= otk_e.Delta * speed; + if (eyeDist < zNear) + eyeDist = zNear; + else if (eyeDist > zFar) + eyeDist = zFar; + UpdateViewMatrix (); + + MouseWheelChanged.Raise (sender, otk_e); + } + #endregion + + #region keyboard Handling + void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (!CrowInterface.ProcessKeyDown((int)otk_e.Key)) + KeyboardKeyDown.Raise (this, otk_e); + } + void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (!CrowInterface.ProcessKeyUp((int)otk_e.Key)) + KeyboardKeyUp.Raise (this, otk_e); + } + void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) + { + CrowInterface.ProcessKeyPress (e.KeyChar); + } + #endregion + + public void UpdateViewMatrix() + { + Rectangle r = this.ClientRectangle; + GL.Viewport( r.X, r.Y, r.Width, r.Height); + projection = Matrix4.CreatePerspectiveFieldOfView (fovY, r.Width / (float)r.Height, zNear, zFar); + vLook = vLookInit.Transform( + Matrix4.CreateRotationX (viewXangle)* + Matrix4.CreateRotationY (viewZangle)); + vLook.Normalize(); + vEye = vEyeTarget + vLook * eyeDist; + modelview = Matrix4.LookAt(vEye, vEyeTarget, Vector3.UnitY); + GL.GetInteger(GetPName.Viewport, viewport); + } + static Vector4 UnProject(ref Matrix4 projection, ref Matrix4 view, int[] viewport, Vector2 mouse) + { + Vector4 vec; + + vec.X = 2.0f * mouse.X / (float)viewport[2] - 1; + vec.Y = -(2.0f * mouse.Y / (float)viewport[3] - 1); + vec.Z = 0f; + vec.W = 1.0f; + + Matrix4 viewInv = Matrix4.Invert(view); + Matrix4 projInv = Matrix4.Invert(projection); + + Vector4.Transform(ref vec, ref projInv, out vec); + Vector4.Transform(ref vec, ref viewInv, out vec); + + if (vec.W > float.Epsilon || vec.W < float.Epsilon) + { + vec.X /= vec.W; + vec.Y /= vec.W; + vec.Z /= vec.W; + } + + return vec; + } + } + + public static class Extensions { + public static Vector4 ToVector4(this Color c){ + float[] f = c.floatArray; + return new Vector4 (f [0], f [1], f [2], f [3]); + } + public static Vector3 Transform(this Vector3 v, Matrix4 m){ + return Vector4.Transform(new Vector4(v, 1), m).Xyz; + } + public static bool IsInBetween(this int v, int min, int max){ + return v >= min & v <= max; + } + } +} diff --git a/Tests/HelloCube.cs b/Tests/HelloCube.cs index e45e8d30..8f6f185c 100644 --- a/Tests/HelloCube.cs +++ b/Tests/HelloCube.cs @@ -26,7 +26,7 @@ using Crow; namespace Tests { - class HelloCube : OpenTKGameWindow + class HelloCube : CrowWindow { [STAThread] static void Main () diff --git a/Tests/HelloWorld.cs b/Tests/HelloWorld.cs index 22362393..5006d48d 100644 --- a/Tests/HelloWorld.cs +++ b/Tests/HelloWorld.cs @@ -3,7 +3,7 @@ using Crow; namespace Tests { - class HelloWorld : OpenTKGameWindow + class HelloWorld : CrowWindow { public HelloWorld () : base(800, 600,"Crow Test with OpenTK") diff --git a/Tests/OpenTKGameWindow.cs b/Tests/OpenTKGameWindow.cs deleted file mode 100644 index c587d768..00000000 --- a/Tests/OpenTKGameWindow.cs +++ /dev/null @@ -1,356 +0,0 @@ -// -// OpenTKGameWindow.cs -// -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2016 jp -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -using System.Threading; -using OpenTK; -using OpenTK.Graphics.OpenGL; -using System.Collections.Generic; - -namespace Crow -{ - public class OpenTKGameWindow : GameWindow, IValueChange - { - #region IValueChange implementation - public event EventHandler ValueChanged; - public virtual void NotifyValueChanged(string MemberName, object _value) - { - if (ValueChanged != null) - ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); - } - #endregion - - public Interface CrowInterface; - - #region FPS - int frameCpt = 0; - int _fps = 0; - - public int fps { - get { return _fps; } - set { - if (_fps == value) - return; - - _fps = value; - - if (_fps > fpsMax) { - fpsMax = _fps; - ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax)); - } else if (_fps < fpsMin) { - fpsMin = _fps; - ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin)); - } - if (frameCpt % 3 == 0) - ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); - #if MEASURE_TIME - foreach (PerformanceMeasure m in PerfMeasures) - m.NotifyChanges(); - #endif - } - } - - public int fpsMin = int.MaxValue; - public int fpsMax = 0; - - void resetFps () - { - fpsMin = int.MaxValue; - fpsMax = 0; - _fps = 0; - } - public string update = ""; - public string drawing = ""; - public string layouting = ""; - public string clipping = ""; - #if MEASURE_TIME - public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10); - #endif - - #endregion - - #region ctor - public OpenTKGameWindow(int _width = 800, int _height = 600, string _title="Crow", - int colors = 32, int depth = 24, int stencil = 0, int samples = 1, - int major=3, int minor=3) - : this(_width, _height, new OpenTK.Graphics.GraphicsMode(colors, depth, stencil, samples), - _title,GameWindowFlags.Default,DisplayDevice.Default, - major,minor,OpenTK.Graphics.GraphicsContextFlags.Default) - { - } - public OpenTKGameWindow (int width, int height, OpenTK.Graphics.GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags) - : base(width,height,mode,title,options,device,major,minor,flags) - { - CrowInterface = new Interface (); - - #if MEASURE_TIME - PerfMeasures = new List ( - new PerformanceMeasure[] { - this.CrowInterface.updateMeasure, - this.CrowInterface.layoutingMeasure, - this.CrowInterface.clippingMeasure, - this.CrowInterface.drawingMeasure, - this.glDrawMeasure - } - ); - #endif - - Thread t = new Thread (interfaceThread); - t.IsBackground = true; - t.Start (); - } - - #endregion - - #if MEASURE_TIME - public List PerfMeasures; - #endif - - void interfaceThread() - { - CrowInterface.Quit += Quit; - CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; - while (CrowInterface.ClientRectangle.Size.Width == 0) - Thread.Sleep (5); - - while (true) { - CrowInterface.Update (); - //Thread.Sleep (1); - } - } - - public void Quit (object sender, EventArgs e) - { - this.Exit (); - } - void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e) - { - this.Cursor = new MouseCursor( - (int)e.NewCursor.Xhot, - (int)e.NewCursor.Yhot, - (int)e.NewCursor.Width, - (int)e.NewCursor.Height, - e.NewCursor.data); - } - - #region Events - //those events are raised only if mouse isn't in a graphic object - public event EventHandler MouseWheelChanged; - public event EventHandler MouseButtonUp; - public event EventHandler MouseButtonDown; - public event EventHandler MouseClick; - public event EventHandler MouseMove; - public event EventHandler KeyboardKeyDown; - public event EventHandler KeyboardKeyUp; - - #endregion - - #region graphic context - public int texID; - public Shader shader; - public vaoMesh quad; - public Matrix4 projection; - - /// Create the texture for the interface redering - void createContext() - { - if (GL.IsTexture(texID)) - GL.DeleteTexture (texID); - GL.GenTextures(1, out texID); - GL.ActiveTexture (TextureUnit.Texture0); - GL.BindTexture(TextureTarget.Texture2D, texID); - - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, - ClientRectangle.Width, ClientRectangle.Height, 0, - OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.bmp); - - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - - GL.BindTexture(TextureTarget.Texture2D, 0); - } - /// Rendering of the interface - void OpenGLDraw() - { - #if MEASURE_TIME - glDrawMeasure.StartCycle(); - #endif - bool blend, depthTest; - GL.GetBoolean (GetPName.Blend, out blend); - GL.GetBoolean (GetPName.DepthTest, out depthTest); - GL.Enable (EnableCap.Blend); - GL.Disable (EnableCap.DepthTest); - - shader.Enable (); - shader.SetMVP (projection); - GL.ActiveTexture (TextureUnit.Texture0); - GL.BindTexture (TextureTarget.Texture2D, texID); - if (Monitor.TryEnter(CrowInterface.RenderMutex)) { - if (CrowInterface.IsDirty) { - GL.TexSubImage2D (TextureTarget.Texture2D, 0, - CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top, - CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, - OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, CrowInterface.dirtyBmp); - CrowInterface.IsDirty = false; - } - Monitor.Exit (CrowInterface.RenderMutex); - } - quad.Render (BeginMode.TriangleStrip); - GL.BindTexture(TextureTarget.Texture2D, 0); - - if (!blend) - GL.Disable (EnableCap.Blend); - if (depthTest) - GL.Enable (EnableCap.DepthTest); - #if MEASURE_TIME - glDrawMeasure.StopCycle(); - #endif - } - #endregion - - /// Override this method for your OpenGL rendering calls - public virtual void OnRender(FrameEventArgs e) - { - } - /// Override this method to customize clear method between frames - public virtual void GLClear() - { - GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit); - } - - #region Game win overrides - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - - this.KeyPress += new EventHandler(OpenTKGameWindow_KeyPress); - Keyboard.KeyDown += new EventHandler(Keyboard_KeyDown); - Keyboard.KeyUp += new EventHandler(Keyboard_KeyUp); - Mouse.WheelChanged += new EventHandler(Mouse_WheelChanged); - Mouse.ButtonDown += new EventHandler(Mouse_ButtonDown); - Mouse.ButtonUp += new EventHandler(Mouse_ButtonUp); - Mouse.Move += new EventHandler(Mouse_Move); - - GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - #if DEBUG - Console.WriteLine("\n\n*************************************"); - Console.WriteLine("GL version: " + GL.GetString (StringName.Version)); - Console.WriteLine("GL vendor: " + GL.GetString (StringName.Vendor)); - Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion)); - Console.WriteLine("*************************************\n"); - #endif - - projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1); - - shader = new Shader (); - quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); - } - - protected override void OnUpdateFrame(FrameEventArgs e) - { - base.OnUpdateFrame(e); - fps = (int)RenderFrequency; - - - if (frameCpt > 500) { - resetFps (); - frameCpt = 0; -// #if DEBUG -// GC.Collect(); -// GC.WaitForPendingFinalizers(); -// NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); -// #endif - } - frameCpt++; - } - protected override void OnRenderFrame(FrameEventArgs e) - { - GLClear (); - - base.OnRenderFrame(e); - - OnRender (e); - OpenGLDraw (); - - SwapBuffers (); - } - - protected override void OnResize(EventArgs e) - { - base.OnResize (e); - CrowInterface.ProcessResize( - new Rectangle( - 0, - 0, - this.ClientRectangle.Width, - this.ClientRectangle.Height)); - createContext (); - GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); - } - #endregion - - #region Mouse Handling - void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){ - for (int i = 0; i < MouseState.MaxButtons; i++) { - if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i)) - e.EnableBit (i); - } - } - void Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) - { - if (!CrowInterface.ProcessMouseMove (otk_e.X, otk_e.Y)) - MouseMove.Raise (sender, otk_e); - } - void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) - { - if (!CrowInterface.ProcessMouseButtonUp ((int)otk_e.Button)) - MouseButtonUp.Raise (sender, otk_e); - } - void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) - { - if (!CrowInterface.ProcessMouseButtonDown ((int)otk_e.Button)) - MouseButtonDown.Raise (sender, otk_e); - } - void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) - { - if (!CrowInterface.ProcessMouseWheelChanged (otk_e.DeltaPrecise)) - MouseWheelChanged.Raise (sender, otk_e); - } - #endregion - - #region keyboard Handling - void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) - { - if (!CrowInterface.ProcessKeyDown((int)otk_e.Key)) - KeyboardKeyDown.Raise (this, otk_e); - } - void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) - { - if (!CrowInterface.ProcessKeyUp((int)otk_e.Key)) - KeyboardKeyUp.Raise (this, otk_e); - } - void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) - { - CrowInterface.ProcessKeyPress (e.KeyChar); - } - #endregion - } -} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a95a034a..4ecaa9a3 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -54,11 +54,12 @@ - + + diff --git a/Tests/UIEditor.cs b/Tests/UIEditor.cs index b08584d4..9e1b26bc 100644 --- a/Tests/UIEditor.cs +++ b/Tests/UIEditor.cs @@ -26,7 +26,7 @@ using Crow; namespace Tests { - class UIEditor : OpenTKGameWindow + class UIEditor : CrowWindow { [STAThread] static void Main ()