<HorizontalStack Style="Control" Background="{./Background}">
<Image Style="Icon" Path="#Crow.Images.Icons.checkbox.svg"
SvgSub="{./IsChecked}"/>
- <Label Font="{./Font}" Text="{./Caption}"/>
+ <Label Font="{./Font}" Text="{./Caption}" Foreground="{./Foreground}"/>
</HorizontalStack>
\ No newline at end of file
namespace Tests
{
- class BasicTests : OpenTKGameWindow
+ class BasicTests : CrowWindow
{
public BasicTests ()
: base(800, 600,"test: press <F3> to toogle test files")
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)
{
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)
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 <F3> 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 ()
{
--- /dev/null
+//
+// OpenTKGameWindow.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+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<ValueChangeEventArgs> 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<InterfaceControler> ifaceControl = new List<InterfaceControler>();
+ 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<OpenTK.Input.MouseWheelEventArgs> MouseWheelChanged;
+ public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonUp;
+ public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonDown;
+ public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseClick;
+ public event EventHandler<OpenTK.Input.MouseMoveEventArgs> MouseMove;
+ public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyDown;
+ public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> 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 ();
+ }
+ /// <summary>Override this method for your OpenGL rendering calls</summary>
+ public virtual void OnRender(FrameEventArgs e)
+ {
+ }
+ /// <summary>Override this method to customize clear method between frames</summary>
+ 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<OpenTK.KeyPressEventArgs>(OpenTKGameWindow_KeyPress);
+ Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown);
+ Keyboard.KeyUp += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyUp);
+ Mouse.WheelChanged += new EventHandler<OpenTK.Input.MouseWheelEventArgs>(Mouse_WheelChanged);
+ Mouse.ButtonDown += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(Mouse_ButtonDown);
+ Mouse.ButtonUp += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(Mouse_ButtonUp);
+ Mouse.Move += new EventHandler<OpenTK.Input.MouseMoveEventArgs>(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
+ }
+}
--- /dev/null
+//
+// HelloCube.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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
namespace Tests
{
- class HelloCube : OpenTKGameWindow
+ class HelloCube : CrowWindow
{
[STAThread]
static void Main ()
{
base.OnLoad (e);
- CrowInterface.AddWidget(
+ AddWidget(
new Window ()
{
Title = "Hello World"
namespace Tests
{
- class HelloWorld : OpenTKGameWindow
+ class HelloWorld : CrowWindow
{
public HelloWorld ()
: base(800, 600,"Crow Test with OpenTK")
{
base.OnLoad (e);
- CrowInterface.AddWidget(new Label("Hello World"));
+ AddWidget(new Label("Hello World"));
}
[STAThread]
--- /dev/null
+//
+// InterfaceControler.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+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<PerformanceMeasure> 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<PerformanceMeasure> (
+ 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 ();
+ }
+ /// <summary>Create the texture for the interface redering</summary>
+ 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);
+ }
+ /// <summary>Rendering of the interface</summary>
+ 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
+ }
+}
+
--- /dev/null
+//
+// Extensions.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+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;
+ }
+ }
+}
+
+++ /dev/null
-//
-// OpenTKGameWindow.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// 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 <http://www.gnu.org/licenses/>.
-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<ValueChangeEventArgs> 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<PerformanceMeasure> (
- 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<PerformanceMeasure> 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<OpenTK.Input.MouseWheelEventArgs> MouseWheelChanged;
- public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonUp;
- public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseButtonDown;
- public event EventHandler<OpenTK.Input.MouseButtonEventArgs> MouseClick;
- public event EventHandler<OpenTK.Input.MouseMoveEventArgs> MouseMove;
- public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyboardKeyDown;
- public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> 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
-
- /// <summary>
- /// Override this method for your OpenGL rendering calls
- /// </summary>
- public virtual void OnRender(FrameEventArgs e)
- {
- }
- /// <summary>
- /// Override this method to customize clear method between frames
- /// </summary>
- 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<OpenTK.KeyPressEventArgs>(OpenTKGameWindow_KeyPress);
- Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown);
- Keyboard.KeyUp += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyUp);
- Mouse.WheelChanged += new EventHandler<OpenTK.Input.MouseWheelEventArgs>(Mouse_WheelChanged);
- Mouse.ButtonDown += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(Mouse_ButtonDown);
- Mouse.ButtonUp += new EventHandler<OpenTK.Input.MouseButtonEventArgs>(Mouse_ButtonUp);
- Mouse.Move += new EventHandler<OpenTK.Input.MouseMoveEventArgs>(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
- }
-}
<OutputType>Exe</OutputType>
<RootNamespace>Tests</RootNamespace>
<AssemblyName>Tests</AssemblyName>
- <StartupObject>Tests.BasicTests</StartupObject>
+ <StartupObject>Tests.Hello3D</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ReleaseVersion>0.5</ReleaseVersion>
<Compile Include="BasicTests.cs" />
<Compile Include="OpenGL\Shader.cs" />
<Compile Include="OpenGL\vaoMesh.cs" />
- <Compile Include="OpenTKGameWindow.cs" />
<Compile Include="OpenGL\Texture.cs" />
<Compile Include="HelloWorld.cs" />
<Compile Include="HelloCube.cs" />
<Compile Include="UIEditor.cs" />
+ <Compile Include="CrowWindow.cs" />
+ <Compile Include="Hello3D.cs" />
+ <Compile Include="OpenGL\Extensions.cs" />
+ <Compile Include="InterfaceControler.cs" />
</ItemGroup>
<ItemGroup>
<None Include="image\u.svg">
namespace Tests
{
- class UIEditor : OpenTKGameWindow
+ class UIEditor : CrowWindow
{
[STAThread]
static void Main ()
{
base.OnLoad (e);
- CrowInterface.AddWidget(
+ AddWidget(
new Window ()
{
Title = "Hello World"
List<Style> styling = new List<Style>();
- //Search for a style mathing :
+ //Search for a style matching :
//1: Full class name, with full namespace
//2: class name
//3: style may have been registered with their ressource ID minus .style extention
using (ImageSurface draw =
new ImageSurface(bmp, Format.Argb32, Slot.Width, Slot.Height, stride)) {
using (Context gr = new Context (draw)) {
- gr.Antialias = Antialias.Subpixel;
+ gr.Antialias = Interface.Antialias;
onDraw (gr);
}
draw.Flush ();
gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
gr.SetFontSize (Font.Size);
gr.FontOptions = Interface.FontRenderingOptions;
-
- gr.Antialias = Antialias.Subpixel;
-
+ gr.Antialias = Interface.Antialias;
rText = new Rectangle(new Size(
measureRawSize(LayoutingType.Width), measureRawSize(LayoutingType.Height)));
gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
gr.SetFontSize (Font.Size);
gr.FontOptions = Interface.FontRenderingOptions;
-
- gr.Antialias = Antialias.Subpixel;
+ gr.Antialias = Interface.Antialias;
rText = new Rectangle (new Size (
measureRawSize (LayoutingType.Width), measureRawSize (LayoutingType.Height)));
/// - rendering and layouting queues and logic.
/// - helpers to load XML interfaces files
/// - global constants and variables of CROW
+ /// - Keyboard and Mouse logic
+ /// - the resulting bitmap of the interface
/// </summary>
public class Interface : ILayoutable
{
#endregion
#region Static and constants
- public static int DoubleClick = 200;//ms
- internal Stopwatch clickTimer = new Stopwatch();
- internal GraphicObject eligibleForDoubleClick = null;
- public static int TabSize = 4;
- public static string LineBreak = "\r\n";
- //TODO: shold be declared in graphicObject
+ /// <summary>If true, mouse focus is given when mouse is over control</summary>
public static bool FocusOnHover = false;
+ /// <summary> Threshold to catch borders for sizing </summary>
+ public static int BorderThreshold = 5;
+ /// <summary>Double click threshold in milisecond</summary>
+ public static int DoubleClick = 200;//max duration between two mouse_down evt for a dbl clk in milisec.
/// <summary> Time to wait in millisecond before starting repeat loop</summary>
public static int DeviceRepeatDelay = 700;
/// <summary> Time interval in millisecond between device event repeat</summary>
public static int DeviceRepeatInterval = 40;
+ /// <summary>Tabulation size in Text controls</summary>
+ public static int TabSize = 4;
public static bool ReplaceTabsWithSpace = false;
+ public static string LineBreak = "\r\n";
/// <summary> Allow rendering of interface in development environment </summary>
public static bool DesignerMode = false;
- /// <summary> Threshold to catch borders for sizing </summary>
- public static int BorderThreshold = 5;
/// <summary> Disable caching for a widget if this threshold is reached </summary>
public const int MaxCacheSize = 2048;
+ /// <summary> Above this count, the layouting is discard from the current
+ /// update cycle and requeued for the next</summary>
+ public const int MaxLayoutingTries = 3;
/// <summary> Above this count, the layouting is discard for the widget and it
/// will not be rendered on screen </summary>
- public const int MaxLayoutingTries = 3;
public const int MaxDiscardCount = 5;
/// <summary> Global font rendering settings for Cairo </summary>
public static FontOptions FontRenderingOptions;
- #endregion
+ /// <summary> Global font rendering settings for Cairo </summary>
+ public static Antialias Antialias = Antialias.Subpixel;
+ /// <summary>
+ /// Each control need a ref to the root interface containing it, if not set in GraphicObject.currentInterface,
+ /// the ref of this one will be stored in GraphicObject.currentInterface
+ /// </summary>
internal static Interface CurrentInterface;
+ internal Stopwatch clickTimer = new Stopwatch();
+ internal GraphicObject eligibleForDoubleClick = null;
+ #endregion
+ #region Events
+ public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
+ public event EventHandler Quit;
+ #endregion
+
+ #region Public Fields
+ /// <summary>Graphic Tree of this interface</summary>
+ public List<GraphicObject> GraphicTree = new List<GraphicObject>();
+ /// <summary>Interface's resulting bitmap</summary>
+ public byte[] bmp;
+ /// <summary>resulting bitmap limited to last redrawn part</summary>
+ public byte[] dirtyBmp;
+ /// <summary>True when host has to repaint Interface</summary>
+ public bool IsDirty = false;
+ /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
+ public Rectangle DirtyRect;
+ /// <summary>Locked for each layouting operation</summary>
+ public object LayoutMutex = new object();
+ /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
+ public object RenderMutex = new object();
+ /// <summary>Global lock of the update cycle</summary>
+ public object UpdateMutex = new object();
+ //TODO:share resource instances
+ /// <summary>
+ /// Store loaded resources instances shared among controls to reduce memory footprint
+ /// </summary>
public Dictionary<string,object> Ressources = new Dictionary<string, object>();
+ /// <summary>The Main layouting queue.</summary>
public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> ();
+ /// <summary>Store discarded lqi between two updates</summary>
public Queue<LayoutingQueueItem> DiscardQueue;
- public Queue<LayoutingQueueItem> ProcessedLayoutingQueue;
+ /// <summary>Main drawing queue, holding layouted controls</summary>
public Queue<GraphicObject> DrawingQueue = new Queue<GraphicObject>();
public string Clipboard;//TODO:use object instead for complex copy paste
- public void EnqueueForRepaint(GraphicObject g)
- {
- lock (DrawingQueue) {
- if (g.IsQueueForRedraw)
- return;
- DrawingQueue.Enqueue (g);
- g.IsQueueForRedraw = true;
- }
- }
- //fast compiled IML instantiators
+ /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
+ /// on the first instance creation of a IML item.
+ /// </summary>
public static Dictionary<String, Instantiator> Instantiators = new Dictionary<string, Instantiator>();
+ #endregion
+
+ #region Private Fields
+ /// <summary>Client rectangle in the host context</summary>
+ Rectangle clientRectangle;
+ /// <summary>Clipping rectangles on the root context</summary>
+ Rectangles clipping = new Rectangles();
+ /// <summary>Main Cairo context</summary>
+ Context ctx;
+ /// <summary>Main Cairo surface</summary>
+ Surface surf;
+ #endregion
#region Default values and Style loading
/// Default values of properties from GraphicObjects are retrieve from XML Attributes.
/// and injected as a dynamic method referenced in the DefaultValuesLoader Dictionnary.
/// The compilation is done on the first object instancing, and is also done for custom widgets
public delegate void LoaderInvoker(object instance);
+ /// <summary>Store one loader per StyleKey</summary>
public static Dictionary<String, LoaderInvoker> DefaultValuesLoader = new Dictionary<string, LoaderInvoker>();
+ /// <summary>Store dictionnary of member/value per StyleKey</summary>
public static Dictionary<string, Style> Styling;
- /// <summary> parse all styling data's and build global Styling Dictionary </summary>
+ /// <summary> parse all styling data's during application startup and build global Styling Dictionary </summary>
static void loadStyling() {
Styling = new Dictionary<string, Style> ();
#endregion
#region Templates
- public static Dictionary<String, string> DefaultTemplates = new Dictionary<string, string>();
+ /// <summary>Store one default templates resource ID per class.
+ /// Resource ID must be 'fullClassName.template' (not case sensitive)
+ /// Those found in application assembly have priority to the default Crow's one
+ /// </summary>
+ public static Dictionary<string, string> DefaultTemplates = new Dictionary<string, string>();
+ /// <summary>Finds available default templates at startup</summary>
static void findAvailableTemplates(){
searchTemplatesIn (Assembly.GetEntryAssembly ());
searchTemplatesIn (Assembly.GetExecutingAssembly ());
#endregion
#region Load/Save
+ /// <summary>Open file or find a resource from path string</summary>
+ /// <returns>A file or resource stream</returns>
+ /// <param name="path">This could be a normal file path, or an embedded ressource ID
+ /// Resource ID's must be prefixed with '#' character</param>
public static Stream GetStreamFromPath (string path)
{
Stream stream = null;
return stream;
}
-
- public static void Save<T> (string file, T graphicObject)
+ /// <summary>Create an instance of a GraphicObject and add it to the GraphicTree
+ /// of this Interface</summary>
+ public GraphicObject LoadInterface (string path)
{
- XmlSerializerNamespaces xn = new XmlSerializerNamespaces ();
- xn.Add ("", "");
- XmlSerializer xs = new XmlSerializer (typeof(T));
+ lock (UpdateMutex) {
+ GraphicObject tmp = Load (path);
+ AddWidget (tmp);
- xs = new XmlSerializer (typeof(T));
- using (Stream s = new FileStream (file, FileMode.Create)) {
- xs.Serialize (s, graphicObject, xn);
+ return tmp;
}
}
+ /// <summary>Create an instance of a GraphicObject linked to this interface but
+ /// not added to the GraphicTree</summary>
public GraphicObject Load (string path)
{
try {
throw new Exception ("Error loading <" + path + ">:", ex);
}
}
- /// <summary>
- /// fetch it from cache or create it
- /// </summary>
+ /// <summary>Fetch it from cache or create it</summary>
public static Instantiator GetInstantiator(string path){
if (!Instantiators.ContainsKey(path))
Instantiators [path] = new Instantiator(path);
return Instantiators [path];
}
+ /// <summary>Item templates have additional properties for recursivity and
+ /// custom display per item type</summary>
public static ItemTemplate GetItemTemplate(string path){
if (!Instantiators.ContainsKey(path))
Instantiators [path] = new ItemTemplate(path);
return Instantiators [path] as ItemTemplate;
}
- public GraphicObject LoadInterface (string path)
+ //TODO: .Net xml serialisation is no longer used, it has been replaced with instantiators
+ public static void Save<T> (string file, T graphicObject)
{
- lock (UpdateMutex) {
- GraphicObject tmp = Load (path);
- AddWidget (tmp);
+ XmlSerializerNamespaces xn = new XmlSerializerNamespaces ();
+ xn.Add ("", "");
+ XmlSerializer xs = new XmlSerializer (typeof(T));
- return tmp;
+ xs = new XmlSerializer (typeof(T));
+ using (Stream s = new FileStream (file, FileMode.Create)) {
+ xs.Serialize (s, graphicObject, xn);
}
}
#endregion
- #if MEASURE_TIME
- public PerformanceMeasure clippingMeasure = new PerformanceMeasure("Clipping", 100);
- public PerformanceMeasure layoutingMeasure = new PerformanceMeasure("Layouting", 100);
- public PerformanceMeasure updateMeasure = new PerformanceMeasure("Update", 100);
- public PerformanceMeasure drawingMeasure = new PerformanceMeasure("Drawing", 100);
- #endif
-
- public List<GraphicObject> GraphicTree = new List<GraphicObject>();
-
- Rectangles _redrawClip = new Rectangles();
-
- Context ctx;
- Surface surf;
- public byte[] bmp;
- public byte[] dirtyBmp;
- public bool IsDirty = false;
- public Rectangle DirtyRect;
- public object LayoutMutex = new object();
- public object RenderMutex = new object();
- public object UpdateMutex = new object();
-
#region focus
GraphicObject _activeWidget; //button is pressed on widget
GraphicObject _hoverWidget; //mouse is over
GraphicObject _focusedWidget; //has keyboard (or other perif) focus
+ /// <summary>Widget is focused and button is down or another perif action is occuring
+ /// , it can not lose focus while Active</summary>
public GraphicObject activeWidget
{
get { return _activeWidget; }
#endif
}
}
+ /// <summary>Pointer is over the widget</summary>
public GraphicObject HoverWidget
{
get { return _hoverWidget; }
#endif
}
}
+ /// <summary>Widget has the keyboard or mouse focus</summary>
public GraphicObject FocusedWidget {
get { return _focusedWidget; }
set {
}
#endregion
- #if DEBUG_LAYOUTING
- public List<LQIList> LQIsTries = new List<LQIList>();
- public LQIList curLQIsTries = new LQIList();
- public List<LQIList> LQIs = new List<LQIList>();
- public LQIList curLQIs = new LQIList();
-// public static LayoutingQueueItem[] MultipleRunsLQIs {
-// get { return curUpdateLQIs.Where(l=>l.LayoutingTries>2 || l.DiscardCount > 0).ToArray(); }
-// }
- public LayoutingQueueItem currentLQI;
- #else
- public List<LQIList> LQIs = null;//still create the var for CrowIDE
- #endif
+
+ #region UPDATE Loops
+ /// <summary>Enqueue Graphic object for Repaint, DrawingQueue is locked because
+ /// GraphObj's property Set methods could trigger an update from another thread</summary>
+ public void EnqueueForRepaint(GraphicObject g)
+ {
+ lock (DrawingQueue) {
+ if (g.IsQueueForRedraw)
+ return;
+ DrawingQueue.Enqueue (g);
+ g.IsQueueForRedraw = true;
+ }
+ }
+ /// <summary>Main Update loop, executed in this interface thread, lock the UpdateMutex
+ /// Steps:
+ /// - execute device Repeat events
+ /// - Layouting
+ /// - Clipping
+ /// - Drawing
+ /// Result: the Interface bitmap is drawn in memory (byte[] bmp) and a dirtyRect and bitmap are available
+ /// </summary>
public void Update(){
if (mouseRepeatCount > 0) {
int mc = mouseRepeatCount;
Monitor.Exit (UpdateMutex);
}
+ /// <summary>Layouting loop, this is the first step of the udpate and process registered
+ /// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which
+ /// trigger an enqueue for the next Update Cycle</summary>
void processLayouting(){
#if MEASURE_TIME
layoutingMeasure.StartCycle();
layoutingMeasure.StopCycle();
#endif
}
+ /// <summary>Degueue Widget to clip from DrawingQueue and register the last painted slot and the new one
+ /// Clipping rectangles are added at each level of the tree from leef to root, that's the way for the painting
+ /// operation to known if it should go down in the tree for further graphic updates and repaints</summary>
void clippingRegistration(){
#if MEASURE_TIME
clippingMeasure.StartCycle();
clippingMeasure.StopCycle();
#endif
}
+ /// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
+ /// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place</summary>
void processDrawing(){
#if MEASURE_TIME
drawingMeasure.StartCycle();
drawingMeasure.StopCycle();
#endif
}
+ #endregion
- public Rectangles clipping {
- get { return _redrawClip; }
- set { _redrawClip = value; }
- }
+ #region GraphicTree handling
+ /// <summary>Add widget to the Graphic tree of this interface and register it for layouting</summary>
public void AddWidget(GraphicObject g)
{
g.Parent = this;
g.RegisteredLayoutings = LayoutingType.None;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
}
+ /// <summary>Set visible state of widget to false and remove if from the graphic tree</summary>
public void DeleteWidget(GraphicObject g)
{
g.Visible = false;//trick to ensure clip is added to refresh zone
GraphicTree.Remove (g);
}
+ /// <summary> Put widget on top of other root widgets</summary>
public void PutOnTop(GraphicObject g)
{
if (GraphicTree.IndexOf(g) > 0)
curLQIs = new LQIList();
#endif
}
+ /// <summary>Search a Graphic object in the tree named 'nameToFind'</summary>
public GraphicObject FindByName (string nameToFind)
{
foreach (GraphicObject w in GraphicTree) {
}
return null;
}
-
-
+ #endregion
public void ProcessResize(Rectangle bounds){
lock (UpdateMutex) {
}
}
+ #region Mouse and Keyboard Handling
XCursor cursor = XCursor.Default;
+
public MouseState Mouse;
public KeyboardState Keyboard;
- Rectangle clientRectangle;
-
- public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
- public event EventHandler Quit;
-
- #region Mouse Handling
public XCursor MouseCursor {
set {
MouseCursorChanged.Raise (this,new MouseCursorChangedEventArgs(cursor));
}
}
+ /// <summary>Processes mouse move events from the root container</summary>
+ /// <returns><c>true</c>if mouse is in the interface</returns>
public bool ProcessMouseMove(int x, int y)
{
int deltaX = x - Mouse.X;
HoverWidget.onMouseWheel (this, e);
return true;
}
- #endregion
-
- #region Keyboard
public bool ProcessKeyDown(int Key){
Keyboard.SetKeyState((Crow.Key)Key,true);
if (_focusedWidget == null)
}
public Rectangle getSlot () { return ClientRectangle; }
#endregion
+
+ #if MEASURE_TIME
+ public PerformanceMeasure clippingMeasure = new PerformanceMeasure("Clipping", 100);
+ public PerformanceMeasure layoutingMeasure = new PerformanceMeasure("Layouting", 100);
+ public PerformanceMeasure updateMeasure = new PerformanceMeasure("Update", 100);
+ public PerformanceMeasure drawingMeasure = new PerformanceMeasure("Drawing", 100);
+ #endif
+ #if DEBUG_LAYOUTING
+ public List<LQIList> LQIsTries = new List<LQIList>();
+ public LQIList curLQIsTries = new LQIList();
+ public List<LQIList> LQIs = new List<LQIList>();
+ public LQIList curLQIs = new LQIList();
+ // public static LayoutingQueueItem[] MultipleRunsLQIs {
+ // get { return curUpdateLQIs.Where(l=>l.LayoutingTries>2 || l.DiscardCount > 0).ToArray(); }
+ // }
+ public LayoutingQueueItem currentLQI;
+ #else
+ public List<LQIList> LQIs = null;//still create the var for CrowIDE
+ #endif
}
}