diff options
| author | jpbruyere <jp.bruyere@hotmail.com> | 2016-02-19 11:06:44 +0100 |
|---|---|---|
| committer | jpbruyere <jp.bruyere@hotmail.com> | 2016-03-01 05:06:16 +0100 |
| commit | 328c6d4eab1127cd9799540f253deda66060b68a (patch) | |
| tree | eeb1c888ed94c444d673f9f827b4df447e249ea4 /OTKCrow | |
| parent | 2cb0e7507022aa0449c1af264230784039b24e15 (diff) | |
free Crow base from OpenTK
Diffstat (limited to 'OTKCrow')
| -rw-r--r-- | OTKCrow/OTKCrow.csproj | 57 | ||||
| -rw-r--r-- | OTKCrow/OpenGL/QuadVAO.cs | 44 | ||||
| -rw-r--r-- | OTKCrow/OpenGL/Shader.cs | 307 | ||||
| -rw-r--r-- | OTKCrow/OpenGL/TexturedShader.cs | 41 | ||||
| -rw-r--r-- | OTKCrow/OpenGL/VertexArrayObject.cs | 93 | ||||
| -rw-r--r-- | OTKCrow/OpenTKGameWindow.cs | 669 |
6 files changed, 1211 insertions, 0 deletions
diff --git a/OTKCrow/OTKCrow.csproj b/OTKCrow/OTKCrow.csproj new file mode 100644 index 00000000..6fc4f854 --- /dev/null +++ b/OTKCrow/OTKCrow.csproj @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">Linux_x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{350D4F49-9901-4998-9903-BCA7D48DA58C}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>OTKCrow</RootNamespace> + <AssemblyName>OTKCrow</AssemblyName> + <ReleaseVersion>0.4</ReleaseVersion> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Linux_x86' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;MEASURE_TIME</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Linux_x86' "> + <DebugType>full</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <ItemGroup> + <Reference Include="OpenTK"> + <HintPath>..\..\opentk\Binaries\OpenTK\Release\OpenTK.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + <Reference Include="Mono.Cairo" /> + <Reference Include="System.Drawing" /> + </ItemGroup> + <ItemGroup> + <Compile Include="OpenTKGameWindow.cs" /> + <Compile Include="OpenGL\QuadVAO.cs" /> + <Compile Include="OpenGL\Shader.cs" /> + <Compile Include="OpenGL\TexturedShader.cs" /> + <Compile Include="OpenGL\VertexArrayObject.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Crow.csproj"> + <Project>{C2980F9B-4798-4C05-99E2-E174810F7C7B}</Project> + <Name>Crow</Name> + </ProjectReference> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/OTKCrow/OpenGL/QuadVAO.cs b/OTKCrow/OpenGL/QuadVAO.cs new file mode 100644 index 00000000..36231cc1 --- /dev/null +++ b/OTKCrow/OpenGL/QuadVAO.cs @@ -0,0 +1,44 @@ +using System; +using OpenTK; + +namespace Crow +{ + public class QuadVAO : VertexArrayObject + { + public QuadVAO (float x, float y, float width, float height):base( + new Vector2[] { + new Vector2 (x, y), + new Vector2 (x, y + height), + new Vector2 (x + width, y), + new Vector2 (x + width, y + height) + }, + new Vector2[] { + new Vector2 (0, 1), + new Vector2 (0, 0), + new Vector2 (1, 1), + new Vector2 (1, 0) + }, + new int[] { 0, 1, 2, 3 }) + { + + } + public QuadVAO (float x, float y, float width, float height, + float texX, float texY, float texW, float texH):base( + new Vector2[] { + new Vector2 (x, y), + new Vector2 (x, y + height), + new Vector2 (x + width, y), + new Vector2 (x + width, y + height) + }, + new Vector2[] { + new Vector2 (texX, texY+texH), + new Vector2 (texX, texY), + new Vector2 (texX+texW, texY+texH), + new Vector2 (texX+texW, texY) + }, + new int[] { 0, 1, 2, 3 }) + { + + } + } +} diff --git a/OTKCrow/OpenGL/Shader.cs b/OTKCrow/OpenGL/Shader.cs new file mode 100644 index 00000000..b4603ad8 --- /dev/null +++ b/OTKCrow/OpenGL/Shader.cs @@ -0,0 +1,307 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace Crow +{ + public class Shader : IDisposable + { + #region CTOR + public Shader () + { + Compile (); + } + public Shader (string vertResId, string fragResId) + { + + Stream s = tryGetStreamForResource (vertResId); + if (s != null) { + using (StreamReader sr = new StreamReader (s)) { + vertSource = sr.ReadToEnd (); + } + } + + s = tryGetStreamForResource (fragResId); + if (s != null) { + using (StreamReader sr = new StreamReader (s)) { + fragSource = sr.ReadToEnd (); + } + } + + Compile (); + } + Stream tryGetStreamForResource(string resId){ + if (string.IsNullOrEmpty (resId)) + return null; + + Stream s = Assembly.GetEntryAssembly (). + GetManifestResourceStream (resId); + return s == null ? + Assembly.GetExecutingAssembly (). + GetManifestResourceStream (resId) : + s; + } + #endregion + + #region Sources + protected string _vertSource = @" + #version 330 + + precision highp float; + + uniform mat4 Projection; + uniform mat4 ModelView; + uniform mat4 Model; + uniform mat4 Normal; + + in vec2 in_position; + in vec2 in_tex; + + out vec2 texCoord; + + + void main(void) + { + texCoord = in_tex; + gl_Position = Projection * ModelView * Model * vec4(in_position, 0, 1); + }"; + + protected string _fragSource = @" + #version 330 + precision highp float; + + uniform vec4 color; + uniform sampler2D tex; + + in vec2 texCoord; + out vec4 out_frag_color; + + void main(void) + { + out_frag_color = texture( tex, texCoord); + }"; + string _geomSource = @""; +// #version 330 +// layout(triangles) in; +// layout(triangle_strip, max_vertices=3) out; +// void main() +// { +// for(int i=0; i<3; i++) +// { +// gl_Position = gl_in[i].gl_Position; +// EmitVertex(); +// } +// EndPrimitive(); +// }"; + #endregion + + #region Private and protected fields + protected int vsId, fsId, gsId, pgmId, + modelViewLocation, + modelLocation, + projectionLocation, + normalLocation, + colorLocation; + + Matrix4 projectionMat = Matrix4.Identity, + modelMat = Matrix4.Identity, + modelViewMat = Matrix4.Identity; + Vector4 color = new Vector4(1,1,1,1); + int texture; + #endregion + + + #region Public properties + public virtual string vertSource + { + get { return _vertSource;} + set { _vertSource = value; } + } + public virtual string fragSource + { + get { return _fragSource;} + set { _fragSource = value; } + } + public virtual string geomSource + { + get { return _geomSource; } + set { _geomSource = value; } + } + + public Matrix4 ProjectionMatrix{ + set { projectionMat = value; } + get { return projectionMat; } + } + public Matrix4 ModelViewMatrix { + set { modelViewMat = value; } + get { return modelViewMat; } + } + public Matrix4 ModelMatrix { + set { modelMat = value; } + get { return modelMat; } + } + public Vector4 Color { + set { color = value; } + get { return color; } + } + + public int Texture { + get { return texture; } + set { texture = value; } + } + + #endregion + + void updateNormalMatrix() + { + Matrix4 normalMat = (modelViewMat).Inverted(); + normalMat.Transpose (); + GL.UniformMatrix4 (normalLocation, false, ref normalMat); + } + + #region Public functions + public virtual void Compile() + { + Dispose (); + + pgmId = GL.CreateProgram(); + + if (!string.IsNullOrEmpty(vertSource)) + { + vsId = GL.CreateShader(ShaderType.VertexShader); + compileShader(vsId, vertSource); + } + if (!string.IsNullOrEmpty(fragSource)) + { + fsId = GL.CreateShader(ShaderType.FragmentShader); + compileShader(fsId, fragSource); + + } + if (!string.IsNullOrEmpty(geomSource)) + { + gsId = GL.CreateShader(ShaderType.GeometryShader); + compileShader(gsId,geomSource); + } + + if (vsId != 0) + GL.AttachShader(pgmId, vsId); + if (fsId != 0) + GL.AttachShader(pgmId, fsId); + if (gsId != 0) + GL.AttachShader(pgmId, gsId); + + BindVertexAttributes (); + + string info; + GL.LinkProgram(pgmId); + GL.GetProgramInfoLog(pgmId, out info); + + if (!string.IsNullOrEmpty (info)) { + Debug.WriteLine ("Linkage:"); + Debug.WriteLine (info); + } + + info = null; + + GL.ValidateProgram(pgmId); + GL.GetProgramInfoLog(pgmId, out info); + if (!string.IsNullOrEmpty (info)) { + Debug.WriteLine ("Validation:"); + Debug.WriteLine (info); + } + + GL.UseProgram (pgmId); + + GetUniformLocations (); + BindSamplesSlots (); + + Disable (); + } + + protected virtual void BindVertexAttributes() + { + GL.BindAttribLocation(pgmId, 0, "in_position"); + GL.BindAttribLocation(pgmId, 1, "in_tex"); + } + protected virtual void GetUniformLocations() + { + projectionLocation = GL.GetUniformLocation(pgmId, "Projection"); + modelViewLocation = GL.GetUniformLocation(pgmId, "ModelView"); + modelLocation = GL.GetUniformLocation(pgmId, "Model"); + normalLocation = GL.GetUniformLocation(pgmId, "Normal"); + colorLocation = GL.GetUniformLocation (pgmId, "color"); + + } + protected virtual void BindSamplesSlots(){ + GL.Uniform1(GL.GetUniformLocation (pgmId, "tex"), 0); + } + + public virtual void Enable(){ + GL.UseProgram (pgmId); + + GL.UniformMatrix4(projectionLocation, false, ref projectionMat); + GL.UniformMatrix4 (modelLocation, false, ref modelMat); + GL.UniformMatrix4 (modelViewLocation, false, ref modelViewMat); + updateNormalMatrix (); + GL.Uniform4 (colorLocation, color); + + if (texture < 0) + return; + + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, texture); + } + public virtual void Disable(){ + GL.UseProgram (0); + } + public static void Enable(Shader s) + { + if (s == null) + return; + s.Enable (); + } + public static void Disable(Shader s) + { + if (s == null) + return; + s.Disable (); + } + #endregion + + void compileShader(int shader, string source) + { + GL.ShaderSource(shader, source); + GL.CompileShader(shader); + + string info; + GL.GetShaderInfoLog(shader, out info); + Debug.WriteLine(info); + + int compileResult; + GL.GetShader(shader, ShaderParameter.CompileStatus, out compileResult); + if (compileResult != 1) + { + Debug.WriteLine("Compile Error!"); + Debug.WriteLine(source); + } + } + + #region IDisposable implementation + public virtual void Dispose () + { + if (GL.IsProgram (pgmId)) + GL.DeleteProgram (pgmId); + + if (GL.IsShader (vsId)) + GL.DeleteShader (vsId); + if (GL.IsShader (fsId)) + GL.DeleteShader (fsId); + if (GL.IsShader (gsId)) + GL.DeleteShader (gsId); + } + #endregion + } +} diff --git a/OTKCrow/OpenGL/TexturedShader.cs b/OTKCrow/OpenGL/TexturedShader.cs new file mode 100644 index 00000000..9e29b690 --- /dev/null +++ b/OTKCrow/OpenGL/TexturedShader.cs @@ -0,0 +1,41 @@ +using System; +using OpenTK.Graphics.OpenGL; + +namespace Crow +{ + public class TexturedShader : Shader + { + public TexturedShader () + { + + fragSource = @" + #version 130 + precision highp float; + + uniform sampler2D tex; + + in vec2 texCoord; + out vec4 out_frag_color; + + void main(void) + { + out_frag_color = texture( tex, texCoord); + }"; + + Compile (); + + } + + protected override void BindSamplesSlots () + { + base.BindSamplesSlots (); + + GL.Uniform1(GL.GetUniformLocation (pgmId, "stencil"),1); + } + public override void Enable () + { + base.Enable (); + + } + } +} diff --git a/OTKCrow/OpenGL/VertexArrayObject.cs b/OTKCrow/OpenGL/VertexArrayObject.cs new file mode 100644 index 00000000..c7b685d9 --- /dev/null +++ b/OTKCrow/OpenGL/VertexArrayObject.cs @@ -0,0 +1,93 @@ +using System; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace Crow +{ + public class VertexArrayObject : IDisposable + { + public int vaoHandle, + positionVboHandle, + texVboHandle, + eboHandle; + + Vector2[] positionVboData; + public int[] indicesVboData; + Vector2[] texVboData; + + public VertexArrayObject (Vector2[] _positions, Vector2[] _texCoord, int[] _indices) + { + positionVboData = _positions; + texVboData = _texCoord; + indicesVboData = _indices; + + CreateVBOs (); + CreateVAOs (); + } + + void deleteVAOs() + { + GL.DeleteBuffer (positionVboHandle); + GL.DeleteBuffer (texVboHandle); + GL.DeleteBuffer (eboHandle); + GL.DeleteVertexArray (vaoHandle); + } + + void CreateVBOs() + { + positionVboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); + GL.BufferData<Vector2>(BufferTarget.ArrayBuffer, + new IntPtr(positionVboData.Length * Vector2.SizeInBytes), + positionVboData, BufferUsageHint.StaticDraw); + + texVboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, texVboHandle); + GL.BufferData<Vector2>(BufferTarget.ArrayBuffer, + new IntPtr(texVboData.Length * Vector2.SizeInBytes), + texVboData, BufferUsageHint.StaticDraw); + // + eboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); + GL.BufferData(BufferTarget.ElementArrayBuffer, + new IntPtr(sizeof(uint) * indicesVboData.Length), + indicesVboData, BufferUsageHint.StaticDraw); + + GL.BindBuffer(BufferTarget.ArrayBuffer, 0); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); + } + + void CreateVAOs() + { + vaoHandle = GL.GenVertexArray(); + GL.BindVertexArray(vaoHandle); + + GL.EnableVertexAttribArray(0); + GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); + GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, true, Vector2.SizeInBytes, 0); + + GL.EnableVertexAttribArray(1); + GL.BindBuffer(BufferTarget.ArrayBuffer, texVboHandle); + GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, true, Vector2.SizeInBytes, 0); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); + + GL.BindVertexArray(0); + } + + public void Render(PrimitiveType _primitiveType){ + GL.BindVertexArray(vaoHandle); + GL.DrawElements(_primitiveType, indicesVboData.Length, + DrawElementsType.UnsignedInt, IntPtr.Zero); + GL.BindVertexArray (0); + } + + + #region IDisposable implementation + public void Dispose () + { + deleteVAOs (); + } + #endregion + } +} diff --git a/OTKCrow/OpenTKGameWindow.cs b/OTKCrow/OpenTKGameWindow.cs new file mode 100644 index 00000000..111163b4 --- /dev/null +++ b/OTKCrow/OpenTKGameWindow.cs @@ -0,0 +1,669 @@ +// +// 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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Xml; +using Cairo; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace Crow +{ + public class OpenTKGameWindow : GameWindow, ILayoutable, IGOLibHost + { + #region ctor +// public OpenTKGameWindow(int _width, int _height, string _title="golib") +// : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 1), _title, +// GameWindowFlags.Fullscreen, +// DisplayDevice.Default, +// 3,0,OpenTK.Graphics.GraphicsContextFlags.Default) + public OpenTKGameWindow(int _width, int _height, string _title="Crow") + : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 1), + _title,GameWindowFlags.Default,DisplayDevice.GetDisplay(DisplayIndex.Second), + 3,3,OpenTK.Graphics.GraphicsContextFlags.Debug) +// public OpenTKGameWindow(int _width, int _height, string _title="golib") +// : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 8), _title) + { + //VSync = VSyncMode.On; + currentWindow = this; + //Load cursors + XCursor.Cross = XCursorFile.Load("#Crow.Images.Icons.Cursors.cross").Cursors[0]; + XCursor.Default = XCursorFile.Load("#Crow.Images.Icons.Cursors.arrow").Cursors[0]; + XCursor.NW = XCursorFile.Load("#Crow.Images.Icons.Cursors.top_left_corner").Cursors[0]; + XCursor.NE = XCursorFile.Load("#Crow.Images.Icons.Cursors.top_right_corner").Cursors[0]; + XCursor.SW = XCursorFile.Load("#Crow.Images.Icons.Cursors.bottom_left_corner").Cursors[0]; + XCursor.SE = XCursorFile.Load("#Crow.Images.Icons.Cursors.bottom_right_corner").Cursors[0]; + XCursor.H = XCursorFile.Load("#Crow.Images.Icons.Cursors.sb_h_double_arrow").Cursors[0]; + XCursor.V = XCursorFile.Load("#Crow.Images.Icons.Cursors.sb_v_double_arrow").Cursors[0]; + } + #endregion + + public List<GraphicObject> GraphicObjects = new List<GraphicObject>(); + public Color Background = Color.Transparent; + + internal static OpenTKGameWindow currentWindow; + + Rectangles _redrawClip = new Rectangles();//should find another way to access it from child + List<GraphicObject> _gobjsToRedraw = new List<GraphicObject>(); + + #region IGOLibHost implementation + public Rectangles clipping { + get { return _redrawClip; } + set { _redrawClip = value; } + } + public XCursor MouseCursor { + set { + if (value == null) { + Cursor = null; + return; + } + Cursor = new MouseCursor + ((int)value.Xhot, (int)value.Yhot, (int)value.Width, (int)value.Height,value.data);; } + } + public List<GraphicObject> gobjsToRedraw { + get { return _gobjsToRedraw; } + set { _gobjsToRedraw = value; } + } + public void AddWidget(GraphicObject g) + { + g.Parent = this; + GraphicObjects.Insert (0, g); + + g.RegisterForLayouting (LayoutingType.Sizing); + } + public void DeleteWidget(GraphicObject g) + { + g.Visible = false;//trick to ensure clip is added to refresh zone + g.ClearBinding(); + GraphicObjects.Remove (g); + } + public void PutOnTop(GraphicObject g) + { + if (GraphicObjects.IndexOf(g) > 0) + { + GraphicObjects.Remove(g); + GraphicObjects.Insert(0, g); + //g.registerClipRect (); + } + } + public void Quit () + { + this.Exit (); + } + + #region focus + GraphicObject _activeWidget; //button is pressed on widget + GraphicObject _hoverWidget; //mouse is over + GraphicObject _focusedWidget; //has keyboard (or other perif) focus + + public GraphicObject activeWidget + { + get { return _activeWidget; } + set + { + if (_activeWidget == value) + return; + + if (_activeWidget != null) + _activeWidget.IsActive = false; + + _activeWidget = value; + + if (_activeWidget != null) + _activeWidget.IsActive = true; + } + } + public GraphicObject hoverWidget + { + get { return _hoverWidget; } + set { + if (_hoverWidget == value) + return; + _hoverWidget = value; + } + } + public GraphicObject FocusedWidget { + get { return _focusedWidget; } + set { + if (_focusedWidget == value) + return; + if (_focusedWidget != null) + _focusedWidget.onUnfocused (this, null); + _focusedWidget = value; + if (_focusedWidget != null) + _focusedWidget.onFocused (this, null); + } + } + #endregion + + #endregion + + /// <summary> Remove all Graphic objects from top container </summary> + public void ClearInterface() + { + int i = 0; + while (GraphicObjects.Count>0) { + //TODO:parent is not reset to null because object will be added + //to ObjectToRedraw list, and without parent, it fails + GraphicObject g = GraphicObjects [i]; + g.Visible = false; + g.ClearBinding (); + GraphicObjects.RemoveAt (0); + } + } + public GraphicObject FindByName (string nameToFind) + { + foreach (GraphicObject w in GraphicObjects) { + GraphicObject r = w.FindByName (nameToFind); + if (r != null) + return r; + } + return null; + } + #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; + #endregion + + #region graphic contexte + Context ctx; + Surface surf; + byte[] bmp; + int texID; + + public QuadVAO uiQuad, uiQuad2; + Crow.Shader shader; + int[] viewport = new int[4]; + + void createContext() + { + createOpenGLSurface (); + + if (uiQuad != null) + uiQuad.Dispose (); + uiQuad = new QuadVAO (0, 0, ClientRectangle.Width, ClientRectangle.Height, 0, 1, 1, -1); + uiQuad2 = new QuadVAO (0, 0, ClientRectangle.Width, ClientRectangle.Height, 0, 0, 1, 1); + + shader.ProjectionMatrix = Matrix4.CreateOrthographicOffCenter + (0, ClientRectangle.Width, ClientRectangle.Height, 0, 0, 1); + + clipping.AddRectangle (ClientRectangle); + } + void createOpenGLSurface() + { + currentWindow = this; + + int stride = 4 * ClientRectangle.Width; + int bmpSize = Math.Abs (stride) * ClientRectangle.Height; + bmp = new byte[bmpSize]; + + //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, bmp); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + + GL.BindTexture(TextureTarget.Texture2D, 0); + + shader.Texture = texID; + } + void OpenGLDraw() + { + GL.GetInteger (GetPName.Viewport, viewport); + GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); + + shader.Enable (); + + if (isDirty) { + byte[] tmp = new byte[4 * DirtyRect.Width * DirtyRect.Height]; + for (int y = 0; y < DirtyRect.Height; y++) { + Array.Copy(bmp, + ((DirtyRect.Top + y) * ClientRectangle.Width * 4) + DirtyRect.Left * 4, + tmp, y * DirtyRect.Width * 4, DirtyRect.Width *4); + } + GL.TexSubImage2D (TextureTarget.Texture2D, 0, + DirtyRect.Left, DirtyRect.Top, DirtyRect.Width, DirtyRect.Height, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, tmp); + isDirty = false; + } + uiQuad.Render (PrimitiveType.TriangleStrip); + + GL.BindTexture(TextureTarget.Texture2D, 0); + + shader.Disable (); + GL.Viewport (viewport [0], viewport [1], viewport [2], viewport [3]); + } + #endregion + + #if MEASURE_TIME + public Stopwatch updateTime = new Stopwatch (); + public Stopwatch layoutTime = new Stopwatch (); + public Stopwatch guTime = new Stopwatch (); + public Stopwatch drawingTime = new Stopwatch (); + #endif + + bool isDirty = false; + Rectangle DirtyRect; + + #region update + void update () + { + if (mouseRepeatCount > 0) { + int mc = mouseRepeatCount; + mouseRepeatCount -= mc; + for (int i = 0; i < mc; i++) { + FocusedWidget.onMouseClick (this, new MouseButtonEventArgs (Mouse.X, Mouse.Y, MouseButton.Left, true)); + } + } + #if MEASURE_TIME + layoutTime.Reset (); + guTime.Reset (); + drawingTime.Reset (); + updateTime.Restart (); + #endif + + GraphicObject[] invGOList = new GraphicObject[GraphicObjects.Count]; + GraphicObjects.CopyTo (invGOList, 0); + invGOList = invGOList.Reverse ().ToArray (); + + #if MEASURE_TIME + layoutTime.Start (); + #endif + //Debug.WriteLine ("======= Layouting queue start ======="); + + while (Interface.LayoutingQueue.Count > 0) { + LayoutingQueueItem lqi = Interface.LayoutingQueue.Dequeue (); + lqi.ProcessLayouting (); + } + + #if MEASURE_TIME + layoutTime.Stop (); + #endif + + //Debug.WriteLine ("otd:" + gobjsToRedraw.Count.ToString () + "-"); + //final redraw clips should be added only when layout is completed among parents, + //that's why it take place in a second pass + GraphicObject[] gotr = new GraphicObject[gobjsToRedraw.Count]; + gobjsToRedraw.CopyTo (gotr); + gobjsToRedraw.Clear (); + foreach (GraphicObject p in gotr) { + p.IsQueuedForRedraw = false; + p.Parent.RegisterClip (p.LastPaintedSlot); + p.Parent.RegisterClip (p.getSlot()); + } + + #if MEASURE_TIME + updateTime.Stop (); + drawingTime.Start (); + #endif + + using (surf = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, ClientRectangle.Width * 4)) { + using (ctx = new Context (surf)){ + + + if (clipping.count > 0) { + //Link.draw (ctx); + clipping.clearAndClip(ctx); + + foreach (GraphicObject p in invGOList) { + if (!p.Visible) + continue; + if (!clipping.intersect (p.Slot)) + continue; + ctx.Save (); + + p.Paint (ref ctx); + + ctx.Restore (); + } + + #if DEBUG_CLIP_RECTANGLE + clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); + #endif + + if (isDirty) + DirtyRect += clipping.Bounds; + else + DirtyRect = clipping.Bounds; + isDirty = true; + + DirtyRect.Left = Math.Max (0, DirtyRect.Left); + DirtyRect.Top = Math.Max (0, DirtyRect.Top); + DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); + DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); + + clipping.Reset (); + } + + #if MEASURE_TIME + drawingTime.Stop (); + #endif + //surf.WriteToPng (@"/mnt/data/test.png"); + } + } +// if (ToolTip.isVisible) { +// ToolTip.panel.processkLayouting(); +// if (ToolTip.panel.layoutIsValid) +// ToolTip.panel.Paint(ref ctx); +// } +// Debug.WriteLine("INTERFACE: layouting: {0} ticks \t graphical update {1} ticks \t drawing {2} ticks", +// layoutTime.ElapsedTicks, +// guTime.ElapsedTicks, +// drawingTime.ElapsedTicks); +// Debug.WriteLine("INTERFACE: layouting: {0} ms \t graphical update {1} ms \t drawing {2} ms", +// layoutTime.ElapsedMilliseconds, +// guTime.ElapsedMilliseconds, +// drawingTime.ElapsedMilliseconds); + +// Debug.WriteLine("UPDATE: {0} ticks \t, {1} ms", +// updateTime.ElapsedTicks, +// updateTime.ElapsedMilliseconds); + } + #endregion + + #region loading + public GraphicObject LoadInterface (string path) + { + GraphicObject tmp = Interface.Load (path, this); + AddWidget (tmp); + return tmp; + } + #endregion + + public virtual void OnRender(FrameEventArgs e) + { + } + public virtual void GLClear() + { + GL.Clear (ClearBufferMask.ColorBufferBit); + } + + #region Game win overrides + protected override void OnUpdateFrame(FrameEventArgs e) + { + base.OnUpdateFrame(e); + update (); + } + protected override void OnRenderFrame(FrameEventArgs e) + { + GLClear (); + + + base.OnRenderFrame(e); + + OnRender (e); + OpenGLDraw (); + + + SwapBuffers (); + } + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown); + 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"); + + shader = new Crow.TexturedShader (); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize (e); + createContext (); + foreach (GraphicObject g in GraphicObjects) + g.RegisterForLayouting (LayoutingType.All); + } + #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) + { + MouseMoveEventArgs e = new MouseMoveEventArgs (otk_e.X, otk_e.Y, otk_e.XDelta, otk_e.YDelta); + MouseState ms = e.Mouse; + update_mouseButtonStates (ref ms, otk_e.Mouse); + e.Mouse = ms; + + if (_activeWidget != null) { + //first, ensure object is still in the graphic tree + if (_activeWidget.HostContainer == null) { + activeWidget = null; + } else { + + //send move evt even if mouse move outside bounds + _activeWidget.onMouseMove (this, e); + return; + } + } + + if (hoverWidget != null) { + //first, ensure object is still in the graphic tree + if (hoverWidget.HostContainer == null) { + hoverWidget = null; + } else { + //check topmost graphicobject first + GraphicObject tmp = hoverWidget; + GraphicObject topc = null; + while (tmp is GraphicObject) { + topc = tmp; + tmp = tmp.Parent as GraphicObject; + } + int idxhw = GraphicObjects.IndexOf (topc); + if (idxhw != 0) { + int i = 0; + while (i < idxhw) { + if (GraphicObjects [i].MouseIsIn (e.Position)) { + hoverWidget.onMouseLeave (this, e); + GraphicObjects [i].checkHoverWidget (e); + return; + } + i++; + } + } + + + if (hoverWidget.MouseIsIn (e.Position)) { + hoverWidget.checkHoverWidget (e); + return; + } else { + hoverWidget.onMouseLeave (this, e); + //seek upward from last focused graph obj's + while (hoverWidget.Parent as GraphicObject != null) { + hoverWidget = hoverWidget.Parent as GraphicObject; + if (hoverWidget.MouseIsIn (e.Position)) { + hoverWidget.checkHoverWidget (e); + return; + } else + hoverWidget.onMouseLeave (this, e); + } + } + } + } + + //top level graphic obj's parsing + for (int i = 0; i < GraphicObjects.Count; i++) { + GraphicObject g = GraphicObjects[i]; + if (g.MouseIsIn (e.Position)) { + g.checkHoverWidget (e); + PutOnTop (g); + return; + } + } + hoverWidget = null; + MouseMove.Raise (this, otk_e); + } + void Mouse_ButtonUp(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + MouseButtonEventArgs e = new MouseButtonEventArgs (otk_e.X, otk_e.Y, (Crow.MouseButton)otk_e.Button, otk_e.IsPressed); + MouseState ms = e.Mouse; + update_mouseButtonStates (ref ms, otk_e.Mouse); + e.Mouse = ms; + + if (_activeWidget == null) { + MouseButtonUp.Raise (this, otk_e); + return; + } + + if (mouseRepeatThread != null) { + mouseRepeatOn = false; + mouseRepeatThread.Abort(); + mouseRepeatThread.Join (); + } + + _activeWidget.onMouseUp (this, e); + activeWidget = null; + } + void Mouse_ButtonDown(object sender, OpenTK.Input.MouseButtonEventArgs otk_e) + { + MouseButtonEventArgs e = new MouseButtonEventArgs (otk_e.X, otk_e.Y, (Crow.MouseButton)otk_e.Button, otk_e.IsPressed); + MouseState ms = e.Mouse; + update_mouseButtonStates (ref ms, otk_e.Mouse); + e.Mouse = ms; + + if (hoverWidget == null) { + MouseButtonDown.Raise (this, otk_e); + return; + } + + hoverWidget.onMouseDown(hoverWidget,new BubblingMouseButtonEventArg(e)); + + if (FocusedWidget == null) + return; + if (!FocusedWidget.MouseRepeat) + return; + mouseRepeatThread = new Thread (mouseRepeatThreadFunc); + mouseRepeatThread.Start (); + } + void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) + { + MouseWheelEventArgs e = new MouseWheelEventArgs (otk_e.X, otk_e.Y, otk_e.Value, otk_e.Delta); + MouseState ms = e.Mouse; + update_mouseButtonStates (ref ms, otk_e.Mouse); + e.Mouse = ms; + + if (hoverWidget == null) { + MouseWheelChanged.Raise (this, otk_e); + return; + } + hoverWidget.onMouseWheel (this, e); + } + + volatile bool mouseRepeatOn; + volatile int mouseRepeatCount; + Thread mouseRepeatThread; + void mouseRepeatThreadFunc() + { + mouseRepeatOn = true; + Thread.Sleep (Interface.DeviceRepeatDelay); + while (mouseRepeatOn) { + mouseRepeatCount++; + Thread.Sleep (Interface.DeviceRepeatInterval); + } + mouseRepeatCount = 0; + } + #endregion + + #region keyboard Handling + KeyboardState Keyboad = new KeyboardState (); + void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) + { +// if (_focusedWidget == null) { + KeyboardKeyDown.Raise (this, otk_e); +// return; +// } + Keyboad.SetKeyState ((Crow.Key)otk_e.Key, true); + KeyboardKeyEventArgs e = new KeyboardKeyEventArgs((Crow.Key)otk_e.Key, otk_e.IsRepeat,Keyboad); + _focusedWidget.onKeyDown (sender, e); + } + #endregion + + #region ILayoutable implementation + public void RegisterClip(Rectangle r){ + clipping.AddRectangle (r); + } + public bool ArrangeChildren { get { return false; }} + public int LayoutingTries { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + public LayoutingType RegisteredLayoutings { + get { return LayoutingType.None; } + set { throw new NotImplementedException (); } + } + public void RegisterForLayouting (LayoutingType layoutType) { throw new NotImplementedException (); } + public bool UpdateLayout (LayoutingType layoutType) { throw new NotImplementedException (); } + public Rectangle ContextCoordinates (Rectangle r) => r; + public Rectangle ScreenCoordinates (Rectangle r) => r; + + public ILayoutable Parent { + get { return null; } + set { throw new NotImplementedException (); } + } + public ILayoutable LogicalParent { + get { return null; } + set { throw new NotImplementedException (); } + } + + Rectangle ILayoutable.ClientRectangle { + get { return new Size(this.ClientRectangle.Size.Width,this.ClientRectangle.Size.Height); } + } + public IGOLibHost HostContainer { + get { return this; } + } + public Rectangle getSlot () => ClientRectangle; + public Rectangle getBounds () => ClientRectangle; + #endregion + } +} |