From e4b3f163986955b39913d1e4ff1456bb0b299252 Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Fri, 13 Jan 2017 23:36:14 +0100 Subject: [PATCH] 3d interfaces --- Templates/CheckBox.template | 2 +- Tests/BasicTests.cs | 88 +++--- Tests/{OpenTKGameWindow.cs => CrowWindow.cs} | 292 +++++++++---------- Tests/Hello3D.cs | 149 ++++++++++ Tests/HelloCube.cs | 4 +- Tests/HelloWorld.cs | 4 +- Tests/InterfaceControler.cs | 220 ++++++++++++++ Tests/OpenGL/Extensions.cs | 64 ++++ Tests/Tests.csproj | 7 +- Tests/UIEditor.cs | 4 +- src/GraphicObjects/GraphicObject.cs | 4 +- src/GraphicObjects/Label.cs | 4 +- src/GraphicObjects/TextRun.cs | 3 +- src/Interface.cs | 249 ++++++++++------ 14 files changed, 797 insertions(+), 297 deletions(-) rename Tests/{OpenTKGameWindow.cs => CrowWindow.cs} (56%) create mode 100644 Tests/Hello3D.cs create mode 100644 Tests/InterfaceControler.cs create mode 100644 Tests/OpenGL/Extensions.cs 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..8b9f1afb 100644 --- a/Tests/BasicTests.cs +++ b/Tests/BasicTests.cs @@ -10,7 +10,7 @@ using System.Diagnostics; namespace Tests { - class BasicTests : OpenTKGameWindow + class BasicTests : CrowWindow { public BasicTests () : base(800, 600,"test: press to toogle test files") @@ -129,7 +129,7 @@ namespace Tests testFiles = testFiles.Concat (Directory.GetFiles (@"Interfaces/Unsorted", "*.crow")).ToArray (); object tc = Color.AirForceBlueRaf; - CrowInterface.LoadInterface(testFiles[idx]).DataSource = this; + Load(testFiles[idx]).DataSource = this; } void KeyboardKeyDown1 (object sender, OpenTK.Input.KeyboardKeyEventArgs e) { @@ -141,19 +141,19 @@ namespace Tests NotifyValueChanged ("TestList", TestList); return; } else if (e.Key == OpenTK.Input.Key.F4) { - GraphicObject w = CrowInterface.LoadInterface ("Interfaces/TemplatedContainer/testWindow.goml"); + GraphicObject w = Load ("Interfaces/TemplatedContainer/testWindow.goml"); w.DataSource = this; return; } else if (e.Key == OpenTK.Input.Key.F5) { - GraphicObject w = CrowInterface.LoadInterface ("Interfaces/TemplatedContainer/testWindow2.goml"); + GraphicObject w = Load ("Interfaces/TemplatedContainer/testWindow2.goml"); w.DataSource = this; return; }else if (e.Key == OpenTK.Input.Key.F6) { - GraphicObject w = CrowInterface.LoadInterface ("Interfaces/Divers/0.crow"); + GraphicObject w = Load ("Interfaces/Divers/0.crow"); w.DataSource = this; return; }else if (e.Key == OpenTK.Input.Key.F7) { - GraphicObject w = CrowInterface.LoadInterface ("Interfaces/Divers/perfMeasures.crow"); + GraphicObject w = Load ("Interfaces/Divers/perfMeasures.crow"); w.DataSource = this; return; } else if (e.Key == OpenTK.Input.Key.F2) @@ -162,61 +162,61 @@ namespace Tests idx++; else return; - + try { - CrowInterface.ClearInterface (); + ClearInterface (); if (idx == testFiles.Length) idx = 0; else if (idx < 0) idx = testFiles.Length - 1; - + this.Title = testFiles [idx] + ". Press to cycle examples."; - GraphicObject obj = CrowInterface.LoadInterface(testFiles[idx]); + GraphicObject obj = Load (testFiles[idx]); obj.DataSource = this; } catch (Exception ex) { Debug.WriteLine (ex.Message + ex.InnerException); } } - void Tv_SelectedItemChanged (object sender, SelectionChangeEventArgs e) - { - FileInfo fi = e.NewValue as FileInfo; - if (fi == null) - return; - if (fi.Extension == ".crow" || fi.Extension == ".goml") { - Instantiator i = new Instantiator(fi.FullName); - lock (CrowInterface.UpdateMutex) { - (CrowInterface.FindByName ("crowContainer") as Container).SetChild - (i.CreateInstance(CrowInterface)); - //CurSources = i.GetImlSourcesCode(); - } - } - } - void onImlSourceChanged(Object sender, TextChangeEventArgs e){ - Instantiator i; - try { - i = Instantiator.CreateFromImlFragment (e.Text); - } catch (Exception ex) { - Debug.WriteLine (ex); - return; - } - lock (CrowInterface.UpdateMutex) { - (CrowInterface.FindByName ("crowContainer") as Container).SetChild - (i.CreateInstance(CrowInterface)); - } - } +// void Tv_SelectedItemChanged (object sender, SelectionChangeEventArgs e) +// { +// FileInfo fi = e.NewValue as FileInfo; +// if (fi == null) +// return; +// if (fi.Extension == ".crow" || fi.Extension == ".goml") { +// Instantiator i = new Instantiator(fi.FullName); +// lock (ifaceControl.CrowInterface.UpdateMutex) { +// (ifaceControl.CrowInterface.FindByName ("crowContainer") as Container).SetChild +// (i.CreateInstance(ifaceControl.CrowInterface)); +// //CurSources = i.GetImlSourcesCode(); +// } +// } +// } +// void onImlSourceChanged(Object sender, TextChangeEventArgs e){ +// Instantiator i; +// try { +// i = Instantiator.CreateFromImlFragment (e.Text); +// } catch (Exception ex) { +// Debug.WriteLine (ex); +// return; +// } +// lock (ifaceControl.CrowInterface.UpdateMutex) { +// (ifaceControl.CrowInterface.FindByName ("crowContainer") as Container).SetChild +// (i.CreateInstance(ifaceControl.CrowInterface)); +// } +// } void onButClick(object send, MouseButtonEventArgs e) { Console.WriteLine ("button clicked:" + send.ToString()); } - void onAddTabButClick(object sender, MouseButtonEventArgs e){ - - TabView tv = CrowInterface.FindByName("tabview1") as TabView; - if (tv == null) - return; - tv.AddChild (new TabItem () { Caption = "NewTab" }); - } +// void onAddTabButClick(object sender, MouseButtonEventArgs e){ +// +// TabView tv = ifaceControl.CrowInterface.FindByName("tabview1") as TabView; +// if (tv == null) +// return; +// tv.AddChild (new TabItem () { Caption = "NewTab" }); +// } [STAThread] static void Main () { diff --git a/Tests/OpenTKGameWindow.cs b/Tests/CrowWindow.cs similarity index 56% rename from Tests/OpenTKGameWindow.cs rename to Tests/CrowWindow.cs index 1f103079..25211744 100644 --- a/Tests/OpenTKGameWindow.cs +++ b/Tests/CrowWindow.cs @@ -26,19 +26,17 @@ using System.Collections.Generic; namespace Crow { - public class OpenTKGameWindow : GameWindow, IValueChange + public class CrowWindow : GameWindow, IValueChange { #region IValueChange implementation public event EventHandler ValueChanged; public virtual void NotifyValueChanged(string MemberName, object _value) { - if (ValueChanged != null) + if (ValueChanged != null) ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); } #endregion - public Interface CrowInterface; - #region FPS int frameCpt = 0; int _fps = 0; @@ -50,7 +48,7 @@ namespace Crow return; _fps = value; - + #if MEASURE_TIME if (_fps > fpsMax) { fpsMax = _fps; ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMax", fpsMax)); @@ -58,15 +56,19 @@ namespace Crow fpsMin = _fps; ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin)); } + #endif if (frameCpt % 3 == 0) ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); #if MEASURE_TIME - foreach (PerformanceMeasure m in PerfMeasures) - m.NotifyChanges(); +// foreach (PerformanceMeasure m in PerfMeasures) +// m.NotifyChanges(); #endif } } + #if MEASURE_TIME + public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10); + public int fpsMin = int.MaxValue; public int fpsMax = 0; @@ -76,18 +78,12 @@ namespace Crow 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", + 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), @@ -95,45 +91,55 @@ namespace Crow 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) + 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 + protected Shader shader; + public List ifaceControl = new List(); + int focusedIdx = -1, activeIdx = -2; - void interfaceThread() + void addInterfaceControler(InterfaceControler ifaceControler) { - CrowInterface.Quit += Quit; - CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; - while (CrowInterface.ClientRectangle.Size.Width == 0) - Thread.Sleep (5); - - while (true) { - CrowInterface.Update (); - //Thread.Sleep (1); + ifaceControler.CrowInterface.Quit += Quit; + ifaceControler.CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; + + ifaceControl.Add (ifaceControler); + } + void openGLDraw(){ + //save GL states + bool blend, depthTest, cullFace; + GL.GetBoolean (GetPName.Blend, out blend); + GL.GetBoolean (GetPName.DepthTest, out depthTest); + GL.GetBoolean (GetPName.CullFace, out cullFace); + GL.Enable (EnableCap.Blend); + GL.Disable (EnableCap.DepthTest); + GL.Disable (EnableCap.CullFace); + + #if MEASURE_TIME + glDrawMeasure.StartCycle(); + #endif + + shader.Enable (); + for (int i = 0; i < ifaceControl.Count; i++) { + shader.SetMVP (ifaceControl [i].InterfaceMVP); + ifaceControl [i].OpenGLDraw (); } + + #if MEASURE_TIME + glDrawMeasure.StopCycle(); + #endif + + //restore GL states + if (!blend) + GL.Disable (EnableCap.Blend); + if (depthTest) + GL.Enable (EnableCap.DepthTest); + if (cullFace) + GL.Enable (EnableCap.CullFace); } public void Quit (object sender, EventArgs e) @@ -162,78 +168,32 @@ namespace Crow #endregion - #region graphic context - public int texID; - public Shader shader; - public vaoMesh quad; - public Matrix4 projection; - - void createContext() - { - #region Create texture - 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); - #endregion + public ProjectiveIFaceControler Add3DInterface(int width, int height, Matrix4 ifaceModelMat){ + ProjectiveIFaceControler tmp = new ProjectiveIFaceControler (new Rectangle (0, 0, width, height), ifaceModelMat); + ifaceControl.Add (tmp); + return tmp; } - 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 + public GraphicObject AddWidget (GraphicObject g, int interfaceIdx = 0){ + if (ifaceControl.Count == 0)//create default orthogonal interface + addInterfaceControler (new InterfaceControler ( + new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height))); + ifaceControl [interfaceIdx].CrowInterface.AddWidget (g); + return g; } - #endregion - - /// - /// Override this method for your OpenGL rendering calls - /// + public GraphicObject Load (string path, int interfaceIdx = 0){ + if (ifaceControl.Count == 0)//create default orthogonal interface + addInterfaceControler (new InterfaceControler ( + new Rectangle (0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height))); + return ifaceControl [interfaceIdx].CrowInterface.LoadInterface (path); + } + public void ClearInterface (int interfaceIdx = 0){ + ifaceControl [interfaceIdx].CrowInterface.ClearInterface (); + } + /// Override this method for your OpenGL rendering calls public virtual void OnRender(FrameEventArgs e) { } - /// - /// Override this method to customize clear method between frames - /// + /// Override this method to customize clear method between frames public virtual void GLClear() { GL.Clear (ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit); @@ -252,26 +212,25 @@ namespace Crow 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"); - - projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1); + #endif shader = new Shader (); - quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); - } + shader.Enable (); + GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); fps = (int)RenderFrequency; - + #if MEASURE_TIME if (frameCpt > 500) { resetFps (); frameCpt = 0; @@ -281,6 +240,8 @@ namespace Crow // NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); // #endif } + #endif + frameCpt++; } protected override void OnRenderFrame(FrameEventArgs e) @@ -290,68 +251,99 @@ namespace Crow base.OnRenderFrame(e); OnRender (e); - OpenGLDraw (); + 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); + for (int i = 0; i < ifaceControl.Count; i++) { + ifaceControl[i].ProcessResize( + new Rectangle( + 0, + 0, + this.ClientRectangle.Width, + this.ClientRectangle.Height)); + } } #endregion - #region Mouse Handling + #region Mouse and Keyboard 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) + protected virtual void Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) { - if (!CrowInterface.ProcessMouseMove (otk_e.X, otk_e.Y)) + if (activeIdx == -2) { + focusedIdx = -1; + for (int i = 0; i < ifaceControl.Count; i++) { + if (ifaceControl [i].ProcessMouseMove (otk_e.X, otk_e.Y)) { + focusedIdx = i; + return; + } + } + } else if (focusedIdx >= 0) { + ifaceControl [focusedIdx].ProcessMouseMove (otk_e.X, otk_e.Y); + return; + } + if (focusedIdx < 0) MouseMove.Raise (sender, otk_e); } - void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + protected virtual void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) { - if (!CrowInterface.ProcessMouseButtonUp ((int)otk_e.Button)) - MouseButtonUp.Raise (sender, otk_e); + activeIdx = -2; + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseButtonUp ((int)otk_e.Button)) + return; + } + MouseButtonUp.Raise (sender, otk_e); } - void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + protected virtual void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) { - if (!CrowInterface.ProcessMouseButtonDown ((int)otk_e.Button)) - MouseButtonDown.Raise (sender, otk_e); + activeIdx = focusedIdx; + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseButtonDown ((int)otk_e.Button)) + return; + } + MouseButtonDown.Raise (sender, otk_e); } - void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) + protected virtual void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) { - if (!CrowInterface.ProcessMouseWheelChanged (otk_e.DeltaPrecise)) - MouseWheelChanged.Raise (sender, otk_e); + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseWheelChanged (otk_e.DeltaPrecise)) + return; + } + MouseWheelChanged.Raise (sender, otk_e); } - #endregion - #region keyboard Handling - void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + protected virtual void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) { - if (!CrowInterface.ProcessKeyDown((int)otk_e.Key)) - KeyboardKeyDown.Raise (this, otk_e); + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessKeyDown((int)otk_e.Key)) + return; + } + KeyboardKeyDown.Raise (this, otk_e); } - void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + protected virtual void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) { - if (!CrowInterface.ProcessKeyUp((int)otk_e.Key)) - KeyboardKeyUp.Raise (this, otk_e); + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessKeyUp((int)otk_e.Key)) + return; + } + KeyboardKeyUp.Raise (this, otk_e); } - void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) + protected virtual void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) { - CrowInterface.ProcessKeyPress (e.KeyChar); + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessKeyPress (e.KeyChar)) + return; + } + //TODO:create keyboardkeypress evt } #endregion } diff --git a/Tests/Hello3D.cs b/Tests/Hello3D.cs new file mode 100644 index 00000000..c03a5ced --- /dev/null +++ b/Tests/Hello3D.cs @@ -0,0 +1,149 @@ +// +// HelloCube.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 OpenTK; +using OpenTK.Graphics.OpenGL; +using Crow; + +namespace Tests +{ + class Hello3D : CrowWindow + { + [STAThread] + static void Main () + { + Hello3D win = new Hello3D (); + win.Run (30); + } + + public Hello3D () + : base(800, 600,"Crow Test with OpenTK") + { + } + + public Matrix4 modelview, projection; + public int[] viewport = new int[4]; + public Vector3 vEyeTarget = new Vector3(0f, 0f, 0f); + public Vector3 vEye; + public Vector3 vLookInit = Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f)); + public Vector3 vLook; // Camera vLook Vector + public float zNear = 0.001f, zFar = 300.0f; + public float fovY = (float)Math.PI / 4; + public float eyeDist = 10.2f; + public float viewZangle, viewXangle; + public const float MoveSpeed = 0.02f; + public const float RotationSpeed = 0.005f; + public const float ZoomSpeed = 0.22f; + + vaoMesh cube; + Texture texture; + ProjectiveIFaceControler iface3D; + + void initGL(){ + GL.Enable (EnableCap.CullFace); + GL.Enable (EnableCap.Blend); + GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); + + cube = vaoMesh.CreateCube (); + texture = new Texture ("image/textest.png"); + } + + protected override void OnLoad (EventArgs e) + { + base.OnLoad (e); + + MouseMove += HelloCube_MouseMove; + MouseWheelChanged += Hello3D_MouseWheelChanged; + + iface3D = Add3DInterface (2048, 2048, + Matrix4.CreateScale (6f) * + Matrix4.CreateRotationX (MathHelper.PiOver2) * + Matrix4.CreateTranslation (Vector3.UnitY * -1.1f)); + Load (@"Interfaces/Divers/0.crow").DataSource = this; + initGL (); + shader.Enable (); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + UpdateViewMatrix (); + } + + public override void OnRender (FrameEventArgs e) + { + base.OnRender (e); + + shader.SetMVP(modelview * projection); + + GL.BindTexture (TextureTarget.Texture2D, texture); + cube.Render (BeginMode.Triangles); + GL.BindTexture (TextureTarget.Texture2D, 0); + } + + 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.CreateRotationZ (viewZangle)); + vLook.Normalize(); + vEye = vEyeTarget + vLook * eyeDist; + modelview = Matrix4.LookAt(vEye, vEyeTarget, Vector3.UnitZ); + GL.GetInteger(GetPName.Viewport, viewport); + + iface3D.UpdateView (projection, modelview, viewport, vEye); + } + + void HelloCube_MouseMove(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) + { + if (otk_e.Mouse.MiddleButton == OpenTK.Input.ButtonState.Pressed) { + viewZangle -= (float)otk_e.XDelta * RotationSpeed; + viewXangle -= (float)otk_e.YDelta * RotationSpeed; + 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.Xy.Normalized (); + Vector2 disp = v2Look.PerpendicularLeft * otk_e.XDelta * MoveSpeed + + v2Look * otk_e.YDelta * MoveSpeed; + vEyeTarget += new Vector3 (disp.X, disp.Y, 0); + UpdateViewMatrix (); + } + } + void Hello3D_MouseWheelChanged (object sender, OpenTK.Input.MouseWheelEventArgs e) + { + float speed = ZoomSpeed; + if (Keyboard[OpenTK.Input.Key.ControlLeft]) + speed *= 20.0f; + + eyeDist -= e.Delta * speed; + if (eyeDist < zNear) + eyeDist = zNear; + else if (eyeDist > zFar) + eyeDist = zFar; + UpdateViewMatrix (); + } + } +} \ No newline at end of file diff --git a/Tests/HelloCube.cs b/Tests/HelloCube.cs index e45e8d30..d9223f5a 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 () @@ -63,7 +63,7 @@ namespace Tests { base.OnLoad (e); - CrowInterface.AddWidget( + AddWidget( new Window () { Title = "Hello World" diff --git a/Tests/HelloWorld.cs b/Tests/HelloWorld.cs index 22362393..a38c7974 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") @@ -14,7 +14,7 @@ namespace Tests { base.OnLoad (e); - CrowInterface.AddWidget(new Label("Hello World")); + AddWidget(new Label("Hello World")); } [STAThread] diff --git a/Tests/InterfaceControler.cs b/Tests/InterfaceControler.cs new file mode 100644 index 00000000..6cb13b2f --- /dev/null +++ b/Tests/InterfaceControler.cs @@ -0,0 +1,220 @@ +// +// InterfaceControler.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 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 OpenTK; +using OpenTK.Graphics.OpenGL; +using System.Threading; +using System.Collections.Generic; + +namespace Crow +{ + public class ProjectiveIFaceControler : InterfaceControler { + Matrix4 modelview; + int[] viewport = new int[4]; + Vector3 vEyePosition; + + public Matrix4 ifaceModelMat; + Point localMousePos; + + public ProjectiveIFaceControler(Rectangle ifaceBounds, Matrix4 _ifaceModelMat) + : base(ifaceBounds){ + ifaceModelMat = _ifaceModelMat; + } + + public override Matrix4 InterfaceMVP { + get { return ifaceModelMat * modelview * projection; } + } + + public override void initGL(){ + quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); + //ifaceModelMat = Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(Vector3.UnitY); + CrowInterface.ProcessResize(iRect); + createContext (); + //CrowInterface.ProcessResize (iRect); + } + public override void ProcessResize (Rectangle newSize) + { + } + + public void UpdateView (Matrix4 _projection, Matrix4 _modelview, int[] _viewport, Vector3 _vEyePosition) + { + projection = _projection; + modelview = _modelview; + viewport = _viewport; + vEyePosition = _vEyePosition; + } + public override bool ProcessMouseMove (int x, int y) + { + Matrix4 mv = ifaceModelMat * modelview; + Vector3 vMouse = Extensions.UnProject(ref projection, ref mv, viewport, new Vector2 (x, y)).Xyz; + Vector3 vE = vEyePosition.Transform (ifaceModelMat.Inverted()); + Vector3 vMouseRay = Vector3.Normalize(vMouse - vE); + float a = vE.Z / vMouseRay.Z; + vMouse = vE - vMouseRay * a; + //vMouse = vMouse.Transform (interfaceModelView.Inverted()); + localMousePos = new Point ((int)Math.Truncate ((vMouse.X + 0.5f) * iRect.Width), + iRect.Height - (int)Math.Truncate ((vMouse.Y + 0.5f) * iRect.Height)); + mouseIsInInterface = localMousePos.X.IsInBetween (0, iRect.Width) & localMousePos.Y.IsInBetween (0, iRect.Height); + + return mouseIsInInterface ? CrowInterface.ProcessMouseMove (localMousePos.X, localMousePos.Y) : false; + } + } + public class InterfaceControler { + public Interface CrowInterface; + public int texID; + public vaoMesh quad; + public Rectangle iRect = new Rectangle(0,0,2048,2048); + public bool mouseIsInInterface = false; + + protected Matrix4 projection; + public virtual Matrix4 InterfaceMVP { + get { return projection; } + } + + #if MEASURE_TIME + public List PerfMeasures; + public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10); + #endif + + #region CTOR + public InterfaceControler(Rectangle ifaceBounds){ + iRect = ifaceBounds; + + 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 (); + + initGL (); + } + #endregion + + void interfaceThread() + { + while (CrowInterface.ClientRectangle.Size.Width == 0) + Thread.Sleep (5); + + while (true) { + CrowInterface.Update (); + //Thread.Sleep (1); + } + } + + #region Mouse And Keyboard handling + public virtual void ProcessResize(Rectangle newSize){ + iRect = newSize; + CrowInterface.ProcessResize(newSize); + createContext (); + GL.Viewport (0, 0, newSize.Width, newSize.Height);//TODO:find a better place for this + } + public virtual bool ProcessMouseMove(int x, int y){ + return CrowInterface.ProcessMouseMove (x, y); + } + public virtual bool ProcessMouseButtonUp(int button) + { + return CrowInterface.ProcessMouseButtonUp (button); + } + public virtual bool ProcessMouseButtonDown(int button) + { + return CrowInterface.ProcessMouseButtonDown (button); + } + public virtual bool ProcessMouseWheelChanged(float delta) + { + return CrowInterface.ProcessMouseWheelChanged (delta); + } + public virtual bool ProcessKeyDown(int Key){ + return CrowInterface.ProcessKeyDown(Key); + } + public virtual bool ProcessKeyUp(int Key){ + return CrowInterface.ProcessKeyUp(Key); + } + public virtual bool ProcessKeyPress(char Key){ + return CrowInterface.ProcessKeyPress(Key); + } + #endregion + + #region graphic context + public virtual void initGL(){ + projection = OpenTK.Matrix4.CreateOrthographicOffCenter (-0.5f, 0.5f, -0.5f, 0.5f, 1, -1); + quad = new Crow.vaoMesh (0, 0, 0, 1, 1, 1, -1); + createContext (); + } + /// Create the texture for the interface redering + public virtual 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, + iRect.Width, iRect.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 + public virtual void OpenGLDraw() + { + #if MEASURE_TIME + glDrawMeasure.StartCycle(); + #endif + + 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 MEASURE_TIME + glDrawMeasure.StopCycle(); + #endif + } + #endregion + } +} + diff --git a/Tests/OpenGL/Extensions.cs b/Tests/OpenGL/Extensions.cs new file mode 100644 index 00000000..17fe6086 --- /dev/null +++ b/Tests/OpenGL/Extensions.cs @@ -0,0 +1,64 @@ +// +// Extensions.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 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 OpenTK; +using Crow; + +namespace Crow +{ + 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; + } + public 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; + } + } +} + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a95a034a..4e19b4d8 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -8,7 +8,7 @@ Exe Tests Tests - Tests.BasicTests + Tests.Hello3D v4.5 AnyCPU 0.5 @@ -54,11 +54,14 @@ - + + + + diff --git a/Tests/UIEditor.cs b/Tests/UIEditor.cs index b08584d4..2c03bdbb 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 () @@ -44,7 +44,7 @@ namespace Tests { base.OnLoad (e); - CrowInterface.AddWidget( + AddWidget( new Window () { Title = "Hello World" diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 25332832..e0f1ebfd 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -634,7 +634,7 @@ namespace Crow List