From: jpbruyere Date: Fri, 13 Jan 2017 22:36:14 +0000 (+0100) Subject: 3d interfaces X-Git-Tag: v0.5.1~42 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=e4b3f163986955b39913d1e4ff1456bb0b299252;p=jp%2Fcrow.git 3d interfaces --- 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/CrowWindow.cs b/Tests/CrowWindow.cs new file mode 100644 index 00000000..25211744 --- /dev/null +++ b/Tests/CrowWindow.cs @@ -0,0 +1,350 @@ +// +// 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 + + #region FPS + int frameCpt = 0; + int _fps = 0; + + public int fps { + get { return _fps; } + set { + if (_fps == value) + return; + + _fps = value; + #if MEASURE_TIME + 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)); + } + #endif + if (frameCpt % 3 == 0) + ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); + #if MEASURE_TIME +// 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; + + void resetFps () + { + fpsMin = int.MaxValue; + fpsMax = 0; + _fps = 0; + } + #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) + { + } + + #endregion + + protected Shader shader; + public List ifaceControl = new List(); + int focusedIdx = -1, activeIdx = -2; + + void addInterfaceControler(InterfaceControler ifaceControler) + { + 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) + { + 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 + + 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; + } + 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; + } + 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 + 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 + + shader = new Shader (); + 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; +// #if DEBUG +// GC.Collect(); +// GC.WaitForPendingFinalizers(); +// NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); +// #endif + } + #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); + for (int i = 0; i < ifaceControl.Count; i++) { + ifaceControl[i].ProcessResize( + new Rectangle( + 0, + 0, + this.ClientRectangle.Width, + this.ClientRectangle.Height)); + } + } + #endregion + + #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); + } + } + protected virtual void Mouse_Move(object sender, OpenTK.Input.MouseMoveEventArgs otk_e) + { + 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); + } + protected virtual void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + activeIdx = -2; + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseButtonUp ((int)otk_e.Button)) + return; + } + MouseButtonUp.Raise (sender, otk_e); + } + protected virtual void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + activeIdx = focusedIdx; + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseButtonDown ((int)otk_e.Button)) + return; + } + MouseButtonDown.Raise (sender, otk_e); + } + protected virtual void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) + { + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessMouseWheelChanged (otk_e.DeltaPrecise)) + return; + } + MouseWheelChanged.Raise (sender, otk_e); + } + + protected virtual void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessKeyDown((int)otk_e.Key)) + return; + } + KeyboardKeyDown.Raise (this, otk_e); + } + protected virtual void Keyboard_KeyUp(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { + if (focusedIdx >= 0) { + if (ifaceControl [focusedIdx].ProcessKeyUp((int)otk_e.Key)) + return; + } + KeyboardKeyUp.Raise (this, otk_e); + } + protected virtual void OpenTKGameWindow_KeyPress (object sender, OpenTK.KeyPressEventArgs e) + { + 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/OpenTKGameWindow.cs b/Tests/OpenTKGameWindow.cs deleted file mode 100644 index 1f103079..00000000 --- a/Tests/OpenTKGameWindow.cs +++ /dev/null @@ -1,358 +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; - - 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 - } - 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); - - 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); - - 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..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