From 665d8153a72951068d66e41351b2cafabd9d0b10 Mon Sep 17 00:00:00 2001 From: Jochem Date: Fri, 4 Apr 2014 15:21:43 +0100 Subject: [PATCH 1/8] Basic SharpGL Model Viewer. --- .../SharpGLBase/Events/ModelSelectedEvent.cs | 23 + .../Events/ModelSelectedEventArgs.cs | 24 + .../Extensions/CommonExtensions.cs | 33 + .../Extensions/GlmNetExtensions.cs | 409 ++ .../SharpGLBase/IO/IFileModel.cs | 20 + .../SharpGLBase/ManifestResourceLoader.cs | 32 + .../SharpGLBase/Primitives/Axis.cs | 222 + .../SharpGLBase/Primitives/AxisVBO.cs | 178 + .../SharpGLBase/Primitives/Lines.cs | 195 + .../SharpGLBase/Primitives/Model3DBase.cs | 386 + .../Primitives/ModelComponents/Face.cs | 71 + .../Primitives/ModelComponents/Mesh.cs | 175 + .../Primitives/ModelComponents/Vertex.cs | 71 + .../Primitives/PrimitivesGlobal.cs | 23 + .../SharpGLBase/Primitives/SquareGrid.cs | 154 + .../SharpGLBase/Primitives/SquareGridVBO.cs | 155 + .../SharpGLBase/Properties/AssemblyInfo.cs | 36 + .../SharpGLBase/Scene/ModelView.cs | 112 + .../SharpGLBase/Scene/Normal.cs | 48 + .../Scene/OpenGLHitTestExtensions.cs | 20 + .../SharpGLBase/Scene/OpenGLScene.cs | 292 + .../SharpGLBase/Scene/Projection.cs | 157 + .../SharpGLBase/Scene/Shaders.cs | 85 + .../SharpGLBase/Scene/TransformableBase.cs | 312 + .../SharpGLBase/Shaders/ExtShaderProgram.cs | 160 + .../Shaders/Parameters/IMVPNParameters.cs | 17 + .../Parameters/IMaterialShaderParameters.cs | 20 + .../Shaders/Parameters/IShaderParameterIds.cs | 15 + .../Parameters/ISingleLightParameters.cs | 13 + .../Shaders/Parameters/PerPixelParameters.cs | 61 + .../Parameters/SimpleShaderParameters.cs | 72 + .../Shaders/Parameters/ToonParameters.cs | 62 + .../SharpGLBase/Shaders/PerPixel.frag | 24 + .../SharpGLBase/Shaders/PerPixel.vert | 18 + .../SharpGLBase/Shaders/SimpleShader.frag | 9 + .../SharpGLBase/Shaders/SimpleShader.vert | 19 + .../SharpGLBase/Shaders/Toon.frag | 54 + .../SharpGLBase/Shaders/Toon.vert | 18 + .../SharpGLBase/SharpGLBase.csproj | 134 + .../SharpGLBase/VertexAttributes.cs | 18 + .../SharpGLBase/packages.config | 4 + .../SharpGLTest/App.config | 18 + .../SharpGLViewerSample/SharpGLTest/App.xaml | 8 + .../SharpGLTest/App.xaml.cs | 17 + .../SharpGLTest/MainWindow.xaml | 14 + .../SharpGLTest/MainWindow.xaml.cs | 181 + .../SharpGLTest/MainWindowViewModel.cs | 314 + .../SharpGLTest/MyScene.cs | 205 + .../SharpGLTest/Properties/AssemblyInfo.cs | 55 + .../Properties/Resources.Designer.cs | 63 + .../SharpGLTest/Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 26 + .../SharpGLTest/Properties/Settings.settings | 7 + .../SharpGLTest/Shapes/FlatShadedCube.cs | 73 + .../SharpGLTest/Shapes/MyTrefoilKnot.cs | 160 + .../SharpGLTest/Shapes/SmoothShadedCube.cs | 68 + .../SharpGLTest/SharpGLTest.csproj | 133 + .../SharpGLTest/packages.config | 6 + .../SharpGLViewerSample.sln | 27 + .../GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg | Bin 0 -> 17026 bytes .../GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec | 17 + .../GlmNet.0.0.2.0/lib/net40/GlmNet.XML | 281 + .../GlmNet.0.0.2.0/lib/net40/GlmNet.dll | Bin 0 -> 13824 bytes .../GlmNet.0.0.2.0/lib/net40/GlmNet.pdb | Bin 0 -> 44544 bytes .../SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg | Bin 0 -> 282901 bytes .../SharpGLCore.2.1.0.nuspec | 15 + .../lib/SharpGL.SceneGraph.dll | Bin 0 -> 143360 bytes .../lib/SharpGL.SceneGraph.xml | 6188 +++++++++++++++++ .../lib/SharpGL.Serialization.dll | Bin 0 -> 22016 bytes .../lib/SharpGL.Serialization.xml | 209 + .../SharpGLCore.2.1.0/lib/SharpGL.dll | Bin 0 -> 355840 bytes .../SharpGLCore.2.1.0/lib/SharpGL.xml | 4451 ++++++++++++ .../SharpGLforWPF.2.1.0.nupkg | Bin 0 -> 19252 bytes .../SharpGLforWPF.2.1.0.nuspec | 20 + .../SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll | Bin 0 -> 24576 bytes .../SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml | 341 + .../packages/repositories.config | 5 + 77 files changed, 16970 insertions(+) create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.pdb create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.xml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nuspec create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml create mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs new file mode 100644 index 00000000..04e90bc6 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs @@ -0,0 +1,23 @@ +using SharpGLBase.Primitives; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Events +{ + // A delegate type for hooking up change notifications. + public delegate void ModelSelectedEvent(object sender, ModelSelectedEventArgs e); + public class ModelSelectedEventArgs : EventArgs + { + public Point Point { get; set; } + public Model3DBase SelectedModel { get; set; } + + public ModelSelectedEventArgs(Point p, Model3DBase m) + { + Point = p; + SelectedModel = m; + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs new file mode 100644 index 00000000..c60bedf9 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs @@ -0,0 +1,24 @@ +using Scene.Primitives; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace Scene.Events +{ + + // A delegate type for hooking up change notifications. + public delegate void ModelSelectedEvent(object sender, ModelSelectedEventArgs e); + public class ModelSelectedEventArgs : EventArgs + { + public Point Point { get; set; } + public Model3DBase SelectedModel { get; set; } + + public ModelSelectedEventArgs(Point p, Model3DBase m) + { + Point = p; + SelectedModel = m; + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs new file mode 100644 index 00000000..3c852484 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Extensions +{ + public static class CommonExtensions + { + public static List ToValueList(this Dictionary> dic) + { + var list = new List(); + foreach (var item in dic) + { + list.AddRange(item.Value); + } + + return list; + } + + public static List ToValueList(this Dictionary dic) + { + var list = new List(); + + foreach (var item in dic) + { + list.Add(item.Value); + } + + return list; + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs new file mode 100644 index 00000000..c08dac0a --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs @@ -0,0 +1,409 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Extensions +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs new file mode 100644 index 00000000..ce411b88 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs @@ -0,0 +1,20 @@ +using SharpGL.SceneGraph.Assets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IO +{ + public interface IFileModel + { + float[] Vertices { get; set; } + float[] Indices { get; set; } + float[] Normals { get; set; } + Material[] Materials { get; set; } + + + IFileModel LoadModel(string path); + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs new file mode 100644 index 00000000..64494a4c --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs @@ -0,0 +1,32 @@ +using System.IO; +using System.Reflection; + +namespace SharpGLBase +{ + /// + /// A small helper class to load manifest resource files. + /// + public static class ManifestResourceLoader + { + /// + /// Loads the named manifest resource as a text string. + /// + /// Name of the text file. + /// The contents of the manifest resource. + public static string LoadTextFile(string textFileName) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + var pathToDots = textFileName.Replace("\\", "."); + var location = string.Format("{0}.{1}", executingAssembly.GetName().Name, pathToDots); + + var names = executingAssembly.GetManifestResourceNames(); + using (var stream = executingAssembly.GetManifestResourceStream(location)) + { + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs new file mode 100644 index 00000000..4636e3ee --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs @@ -0,0 +1,222 @@ +using GlmNet; +using SharpGLBase.Shaders; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + /// + /// Draws an axis in the center of the world. + /// + public class Axis : IRenderable + { + #region fields + private float _axisLength = 4, + _lineThickness = 2; + private Material _materialX, _materialY, _materialZ; + private List> _linesX, _linesY, _linesZ; + #endregion fields + + #region properties + /// + /// The length of each axis. + /// + public float AxisLength + { + get { return _axisLength; } + set { _axisLength = value; } + } + /// + /// The thickness of each axis. + /// + public float LineThickness + { + get { return _lineThickness; } + set { _lineThickness = value; } + } + /// + /// The material of the the X-axis + /// + public Material MaterialX + { + get { return _materialX; } + set { _materialX = value; } + } + /// + /// The material of the the Y-axis + /// + public Material MaterialY + { + get { return _materialY; } + set { _materialY = value; } + } + + /// + /// The material of the the Z-axis + /// + public Material MaterialZ + { + get { return _materialZ; } + set { _materialZ = value; } + } + #endregion properties + + #region constructors + public Axis() + { + _materialX = new Material(); + _materialX.Ambient = Color.Red; + _materialX.Shininess = 1f; + + _materialY = new Material(); + _materialY.Ambient = Color.Green; + _materialY.Shininess = 1f; + + _materialZ = new Material(); + _materialZ.Ambient = Color.Blue; + _materialZ.Shininess = 1f; + + RecalculateShape(); + } + + public Axis(Material matX, Material matY, Material matZ) + { + _materialX = matX; + _materialY = matY; + _materialY = matZ; + + RecalculateShape(); + } + #endregion constructors + + + /// + /// Renders the axis to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + /// Pass the shader so the material color(s) can be applied locally. + public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) + { + // Ensure that we're in design mode (we don't want axis during render) + if (renderMode != RenderMode.Design) + return; + + ValidateBeforeRender(); + + LoadAttributes(gl); + + shader.ApplyMaterial(gl, MaterialX); + gl.Begin(OpenGL.GL_LINES); + PrimitivesGlobal.RenderLines(gl, _linesX); + gl.End(); + + shader.ApplyMaterial(gl, MaterialZ); + gl.Begin(OpenGL.GL_LINES); + PrimitivesGlobal.RenderLines(gl, _linesZ); + gl.End(); + + shader.ApplyMaterial(gl, MaterialY); + gl.Begin(OpenGL.GL_LINES); + PrimitivesGlobal.RenderLines(gl, _linesY); + gl.End(); + + // Undo last attribute changes + PopAttributes(gl); + } + + /// + /// Renders the axis to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + public virtual void Render(OpenGL gl, RenderMode renderMode) + { + // Ensure that we're in design mode (we don't want axis during render) + if (renderMode != RenderMode.Design) + return; + + ValidateBeforeRender(); + + LoadAttributes(gl); + // Draw the lines. + // TODO: Inefficient, consumes a lot of resources. + gl.Begin(OpenGL.GL_LINES); + PrimitivesGlobal.RenderLines(gl, _linesX); + PrimitivesGlobal.RenderLines(gl, _linesY); + PrimitivesGlobal.RenderLines(gl, _linesZ); + gl.End(); + + PopAttributes(gl); + } + + /// + /// Calculates the lines using the current axis properties. + /// + public virtual void RecalculateShape() + { + _linesX = new List>(); + _linesY = new List>(); + _linesZ = new List>(); + + _linesX.Add( + new Tuple( + new vec3(0, 0, 0), + new vec3(_axisLength,0,0)) + ); + + _linesY.Add( + new Tuple( + new vec3(0, 0, 0), + new vec3(0, _axisLength, 0)) + ); + + _linesZ.Add( + new Tuple( + new vec3(0, 0, 0), + new vec3(0, 0, _axisLength)) + ); + } + + /// + /// Pushes and sets some attributes. + /// + /// The GL. + public virtual void LoadAttributes(OpenGL gl) + { + // Push all attributes, disable lighting and depth testing. + gl.PushAttrib(OpenGL.GL_CURRENT_BIT | OpenGL.GL_ENABLE_BIT | + OpenGL.GL_LINE_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + gl.DepthFunc(OpenGL.GL_ALWAYS); + gl.LineWidth(_lineThickness); + } + + /// + /// Pops last attributes. + /// + /// The GL. + public virtual void PopAttributes(OpenGL gl) + { + gl.PopAttrib(); + } + + /// + /// Ensures that all required properties are acceptable. + /// + private void ValidateBeforeRender() + { + if (_linesX == null || _linesY == null || _linesZ == null) + { + throw new Exception("Axis aren't calculated."); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs new file mode 100644 index 00000000..7e251f53 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs @@ -0,0 +1,178 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGLBase.Shaders; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + public class AxisVBO + { + + #region fields + private float _axisLength = 4, + _lineThickness = 2; + private Lines _lineX, _lineY, _lineZ; + #endregion fields + + #region properties + /// + /// The length of each axis. + /// + public float AxisLength + { + get { return _axisLength; } + set { _axisLength = value; } + } + /// + /// The thickness of each axis. + /// + public float LineThickness + { + get { return _lineThickness; } + set { _lineThickness = value; } + } + /// + /// The material of the the X-axis + /// + public Material MaterialX + { + get { return _lineX.Material; } + set { _lineX.Material = value; } + } + /// + /// The material of the the Y-axis + /// + public Material MaterialY + { + get { return _lineY.Material; } + set { _lineY.Material = value; } + } + + /// + /// The material of the the Z-axis + /// + public Material MaterialZ + { + get { return _lineZ.Material; } + set { _lineZ.Material = value; } + } + #endregion properties + + #region constructors + public AxisVBO(OpenGL gl) + { + RecalculateShape(gl); + + _lineX.Material = new Material(); + _lineX.Material.Diffuse = Color.Red; + + _lineY.Material = new Material(); + _lineY.Material.Diffuse = Color.Green; + _lineY.Material.Shininess = 0.1f; + + _lineZ.Material = new Material(); + _lineZ.Material.Diffuse = Color.Blue; + _lineZ.Material.Shininess = 0.1f; + + var lineWidth = 5f; + + _lineX.LineWidth = lineWidth; + _lineY.LineWidth = lineWidth; + _lineZ.LineWidth = lineWidth; + } + + public AxisVBO(OpenGL gl, Material matX, Material matY, Material matZ, float lineWidth) + { + RecalculateShape(gl); + + _lineX.Material = matX; + _lineY.Material = matY; + _lineZ.Material = matZ; + + _lineX.LineWidth = lineWidth; + _lineY.LineWidth = lineWidth; + _lineZ.LineWidth = lineWidth; + } + #endregion constructors + + + public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) + { + // Ensure that we're in design mode (we don't want axis during render) + if (renderMode != RenderMode.Design) + return; + + ValidateBeforeRender(); + + //gl.DepthFunc(OpenGL.GL_ALWAYS); + + shader.UseProgram(gl, () => + { + shader.ApplyMaterial(gl, MaterialX); + _lineX.Render(gl, renderMode, shader); + + shader.ApplyMaterial(gl, MaterialY); + _lineY.Render(gl, renderMode, shader); + + shader.ApplyMaterial(gl, MaterialZ); + _lineZ.Render(gl, renderMode, shader); + }); + + //gl.DepthFunc(OpenGL.GL_LESS); + } + + + + /// + /// Calculates the lines using the current axis properties. + /// + public virtual void RecalculateShape(OpenGL gl) + { + var riseAxisValue = 0f;// .0001f; // Axis didn't combine well with + + var lineX = new List>(); + var lineY = new List>(); + var lineZ = new List>(); + + lineX.Add( + new Tuple( + new vec3(0, riseAxisValue, 0), + new vec3(_axisLength, riseAxisValue, 0)) + ); + + lineY.Add( + new Tuple( + new vec3(0, riseAxisValue, 0), + new vec3(0, _axisLength, 0)) + ); + + lineZ.Add( + new Tuple( + new vec3(0, riseAxisValue, 0), + new vec3(0, riseAxisValue, _axisLength)) + ); + + + _lineX = new Lines(gl, lineX, null); + _lineY = new Lines(gl, lineY, null); + _lineZ = new Lines(gl, lineZ, null); + } + + /// + /// Ensures that all required properties are acceptable. + /// + private void ValidateBeforeRender() + { + if (_lineX == null || _lineY == null || _lineZ == null) + { + throw new Exception("Axis aren't calculated."); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs new file mode 100644 index 00000000..2eb8092a --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs @@ -0,0 +1,195 @@ +using GlmNet; +using SharpGL; +using SharpGL.Enumerations; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + public class Lines + { + #region fields + private uint _glDrawMode = SharpGL.OpenGL.GL_LINE; + vec3[] _vertices, _normals; + ushort[] _indices; + Material _material; + OpenGL _openGL; + private VertexBuffer _vertexBuffer, _normalBuffer; + private IndexBuffer _indexBuffer; + float _lineWidth = 1f; + #endregion fields + + + #region properties + public vec3[] Vertices + { + get { return _vertices; } + set { _vertices = value; } + } + + public vec3[] Normals + { + get { return _normals; } + set { _normals = value; } + } + + public ushort[] Indices + { + get { return _indices; } + set { _indices = value; } + } + + public uint GlDrawMode + { + get { return _glDrawMode; } + set { _glDrawMode = value; } + } + + public Material Material + { + get { return _material; } + set { _material = value; } + } + + public OpenGL GL + { + get { return _openGL; } + set { _openGL = value; } + } + + public VertexBuffer VertexBuffer + { + get { return _vertexBuffer; } + set { _vertexBuffer = value; } + } + + public VertexBuffer NormalBuffer + { + get { return _normalBuffer; } + set { _normalBuffer = value; } + } + public IndexBuffer IndexBuffer + { + get { return _indexBuffer; } + set { _indexBuffer = value; } + } + + public float LineWidth + { + get { return _lineWidth; } + set { _lineWidth = value; } + } + + #endregion properties + + public Lines(OpenGL gl, List> lines, Material material = null) + { + + var verts = new vec3[lines.Count * 2]; + var normals = new vec3[lines.Count * 2]; + var indices = new ushort[lines.Count * 2]; + + for (int i = 0; i < lines.Count; i++) + { + var i2 = i * 2; + verts[i2] = lines[i].Item1; + verts[i2 + 1] = lines[i].Item2; + + normals[i2] = new vec3(1, 1, 1); + normals[i2 + 1] = new vec3(1, 1, 1); + + indices[i2] = (ushort)i2; + indices[i2 + 1] = (ushort)(i2 + 1); + } + + if (material != null) + Material = material; + + _vertices = verts; + _normals = normals; + _indices = indices; + GlDrawMode = OpenGL.GL_LINES; + + + if (gl != null) + GenerateGeometry(gl); + } + + /// + /// Generates the vertices, normals and indices and creates them for the OpenGL. + /// This method has to be called once before drawing. + /// + /// + public void GenerateGeometry(OpenGL gl) + { + _openGL = gl; + + // Create the index data buffer. + _indexBuffer = new IndexBuffer(); + _indexBuffer.Create(_openGL); + + // Create the vertex data buffer. + _vertexBuffer = new VertexBuffer(); + _vertexBuffer.Create(_openGL); + + _normalBuffer = new VertexBuffer(); + _normalBuffer.Create(_openGL); + } + + public void Render(OpenGL gl, RenderMode renderMode, Shaders.ExtShaderProgram shader = null) + { + + // Binds buffers. + Bind(); + + // Sets the linewidth. + gl.LineWidth(LineWidth); + // Draw the elements. + gl.DrawArrays(GlDrawMode, 0, Vertices.Length); + //gl.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); + + //gl.PopAttrib(); + } + + + + /// + /// Calls VertexBuffer.Bind(gl), IndexBuffer.Bind(gl) and Material.Bind(gl). + /// + /// The OpenGL + public void Bind() + { + if (_openGL == null) + { + throw new ArgumentNullException("OpenGL parameter cannot be null. Call 'GenerateGeomerty(...)' before attempting to bind."); + } + + // Bind the vertex, normal and index buffers. + if (_vertexBuffer != null) + { + _vertexBuffer.Bind(_openGL); + _vertexBuffer.SetData(_openGL, VertexAttributes.Position, Vertices.SelectMany(v => v.to_array()).ToArray(), false, 3); + } + + if (_normalBuffer != null) + { + _normalBuffer.Bind(_openGL); + _normalBuffer.SetData(_openGL, VertexAttributes.Normal, Normals.SelectMany(v => v.to_array()).ToArray(), false, 3); + } + + if (_indexBuffer != null) + { + _indexBuffer.Bind(_openGL); + _indexBuffer.SetData(_openGL, Indices); + } + + if (Material != null) + Material.Bind(_openGL); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs new file mode 100644 index 00000000..f1181457 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs @@ -0,0 +1,386 @@ +using GlmNet; +using SharpGLBase.Scene; +using SharpGLBase.Extensions; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SharpGLBase.Primitives.ModelComponents; +using SharpGLBase.Shaders; + +namespace SharpGLBase.Primitives +{ + public abstract class Model3DBase : TransformableBase, IHasMaterial, IDisposable + { + #region fields + //private ushort[] _indices; + private vec3[] _baseVertices;//, _transformedVertices, _normals; + private VertexBuffer _vertexBuffer, _normalBuffer; + private IndexBuffer _indexBuffer; + private OpenGL _openGL; + private bool _visible = true; + private bool _autoCalculateNormals = true; + private Material _material = new Material(){ Ambient = Color.Red}; + private Mesh _mesh; + private uint _glDrawMode = OpenGL.GL_TRIANGLES; + private int _bufferStride = 3; + #endregion fields + + #region properties + /// + /// The material that has to be applied to this model. + /// + public Material Material + { + get; + set; + } + /// + /// This indices for this model. Used for pointing to a position in the Normals- and Vertices arrays. + /// + public ushort[] Indices + { + get { return _mesh.Indices; } + set { _mesh.Indices = value; } + } + /// + /// The normals for this model. Primarily used for lighting calculations by telling the GL in which direction the surface is facing. + /// + public vec3[] Normals + { + get { return _mesh.Normals; } + set { _mesh.Normals = value; } + } + /// + /// The vertices for this model. + /// + public vec3[] BaseVertices + { + get { return _baseVertices; } + set { _baseVertices = value; } + } + /// + /// The vertices for this model after applying the transformations to it. + /// + public vec3[] TransformedVertices + { + get { return _mesh.Vertices == null ? _baseVertices : _mesh.Vertices; } + set { _mesh.Vertices = value; } + } + /// + /// The normal buffer for binding with the GL. + /// + public VertexBuffer NormalBuffer + { + get { return _normalBuffer; } + set { _normalBuffer = value; } + } + /// + /// The vertex buffer for binding with the GL. + /// + public VertexBuffer VertexBuffer + { + get { return _vertexBuffer; } + set { _vertexBuffer = value; } + } + /// + /// The index buffer for binding with the GL. + /// + public IndexBuffer IndexBuffer + { + get { return _indexBuffer; } + set { _indexBuffer = value; } + } + /// + /// The opengl instance. + /// + public OpenGL OpenGL + { + get { return _openGL; } + } + /// + /// Checks whether this model should be drawn during the next draw-call. Implement this in your Render-method. + /// + public bool Visible + { + get { return _visible; } + set { _visible = value; } + } + /// + /// Checks if the normals can be automatically calculated if they're unavailable or after a transformation. + /// + public bool AutoCalculateNormals + { + get { return _autoCalculateNormals; } + set { _autoCalculateNormals = value; } + } + /// + /// The mode that this model should be drawn with (GL_LINES, GL_TRIANGLES, GL_QUADS,...). + /// + public uint GlDrawMode + { + get { return _glDrawMode; } + set { _glDrawMode = value; } + } + /// + /// The stride between + /// + public int BufferStride + { + get { return _bufferStride; } + set { _bufferStride = value; } + } + #endregion properties + + #region abstract methods + /// + /// Draws the model to the OpenGL. GenerateGeometry(...) has to be called at least once before Draw(...). + /// + /// + /// + /// + /// + //public abstract void Draw(); + public abstract void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null); + + #endregion abstract methods + + /// + /// Call this method to prepare the object for being displayed or fill -BaseVertices, -Indices, -Normals manually. + /// Also provide the OpenGL to automatically call GenerateGeometry. + /// + /// The BaseVertices + /// The Indices + /// The Normals + /// The OpenGL + public void Init(vec3[] vertices, ushort[] indices, vec3[] normals = null, OpenGL gl = null) + { + _baseVertices = vertices; + //_indices = indices; + + + _mesh = new Mesh(indices, _baseVertices, normals); + //_normals = normals; + + if (gl != null) + { + GenerateGeometry(gl); + } + } + + /// + /// Generates the vertices, normals and indices and creates them for the OpenGL. + /// This method has to be called once before drawing. + /// + /// + public void GenerateGeometry(OpenGL gl) + { + _openGL = gl; + + // Create the index data buffer. + _indexBuffer = new IndexBuffer(); + _indexBuffer.Create(_openGL); + + // Create the vertex data buffer. + _vertexBuffer = new VertexBuffer(); + _vertexBuffer.Create(_openGL); + + if (_mesh.Normals != null) + { + _normalBuffer = new VertexBuffer(); + _normalBuffer.Create(_openGL); + } + else if (_autoCalculateNormals) + { + CalculateNormals(); + _normalBuffer = new VertexBuffer(); + _normalBuffer.Create(_openGL); + } + } + + + /// + /// Calls VertexBuffer.Bind(gl), IndexBuffer.Bind(gl) and Material.Bind(gl). + /// + /// The OpenGL + public void Bind() + { + if (_openGL == null) + { + throw new ArgumentNullException("OpenGL parameter cannot be null. Call 'GenerateGeomerty(...)' before attempting to bind."); + } + + // Bind the vertex, normal and index buffers. + if (_vertexBuffer != null) + { + _vertexBuffer.Bind(_openGL); + _vertexBuffer.SetData(_openGL, VertexAttributes.Position, TransformedVertices.SelectMany(v => v.to_array()).ToArray(), false, _bufferStride); + } + + if (_normalBuffer != null) + { + _normalBuffer.Bind(_openGL); + _normalBuffer.SetData(_openGL, VertexAttributes.Normal, _mesh.Normals.SelectMany(v => v.to_array()).ToArray(), false, _bufferStride); + } + + if (_indexBuffer != null) + { + _indexBuffer.Bind(_openGL); + _indexBuffer.SetData(_openGL, _mesh.Indices); + } + + if (Material != null) + Material.Bind(_openGL); + } + + /// + /// When the creation of the new transformation matrix is finished, this matrix must to be applied to every vertex. + /// + public override void RecalculateResultMatrix() + { + base.RecalculateResultMatrix(); + + vec3[] vertices = new vec3[BaseVertices.Length]; + // Apply transformations to each vertex + for (int baseVertIdx = 0; baseVertIdx < BaseVertices.Length; baseVertIdx++) + { + vec3 vec3Vert = BaseVertices[baseVertIdx]; + vec4 vec4Vert = new vec4(vec3Vert.x, vec3Vert.y, vec3Vert.z, 1); + + // vec4 res = base.ResultMatrix * vec4Vert; // Apparently not supported in GlmNET, so we do it manually. + vec4 res = new vec4(); + for (int i = 0; i < 4; i++) // i = collumn for mat4 + { + float val = 0; + for (int j = 0; j < 4; j++) // j = row for mat4 and col for vec4 + { + val += vec4Vert[j] * base.ResultMatrix[j][i]; + } + res[i] = val; + } + vertices[baseVertIdx] = new vec3(res[0], res[1], res[2]); + } + + TransformedVertices = vertices; + //Vertices changed, so normals need to be recalculated + CalculateNormals(); + } + + /// + /// Recalculates the normals. + /// NOTE: this method is virtual. + /// + public virtual void CalculateNormals() + { + _mesh.CalculateNormals(); + + } + + + /// + /// Cleans up OpenGL memory when this element is no longer needed. + /// + public void Dispose() + { + if (_openGL == null) + return; + + List buffersToBeRemoved = new List(); + + if (_indexBuffer != null) + buffersToBeRemoved.Add(_indexBuffer.IndexBufferObject); + if (_vertexBuffer != null) + buffersToBeRemoved.Add(_vertexBuffer.VertexBufferObject); + if (_normalBuffer != null) + buffersToBeRemoved.Add(_normalBuffer.VertexBufferObject); + + _openGL.DeleteBuffers(buffersToBeRemoved.Count, buffersToBeRemoved.ToArray()); + } + + /// + /// Generates and draws the model from scratch for the given GL. Do NOT use this method for each draw-call. + /// This method should only be used for drawing a model once. + /// + /// + /// + public static void GenerateAndDrawOnce(OpenGL gl, Model3DBase model) + { + var verts = model.TransformedVertices.SelectMany(v => v.to_array()).ToArray(); + var normals = model.Normals.SelectMany(v => v.to_array()).ToArray(); + var indices = model.Indices; + var drawMode = model.GlDrawMode; + + + // Create the index data buffer. + var indexBuffer = new IndexBuffer(); + indexBuffer.Create(gl); + + // Create the vertex data buffer. + var vertexBuffer = new VertexBuffer(); + vertexBuffer.Create(gl); + + // Create the normal data buffer. + var normalBuffer = new VertexBuffer(); + normalBuffer.Create(gl); + + + // Bind the vertex, normal and index buffers. + vertexBuffer.Bind(gl); + vertexBuffer.SetData(gl, VertexAttributes.Position, verts, false, 3); + + normalBuffer.Bind(gl); + normalBuffer.SetData(gl, VertexAttributes.Normal, normals, false, 3); + + indexBuffer.Bind(gl); + indexBuffer.SetData(gl, indices); + + gl.FrontFace(OpenGL.GL_CW); + + // Draw the elements. + gl.DrawElements(drawMode, indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); + + + // Clean up + List buffersToBeRemoved = new List(); + + if (indexBuffer != null) + buffersToBeRemoved.Add(indexBuffer.IndexBufferObject); + if (vertexBuffer != null) + buffersToBeRemoved.Add(vertexBuffer.VertexBufferObject); + if (normalBuffer != null) + buffersToBeRemoved.Add(normalBuffer.VertexBufferObject); + + gl.DeleteBuffers(buffersToBeRemoved.Count, buffersToBeRemoved.ToArray()); + } + + + /// + /// Converts an (uint)model.VertexBuffer.VertexBufferObject to a ARGB color. + /// + /// The model. + /// A float[4] containing RGBA values. + public Color GenerateColorFromId() + { + if (VertexBuffer == null) + { + return Color.Black; + } + + // Get the integer ID + var i = (int)VertexBuffer.VertexBufferObject; + + int b = (i >> 16) & 0xFF; + int g = (i >> 8) & 0xFF; + int r = i & 0xFF; + + return Color.FromArgb(255, r, g, b); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs new file mode 100644 index 00000000..0b90f8c0 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs @@ -0,0 +1,71 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives.ModelComponents +{ + public class Face + { + #region fields + Vertex[] _vertices; + vec3 _normal; + #endregion fields + + #region properties + public Vertex[] Vertices + { + get { return _vertices; } + } + + public vec3 Normal + { + get { return _normal; } + set { _normal = value; } + } + #endregion properties + + + public Face(Vertex[] vertices) + { + _vertices = vertices; + foreach (var vertex in vertices) + { + vertex.ParentFaces.Add(this); // Establish many-to-many relationship. + } + } + public void CalculateNormal() + { + var v1 = _vertices[0]; + var v2 = _vertices[1]; + var v3 = _vertices[2]; + var edge1 = v2.Vec3-v1.Vec3; + var edge2 = v3.Vec3-v1.Vec3; + var normal = glm.cross(edge1, edge2); + + //for (int i = 0; i < _vertices.Length - 1; i++) + //{ + // vec3 curVert = _vertices[i].Vec3; + // vec3 nextVert = _vertices[(i + 1) % _vertices.Length].Vec3; + + // normal.x += (curVert.y - nextVert.y) * (curVert.z + nextVert.z); + // normal.y += (curVert.z - nextVert.z) * (curVert.x + nextVert.x); + // normal.z += (curVert.x - nextVert.x) * (curVert.y + nextVert.y); + //} + + + if (normal.x == 0 && normal.y == 0 && normal.z ==0) + { + Normal = new vec3(0, 0, 0); + } + else + { + normal.z = -normal.z; + normal.x = -normal.x; + normal.y = -normal.y; + Normal = glm.normalize(normal); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs new file mode 100644 index 00000000..b6747371 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs @@ -0,0 +1,175 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives.ModelComponents +{ + public class Mesh + { + #region fields + Face[] _faces; + vec3[] _vertices, _normals; + ushort[] _indices; + Vertex[] _allVertices; + Dictionary _idxForVertex; + #endregion fields + + #region properties + public Face[] Faces + { + get { return _faces; } + set { _faces = value; } + } + public vec3[] Vertices + { + get { return _vertices; } + set + { + _vertices = value; + UpdateFaceVertices(); + } + } + + public vec3[] Normals + { + get { return _normals; } + set { _normals = value; } + } + public ushort[] Indices + { + get { return _indices; } + set { _indices = value; } + } + #endregion properties + + #region constructors + public Mesh() + { + + } + public Mesh(Face[] faces) + { + _faces = faces; + } + + public Mesh(ushort[] indices, vec3[] vertices, vec3[] normals) + { + var n = 3; + var faces = new List(); + + _indices = indices; + _normals = normals; + _vertices = vertices; + + _idxForVertex = new Dictionary(); + _allVertices = new Vertex[vertices.Length]; + + for (int i = 0; i < indices.Length; i+=n) + { + var idx0 = indices[i]; + var idx1 = indices[i + 1]; + var idx2 = indices[i + 2]; + + #region getVertex(...) function + Func getVertex = idx => + { + if (_idxForVertex.ContainsKey(idx)) + { + return _idxForVertex[idx]; + } + else + { + var vert = new Vertex(idx, + normals == null ? + new vec3() + : normals[idx], vertices[idx]); + _idxForVertex[idx] = vert; + + _allVertices[idx] = vert; + return vert; + } + }; + #endregion getVertex(...) function + + + Vertex v0 = getVertex(idx0); + Vertex v1 = getVertex(idx1); + Vertex v2 = getVertex(idx2); + + + faces.Add(new Face(new Vertex[]{v0,v1,v2})); + + } + + _faces = faces.ToArray(); + + + + if (_normals == null) + { + CalculateNormals(); + } + } + + #endregion constructors + + public void CalculateNormals() + { + //// Set indices to null. + //foreach (var face in _faces) + //{ + // foreach (var vertex in face.Vertices) + // { + // vertex.Index = null; + // } + //} + + //ushort nxtIdx = 0; + //var vertices = new List(); + var normals = new vec3[_allVertices.Length]; + //var indices = new List(); + //foreach (var face in _faces) + //{ + // foreach (var vertex in face.Vertices) + // { + // if (vertex.Index == null) + // { + // //vertex.Index = nxtIdx++; // Set vertex and increase nxtIdx + // //vertices.Add(vertex.Vec3); + // normals.Add(vertex.Normal); + // } + // //indices.Add(vertex.Index.Value); + // } + //} + + foreach (var face in _faces) + { + face.CalculateNormal(); + } + + foreach (var vert in _allVertices) + { + vert.CalculateVertexNormal(); + normals[vert.Index.Value] = vert.Normal; + } + + //Vertices = vertices.ToArray(); + Normals = normals;//.ToArray(); + //Indices = indices.ToArray(); + + } + + public void UpdateFaceVertices() + { + foreach (var idx in _indices) + { + Vertex vert = _idxForVertex[idx]; + vec3 vec3Vert = _vertices[idx]; + + vert.Vec3 = vec3Vert; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs new file mode 100644 index 00000000..0206fd41 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs @@ -0,0 +1,71 @@ +using GlmNet; +using SharpGLBase.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives.ModelComponents +{ + public class Vertex + { + #region fields + ushort? _index = null; + List _parentFaces = new List(); + vec3 _vertex; + vec3 _normal; + #endregion fields + + + #region properties + public ushort? Index + { + get { return _index; } + set { _index = value; } + } + public vec3 Normal + { + get { return _normal; } + set { _normal = value; } + } + + public vec3 Vec3 + { + get { return _vertex; } + set { _vertex = value; } + } + + public List ParentFaces + { + get { return _parentFaces; } + set { _parentFaces = value; } + } + #endregion properties + + public Vertex() { } + + public Vertex(ushort index, vec3 normal, vec3 vertex) + { + _index = index; + _normal = normal; + _vertex = vertex; + } + + + public void CalculateVertexNormal() + { + vec3 normalSum = new vec3(); + foreach (var plane in _parentFaces) + { + normalSum += plane.Normal; + } + + Normal = glm.normalize(normalSum); + } + + public override string ToString() + { + return _vertex.ToValueString(); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs new file mode 100644 index 00000000..9e043063 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs @@ -0,0 +1,23 @@ +using GlmNet; +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + public static class PrimitivesGlobal + { + public static void RenderLines(OpenGL gl, List> lines) + { + foreach (var item in lines) + { + vec3 v1 = item.Item1; + vec3 v2 = item.Item2; + gl.Vertex(v1.x, v1.y, v1.z); + gl.Vertex(v2.x, v2.y, v2.z); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs new file mode 100644 index 00000000..136e905f --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs @@ -0,0 +1,154 @@ +using GlmNet; +using SharpGLBase.Shaders; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + /// + /// Draws a grid in the center of the world. + /// + public class SquareGrid : IRenderable, IHasMaterial + { + #region fields + private int _directionLineCount; + private float _stepSize, _lineThickness = 0.001f; + private Material _material; + private List> _lines = null; + #endregion fields + + #region properties + /// + /// Gets or sets the amount of lines in each direction. + /// + public int DirectionLineCount + { + get { return _directionLineCount; } + set { _directionLineCount = value; } + } + + /// + /// Distance between 2 lines. + /// + public float StepSize + { + get { return _stepSize; } + set { _stepSize = value; } + } + public float LineThickness + { + get { return _lineThickness; } + set { _lineThickness = value; } + } + + /// + /// The applied material for the grid. + /// + public Material Material + { + get { return _material; } + set { _material = value; } + } + #endregion properties + + public SquareGrid() + :this(10, 1f) + { } + + public SquareGrid(int directionLineCount, float stepSize) + { + _directionLineCount = directionLineCount; + _stepSize = stepSize; + + _material = new Material(); + _material.Ambient = Color.FromArgb(255, 146, 134, 188); // Purple. + _material.Shininess = 1f; + + RecalculateShape(); + } + + /// + /// Renders the grid to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + /// Pass the shader so the material color(s) can be applied locally. + public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) + { + if (renderMode != RenderMode.Design) + return; + + shader.ApplyMaterial(gl, _material); + + Render(gl, renderMode); + } + + /// + /// Renders the grid to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + public void Render(OpenGL gl, RenderMode renderMode) + { + // Ensure that we're in design mode (we don't want axis during render) + if (renderMode != RenderMode.Design) + return; + + + ValidateBeforeRender(); + + // Draw the lines. + // TODO: Inefficient, consumes a lot of resources. + gl.LineWidth(_lineThickness); + gl.Begin(OpenGL.GL_LINES); + PrimitivesGlobal.RenderLines(gl, _lines); + gl.End(); + } + + /// + /// Calculates the lines using the current grid properties. + /// + public void RecalculateShape() + { + _lines = new List>(); + + float min = -StepSize * DirectionLineCount; + float max = StepSize * DirectionLineCount; + for (float x = min; x <= max; x += StepSize) + { + for (float z = min; z <= max; z += StepSize) + { + _lines.Add( + new Tuple( + new vec3(x, 0.0f, min), + new vec3(x, 0.0f, max)) + ); + + _lines.Add( + new Tuple( + new vec3(min, 0.0f, z), + new vec3(max, 0.0f, z)) + ); + } + } + } + + /// + /// Ensures that all required properties are acceptable. + /// + private void ValidateBeforeRender() + { + if (_lines == null) + { + throw new Exception("Grid lines aren't calculated."); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs new file mode 100644 index 00000000..8c8dbfea --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs @@ -0,0 +1,155 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGLBase.Shaders; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Primitives +{ + public class SquareGridVBO + { + #region fields + private int _directionLineCount; + private float _stepSize, _lineThickness = 1f; + private List> _lines = null; + private Lines _gridLines = null; + #endregion fields + + #region properties + /// + /// Gets or sets the amount of lines in each direction. + /// + public int DirectionLineCount + { + get { return _directionLineCount; } + set { _directionLineCount = value; } + } + + /// + /// Distance between 2 lines. + /// + public float StepSize + { + get { return _stepSize; } + set { _stepSize = value; } + } + public float LineThickness + { + get { return _lineThickness; } + set { _lineThickness = value; } + } + + /// + /// The applied material for the grid. + /// + public Material Material + { + get { return _gridLines.Material; } + set { _gridLines.Material = value; } + } + #endregion properties + + public SquareGridVBO(OpenGL gl) + :this(gl, 10, 1f) + { } + + public SquareGridVBO(OpenGL gl, int directionLineCount, float stepSize) + { + _directionLineCount = directionLineCount; + _stepSize = stepSize; + + RecalculateShape(); + + _gridLines = new Lines(gl, _lines); + + Material = new Material(); + Material.Diffuse = Color.FromArgb(255, 146, 134, 188); // Purple. + Material.Shininess = 1f; + } + + /// + /// Renders the grid to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + /// Pass the shader so the material color(s) can be applied locally. + public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) + { + if (renderMode != RenderMode.Design) + return; + + shader.UseProgram(gl, () => + { + shader.ApplyMaterial(gl, Material); + + Render(gl, renderMode); + }); + } + + /// + /// Renders the grid to the gl if it's in DesignMode. + /// + /// The gl + /// The rendermode + public void Render(OpenGL gl, RenderMode renderMode) + { + // Ensure that we're in design mode (we don't want axis during render) + if (renderMode != RenderMode.Design) + return; + + + ValidateBeforeRender(); + + // Draw the lines. + + _gridLines.Render(gl, renderMode, null); + } + + /// + /// Calculates the lines using the current grid properties. + /// + public void RecalculateShape() + { + _lines = new List>(); + List verts = new List(); + + float min = -StepSize * DirectionLineCount; + float max = StepSize * DirectionLineCount; + for (float x = min; x <= max; x += StepSize) + { + for (float z = min; z <= max; z += StepSize) + { + vec3 v1 = new vec3(x, 0.0f, min); + vec3 v2 = new vec3(x, 0.0f, max); + vec3 v3 = new vec3(min, 0.0f, z); + vec3 v4 = new vec3(max, 0.0f, z); + + verts.AddRange(new vec3[] { v1, v2, v3, v4 }); + + + _lines.Add( + new Tuple(v1, v2)); + + _lines.Add( + new Tuple(v3,v4)); + } + } + } + + /// + /// Ensures that all required properties are acceptable. + /// + private void ValidateBeforeRender() + { + if (_lines == null) + { + throw new Exception("Grid lines aren't calculated."); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a093696d --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Scene")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Scene")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c1ec0990-87c3-4af8-93dd-5a0f1160f45b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs new file mode 100644 index 00000000..d2d66ec5 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs @@ -0,0 +1,112 @@ +using GlmNet; +using SharpGLBase.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Scene +{ + public enum CameraRotationHandling { SRT, TRS} + /// + /// This class contains all functionality related to the ModelView matrix. + /// + public class ModelView : TransformableBase,INotifyPropertyChanged + { + #region events + + #region propertychanged event + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion propertychanged event + + #endregion events + + #region fields + CameraRotationHandling _cameraHandling = CameraRotationHandling.SRT; + #endregion fields + + #region properties + /// + /// The ModelView Matrix. + /// + public mat4 ModelviewMatrix + { + get { return ResultMatrix; } + } + + /// + /// Get or set the sequence of the modelview rotation transformation. + /// + public CameraRotationHandling CameraHandling + { + get { return _cameraHandling; } + set { _cameraHandling = value; } + } + #endregion properties + + /// + /// Converts ModelviewMatrix to a float[]. + /// + /// A float[] containing all the values from the initial matrix. + public float[] ToArray() + { + return ModelviewMatrix.to_array(); + } + + /// + /// Converst the this.ToArray() from a float[] to a double[] + /// + /// + public double[] ToDoubleArray() + { + float[] arr = ToArray(); + var newArr = new double[arr.Length]; + for (int i = 0; i < arr.Length; i++) + { + newArr[i] = (double)arr[i]; + } + + return newArr; + } + + /// + /// Modelview needs different sequences of transformations. + /// + public override void RecalculateResultMatrix() + { + if (CameraHandling == Scene.CameraRotationHandling.TRS) + ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix; // rotate around center + else if (CameraHandling == Scene.CameraRotationHandling.SRT) + ResultMatrix = ScalingMatrix * RotationMatrix * TranslationMatrix; // rotate around camera center + + //ResultMatrix = ScalingMatrix * RotationMatrix * TranslationMatrix; // rotate around camera center + //ResultMatrix = TranslationMatrix * ScalingMatrix * RotationMatrix; // rotate around camera center (swap axis) + //ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix; // rotate around own center + //ResultMatrix = RotationMatrix * ScalingMatrix * TranslationMatrix; // rotate around own center (swap axis) + //ResultMatrix = RotationMatrix * TranslationMatrix * ScalingMatrix; // stretches shape (swap axis) + //ResultMatrix = ScalingMatrix * TranslationMatrix * RotationMatrix; // stretches shape (swap axis) + //ResultMatrix = RotationMatrix * TranslationMatrix.Transpose() * ScalingMatrix; // stretches shape (swap axis) + //ResultMatrix = ScalingMatrix * TranslationMatrix.Transpose() * RotationMatrix; // stretches shape (swap axis) + + OnPropertyChanged("ModelviewMatrix"); + } + + /// + /// Allow direct array access to the ModelviewMatrix. + /// + /// Collumn index. + /// The vec4 at this position. + public vec4 this[int col]{ + get + { + return ModelviewMatrix[col]; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs new file mode 100644 index 00000000..2ef000ec --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs @@ -0,0 +1,48 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Scene +{ + /// + /// This class contains all functionality related to the Normal matrix. + /// + public class Normal + { + #region fields + private mat3 _normalMatrix = mat3.identity(); + + #endregion fields + + #region properties + /// + /// The Normal matrix. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set { _normalMatrix = value; } + } + #endregion properties + + /// + /// Simplify the creation of the normal matrix by using a modelView. + /// + /// + public void CreateFromModelView(ModelView modelView) + { + _normalMatrix = modelView.ModelviewMatrix.to_mat3(); + } + + /// + /// Converts NormalMatrix to a float[]. + /// + /// A float[] containing all the values from the initial matrix. + public float[] ToArray() + { + return _normalMatrix.to_array(); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs new file mode 100644 index 00000000..2c6b1758 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs @@ -0,0 +1,20 @@ +using GlmNet; +using SharpGLBase.Primitives; +using SharpGLBase.Shaders; +using SharpGL; +using SharpGL.SceneGraph.Core; +using SharpGL.Shaders; +using SharpGL.Version; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using SharpGLBase.Extensions; +using SharpGL.RenderContextProviders; +using System.Threading.Tasks; +using SharpGLBase.Shaders.Parameters; + +namespace SharpGLBase.Scene +{ +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs new file mode 100644 index 00000000..d2f35a9b --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs @@ -0,0 +1,292 @@ +using GlmNet; +using SharpGLBase.Events; +using SharpGLBase.Primitives; +using SharpGL; +using SharpGL.Enumerations; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Cameras; +using SharpGL.SceneGraph.Core; +using SharpGL.SceneGraph.Primitives; +using SharpGL.Shaders; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using SharpGLBase.Shaders; +using System.Threading.Tasks; +using System.Threading; +using SharpGL.Version; +using SharpGLBase.Shaders.Parameters; + +namespace SharpGLBase.Scene +{ + /// + /// A Scene object is the central place where everything -that influences the visual result- comes together. + /// + public abstract class OpenGLScene + { + #region fields + ModelView _modelView = new ModelView(); + Normal _normal = new Normal(); + Projection _projection = new Projection(); + ExtShaderProgram _currentShader; + float _performanceScaleValue = 1f; + Size _sceneSize; + Size _viewPortSize; + Point? _modelSelectionPoint = null; + #endregion fields + + #region properties + /// + /// The projection matrix is contained in here. + /// + public Projection Projection + { + get { return _projection; } + set { _projection = value; } + } + /// + /// The modelview matrix is contained in here. + /// + public ModelView ModelView + { + get { return _modelView; } + set { _modelView = value; } + } + /// + /// The normal matrix is contained in here. + /// + public Normal Normal + { + get { return _normal; } + set { _normal = value; } + } + /// + /// The shader that's currently being used for rendering the models. + /// + public ExtShaderProgram CurrentShader + { + get { return _currentShader; } + set { _currentShader = value; } + } + /// + /// A value that will be multiplied to the passed view width and -height during resizing. + /// + public float PerformanceScaleValue + { + get { return _performanceScaleValue; } + set { _performanceScaleValue = value; } + } + /// + /// The size of the scene. ( = ViewPortSize * PerformanceScaleValue) + /// + public Size SceneSize + { + get { return _sceneSize; } + private set { _sceneSize = value; } + } + /// + /// The size of the viewport. + /// + public Size ViewPortSize + { + get { return _viewPortSize; } + private set { _viewPortSize = value; } + } + + public OpenGL GL { get; private set; } + #endregion properties + + #region events + public event ModelSelectedEvent ModelSelected; + public void OnModelSelected(Point p, Model3DBase m) + { + if (ModelSelected != null) + ModelSelected(this, new ModelSelectedEventArgs(p, m)); + } + #endregion events + + /// + /// Should be called before the first Draw-call is being made. Sets the GL. + /// + /// + public virtual void OpenGLInitialized(OpenGL gl) + { + GL = gl; + } + /// + /// Should be called before the first Draw-call is being made. Sets the GL and shader. + /// + /// + public virtual void OpenGLInitialized(OpenGL gl, ExtShaderProgram shader) + { + OpenGLInitialized(gl); + CurrentShader = shader; + } + + /// + /// Redraw the scene. + /// + /// OpenGL viewport + public abstract void Draw(OpenGL gl); + + public virtual void ViewResized(OpenGL gl, double actualWidth, double actualHeight) + { + var viewPortWidth = (float)actualWidth * _performanceScaleValue; + var viewPortHeight = (float)actualHeight * _performanceScaleValue; + + ViewPortSize = new Size((int)actualWidth, (int)actualHeight); + SceneSize = new Size((int)viewPortWidth, (int)viewPortHeight); + + // Create a projection matrix for the scene with the screen size. + Projection.SetFrustum((float)viewPortWidth, (float)viewPortHeight); + + gl.SetDimensions((int)++viewPortWidth, (int)++viewPortHeight); + gl.Viewport(0, 0, (int)++viewPortWidth, (int)++viewPortHeight); + } + + + /// + /// This method let's the Draw(...) know to retrieve the object at the requested location. When an object is found, the ModelSelectedEvent will be triggered. + /// + /// The 2D point relative to the OpenGL viewport. + public void GetModelAtPoint(Point p, IEnumerable models, HitTestMethod method = HitTestMethod.OpenGLHack) + { + if (p != null && models != null && models.Count() > 0) + { + Point correctedPoint = new Point((int)(p.X * _performanceScaleValue), (int)(p.Y * _performanceScaleValue)); + + + // Create an array that will be the viewport. + int[] viewport = new int[4]; + // Get the viewport, then convert the mouse point to an opengl point. + GL.GetInteger(OpenGL.GL_VIEWPORT, viewport); + + + // Take deep copy of everything we need. + var mvCopy = new ModelView() + { + ResultMatrix = ModelView.ModelviewMatrix + }; + var prCopy = new Projection() + { + ProjectionMatrix = Projection.ProjectionMatrix + }; + var nrmlCopy = new Normal() + { + NormalMatrix = Normal.NormalMatrix + }; + + Task t = new Task(() => + { + Model3DBase clickedModel = null; + + if (method == HitTestMethod.OpenGLHack) + { + clickedModel = GetModelAtPointHack(correctedPoint, models, viewport, mvCopy, prCopy, nrmlCopy); + } + + OnModelSelected(correctedPoint, clickedModel); + }); + + t.Start(); + } + } + + + #region HitTest + + public enum HitTestMethod { OpenGLHack }//, RayOBB} + + + /// + /// Source: http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-an-opengl-hack/ + /// It's recommended to read the source before using this algorithm. + /// + /// The OpenGLScene. + /// The 2D point. + /// The drawn models. + /// A factor that affects performance by scaling the size of the temperory viewport. + /// The model on this location or null. + public static Model3DBase GetModelAtPointHack(Point point, IEnumerable models, + int[] viewport, ModelView modelview, Projection projection, Normal normal, float performanceScaleValue = 1) + { + int id = -1; + + int width = (int)(viewport[2] * performanceScaleValue); + int height = (int)(viewport[3] * performanceScaleValue); + int x = (int)(point.X * performanceScaleValue); + int y = height - (int)(point.Y * performanceScaleValue); + + + #region create a temperory gl to prevent flickering + OpenGL gl = new OpenGL(); + + // Create OpenGL. + var openGLVersion = OpenGLVersion.OpenGL2_1; + var renderContextType = RenderContextType.FBO; + gl.Create(openGLVersion, renderContextType, 1, 1, 32, null); + // Set the dimensions and viewport. + gl.SetDimensions(width, height); + gl.Viewport(0, 0, width, height); + + + // Make GL current. + gl.MakeCurrent(); + + gl.Enable(OpenGL.GL_DEPTH_TEST); + //gl.Clear(OpenGL.GL_DEPTH_CLEAR_VALUE); + + #endregion create a temperory gl to prevent flickering + + // Initialize the shader for our new GL. + var esp = Shaders.LoadSimpleShader(gl); + + esp.UseProgram(gl, () => + { + // Set the matrices. + esp.ApplyMVPNMatrices(gl, modelview, projection, normal); + + // render models, using a temperory color + foreach (var model in models) + { + var col = model.GenerateColorFromId(); + esp.ApplyMaterial(gl, new Material() { Ambient = col }); + Model3DBase.GenerateAndDrawOnce(gl, model); // model.Render(gl, RenderMode.HitTest); + } + }); + esp.Dispose(); + + // Wait for GPU to finish. + gl.Flush(); + gl.Finish(); + + + gl.PixelStore(OpenGL.GL_UNPACK_ALIGNMENT, 1); + + uint format = OpenGL.GL_RGBA; + uint type = OpenGL.GL_UNSIGNED_BYTE; + + byte[] data = new byte[40]; + gl.ReadPixels(x, y, 1, 1, format, type, data); + + + // Remove the temperory gl from memory. + gl.RenderContextProvider.Dispose(); + + // Get color id from pixel data. + id = data[0] + data[1] * 255 + data[2] * 65025; // id = r + g * 255 + b * 255². + + // Find model with id. + var resultModel = models.FirstOrDefault(m => m.VertexBuffer.VertexBufferObject == id); + + return resultModel; + } + #endregion HitTest + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs new file mode 100644 index 00000000..d167bac4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs @@ -0,0 +1,157 @@ +using GlmNet; +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Scene +{ + /// + /// This class contains all functionality related to the projection matrix. + /// + public class Projection + { + #region fields + mat4 _projectionMatrix = mat4.identity(); + float _left, _right, _bottom, _top, _nearVal = 2f, _farVal = -1.2f; + vec3 _translationVector = new vec3(); + + #endregion fields + + #region properties + /// + /// The Projection Matrix. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + /// + /// The Left. + /// Used in GlmNET.glm.frustum(...); + /// + public float Left + { + get { return _left; } + set { _left = value; } + } + + /// + /// The Right. + /// Used in GlmNET.glm.frustum(...); + /// + public float Right + { + get { return _right; } + set { _right = value; } + } + + /// + /// The Bottom. + /// Used in GlmNET.glm.frustum(...); + /// + public float Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + /// + /// The Top. + /// Used in GlmNET.glm.frustum(...); + /// + public float Top + { + get { return _top; } + set { _top = value; } + } + + /// + /// The Near Val. + /// Used in GlmNET.glm.frustum(...); + /// + public float NearVal + { + get { return _nearVal; } + set { _nearVal = value; } + } + + /// + /// The Far val. + /// Used in GlmNET.glm.frustum(...); + /// + public float FarVal + { + get { return _farVal; } + set { _farVal = value; } + } + + + #endregion properties + + + /// + /// Resets the frustum using the current values for NearVal and FarVal. + /// + /// Width of the screen. + /// Height of the screen. + public void SetFrustum(float screenWidth, float screenHeight) + { + SetFrustum(screenWidth, screenHeight, _nearVal, _farVal); + } + + /// + /// Resets the frustum. + /// + /// Width of the screen. + /// Height of the screen. + /// + /// + public void SetFrustum(float screenWidth, float screenHeight, float nearVal = 1, float farVal = 0) + { + float scale = 1 / screenWidth; + screenWidth *= scale; + screenHeight *= scale; + + Left = -screenWidth; + Right = -Left; + Bottom = -screenHeight; + Top = -Bottom; + NearVal = nearVal; + FarVal = farVal; + CalculateFrustum(); + } + + /// + /// Recalculate the frustum from the available properties. + /// + public void CalculateFrustum() + { + _projectionMatrix = glm.frustum(Left, Right , Bottom , Top , NearVal, FarVal); + + glm.translate(_projectionMatrix, _translationVector); + } + + /// + /// Changes the z values from the TranslationVector, resulting in a zoom effect. + /// + /// Zooming distance (positive => zoom in, negative => zoom out) + public void Zoom(float distance) + { + _translationVector.z += distance; + CalculateFrustum(); + } + + /// + /// Converts ProjectionMatrix to a float[]. + /// + /// A float[] containing all the values from the initial matrix. + public float[] ToArray() + { + return _projectionMatrix.to_array(); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs new file mode 100644 index 00000000..5939a949 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs @@ -0,0 +1,85 @@ +using SharpGLBase.Shaders; +using SharpGL; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SharpGLBase.Shaders.Parameters; + +namespace SharpGLBase.Scene +{ + /// + /// + /// + public static class Shaders + { + #region fields + // We're going to specify the attribute locations for the position and normal, + // so that we can force both shaders to explicitly have the same locations. + const uint _positionAttribute = 0; + const uint _normalAttribute = 1; + static Dictionary _attributeLocations; + + // The shaders we use. + static Dictionary _allShaders = new Dictionary(); + + #endregion fields + + #region properties + /// + /// Contains all the initialized named shaders. + /// + public static Dictionary AllShaders + { + get { return _allShaders; } + set { _allShaders = value; } + } + #endregion properties + + /// + /// Static constructor. + /// + static Shaders() + { + _attributeLocations = new Dictionary + { + {_positionAttribute, "Position"}, + {_normalAttribute, "Normal"}, + }; + } + + public static ExtShaderProgram LoadPerPixelShader(OpenGL gl) + { + return CreateShader(gl, new PerPixelParameters(), @"Shaders\PerPixel.vert", @"Shaders\PerPixel.frag"); + } + public static ExtShaderProgram LoadToonShader(OpenGL gl) + { + return CreateShader(gl, new ToonParameters(), @"Shaders\Toon.vert", @"Shaders\Toon.frag"); + } + public static ExtShaderProgram LoadSimpleShader(OpenGL gl) + { + return CreateShader(gl, new SimpleShaderParameters(), @"Shaders\SimpleShader.vert", @"Shaders\SimpleShader.frag"); + } + + + /// + /// Create and add a new ShaderProgram from the given sources. + /// Call this function if you decide to add your own shaders. + /// + /// The OpenGL + /// The path to the vertex shader code. + /// The path to the fragment shader code. + /// The name for the shader. + public static ExtShaderProgram CreateShader(OpenGL gl, IShaderParameterIds parameters, string vertexShaderSource, string fragmentShaderSource) + { + // Create the per pixel shader. + ShaderProgram shader = new ShaderProgram(); + shader.Create(gl, + ManifestResourceLoader.LoadTextFile(vertexShaderSource), + ManifestResourceLoader.LoadTextFile(fragmentShaderSource), _attributeLocations); + + return new ExtShaderProgram(shader, parameters); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs new file mode 100644 index 00000000..94aa479f --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs @@ -0,0 +1,312 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SharpGLBase.Extensions; + +namespace SharpGLBase.Scene +{ + public enum RotationMethod { TurnTableYZ, TurnTableXZ, TurnTableXY, Simple } + /// + /// Contains the rotation, scaling and translation matrices, together with the result produced from multiplying them. + /// Override RecalculateResultMatrix(...) in order to multiply the result matrix to your vectors/matrices whenever a transformation has been done. + /// + public abstract class TransformableBase + { + #region fields + private mat4 _translationMatrix = mat4.identity(); + private mat4 _rotationMatrix = mat4.identity(); + private mat4 _scalingMatrix = mat4.identity(); + private mat4 _resultMatrix = mat4.identity(); + private RotationMethod _rotationMethod = RotationMethod.Simple; + private vec3 _rotatedRadians = new vec3(0, 0, 0); + + #endregion fields + + #region properties + /// + /// Contains the result of all transformations. + /// + public mat4 ResultMatrix + { + get { return _resultMatrix; } + set { _resultMatrix = value; } + } + /// + /// Represents all translations. + /// + public mat4 TranslationMatrix + { + get { return _translationMatrix; } + set { _translationMatrix = value; } + } + /// + /// Represents all rotations. + /// + public mat4 RotationMatrix + { + get { return _rotationMatrix; } + set { _rotationMatrix = value; } + } + /// + /// Represents all scalings. + /// + public mat4 ScalingMatrix + { + get { return _scalingMatrix; } + set { _scalingMatrix = value; } + } + /// + /// Defines the way of rotating, TurnTable is usually more intuitive for camera control. TrackBall provides more freedom. + /// + public RotationMethod RotationMethod + { + get { return _rotationMethod; } + set { _rotationMethod = value; } + } + /// + /// Gets the value of rotation (radians) in each direction. + /// + public vec3 RotatedRadians + { + get { return _rotatedRadians; } + } + #endregion properties + + #region absolute rotation + /// + /// Rotates by angleRadians in the direction(s) v and forces a recalculation of the result matrix. + /// + /// The angle of the rotation in radians. + /// The vector that represents the axis around which should be rotated. + public void RotateAbsolute(float angleRadians, vec3 v) + { + if (angleRadians == 0) + return; + + mat4 tempRotationMatrix = _rotationMatrix; + switch (_rotationMethod) + { + case RotationMethod.TurnTableXY: + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.x, new vec3(1, 0, 0)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.y, new vec3(0, 1, 0)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.y, new vec3(0, 1, 0)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.x, new vec3(1, 0, 0)); + break; + case RotationMethod.TurnTableXZ: + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.x, new vec3(1, 0, 0)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.z, new vec3(0, 0, 1)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.z, new vec3(0, 0, 1)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.x, new vec3(1, 0, 0)); + break; + case RotationMethod.TurnTableYZ: + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.y, new vec3(0, 1, 0)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.z, new vec3(0, 0, 1)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.z, new vec3(0, 0, 1)); + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.y, new vec3(0, 1, 0)); + break; + default: + tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); + break; + } + + _rotationMatrix = tempRotationMatrix; + + + _rotatedRadians.x += v.x * angleRadians; + _rotatedRadians.y += v.y * angleRadians; + _rotatedRadians.z += v.z * angleRadians; + + + RecalculateResultMatrix(); + } + /// + /// Calls RotateAbsolute(angleRadians, new vec3(1, 0, 0)); + /// + /// + public void RotateAbsoluteX(float angleRadians) + { + RotateAbsolute(angleRadians, new vec3(1, 0, 0)); + } + /// + /// Calls RotateAbsolute(angleRadians, new vec3(0, 1, 0)); + /// + /// + public void RotateAbsoluteY(float angleRadians) + { + RotateAbsolute(angleRadians, new vec3(0, 1, 0)); + } + + /// + /// RotateAbsolute(angleRadians, new vec3(0, 0, 1)); + /// + /// + public void RotateAbsoluteZ(float angleRadians) + { + RotateAbsolute(angleRadians, new vec3(0, 0, 1)); + } + + #endregion absolute rotation + + #region absolute translation + /// + /// Translates by the values contained in 'vec'. + /// + /// Translation vector. + public void TranslateAbsolute(vec3 vec) + { + _translationMatrix = GlmNet.glm.translate(_translationMatrix, vec); + RecalculateResultMatrix(); + } + /// + /// Calls TranslateAbsolute(new vec3(distance, 0, 0)); + /// + /// The distance. + public void TranslateAbsoluteX(float distance) + { + TranslateAbsolute(new vec3(distance, 0, 0)); + } + /// + /// Calls TranslateAbsolute(new vec3(0, distance, 0)); + /// + /// The distance. + public void TranslateAbsoluteY(float distance) + { + TranslateAbsolute(new vec3(0, distance, 0)); + } + /// + /// Calls TranslateAbsolute(new vec3(0, 0, distance)); + /// + /// The distance. + public void TranslateAbsoluteZ(float distance) + { + TranslateAbsolute(new vec3(0, 0, distance)); + } + #endregion absolute translation + + #region relative translation + public void TranslateOnRotationMatrix(vec3 vec) + { + ////var tMatrix = GlmNet.glm.translate(mat4.identity(), vec); + ////var invRotMatrix = _rotationMatrix.Inverse(); + ////var resMat = (tMatrix * _rotationMatrix).Transpose(); // + ////var translateVector = new vec3(resMat[3].x, resMat[3].y, resMat[3].z); + + + //float largestRot; + //float totRot = RotatedRadians.x + RotatedRadians.y + RotatedRadians.z; + ////if (RotatedRadians.x > RotatedRadians.y) + ////{ + //// if (RotatedRadians.x > RotatedRadians.z) + //// { + //// // x is largest + //// largestRot = RotatedRadians.x; + //// } + //// else + //// { + //// // z is largest + //// largestRot = RotatedRadians.z; + //// } + ////} + ////else { + //// if (RotatedRadians.y > RotatedRadians.z) + //// { + //// // y is largest + //// largestRot = RotatedRadians.y; + //// } + //// else + //// { + //// // z is largest + //// largestRot = RotatedRadians.z; + //// } + ////} + + //var totMoveDistance = (float)Math.Sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); + + //float addX; + //float addY = 0; + //float addZ; + //if (totRot == 0) + //{ + // addX = vec.x; + // addY = vec.y; + // addZ = vec.z; + //} + //else + //{ + // var scaleX = RotatedRadians.x / totRot; + // var scaleY = RotatedRadians.y / totRot; + // var scaleZ = RotatedRadians.z / totRot; + + // addX = vec.x * scaleX; + // //addY = vec.x * scaleY; + // addZ = vec.x * scaleZ; + //} + //vec3 translateVector = new vec3(addX, addY, addZ); + + + + + ////ResMatDeleteMeLater = resMat; + ////TranslationVecDeleteMeLater = vec; + ////TranslateAbsolute(translateVector); + + //var t = _translationMatrix[3]; + //t.x += translateVector.x; + //t.y += translateVector.y; + //t.z += translateVector.z; + //_translationMatrix[3] = t; + + //RecalculateResultMatrix(); + } + #endregion relative translation + + #region absolute scaling + /// + /// Scales by the values contained in 'vec'. + /// + /// Scaling vector. + public void Scale(vec3 vec) + { + _scalingMatrix = GlmNet.glm.scale(_scalingMatrix, vec); + RecalculateResultMatrix(); + } + /// + /// Calls Scale(new vec3(scale, 1, 1)); + /// + /// + public void ScaleX(float scale) + { + Scale(new vec3(scale, 1, 1)); + } + /// + /// Calls Scale(new vec3(1, scale, 1)); + /// + /// + public void ScaleY(float scale) + { + Scale(new vec3(1, scale, 1)); + } + /// + /// Calls Scale(new vec3(1, 1, scale)); + /// + /// + public void ScaleZ(float scale) + { + Scale(new vec3(1, 1, scale)); + } + #endregion absolute scaling + + /// + /// Multiplies all transformations into the ResultMatrix in folowing sequence 'ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix'. + /// + public virtual void RecalculateResultMatrix() + { + _resultMatrix = _translationMatrix * _rotationMatrix * _scalingMatrix; + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs new file mode 100644 index 00000000..fcf45cac --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs @@ -0,0 +1,160 @@ +using SharpGLBase.Scene; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SharpGLBase.Shaders.Parameters; +using GlmNet; + +namespace SharpGLBase.Shaders +{ + /// + /// An extended ShaderProgram. This includes a shadername + /// + public class ExtShaderProgram : IDisposable + { + #region fields + OpenGL _gl = null; + #endregion fields + + #region properties + /// + /// The shader program. + /// + public ShaderProgram Program { get; private set; } + + /// + /// + /// + public IShaderParameterIds Parameters { get; private set; } + + #endregion properties + + public ExtShaderProgram(ShaderProgram program, IShaderParameterIds parameters) + { + Program = program; + Parameters = parameters; + } + + /// + /// Applies the material to the shader if the "Parameters" are an implementation of "IMaterialShaderParameters". + /// + /// The GL. + /// The material. + public void ApplyMaterial(OpenGL gl, Material m, bool throwException = true) + { + if (!typeof(IMaterialShaderParameters).IsAssignableFrom(Parameters.GetType())) + { + if (!throwException) + return; + + throw new InvalidCastException("'Parameters' does not implement 'IMaterialShaderParameters'." + + "This has to be implemented for this method to know how the shader expects it's parameter names."); + } + + var s = Program; + var prms = Parameters as IMaterialShaderParameters; + + var amb = m.Ambient; + var diff = m.Diffuse; + var spec = m.Specular; + var shini = m.Shininess; + var emit = m.Emission; + + if (prms.AmbientId != null) + s.SetUniform3(gl, prms.AmbientId, amb.R / 255.0f, amb.G / 255.0f, amb.B / 255.0f); + if (prms.DiffuseId != null) + s.SetUniform3(gl, prms.DiffuseId, diff.R / 255.0f, diff.G / 255.0f, diff.B / 255.0f); + if (prms.SpecularId != null) + s.SetUniform3(gl, prms.SpecularId, spec.R / 255.0f, spec.G / 255.0f, spec.B / 255.0f); + if (prms.ShininessId != null) + s.SetUniform1(gl, prms.ShininessId, shini); + if (prms.EmissionId != null) + s.SetUniform3(gl, prms.EmissionId, emit.R / 255.0f, emit.G / 255.0f, emit.B / 255.0f); + } + + /// + /// Applies the Modelview-, projection- and normal matrix to the shaders if the "Parameters" are an implementation of "IMVPNParameters". + /// + /// The GL. + /// The modelview class that contains the matrix. + /// The projection class that contains the matrix. + /// The normal class that contains the matrix. + public void ApplyMVPNMatrices(OpenGL gl, ModelView modelview, Projection projection, Normal normal, bool throwException = true) + { + if (!typeof(IMVPNParameters).IsAssignableFrom(Parameters.GetType())) + { + if (!throwException) + return; + + throw new InvalidCastException("'Parameters' does not implement 'IMVPNParameters'." + + "This has to be implemented for this method to know how the shader expects it's parameter names."); + } + + var prms = Parameters as IMVPNParameters; + + // Set the matrices. + Program.SetUniformMatrix4(gl, prms.ProjectionMatrixId, projection.ToArray()); + Program.SetUniformMatrix4(gl, prms.ModelviewMatrixId, modelview.ToArray()); + Program.SetUniformMatrix3(gl, prms.NormalMatrixId, normal.ToArray()); + } + + /// + /// Sets the light position to the shader if the "Parameters" are an implementation of "ISingleLightParameters" + /// + /// + /// + public void SetLight(OpenGL gl, vec3 lightPosition, bool throwException = true) + { + if (!typeof(ISingleLightParameters).IsAssignableFrom(Parameters.GetType())) + { + if (!throwException) + return; + + + throw new InvalidCastException("'Parameters' does not implement 'ILightingParameters'." + + "This has to be implemented for this method to know how the shader expects it's parameter names."); + } + + var prms = Parameters as ISingleLightParameters; + + // Set the light position. + if (prms.LightPositionId != null) + Program.SetUniform3(gl, prms.LightPositionId, lightPosition.x, lightPosition.y, lightPosition.z); + } + + /// + /// This method binds the shaderprogram to the GL, invokes the function and unbinds the shader. + /// The function should contain everything that has to be loaded with this shader's settings. + /// + /// The GL. + /// The code that has to be executing in this ShaderProgram. + public void UseProgram(OpenGL gl, Action func) + { + _gl = gl; + + // Bind the shader. + Program.Bind(gl); + + + // Invoke logic. + func.Invoke(); + + // Unbind the shader. + Program.Unbind(gl); + } + + /// + /// Deletes the shaderprogram van the GL and clears the parameters of this object. + /// + public void Dispose() + { + Program.Delete(_gl); + Program = null; + Parameters = null; + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs new file mode 100644 index 00000000..af121d71 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + /// + /// Implement this interface for shaders that accept Modelview-, Projection- and/or Normal matrices. + /// + interface IMVPNParameters + { + string ProjectionMatrixId { get; } + string ModelviewMatrixId { get; } + string NormalMatrixId { get; } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs new file mode 100644 index 00000000..bad92027 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + /// + /// Implement this interface for shaders that have similar input parameters as SharpGL.SceneGraph.Assets.Material. + /// + public interface IMaterialShaderParameters : IShaderParameterIds + { + string LightPositionId { get; } + string DiffuseId { get; } + string AmbientId { get; } + string SpecularId { get; } + string ShininessId { get; } + string EmissionId { get; } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs new file mode 100644 index 00000000..81f2d7a9 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + /// + /// Convert this type to one of it's child types, to get access to the available parameters of a shader without + /// having to browse through the vert- and frag shader code. + /// + public interface IShaderParameterIds + { + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs new file mode 100644 index 00000000..e2afddd3 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs @@ -0,0 +1,13 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + public interface ISingleLightParameters + { + string LightPositionId { get; } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs new file mode 100644 index 00000000..b4c1d7a6 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + public class PerPixelParameters : IMaterialShaderParameters, IMVPNParameters, ISingleLightParameters + { + public string LightPositionId + { + get { return "LightPosition"; } + } + + public string DiffuseId + { + get { return "DiffuseMaterial"; } + } + + public string AmbientId + { + get { return "AmbientMaterial"; } + } + + public string SpecularId + { + get { return "SpecularMaterial"; } + } + + public string ShininessId + { + get { return "Shininess"; } + } + + + public string EmissionId + { + get { return "Emission"; } + } + + public string ProjectionMatrixId + { + get { return "Projection"; } + } + + public string ModelviewMatrixId + { + get { return "Modelview"; } + } + + public string NormalMatrixId + { + get { return "NormalMatrix"; } + } + + string ISingleLightParameters.LightPositionId + { + get { return "LightPosition"; } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs new file mode 100644 index 00000000..36cb429d --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + + public class SimpleShaderParameters : IMaterialShaderParameters, IMVPNParameters + { + public string LightPositionId + { + get { return null; } + } + + public string DiffuseId + { + get { return null; } + } + + public string AmbientId + { + get { return "PickingColor"; } + } + + public string SpecularId + { + get { return null; } + } + + public string ShininessId + { + get { return null; } + } + + + public string EmissionId + { + get { return null; } + } + + public string ProjectionMatrixId + { + get { return "Projection"; } + } + + public string ModelviewMatrixId + { + get { return "Modelview"; } + } + + public string NormalMatrixId + { + get { return "NormalMatrix"; } + } + + string IMVPNParameters.ProjectionMatrixId + { + get { return "Projection"; } + } + + string IMVPNParameters.ModelviewMatrixId + { + get { return "Modelview"; } + } + + string IMVPNParameters.NormalMatrixId + { + get { return "NormalMatrix"; } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs new file mode 100644 index 00000000..b9519c65 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs @@ -0,0 +1,62 @@ +using SharpGLBase.Shaders.Parameters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLBase.Shaders.Parameters +{ + public class ToonParameters : IMaterialShaderParameters, IMVPNParameters, ISingleLightParameters + { + public string LightPositionId + { + get { return "LightPosition"; } + } + + public string DiffuseId + { + get { return "DiffuseMaterial"; } + } + + public string AmbientId + { + get { return "AmbientMaterial"; } + } + + public string SpecularId + { + get { return "SpecularMaterial"; } + } + + public string ShininessId + { + get { return "Shininess"; } + } + + + public string EmissionId + { + get { return "Emission"; } + } + + public string ProjectionMatrixId + { + get { return "Projection"; } + } + + public string ModelviewMatrixId + { + get { return "Modelview"; } + } + + public string NormalMatrixId + { + get { return "NormalMatrix"; } + } + + string ISingleLightParameters.LightPositionId + { + get { return "LightPosition"; } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag new file mode 100644 index 00000000..767309e7 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag @@ -0,0 +1,24 @@ +#version 130 +in vec3 EyespaceNormal; +in vec3 Diffuse; +out vec4 FragColor; + +uniform vec3 LightPosition; +uniform vec3 AmbientMaterial; +uniform vec3 SpecularMaterial; +uniform float Shininess; + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 E = vec3(0, 0, 1); + vec3 H = normalize(L + E); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial; + FragColor = vec4(color, 1.0); +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert new file mode 100644 index 00000000..2039a858 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert @@ -0,0 +1,18 @@ +#version 130 +in vec4 Position; +in vec3 Normal; + +uniform mat4 Projection; +uniform mat4 Modelview; +uniform mat3 NormalMatrix; +uniform vec3 DiffuseMaterial; + +out vec3 EyespaceNormal; +out vec3 Diffuse; + +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = Projection * Modelview * Position; + Diffuse = DiffuseMaterial; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag new file mode 100644 index 00000000..07bfe630 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag @@ -0,0 +1,9 @@ +#version 330 core +out vec4 FragColor; + +uniform vec3 PickingColor; + +void main() +{ + FragColor = vec4(PickingColor, 1.0); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert new file mode 100644 index 00000000..ef30074b --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert @@ -0,0 +1,19 @@ +#version 330 core + +in vec4 Position; +in vec3 Normal; + +uniform mat4 Projection; +uniform mat4 Modelview; +uniform mat3 NormalMatrix; +uniform vec3 DiffuseMaterial; + +out vec3 EyespaceNormal; +out vec3 Diffuse; + +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = Projection * Modelview * Position; + Diffuse = DiffuseMaterial; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag new file mode 100644 index 00000000..1a44be4d --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag @@ -0,0 +1,54 @@ +#version 130 +in vec3 EyespaceNormal; +in vec3 Diffuse; +out vec4 FragColor; + +uniform vec3 LightPosition; +uniform vec3 AmbientMaterial; +uniform vec3 SpecularMaterial; +uniform float Shininess; + +float stepmix(float edge0, float edge1, float E, float x) +{ + float T = clamp(0.5 * (x - edge0 + E) / E, 0.0, 1.0); + return mix(edge0, edge1, T); +} + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 Eye = vec3(0, 0, 1); + vec3 H = normalize(L + Eye); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + const float A = 0.1; + const float B = 0.3; + const float C = 0.6; + const float D = 1.0; + float E = fwidth(df); + + if (df > A - E && df < A + E) df = stepmix(A, B, E, df); + else if (df > B - E && df < B + E) df = stepmix(B, C, E, df); + else if (df > C - E && df < C + E) df = stepmix(C, D, E, df); + else if (df < A) df = 0.0; + else if (df < B) df = B; + else if (df < C) df = C; + else df = D; + + E = fwidth(sf); + if (sf > 0.5 - E && sf < 0.5 + E) + { + sf = smoothstep(0.5 - E, 0.5 + E, sf); + } + else + { + sf = step(0.5, sf); + } + + vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial; + FragColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert new file mode 100644 index 00000000..2039a858 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert @@ -0,0 +1,18 @@ +#version 130 +in vec4 Position; +in vec3 Normal; + +uniform mat4 Projection; +uniform mat4 Modelview; +uniform mat3 NormalMatrix; +uniform vec3 DiffuseMaterial; + +out vec3 EyespaceNormal; +out vec3 Diffuse; + +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = Projection * Modelview * Position; + Diffuse = DiffuseMaterial; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj new file mode 100644 index 00000000..253de616 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj @@ -0,0 +1,134 @@ + + + + + Debug + AnyCPU + {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B} + Library + Properties + SharpGLBase + SharpGLBase + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + False + + + ..\..\sharpgl\source\SharpGL\Core\SharpGL\bin\Debug\SharpGL.dll + False + + + ..\..\sharpgl\source\SharpGL\Core\SharpGL.SceneGraph\bin\Debug\SharpGL.SceneGraph.dll + False + + + False + + + False + + + False + + + + + False + + + False + + + False + + + False + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs new file mode 100644 index 00000000..c60516b7 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs @@ -0,0 +1,18 @@ +namespace SharpGLBase +{ + /// + /// Vertex attributes used globally in the sample. + /// + public static class VertexAttributes + { + /// + /// The position vertex attribute, used for vertices. + /// + public const uint Position = 0; + + /// + /// The normal vertex attribute, used for normals. + /// + public const uint Normal = 1; + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config new file mode 100644 index 00000000..e316866a --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config new file mode 100644 index 00000000..4c77df1f --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml new file mode 100644 index 00000000..c6d52e7c --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs new file mode 100644 index 00000000..ab7a41f0 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLTest +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml new file mode 100644 index 00000000..6a8c860b --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml @@ -0,0 +1,14 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs new file mode 100644 index 00000000..1e58fdd8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs @@ -0,0 +1,181 @@ +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.Primitives; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using SharpGLBase.Extensions; +using GlmNet; + +namespace SharpGLTest +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + #region events + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region fields + MainWindowViewModel _viewPortViewModel = new MainWindowViewModel(); + #endregion fields + + #region properties + public string OnScreenData { get; set; } + + public MainWindowViewModel ViewPortViewModel + { + get { return _viewPortViewModel; } + set { _viewPortViewModel = value; } + } + + #endregion properties + + + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + DataContext = this; + InitializeComponent(); + MouseMove += MainWindow_MouseMove; + MouseWheel += MainWindow_MouseWheel; + MouseDown += MainWindow_MouseDown; + + ViewPortViewModel.Scene.ModelView.PropertyChanged += (sender, args) => + { + if (args.PropertyName == "ModelviewMatrix") + { + var modelviewMatrix = ViewPortViewModel.Scene.ModelView.ModelviewMatrix; + var translationMatrix = ViewPortViewModel.Scene.ModelView.TranslationMatrix; + var scalingMatrix = ViewPortViewModel.Scene.ModelView.ScalingMatrix; + var rotationMatrix = ViewPortViewModel.Scene.ModelView.RotationMatrix; + + string txt = ""; + + txt += "ModelviewMatrix:\n" + modelviewMatrix.ToValueString(); + txt += "\n\nTranslationMatrix:\n" + translationMatrix.ToValueString(); + txt += "\n\nScalingMatrix:\n" + scalingMatrix.ToValueString(); + txt += "\n\nRotationMatrix:\n" + rotationMatrix.ToValueString(); + + + + OnScreenData = txt; + OnPropertyChanged("OnScreenData"); + } + }; + } + + + void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + { + Point p = e.MouseDevice.GetPosition(this); + _viewPortViewModel.PointerClicked(PointedClickedAction.SelectModel, new System.Drawing.Point((int)p.X, (int)p.Y)); + //_viewPortViewModel.CameraLookAt.RotateCameraAroundRelativeX(.1); + } + } + + void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + _viewPortViewModel.MouseScroll(MouseScrollAction.ChangePerspectiveDepth, e.Delta > 0); + } + else + { + _viewPortViewModel.MouseScroll(MouseScrollAction.Zoom, e.Delta > 0); + } + } + + void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + if (_viewPortViewModel.LastPointerLocation != null) + { + long t1 = DateTime.Now.Ticks; + long t2 = _viewPortViewModel.TimeLastPointerLocation.Value; + if ( t1 > t2 + 3000000) + { + _viewPortViewModel.PointerMoveEnd(); + } + } + + if (e.RightButton == MouseButtonState.Pressed) + { + var p1 = e.MouseDevice.GetPosition(this); + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + } + else + { + _viewPortViewModel.PointerMoved(new System.Drawing.Point((int)p1.X, (int)p1.Y), PointedMovedAction.RotateAroundCenter); + } + } + else if (e.LeftButton == MouseButtonState.Pressed) + { + var p1 = e.MouseDevice.GetPosition(this); + _viewPortViewModel.PointerMoved(new System.Drawing.Point((int)p1.X, (int)p1.Y), PointedMovedAction.MoveRelatively); + } + else + { + _viewPortViewModel.PointerMoveEnd(); + } + } + + /// + /// Handles the OpenGLDraw event of the OpenGLControl control. + /// + /// The source of the event. + /// The instance containing the event data. + private void OpenGLControl_OpenGLDraw(object sender, OpenGLEventArgs args) + { + OpenGL gl = args.OpenGL; + _viewPortViewModel.OpenGLDraw(gl); + } + + /// + /// Handles the OpenGLInitialized event of the OpenGLControl control. + /// + /// The source of the event. + /// The instance containing the event data. + private void OpenGLControl_OpenGLInitialized(object sender, OpenGLEventArgs args) + { + OpenGL gl = args.OpenGL; + _viewPortViewModel.OpenGLInitialized(gl); + } + + private void OpenGLControl_Resized(object sender, OpenGLEventArgs args) + { + var glCtrl = sender as SharpGL.WPF.OpenGLControl; + // Get the OpenGL instance. + var gl = args.OpenGL; + _viewPortViewModel.ViewResized(gl, glCtrl.ActualWidth, glCtrl.ActualHeight); + } + + private void MainWindow_MouseLeave(object sender, MouseEventArgs e) + { + _viewPortViewModel.PointerMoveEnd(); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs new file mode 100644 index 00000000..1c1252b1 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs @@ -0,0 +1,314 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.Cameras; +using SharpGL.SceneGraph.Core; +using SharpGL.SceneGraph.Primitives; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharpGL.SceneGraph.Assets; +using SharpGLBase.Scene; +using SharpGLBase; +using SharpGLTest.Shapes; +using SharpGLBase.Primitives; +using System.Drawing; +using SharpGLBase.Events; +using SharpGLBase.Extensions; + +namespace SharpGLTest +{ + public enum PointedMovedAction { RotateAroundCenter, MoveRelatively, RotateAroundEye, ChangePerspectiveDepth } + public enum PointedClickedAction { SelectModel } + public enum MouseScrollAction { Zoom, ChangePerspectiveDepth } + public class MainWindowViewModel + { + #region fields + OpenGL _gl = null; // Permits using gl for methods that aren't called by the Draw-event + MyScene _scene = new MyScene(); + Point? _lastPointerLocation; + Model3DBase _selectedModel = null; + float _rotationSensitivity = 0.01f / 200000f; + float _moveSensitivity = 0.01f; + float _zoomSensitivity = 1.1f; + float _changePerspectiveDepthSensitivity = 0.2f; + long? _timeLastPointerLocation; + #endregion fields + + #region properties + public Point? LastPointerLocation + { + get { return _lastPointerLocation; } + set { _lastPointerLocation = value; } + } + public long? TimeLastPointerLocation + { + get { return _timeLastPointerLocation; } + set { _timeLastPointerLocation = value; } + } + + public float MoveSensitivity + { + get { return _moveSensitivity; } + set + { + if (value <= 0) + throw new InvalidOperationException("Sensitivity has to be more than 0."); + _moveSensitivity = value; + } + } + public float RotationSensitivity + { + get { return _rotationSensitivity; } + set + { + if (value <= 0) + throw new InvalidOperationException("Sensitivity has to be more than 0."); + _rotationSensitivity = value; + } + } + + public float ZoomSensitivity + { + get { return _zoomSensitivity; } + set + { + if (value <= 0) + throw new InvalidOperationException("Sensitivity has to be more than 0."); + _zoomSensitivity = value; + } + } + + public float ChangePerspectiveDepthSensitivity + { + get { return _changePerspectiveDepthSensitivity; } + set { _changePerspectiveDepthSensitivity = value; } + } + + public MyScene Scene + { + get { return _scene; } + set { _scene = value; } + } + #endregion properties + + #region user input + /// + /// If LastPointerLocation == null then LastPointerLocation = pointerLocation + /// Else act on movement between the 2 points. + /// + /// The new point to where the pointer moved + public void PointerMoved(Point pointerLocation, PointedMovedAction action) + { + if (_lastPointerLocation != null) + { + var diffX = _lastPointerLocation.Value.X - pointerLocation.X; + var diffY = _lastPointerLocation.Value.Y - pointerLocation.Y; + var values = new Point(diffX, diffY); + + if (action == PointedMovedAction.RotateAroundCenter) + { + Rotate(values); + } + else if (action == PointedMovedAction.MoveRelatively) + { + MoveRelatively(values); + } + } + _lastPointerLocation = pointerLocation; + _timeLastPointerLocation = DateTime.Now.Ticks; + } + + /// + /// Clears LastPointerLocation. + /// + public void PointerMoveEnd() + { + _lastPointerLocation = null; + _timeLastPointerLocation = null; + } + + public void PointerClicked(PointedClickedAction action, Point point) + { + if (action == PointedClickedAction.SelectModel) + { + Scene.GetModelAtPoint(point, Scene.MaterialForObjects.ToValueList()); + } + } + public void MouseScroll(MouseScrollAction action, bool forward) + { + if (action == MouseScrollAction.Zoom) + { + //_zoomSteps += forward ? -1 : 1; + + //float zoomFactor = (float)Math.Pow(ZoomSensitivity, _zoomSteps); + float zoomDistance = forward ? ZoomSensitivity : -ZoomSensitivity; + Zoom(zoomDistance); + } + else if (action == MouseScrollAction.ChangePerspectiveDepth) + { + ChangePerspectiveDepth(forward ? ChangePerspectiveDepthSensitivity : -ChangePerspectiveDepthSensitivity); + } + } + #endregion user input + + #region camera control. + /// + /// Rotates CameraLookAt around its Center. + /// + /// Y => rotate in Y direction (Azimuth). X => rotate sideways (Zenith) + public void Rotate(Point moveValues) + { + // Convert 2D pointer movement to 3D rotation + + var size = _scene.ViewPortSize; + var constForXY = _rotationSensitivity * (DateTime.Now.Ticks - _timeLastPointerLocation.Value); + var vertRotLimiter = size.Width > size.Height ? size.Width / (double)size.Height : size.Height / (double)size.Width; + + + float rotationRadiansX = (float)(moveValues.Y * constForXY / vertRotLimiter);// / 1000.0f + 1); + float rotationRadiansY = (float)(moveValues.X * constForXY);// / 1000.0f + 1); + Scene.ModelView.RotateAbsoluteX(rotationRadiansX); + Scene.ModelView.RotateAbsoluteY(rotationRadiansY); + //Scene.ModelView.RotateAbsoluteZ(rotationRadiansX); + } + /// + /// Moves camera relatively + /// + /// X => move horizontally. Y => move vertically. + public void MoveRelatively(Point moveValues) + { + // Adapt the moving speed to the zoom amount. + //float moveSensitivity = (float)Math.Pow(ZoomSensitivity, _zoomSteps) * MoveSensitivity; + float moveSensitivity = MoveSensitivity; + + // Convert 2D pointer movement to 3D rotation + float moveX = (float)moveValues.X * moveSensitivity; + float moveY = (float)moveValues.Y * moveSensitivity; + Scene.ModelView.TranslateAbsoluteX(-moveX); + Scene.ModelView.TranslateAbsoluteY(moveY); + //Scene.ModelView.TranslateOnRotationMatrix(new vec3(-moveX, moveY, 0)); + } + + + public void Zoom(float distance, OpenGL gl = null) + { + //Scene.Projection.Zoom(zoomFactor, gl == null ? _gl : gl); + Scene.Projection.Zoom(distance); + } + + public void ChangePerspectiveDepth(float distance) + { + + //TODO + } + #endregion camera control. + + private Model3DBase _shape; + public void AddElements(OpenGL gl) + { + var redMat = new Material(); + var blueMat = new Material(); + var redObjects = new List(); + var blueObjects = new List(); + + + // Set red material + redMat.Ambient = System.Drawing.Color.FromArgb(255, 50, 0, 50); + redMat.Diffuse = System.Drawing.Color.FromArgb(255, 100, 0, 100); + redMat.Specular = System.Drawing.Color.FromArgb(255, 225, 225, 225); + redMat.Shininess = 100f; + // Set blue material + //blueMat.Ambient = System.Drawing.Color.FromArgb(255, 0, 0, 100); + blueMat.Diffuse = System.Drawing.Color.FromArgb(255, 0, 100, 255); + //blueMat.Specular = System.Drawing.Color.FromArgb(255, 100, 0, 255); + //blueMat.Shininess = 0.0001f; + + _shape = new MyTrefoilKnot(gl); + _shape.TranslateAbsoluteZ(3); + // Add some test models to the viewport + var cube = new FlatShadedCube(gl); + //cube.Scale(new vec3(0.5f, -0.5f, -0.5f)); + cube.TranslateAbsoluteX(3); + cube.RotateAbsoluteY(2); + cube.CalculateNormals(); + + var trefoilKnot = new MyTrefoilKnot(gl); + trefoilKnot.RotateAbsoluteZ(1f); + //trefoilKnot.RotateAbsoluteY(4.5f); + //trefoilKnot.ScaleY(1.3f); + trefoilKnot.TranslateAbsoluteY(2); + + blueObjects.Add(_shape); + redObjects.Add(cube); + redObjects.Add(trefoilKnot); + blueObjects.Add(new FlatShadedCube(gl)); + + Scene.MaterialForObjects.Add(redMat, redObjects); + Scene.MaterialForObjects.Add(blueMat, blueObjects); + } + + public void OpenGLInitialized(OpenGL gl) + { + _gl = gl; + Scene.ModelSelected += Scene_ModelSelected; + + //Scene.ModelView.CameraHandling = CameraRotationHandling.TSR; + //Scene.ModelView.RotationMethod = RotationMethod.TurnTableYZ; + Scene.ModelView.CameraHandling = CameraRotationHandling.TRS; + Scene.ModelView.RotationMethod = RotationMethod.TurnTableXZ; + + // Scale down the opengl viewport size in order to increase performance. + //Scene.PerformanceScaleValue = 0.5f; + + //Scene.DrawEdgesOnly = true; + Scene.OpenGLInitialized(gl); + AddElements(gl); + var lp = new vec3(5, 50, 15); + Scene.LightPosition = lp; + + // Move view to best position + Scene.Projection.Zoom(-10); + //Scene.ModelView.TranslateAbsoluteZ(-5); + //Scene.ModelView.RotateAbsoluteY((float)Math.PI); + } + + void Scene_ModelSelected(object sender, ModelSelectedEventArgs e) + { + if (_selectedModel != null) + _selectedModel.Material = null; + + if (e.SelectedModel == null) + return; + + var mat = new Material(); + mat.Diffuse = Color.Silver; + mat.Ambient = Color.Gray; + + + e.SelectedModel.Material = mat; + + + _selectedModel = e.SelectedModel; + } + + public void OpenGLDraw(OpenGL gl) + { + float rotPerTime = (float)(DateTime.Now.Millisecond / 500.0 * Math.PI % (2 * Math.PI)); + + //Scene.ModelView.RotateAbsoluteY(0.1f); + + _shape.RotationMatrix = mat4.identity(); + _shape.RotateAbsoluteY(rotPerTime); + Scene.Draw(gl); + } + + public void ViewResized(OpenGL gl, double width, double height) + { + Scene.ViewResized(gl, width, height); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs new file mode 100644 index 00000000..8343bc1e --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs @@ -0,0 +1,205 @@ +using GlmNet; +using SharpGL; +using SharpGL.Enumerations; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Core; +using SharpGLBase.Primitives; +using SharpGLBase.Scene; +using SharpGLBase.Shaders; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using SharpGLBase.Extensions; + +namespace SharpGLTest +{ + public class MyScene : OpenGLScene + { + #region fields + AxisVBO _axis; + SquareGridVBO _grid; + vec3 _lightPosition = new vec3(10, 10, 10); + Dictionary> _materialForObjects = new Dictionary>(); + Color _verticalGradientBackgroundColorTop = Color.FromArgb(146, 134, 188); // Light Purple + Color _verticalGradientBackgroundColorBottom = Color.FromArgb(0, 0, 0); // Black + bool _drawEdgesOnly = false; + #endregion fields + + #region properties + /// + /// Top color of the gradient background. + /// + public Color VerticalGradientBackgroundColorTop + { + get { return _verticalGradientBackgroundColorTop; } + set { _verticalGradientBackgroundColorTop = value; } + } + /// + /// Bottom color of the gradient background. + /// + public Color VerticalGradientBackgroundColorBottom + { + get { return _verticalGradientBackgroundColorBottom; } + set { _verticalGradientBackgroundColorBottom = value; } + } + /// + /// Objects grouped by material. Add an object here and it will be presented to the scene. + /// + public Dictionary> MaterialForObjects + { + get { return _materialForObjects; } + set { _materialForObjects = value; } + } + /// + /// Position of the lightpoint. + /// + public vec3 LightPosition + { + get { return _lightPosition; } + set { _lightPosition = value; } + } + /// + /// If true => models will be rendered in Polygon LineMode. + /// + public bool DrawEdgesOnly + { + get { return _drawEdgesOnly; } + set { _drawEdgesOnly = value; } + } + #endregion properties + + + public MyScene() + { + } + + public override void OpenGLInitialized(SharpGL.OpenGL gl) + { + base.OpenGLInitialized(gl); + + // Initialize the grid and axis. + _axis = new AxisVBO(gl); + _grid = new SquareGridVBO(gl); + + // Set the shader. + CurrentShader = Shaders.LoadToonShader(gl); + } + + public override void Draw(SharpGL.OpenGL gl) + { + // Disable dithering ( = smooth color transition). Should have a slight performance impact. + gl.Disable(OpenGL.GL_DITHER); + + // Clear the viewport. + gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + // Add gradient background. + SetVerticalGradientBackground(gl, VerticalGradientBackgroundColorTop, VerticalGradientBackgroundColorBottom); + + // Use the shader program. + CurrentShader.UseProgram(gl, () => + { + if (DrawEdgesOnly) + { + // Push the polygon attributes and set line mode. + gl.PushAttrib(OpenGL.GL_POLYGON_BIT); + gl.PolygonMode(FaceMode.FrontAndBack, PolygonMode.Lines); + } + + CurrentShader.ApplyMVPNMatrices(gl, ModelView, Projection, Normal); + + // Set the light. + CurrentShader.SetLight(gl, _lightPosition, false); + + // Render all objects. + foreach (var key in MaterialForObjects.Keys) + { + var objects = MaterialForObjects[key]; + RenderObjectsFromMaterial(gl, key, CurrentShader, objects); + } + + // Add axis. + _axis.Render(gl, RenderMode.Design, CurrentShader); + + // Add grid. + _grid.Render(gl, RenderMode.Design, CurrentShader); + + + // Undo draw edges only. + if (DrawEdgesOnly) + { + // Pop the attributes, restoring all polygon state. + gl.PopAttrib(); + } + }); + } + + public override void ViewResized(SharpGL.OpenGL gl, double actualWidth, double actualHeight) + { + base.ViewResized(gl, actualWidth, actualHeight); + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, Color colorTop, Color colorBot) + { + float topRed = colorTop.R / 255.0f; + float topGreen = colorTop.G / 255.0f; + float topBlue = colorTop.B / 255.0f; + float botRed = colorBot.R / 255.0f; + float botGreen = colorBot.G / 255.0f; + float botBlue = colorBot.B / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + /// + /// Renders all objects in MaterialForObjects[materialKey] to the screen, using the given parameters. + /// + /// The OpenGL + /// The material that will be used for the objects. + /// The shader that will be used for this material. + /// The objects to be drawn. + /// True: draw only edges, false: draw faces. + public void RenderObjectsFromMaterial(OpenGL gl, Material material, ExtShaderProgram shader, IEnumerable objects) + { + if (objects == null) + return; + + // Set the variables for the shader program. + shader.ApplyMaterial(gl, material); + + // Bind the vertex buffer arrays. + foreach (var item in objects) + { + // If the object has it's own material, then use this. Else use the material-parameter. + if (item.Material != null) + { + shader.ApplyMaterial(gl, item.Material); + item.Render(gl, RenderMode.Render); + shader.ApplyMaterial(gl, material); + } + else + { + item.Render(gl, RenderMode.Render); + } + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3f6877e5 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLTest")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8603ab8a --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34011 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLTest.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLTest.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs new file mode 100644 index 00000000..d35925ad --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34011 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLTest.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs new file mode 100644 index 00000000..9edd3d92 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs @@ -0,0 +1,73 @@ +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Cameras; +using SharpGL.SceneGraph.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; +using SharpGLBase; +using SharpGLBase.Primitives; +using SharpGLBase.Shaders; + +namespace SharpGLTest.Shapes +{ + /// + /// A simple cube object + /// + public class FlatShadedCube : Model3DBase + { + #region cube data + readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + //readonly vec3[] _normals = new vec3[]{ + // new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + // new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + // new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + // new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + // new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + // new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + //}; + readonly ushort[] _indices = new ushort[]{ + 1, 2,0,2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + #endregion cube data + + public FlatShadedCube(OpenGL gl) + { + base.Init(_vertices, _indices, null, gl); + } + + /// + /// Renders the cube to the screen. + /// + /// + /// + public override void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null) + { + // Load our cube data ClockWise. + gl.FrontFace(OpenGL.GL_CW); + + // Binds buffers. + base.Bind(); + + // Draw the elements. + gl.DrawElements(OpenGL.GL_TRIANGLES, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs new file mode 100644 index 00000000..a7040a89 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ +using GlmNet; +using SharpGLBase; +using SharpGLBase.Primitives; +using SharpGLBase.Primitives.ModelComponents; +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using SharpGLBase.Shaders; + +namespace SharpGLTest.Shapes +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot: Model3DBase + { + #region fields + /// The number of slices and stacks. + private const uint _slices = 128; + private const uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static ushort[] _indices; + #endregion fields + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + public MyTrefoilKnot(OpenGL gl) + { + Init(_vertices, _indices, _normals, gl); + //base.BaseVertices = _vertices; + //base.Normals = _normals; + //base.Indices = _indices; + //GenerateGeometry(gl); + } + + #endregion constructor + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + const uint vertexCount = _slices * _stacks; + const uint indexCount = vertexCount * 6; + _indices = new ushort[indexCount]; + int count = 0; + + ushort n = 0; + for (ushort i = 0; i < _slices; i++) + { + for (ushort j = 0; j < _stacks; j++) + { + _indices[count++] = (ushort)(n + j); + _indices[count++] = (ushort)(n + (j + 1) % _stacks); + _indices[count++] = (ushort)((n + j + _stacks) % vertexCount); + + _indices[count++] = (ushort)((n + j + _stacks) % vertexCount); + _indices[count++] = (ushort)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (ushort)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (ushort)_stacks; + } + } + #endregion calculate trefoil knot + + public override void Render(OpenGL gl, SharpGL.SceneGraph.Core.RenderMode renderMode, ExtShaderProgram shader = null) + { + if (base.Visible) + { + OpenGL.FrontFace(OpenGL.GL_CW); + + base.Bind(); + + // Draw the elements. + OpenGL.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs new file mode 100644 index 00000000..77b9d254 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs @@ -0,0 +1,68 @@ +using SharpGL; +using SharpGL.SceneGraph.Assets; +using SharpGL.SceneGraph.Cameras; +using SharpGL.SceneGraph.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; +using SharpGLBase; +using SharpGLBase.Primitives; +using SharpGLBase.Shaders; + +namespace SharpGLTest.Shapes +{ + /// + /// A simple cube object + /// + public class SmoothShadedCube : Model3DBase + { + #region cube data + readonly vec3[] _vertices = new vec3[]{ + new vec3(-1.0f, -1.0f, -1.0f), + new vec3(1.0f, -1.0f, -1.0f), + new vec3(1.0f, 1.0f, -1.0f), + new vec3(-1.0f, 1.0f, -1.0f), + new vec3(-1.0f, -1.0f, 1.0f), + new vec3(1.0f, -1.0f, 1.0f), + new vec3(1.0f, 1.0f, 1.0f), + new vec3(-1.0f, 1.0f, 1.0f) + }; + + readonly ushort[] _indices = new ushort[]{ + 0, 4, 5, 0, 5, 1, + 1, 5, 6, 1, 6, 2, + 2, 6, 7, 2, 7, 3, + 3, 7, 4, 3, 4, 0, + 4, 7, 6, 4, 6, 5, + 3, 0, 1, 3, 1, 2 + }; + #endregion cube data + + public SmoothShadedCube(OpenGL gl) + { + base.Init(_vertices, _indices, null, gl); + } + + /// + /// Renders the cube to the screen. + /// + /// + /// + public override void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null) + { + // Load our cube data ClockWise. + gl.FrontFace(OpenGL.GL_CW); + + // Binds buffers. + base.Bind(); + + // Draw the elements. + gl.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); + } + } +} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj new file mode 100644 index 00000000..f067275a --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj @@ -0,0 +1,133 @@ + + + + + Debug + AnyCPU + {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9} + WinExe + Properties + SharpGLTest + SharpGLTest + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + False + ..\..\sharpgl\source\SharpGL\Core\SharpGL\bin\Debug\SharpGL.dll + + + False + ..\..\sharpgl\source\SharpGL\Core\SharpGL.SceneGraph\bin\Debug\SharpGL.SceneGraph.dll + + + False + ..\..\sharpgl\source\SharpGL\Core\SharpGL.WPF\bin\Debug\SharpGL.WPF.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + {cffbb91a-c898-45ca-a074-b16f3ffe7f3b} + SharpGLBase + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config new file mode 100644 index 00000000..d001aa11 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln new file mode 100644 index 00000000..10b20b54 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLTest", "SharpGLTest\SharpGLTest.csproj", "{4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLBase", "SharpGLBase\SharpGLBase.csproj", "{CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Release|Any CPU.Build.0 = Release|Any CPU + {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..5f5487064aabfc866ae8cb09cad61f70a805be2d GIT binary patch literal 17026 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 literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec new file mode 100644 index 00000000..36821604 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec @@ -0,0 +1,17 @@ + + + + GlmNet + 0.0.2.0 + GlmNet + Dave Kerr + Dave Kerr + https://github.com/dwmkerr/glmnet + false + GLM .NET is a .NET version of the popular GLM mathematics library. +

GLM .NET is a .NET version of the popular GLM mathematics library. + + Copyright © Dave Kerr 2014 + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML new file mode 100644 index 00000000..7e31a995 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML @@ -0,0 +1,281 @@ + + + + GlmNet + + + + + Represents a 2x2 matrix. + + + + + Initializes a new instance of the struct. + This matrix is the identity matrix scaled by . + + The scale. + + + + Initializes a new instance of the struct. + The matrix is initialised with the . + + The colums of the matrix. + + + + Creates an identity matrix. + + A new identity matrix. + + + + Returns the matrix as a flat array of elements, column major. + + + + + + Multiplies the matrix by the matrix. + + The LHS matrix. + The RHS matrix. + The product of and . + + + + The columms of the matrix. + + + + + Gets or sets the column at the specified index. + + + The column. + + The column index. + The column at index . + + + + Gets or sets the element at and . + + + The element at and . + + The column index. + The row index. + + The element at and . + + + + + Represents a 3x3 matrix. + + + + + Initializes a new instance of the struct. + This matrix is the identity matrix scaled by . + + The scale. + + + + Initializes a new instance of the struct. + The matrix is initialised with the . + + The colums of the matrix. + + + + Creates an identity matrix. + + A new identity matrix. + + + + Returns the matrix as a flat array of elements, column major. + + + + + + Returns the portion of this matrix. + + The portion of this matrix. + + + + Multiplies the matrix by the matrix. + + The LHS matrix. + The RHS matrix. + The product of and . + + + + The columms of the matrix. + + + + + Gets or sets the column at the specified index. + + + The column. + + The column index. + The column at index . + + + + Gets or sets the element at and . + + + The element at and . + + The column index. + The row index. + + The element at and . + + + + + Represents a three dimensional vector. + + + + + Represents a four dimensional vector. + + + + + The glm class contains static functions as exposed in the glm namespace of the + GLM library. The lowercase naming is to keep the code as consistent as possible + with the real GLM. + + + + + Creates a perspective transformation matrix. + + The field of view angle, in radians. + The aspect ratio. + The near depth clipping plane. + The far depth clipping plane. + A that contains the projection matrix for the perspective transformation. + + + + Creates a frustrum projection matrix. + + The left. + The right. + The bottom. + The top. + The near val. + The far val. + + + + + Applies a translation transformation to matrix by vector . + + The matrix to transform. + The vector to translate by. + translated by . + + + + Applies a scale transformation to matrix by vector . + + The matrix to transform. + The vector to scale by. + scaled by . + + + + Represents a 4x4 matrix. + + + + + Initializes a new instance of the struct. + This matrix is the identity matrix scaled by . + + The scale. + + + + Initializes a new instance of the struct. + The matrix is initialised with the . + + The colums of the matrix. + + + + Creates an identity matrix. + + A new identity matrix. + + + + Returns the matrix as a flat array of elements, column major. + + + + + + Returns the portion of this matrix. + + The portion of this matrix. + + + + Multiplies the matrix by the matrix. + + The LHS matrix. + The RHS matrix. + The product of and . + + + + The columms of the matrix. + + + + + Gets or sets the column at the specified index. + + + The column. + + The column index. + The column at index . + + + + Gets or sets the element at and . + + + The element at and . + + The column index. + The row index. + + The element at and . + + + + + Represents a two dimensional vector. + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll new file mode 100644 index 0000000000000000000000000000000000000000..c0b1b2efec79562c59fdc7d13c13c5440aa6a6cf GIT binary patch literal 13824 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

N5D(*T^4UFg5sAkONtFGxhvi0Axq4gh1 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 literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..0f93ceda3aac8d963cd9765f1bc3d3251e63776f GIT binary patch literal 282901 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

<^P^i5leAfjQ1pca* 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 literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec new file mode 100644 index 00000000..782c94cc --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec @@ -0,0 +1,15 @@ + + + + SharpGLCore + 2.1.0 + SharpGL Core + Dave Kerr + Dave Kerr + http://sharpgl.codeplex.com/ + false + SharpGL Core is the core library for SharpGL. It provides wrappers for all OpenGL functions and also includes the Scene Graph classes. Installed as part of SharpGL for WinForms or SharpGL for WPF. + SharpGL Core is the core library for SharpGL. It provides wrappers for all OpenGL functions and also includes the Scene Graph classes. Installed as part of SharpGL for WinForms or SharpGL for WPF. + Copyright © Dave Kerr 2013 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll new file mode 100644 index 0000000000000000000000000000000000000000..c450d6d2c3f50d8124d0cd46ceae33d276513a40 GIT binary patch literal 143360 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 z�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 D8N|AI literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml new file mode 100644 index 00000000..9c972588 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml @@ -0,0 +1,6188 @@ + + + + SharpGL.SceneGraph + + + + + The Quadric orientation. + + + + + Outside. + + + + + Inside. + + + + + Helps with implementing IHasObjectSpace. + + + + + IDeepCloneable objects can create a deep clone of themselves. + + + + + + Creates a deep clones of this instance. + + A deep clone of this instance. + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + Deeps the clone. + + + + + + The linear transformation + + + + + Gets or sets the transformation. + + + The transformation. + + + + + Freezes the specified instance. + + The gl instance. + The renderable. + + + + Renders the specified gl. + + The gl. + + + + Unfreezes the specified gl. + + The gl. + + + + The display list internally. + + + + + If true, we're frozen. + + + + + Gets a value indicating whether this instance is frozen. + + + true if this instance is frozen; otherwise, false. + + + + + Any element or asset which has an OpenGL context has some + associated OpenGL resource. This means that when it is loaded + from file, it may need to be re-created, or if it is moved + between OpenGL contexts it may need to be re-created. + Any object that has an OpenGL context has a Create method, a + Destroy Method and a CurrentContext property. + + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Gets the current OpenGL that the object exists in context. + + + + + This class has all the settings you can edit for fog. + + + + + The OpenGLAttributeGroup is the base for groups of opengl attributes. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + True if any attributes are set + + + + Pushes the attributes onto the specified OpenGL attribute stack. + + The OpenGL instance. + + + + Pops the attributes off the specified OpenGL attribute stack. + + The OpenGL instance. + + + + The attribute flags for the group. + + + + + Gets the attribute flags. + todo use get only, xmlignore and don't store them - return them on the fly. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the viewport X. + + + The viewport X. + + + + + Gets or sets the viewport Y. + + + The viewport Y. + + + + + Gets or sets the width of the viewport. + + + The width of the viewport. + + + + + Gets or sets the height of the viewport. + + + The height of the viewport. + + + + + Gets or sets the depth range near. + + + The depth range near. + + + + + Gets or sets the depth range far. + + + The depth range far. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable stencil test. + + + The enable stencil test. + + + + + Gets or sets the stencil function. + + + The stencil function. + + + + + Gets or sets the stencil reference. + + + The stencil reference. + + + + + Gets or sets the stencil mask. + + + The stencil mask. + + + + + Gets or sets the index of the stencil clear. + + + The index of the stencil clear. + + + + + Gets or sets the stencil write mask. + + + The stencil write mask. + + + + + Gets or sets the operation fail. + + + The operation fail. + + + + + Gets or sets the operation depth pass. + + + The operation depth pass. + + + + + Gets or sets the operation depth pass. + + + The operation depth pass. + + + + + The standard OpenGL teapot. + + + + + The base class for all elements in a scene. Anything in + the scene tree is a Scene Element. Scene elements can + have children but are very lacking in functionality - + implement + + + + + Traverses this instance. Traversing simply returns + the children and all descendents in the correct order. + + + + + + Traverses this instance. Traversing simply returns + the children and all descendents in the correct order. + This traversal allows for a predicate to be used. + + The predicate for traversal. + + + + + Traverses this instance. Traversing simply returns + the children and all descendents of type T in the correct order. + + The type of object to traverse for. + The full set of T objects in the scene. + + + + Traverses this instance. Traversing simply returns + the children and all descendents of type T in the correct order. + + The type of object to traverse for. + The predicate for traversal. + + The full set of T objects in the scene. + + + + + Traverses to root element. + + + + + + Initializes a new instance of the class. + + + + + Adds a child. + + The child scene element. + + + + Removes the child scene element. + + The child scene element. + + + + Adds an effect. + + The effect. + + + + Removes the effect. + + The effect. + + + + Returns a that represents this instance. + + + A that represents this instance. + + + + + The children of the element. + + + + + The effects. + + + + + Gets the children. + + + + + Gets the effects. + + + + + Gets the parent. + + + + + Gets or sets the name. + + + The name. + + + + + Gets or sets a value indicating whether this instance is enabled. + + + true if this instance is enabled; otherwise, false. + + + + + A Scene Element can implement this interface to enable rendering + functionality. Note that many scene elements (materials etc) are + not actually drawn. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The IHasMaterial interface can be implemented by any scene object + to allow a material to be associated with the object. + + + + + Gets or sets the material. + + + The material. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Draws the specified gl. + + The gl. + The grid. + The scale. + The type. + + + + Gets or sets the grid. + + + The grid. + + + + + Gets or sets the scale. + + + The scale. + + + + + Gets or sets the type of the fill. + + + The type of the fill. + + + + + Material to be used when rendering the teapot in lighted mode. + + + The material. + + + + + Extensions for Array type. + + + + + Flattens the specified array. + + The array type. + The array. + The flattened array. + + + + The Grid design time primitive is displays a grid in the scene. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Creates the display list. This function draws the + geometry as well as compiling it. + + + + + The internal display list. + + + + + The feedback class handles feedback easily and well. It is 100% dependant on + OpenGL so use it with care! + + + + + This function begins feedback, recording the scene etc. End finishes + feedback, and parses the feedback buffer. + + + + + This function stops the collection of feedback data. + + The feedback array. + + + + Override this function to do custom functions on the data. + + Number of values. + + + + An effect is something that can be applied to a scene element which + then changes everything in the tree below it. It can be pushed, to apply it + and popped, to restore OpenGL back to the state without the effect. + + + + + Initializes a new instance of the class. + + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pops the effect off the specified parent element. + + The OpenGL instance. + The parent element. + + + + Gets or sets the name. + + + The name. + + + + + Gets or sets a value indicating whether this instance is enabled. + + + true if this instance is enabled; otherwise, false. + + + + + The Vertex class represents a 3D point in space. + + + + + Initializes a new instance of the struct. + + The x. + The y. + The z. + + + + Initializes a new instance of the struct. + + The vertex. + + + + Sets the specified X. + + The X. + The Y. + The Z. + + + + Implements the operator +. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator -. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator *. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator *. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator *. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator *. + + The LHS. + The RHS. + + The result of the operator. + + + + + Implements the operator /. + + The LHS. + The RHS. + + The result of the operator. + + + + + This finds the Scalar Product (Dot Product) of two vectors. + + The right hand side of the equation. + A Scalar Representing the Dot-Product. + + + + Find the Vector product (cross product) of two vectors. + + The right hand side of the equation. + The Cross Product. + + + + If You use this as a Vector, then call this function to get the vector + magnitude. + + + + + + Make this vector unit length. + + + + + Normalizes this instance. + + + + + The X coordinate. + + + + + The Y coordinate. + + + + + The Z coordinate. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + This class has all the settings you can edit for lists. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + The list base. + + + + + Gets or sets the list base. + + + The list base. + + + + + The Fragment Shader. + + + + + The Shader base class. + + + + + Pops the effect off the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Sets the shader source. + + The source. + + + + Loads the shader source. + + The path to the shader file. + + + + Compiles this instance. + + + + + The internal shader object. + + + + + Gets or sets the shader object. + + + The shader object. + + + + + Gets the current OpenGL that the object exists in context. + + + + + Gets the compile status. + + + + + Gets the info log. + + + + + Gets the source code. + + + + + Initializes a new instance of the class. + + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + A Folder is used to organise scene elements. + + + + + Initializes a new instance of the class. + + + + + This takes the feedback data and turns it into triangles. + + + The number of triangles. + + + + A NURBS Surface is a two dimensional non uniform B-Spline. + + + + + The NURBS class is the base for NURBS objects, such as curves and surfaces. + + + + + This is the base class of all evaluators, 1D, 2D etc. It is also the base class + for the NURBS, as they share alot of common code, such as the VertexGrid. + + + + + A SceneElement can implement IHasObjectSpace to allow it to transform + world space into object space. + + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + Gets the transformation that pushes us into object space. + + + + + Initializes a new instance of the class. + + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The control points. + + + + + Draw points flag. + + + + + Draw lines flag. + + + + + The IHasObjectSpace helper. + + + + + Gets or sets the control points. + + + The control points. + + + + + Gets or sets a value indicating whether [draw control points]. + + + true if [draw control points]; otherwise, false. + + + + + Gets or sets a value indicating whether [draw control grid]. + + + true if [draw control grid]; otherwise, false. + + + + + Gets the transformation that pushes us into object space. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + This is the pointer to the underlying NURBS object. + + + + + The display mode. + + + + + Gets or sets the display mode. + + + The display mode. + + + + + Gets the current OpenGL that the object exists in context. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The s knots. + + + + + The t knots. + + + + + Gets the knots. + + + + + Gets the knots. + + + + + An ArcBall is an effect that pushes an arcball transformation + onto the stack. + + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pops the specified parent element. + + The OpenGL instance. + The parent element. + + + + The arcball. + + + + + Gets or sets the linear transformation. + + + The linear transformation. + + + + + A Scene Element can be volumne bound meaning that it can + participate in hit testing and various optimisations. + + + + + Gets the bounding volume. + + + + + An Asset is something which is used in the scene, but is not in the scene + tree. An example of an asset is a material, which there may be one instance + of which is shared between many objects. + + + + + Returns a that represents this instance. + + + A that represents this instance. + + + + + Gets or sets the id. + + + The id. + + + + + Gets or sets the name. + + + The name. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable normalize. + + + The enable normalize. + + + + + Gets or sets the matrix mode. + + + The matrix mode. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + A ScreenPixel, password around when raytracing. + + + + + The Quadric draw style. + + + + + Points. + + + + + Lines. + + + + + Silhouette. + + + + + Fill. + + + + + A polygon contains a set of 'faces' which are indexes into a single list + of vertices. The main thing about polygons is that they are easily editable + by the user, depending on the Context they're in. + + + + + A SceneElement can implement IRayTracable to allow it to + be raytraced. + + + + + Raytraces the specified ray. If an intersection is found, it is returned, + otherwise null is returned. + + The ray. + The scene. + The intersection with the object, or null. + + + + Scene Elements can be marked as Freezeable. If scene objects + are freezable, they can be frozen, meaning that they are locked. + Generally this means compiling the object's geometry into + a display list. + + + + + Freezes this instance using the provided OpenGL instance. + + The OpenGL instance. + + + + Unfreezes this instance using the provided OpenGL instance. + + The OpenGL instance. + + + + Gets a value indicating whether this instance is frozen. + + + true if this instance is frozen; otherwise, false. + + + + + Initializes a new instance of the class. + + + + + This function is cool, just stick in a set of points, it'll add them to the + array, and create a face. It will take account of duplicate vertices too! + + A set of vertices to make into a face. + + + + Triangulate this polygon. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + This creates a polygon from a height map (any picture). Black is low, + and the colors are high (the lighter the color, the higher the surface). + + Path of the image file. + Number of points along X. + Number of points along Y. + True if sucessful, false otherwise. + + + + This function performs lossless optimisation on the polygon, it should be + called when the geometry changes, and the polygon goes into static mode. + + The amount of optimisation (as a %). + + + + Call this function as soon as you change the polygons geometry, it will + re-generate normals, etc. + + Regenerate Normals. + + + + This function tests to see if a ray interesects the polygon. + + The ray you want to test. + + The distance from the origin of the ray to the intersection, or -1 if there + is no intersection. + + + + + Raytraces the specified ray. If an intersection is found, it is returned, + otherwise null is returned. + + The ray. + The scene. + + The intersection with the object, or null. + + + + + This function subdivides the faces of this polygon. + + If set to true the faces will be smoothed. + The number of faces in the new subdivided polygon. + + + + Freezes this instance using the provided OpenGL instance. + + The OpenGL instance. + + + + Unfreezes this instance using the provided OpenGL instance. + + The OpenGL instance. + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + Creates a new object that is a copy of the current instance. + + + A new object that is a copy of this instance. + + + + + The IHasObjectSpace helper. + + + + + The freezable helper. + + + + + The faces that make up the polygon. + + + + + The vertices that make up the polygon. + + + + + The UV coordinates (texture coodinates) for the polygon. + + + + + The normals of the polygon object. + + + + + Should the normals be drawn? + + + + + The bounding volume helper - used to ease implementation of IBoundVolume. + + + + + Gets or sets the faces. + + + The faces. + + + + + Gets or sets the vertices. + + + The vertices. + + + + + Gets or sets the U vs. + + + The U vs. + + + + + Gets or sets the normals. + + + The normals. + + + + + Gets or sets a value indicating whether [draw normals]. + + + true if [draw normals]; otherwise, false. + + + + + Gets the transformation that pushes us into object space. + + + + + Gets the bounding volume. + + + + + Gets a value indicating whether this instance is frozen. + + + true if this instance is frozen; otherwise, false. + + + + + Material to be used when rendering the polygon in lighted mode. + This material may be overriden on a per-face basis. + + + The material. + + + + + This enumeration describes the linear transformation order. + + + + + Translate > Rotate > Scale + + + + + Rotate > Translate > Scale + + + + + The LinearTransformation class represents a linear transformation, such + as a transformation that moves us from world space into object space. + + + + + Base class for transformations. + + + + + Performs the transformation on the current matrix. + + The OpenGL instance. + + + + Performs the transformation on the current matrix. + + The OpenGL instance. + + + + Creates a new object that is a copy of the current instance. + + + A new object that is a copy of this instance. + + + + + X Component of the Translation. + + + + + Y Component of the Translation. + + + + + Z Component of the Translation. + + + + + X Component of the Rotation. + + + + + Y Component of the Rotation. + + + + + Z Component of the Rotation. + + + + + X Component of the Scale. + + + + + Y Component of the Scale. + + + + + Z Component of the Scale. + + + + + The order of the linear transformation. + + + + + Gets the translation vertex. + + + + + Gets or sets the x component of the translation. + + + The x component of the translation. + + + + + Gets or sets the y component of the translation. + + + The y component of the translation. + + + + + Gets or sets the z component of the translation. + + + The z component of the translation. + + + + + Gets or sets the x component of the rotation. + + + The x component of the rotation. + + + + + Gets or sets the y component of the rotation. + + + The y component of the rotation. + + + + + Gets or sets the z component of the rotation. + + + The z component of the rotation. + + + + + Gets or sets the x component of the scale. + + + The x component of the scale. + + + + + Gets or sets the y component of the scale. + + + The y component of the scale. + + + + + Gets or sets the z component of the scale. + + + The z component of the scale. + + + + + Gets or sets the transformation order. + + + The transformation order. + + + + + An index into a set of arrays. + + + + + Initializes a new instance of the class. + + + + + This is the vertex in the polygon vertex array that the index refers to. + + + + + This is the material coord in the polygon UV array that the index refers to. + + + + + This is the index into the normal array for this vertex. A value of -1 will + generate a normal on the fly. + + + + + Gets or sets the vertex. + + + The vertex. + + + + + Gets or sets the UV. + + + The UV. + + + + + Gets or sets the normal. + + + The normal. + + + + + A particle system is, you guessed it, just a collection of particles. + + + + + Initializes a new instance of the class. + + + + + This function should create and initialise 'count' particles of the correct + type. This is done automatically by default, only override if you want + to change the standard behaviour. + + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + This function ticks the particle system. + + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + The IHasObjectSpace helper. + + + + + Gets the transformation that pushes us into object space. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + The Vertex Shader object. + + + + + Initializes a new instance of the class. + + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + A Ray. + + + + + The light. + + + + + The origin. + + + + + The direction. + + + + + The bounding helper. + + + + + The bounding volume. + + + + + Gets the bounding volume. + + + + + The LookAt camera is a camera that does a 'look at' transformation. + + + + + This camera contains the data needed to perform a Perspective transformation + to the projection matrix. + + + + + The camera class is a base for a set of derived classes for manipulating the + projection matrix. + + + + + Initializes a new instance of the class. + + + + + This function projects through the camera, to OpenGL, ie. it + creates a projection matrix. + + + + + This function is for when you simply want to call only the functions that + would transform the projection matrix. Warning, it won't load the identity + first, and it won't set the current matrix to projection, it's really for + people who need to use it for their own projection functions (e.g Picking + uses it to create a composite 'Pick' projection). + + + + + The camera position. + + + + + Every time a camera is used to project, the projection matrix calculated + and stored here. + + + + + The screen aspect ratio. + + + + + Gets or sets the position. + + + The position. + + + + + Gets or sets the aspect. + + + The aspect. + + + + + Initializes a new instance of the class. + + + + + This is the class' main function, to override this function and perform a + perspective transformation. + + + + + The field of view. + + + + + The near clip. + + + + + The far flip. + + + + + Gets or sets the field of view. + + + The field of view. + + + + + Gets or sets the near. + + + The near. + + + + + Gets or sets the far. + + + The far. + + + + + Initializes a new instance of the class. + + + + + This is the class' main function, to override this function and perform a + perspective transformation. + + + + + This is the point in the scene that the camera is pointed at. + + + + + This is a vector that describes the 'up' direction (normally 0, 0, 1). + Use this to tilt the camera. + + + + + Gets or sets the target. + + + The target. + + + + + Gets or sets up vector. + + + Up vector. + + + + + A simple cube polygon. + + + + + Initializes a new instance of the class. + + + + + This function makes a simple cube shape. + + + + + An intersection. + + + + + Is it intersected? + + + + + The normal. + + + + + The point. + + + + + The closeness. + + + + + The OpenGLAttributes are an effect that can set + any OpenGL attributes. + + + + + Initializes a new instance of the class. + + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pops the effect off the specified parent element. + + The OpenGL instance. + The parent element. + + + + Gets or sets the hint attributes. + + + The hint attributes. + + + + + Gets or sets the list attributes. + + + The list attributes. + + + + + Gets or sets the pixel mode attributes. + + + The pixel mode attributes. + + + + + Gets or sets the polygon stipple attributes. + + + The polygon stipple attributes. + + + + + Gets or sets the scissor attributes. + + + The scissor attributes. + + + + + Gets or sets the stencil buffer attributes. + + + The stencil buffer attributes. + + + + + Gets or sets the texture attributes. + + + The texture attributes. + + + + + Gets or sets the transform attributes. + + + The transform attributes. + + + + + Gets or sets the viewport attributes. + + + The viewport attributes. + + + + + Gets or sets the eval attributes. + + + The eval attributes. + + + + + Gets or sets the accum buffer attributes. + + + The accum buffer attributes. + + + + + Gets or sets the color buffer attributes. + + + The color buffer attributes. + + + + + Gets or sets the current attributes. + + + The current buffer. + + + + + Gets or sets the depth buffer attributes. + + + The depth buffer attributes. + + + + + Gets or sets the enable attributes. + + + The enable attributes. + + + + + Gets the fog attributes. + + + + + Gets the lighting attributes. + + + + + Gets the line attributes. + + + + + Gets the point attributes. + + + + + Gets the polygon attributes. + + + + + This class represent's a grid of points, just like you'd get on a NURBS + surface, or a patch. + + + + + Use this to draw the vertex grid. + + OpenGL object. + Draw each individual vertex (with selection names). + Draw the lines connecting the points. + + + + This function returns all of the control points as a float array, which + is in the format [0] = vertex 1 X, [1] = vertex 1 Y, [2] = vertex 1 Z, + [3] = vertex 2 X etc etc... This array is suitable for OpenGL functions + for evaluators and NURBS. + + An array of floats. + + + + The Scene Container is the top-level object in a scene graph. + + + + + Initializes a new instance of the class. + + + + + Gets or sets the parent scene. + + + The parent scene. + + + + + This camera contains the data needed to perform a Frustum transformation + to the projection matrix. + + + + + Initializes a new instance of the class. + + + + + This is the main function of the camera, perform a Frustrum (in this case) + transformation. + + + + + The left pos. + + + + + The right pos. + + + + + The top pos. + + + + + The bottom pos. + + + + + The near pos. + + + + + The far pos. + + + + + Gets or sets the left. + + + The left. + + + + + Gets or sets the right. + + + The right. + + + + + Gets or sets the top. + + + The top. + + + + + Gets or sets the bottom. + + + The bottom. + + + + + Gets or sets the near. + + + The near. + + + + + Gets or sets the far. + + + The far. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable depth writemask. + + + The enable depth writemask. + + + + + Gets or sets the depth clear value. + + + The depth clear value. + + + + + Gets or sets the depth function. + + + The depth function. + + + + + Gets or sets the enable depth test. + + + The enable depth test. + + + + + Pass this class any SceneObject and it'll send you back a polygon. + + + + + This is the main function of the class, it'll create a triangulated polygon + from and SceneObject. + + The gl. + The object to convert. + A camera that can see the whole object. + + A polygon created from 'sourceObject'. + + + + + A plane. + + + + + Initializes a new instance of the class. + + + + + This finds out if a point is in front of, behind, or on this plane. + + The point to classify. + + Less than 0 if behind, 0 if on, Greater than 0 if in front. + + + + + The position. + + + + + The normal. + + + + + The equation. + + + + + An object that is Bindable is able to set itself into + the current OpenGL instance. This can be lights, materials, + attributes and so on. + Bindable objects must be able to be used without interfering + with later rendering, so as well as simply being bound directly, + they must be able to be pushed and popped. + + + + + Pushes this object into the provided OpenGL instance. + This will generally push elements of the attribute stack + and then set current values. + + The OpenGL instance. + + + + Pops this object from the provided OpenGL instance. + This will generally pop elements of the attribute stack, + restoring previous attribute values. + + The OpenGL instance. + + + + Bind to the specified OpenGL instance. + Remember, this will not push or pop the attribute + stack so will affect ALL subsequent rendering. + + The OpenGL instance. + + + + A Face is a set of indices to vertices. + + + + + Initializes a new instance of the class. + + + + + Returns the plane equation (ax + by + cz + d = 0) of the face. + + The parent polygon. + An array of four coefficients a,b,c,d. + + + + Gets the surface normal. + + The parent. + + + + + This function reverses the order of the indices, i.e changes which direction + this face faces in. + + The parent polygon. + + + + This function generates normals for every vertex. + + The parent polygon. + + + + Returns a that represents this instance. + + + A that represents this instance. + + + + + The indices. + + + + + The neighbor indices. + + + + + Gets the count. + + + + + Gets or sets the indices. + + + The indices. + + + + + Gets or sets the neighbour indicies. + + + The neighbour indicies. + + + + + Gets or sets the material. + + + The material. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the polygon stipple. + + + The polygon stipple. + + + + + The Cylinder class wraps the cylinder quadric. + + + + + Quadric is the base class for all SharpGL quadric objects. + It can be interacted with and it can be rendered. + + + + + Initializes a new instance of the class. + + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Pushes us into Object Space using the transformation into the specified OpenGL instance. + + The OpenGL instance. + + + + Pops us from Object Space using the transformation into the specified OpenGL instance. + + The gl. + + + + This is the pointer to the opengl quadric object. + + + + + The draw style, can be filled, line, silouhette or points. + + + + + The IHasObjectSpace helper. + + + + + Gets or sets the quadric draw style. + + + The quadric draw style. + + + + + Gets or sets the normal orientation. + + + The normal orientation. + + + + + Gets or sets the normal generation. + + + The normal generation. + + + + + Gets or sets a value indicating whether [texture coords]. + + + true if [texture coords]; otherwise, false. + + + + + Gets the transformation that pushes us into object space. + + + + + Gets the current OpenGL that the object exists in context. + + + + + Material to be used when rendering the quadric in lighted mode. + + + The material. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Sphere data. + + + + + Top radius. + + + + + The height. + + + + + The slices. + + + + + The stacks. + + + + + Helps us implement IVolumeBound. + + + + + Gets or sets the base radius. + + + The base radius. + + + + + Gets or sets the top radius. + + + The top radius. + + + + + Gets or sets the height. + + + The height. + + + + + Gets or sets the slices. + + + The slices. + + + + + Gets or sets the stacks. + + + The stacks. + + + + + Gets the bounding volume. + + + + + This class provides a means of working with standard and opengl colours. + Use the ColorNet and ColorGL properties to set or access the colour in either + mode. + + + + + Initializes a new instance of the class. + + + + + This property allows you to access the color as if it was a .NET + color. + + + + + This property accesses the color as an opengl value. + + + + + Gets or sets the R. + + + The R. + + + + + Gets or sets the G. + + + The G. + + + + + Gets or sets the B. + + + The B. + + + + + Gets or sets the A. + + + The A. + + + + + This class has the light settings. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + The Shader base class. + + + + + Pops the effect off the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Attaches a shader. + + The shader. + + + + Detaches the shader. + + The shader. + + + + Links this instance. + + + + + Gets the uniform location. + + The name. + + + + + Sets the full shader source. + + The source. + + + + + Gets or sets the shader object. + + + The shader object. + + + + + Gets the current OpenGL that the object exists in context. + + + + + Gets the attached shaders. + + + + + Gets the compile status. + + + + + Gets the info log. + + + + + The axies objects are design time rendered primitives + that show an RGB axies at the origin of the scene. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Creates the display list. This function draws the + geometry as well as compiling it. + + + + + The internal display list. + + + + + The scene helper can be used to create scene presets, + such as designer, application, etc + + + + + Initialises a modeling scene. A modeling scene has: + - A 'Look At' camera targetting the centre of the scene + - Three gentle omnidirectional lights + - A design time grid and axis. + + The scene. + + + + This is a 1D evaluator, i.e a bezier curve. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The points. + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The segments. + + + + + Gets or sets the segments. + + + The segments. + + + + + A Linear Transformation is an effect that pushes a linear transformation (translate, scale, rotate) + onto the stack. + + + + + Pushes the effect onto the specified parent element. + + The OpenGL instance. + The parent element. + + + + Pops the specified parent element. + + The OpenGL instance. + The parent element. + + + + The linear transformation. + + + + + Gets or sets the linear transformation. + + + The linear transformation. + + + + + The display list class basicly wraps an OpenGL display list, making them easier + to manage. Remember this class is completely OpenGL dependant. In time this class + will derive from the IOpenGLDependant interface. + + + + + This function generates the display list. You must call it before you call + anything else! + + OpenGL + + + + This function makes the display list. + + OpenGL + The mode, compile or compile and execute. + + + + This function ends the compilation of a list. + + + + + + This camera contains the data needed to perform an orthographic transformation + to the projection matrix. + + + + + Initializes a new instance of the class. + + + + + This is the main function of the class, to perform a specialised projection + in this case, an orthographic one. + + + + + The left pos. + + + + + The right pos. + + + + + The top pos. + + + + + The bottom pos. + + + + + The near pos. + + + + + The far pos. + + + + + Gets or sets the left. + + + The left. + + + + + Gets or sets the right. + + + The right. + + + + + Gets or sets the top. + + + The top. + + + + + Gets or sets the bottom. + + + The bottom. + + + + + Gets or sets the near. + + + The near. + + + + + Gets or sets the far. + + + The far. + + + + + A Texture object is simply an array of bytes. It has OpenGL functions, but is + not limited to OpenGL, so DirectX or custom library functions could be later added. + + + + + Initializes a new instance of the class. + + + + + Pushes this object into the provided OpenGL instance. + This will generally push elements of the attribute stack + and then set current values. + + The OpenGL instance. + + + + Pops this object from the provided OpenGL instance. + This will generally pop elements of the attribute stack, + restoring previous attribute values. + + The OpenGL instance. + + + + Bind to the specified OpenGL instance. + + The OpenGL instance. + + + + This function creates the underlying OpenGL object. + + + + + + + This function creates the texture from an image. + + The OpenGL object. + The image. + True if the texture was successfully loaded. + + + + This function creates the texture from an image file. + + The OpenGL object. + The path to the image file. + True if the texture was successfully loaded. + + + + This function destroys the OpenGL object that is a representation of this texture. + + + + + This function (attempts) to make a bitmap from the raw data. The fact that + the byte array is a managed type makes it slightly more complicated. + + The texture object as a Bitmap. + + + + This is an array of bytes (r, g, b, a) that represent the pixels in this + texture object. + + + + + The width of the texture image. + + + + + The height of the texture image. + + + + + This is for OpenGL textures, it is the unique ID for the OpenGL texture. + + + + + Gets the name of the texture. + + + The name of the texture. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + This is a 2D evaluator, i.e a bezier patch. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The u. + The v. + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The segments. + + + + + Gets or sets the segments. + + + The segments. + + + + + The RenderMode enumeration is used to identify what kind + of rendering is occuring. + + + + + We are designing. + + + + + We are rendering for a hit test. + + + + + We are rendering. + + + + + The ArcBall camera supports arcball projection, making it ideal for use with a mouse. + + + + + Initializes a new instance of the class. + + + + + This is the class' main function, to override this function and perform a + perspective transformation. + + + + + The OpenGLEventArgs class. + + + + + Initializes a new instance of the class. + + The gl. + + + + The OpenGL instance. + + + + + Gets or sets the open GL. + + The open GL. + + + + The OpenGL Event Handler delegate. + + + + + A NURBS Curve is a one dimensional non uniform B-Spline. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The knots. + + + + + Gets the knots. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the color of the map. + + + The color of the map. + + + + + Gets or sets the map stencil. + + + The map stencil. + + + + + Gets or sets the index shift. + + + The index shift. + + + + + Gets or sets the index offset. + + + The index offset. + + + + + Gets or sets the red scale. + + + The red scale. + + + + + Gets or sets the green scale. + + + The green scale. + + + + + Gets or sets the blue scale. + + + The blue scale. + + + + + Gets or sets the alpha scale. + + + The alpha scale. + + + + + Gets or sets the depth scale. + + + The depth scale. + + + + + Gets or sets the red bias. + + + The red bias. + + + + + Gets or sets the green bias. + + + The green bias. + + + + + Gets or sets the blue bias. + + + The blue bias. + + + + + Gets or sets the alpha bias. + + + The alpha bias. + + + + + Gets or sets the depth bias. + + + The depth bias. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable alpha test. + + + The enable alpha test. + + + + + Gets or sets the alpha test function. + + + The alpha test function. + + + + + Gets or sets the alpha test reference value. + + + The alpha test reference value. + + + + + Gets or sets the enable blend. + + + The enable blend. + + + + + Gets or sets the blending source factor. + + + The blending source factor. + + + + + Gets or sets the blending destination factor. + + + The blending destination factor. + + + + + Gets or sets the enable dither. + + + The enable dither. + + + + + Gets or sets the draw buffer mode. + + + The draw buffer mode. + + + + + Gets or sets the enable logic op. + + + The enable logic op. + + + + + Gets or sets the logic op. + + + The logic op. + + + + + Gets or sets the color of the color mode clear. + + + The color of the color mode clear. + + + + + Gets or sets the color of the index mode clear. + + + The color of the index mode clear. + + + + + Gets or sets the color mode write mask. + + + The color mode write mask. + + + + + Gets or sets the index mode write mask. + + + The index mode write mask. + + + + + A material object is defined in mathematical terms, i.e it's not exclusivly + for OpenGL. This means later on, DirectX or custom library functions could + be added. + + + + + Initializes a new instance of the class. + + + + + Calculates the lighting. + + The light. + The angle. + + + + + Pushes this object into the provided OpenGL instance. + This will generally push elements of the attribute stack + and then set current values. + + The OpenGL instance. + + + + Pops this object from the provided OpenGL instance. + This will generally pop elements of the attribute stack, + restoring previous attribute values. + + The OpenGL instance. + + + + Bind to the specified OpenGL instance. + + The OpenGL instance. + + + + Ambient color. + + + + + Diffuse color. + + + + + Specular color. + + + + + Emission. + + + + + Shininess. + + + + + The texture. + + + + + Gets or sets the ambient. + + + The ambient. + + + + + Gets or sets the diffuse. + + + The diffuse. + + + + + Gets or sets the specular. + + + The specular. + + + + + Gets or sets the emission. + + + The emission. + + + + + Gets or sets the shininess. + + + The shininess. + + + + + Gets or sets the texture. + + + The texture. + + + + + The point settings. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + The size. + + + + + The smooth flag. + + + + + Gets or sets the size. + + + The size. + + + + + Gets or sets the smooth. + + + The smooth. + + + + + The Ray Tracer is an engine that renders a scene using the raytracing mechanism. + + + + + Renders the specified scene. + + The scene. + The camera. + + The scene rendered with raytracing. + + + + + The Sphere class wraps the sphere quadric. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + The radius. + + + + + The slices. + + + + + The stacks. + + + + + The bounding volume helper, used to aid implementation of IVolumeBound. + + + + + Gets or sets the radius. + + + The radius. + + + + + Gets or sets the slices. + + + The slices. + + + + + Gets or sets the stacks. + + + The stacks. + + + + + Gets the bounding volume. + + + + + The Quadric Normals. + + + + + None. + + + + + Flat. + + + + + Smooth. + + + + + A Light is defined purely mathematically, but works well with OpenGL. + A light is a scene element, it can be interacted with using the mouse + and it is bindable. + + + + + Initializes a new instance of the class. + + + + + Pushes this object into the provided OpenGL instance. + This will generally push elements of the attribute stack + and then set current values. + + The OpenGL instance. + + + + Pops this object from the provided OpenGL instance. + This will generally pop elements of the attribute stack, + restoring previous attribute values. + + The OpenGL instance. + + + + This function sets all of the lights parameters into OpenGL. + + The OpenGL instance. + + + + This is the OpenGL code for the light. + + + + + The ambient colour of the light. + + + + + The diffuse color of the light. + + + + + The specular colour of the light. + + + + + The colour of the shadow created by this light. + + + + + True when the light is on. + + + + + The position of the light. + + + + + Should the light cast a shadow? + + + + + Used to aid in the implementation of IVolumeBound. + + + + + Gets the bounding volume. + + + + + Gets or sets the GL code. + + + The GL code. + + + + + Gets or sets the position. + + + The position. + + + + + Gets or sets the ambient. + + + The ambient. + + + + + Gets or sets the diffuse. + + + The diffuse. + + + + + Gets or sets the specular. + + + The specular. + + + + + Gets or sets the color of the shadow. + + + The color of the shadow. + + + + + Gets or sets a value indicating whether this is on. + + + true if on; otherwise, false. + + + + + Gets or sets a value indicating whether [cast shadow]. + + + true if [cast shadow]; otherwise, false. + + + + + A texture coordinate. + + + + + Initializes a new instance of the struct. + + The u. + The v. + + + + The u value. + + + + + The v value. + + + + + Gets or sets the U. + + + The U. + + + + + Gets or sets the V. + + + The V. + + + + + Initializes a new instance of the class. + + + + + Creates the volume from vertices. + + The vertices. + + + + Creates the volume from a spherical volume. + + The centre. + The radius. + + + + Creates the volume from a cylindrical volume. + + The baseline. + The height. + The base radius. + The top radius. + + + + Pads the bounding volume. + + The padding. + + + + Gets the bound dimensions. + + The x size. + The y size. + The z size. + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + This is the main particle class, if you want specialised particles derive from it. + + + + + This function should initialise the particle so that it's ready to tick. + + The random number generator. + + + + This function moves the particle on a stage. + + The random nunber generator. + + + + This function draws the particle. + + + + + + A basic particle. + + + + + Initializes a new instance of the class. + + + + + This function initialises the basic particle. + + + + + + This function 'ticks' the particle, i.e moves it on a stage. + + A random object. + + + + This is the vertex's current position in space. + + + + + This is the velocity, do not modify! + + + + + This is the direction of the particle. + + + + + This shows the potential magnitude of the random effects of the direction. + + + + + This is the gravity affecting the particle. + + + + + Particles colour. + + + + + How much the particles colour can change by each tick. + + + + + The life left of the particle. + + + + + The lifespan of the particle. + + + + + Does the particle only exist once? + + + + + A Sphere particle. + + + + + Initializes a new instance of the class. + + + + + Draws the specified gl. + + The gl. + + + + Extensions to the OpenGL class for use with the Scene Graph types (allowing + vertices, GLColors etc to be used). + + + + + Set the current color. + + The OpenGL instance. + The color. + + + + This is a SharpGL helper version, that projects the vertex passed, using the + current matrixes. + + The gl. + The object coordinates. + + The screen coords. + + + + + Gets the model view matrix. + + The gl. + + + + + Gets the projection matrix. + + The gl. + + + + + Gets the texture matrix. + + The gl. + + + + + Vertexes the pointer. + + The gl. + The size. + The type. + The stride. + The pointer. + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable scissor test. + + + The enable scissor test. + + + + + Gets or sets the scissor X. + + + The scissor X. + + + + + Gets or sets the scissor Y. + + + The scissor Y. + + + + + Gets or sets the width of the scissor. + + + The width of the scissor. + + + + + Gets or sets the height of the scissor. + + + The height of the scissor. + + + + + This class has all the settings you can edit for fog. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable alpha test. + + + The enable alpha test. + + + + + Gets or sets the enable auto normal. + + + The enable auto normal. + + + + + Gets or sets the enable blend. + + + The enable blend. + + + + + Gets or sets the enable cull face. + + + The enable cull face. + + + + + Gets or sets the enable depth test. + + + The enable depth test. + + + + + Gets or sets the enable dither. + + + The enable dither. + + + + + Gets or sets the enable fog. + + + The enable fog. + + + + + Gets or sets the enable lighting. + + + The enable lighting. + + + + + Gets or sets the enable line smooth. + + + The enable line smooth. + + + + + Gets or sets the enable line stipple. + + + The enable line stipple. + + + + + Gets or sets the enable color logic op. + + + The enable color logic op. + + + + + Gets or sets the enable index logic op. + + + The enable index logic op. + + + + + Gets or sets the enable normalize. + + + The enable normalize. + + + + + Gets or sets the enable point smooth. + + + The enable point smooth. + + + + + Gets or sets the enable polygon offset line. + + + The enable polygon offset line. + + + + + Gets or sets the enable polygon offset fill. + + + The enable polygon offset fill. + + + + + Gets or sets the enable polygon offset point. + + + The enable polygon offset point. + + + + + Gets or sets the enable polygon smooth. + + + The enable polygon smooth. + + + + + Gets or sets the enable polygon stipple. + + + The enable polygon stipple. + + + + + Gets or sets the enable scissor test. + + + The enable scissor test. + + + + + Gets or sets the enable stencil test. + + + The enable stencil test. + + + + + Gets or sets the enable texture1 D. + + + The enable texture1 D. + + + + + Gets or sets the enable texture2 D. + + + The enable texture2 D. + + + + + This class has all the settings you can edit for current. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the color of the current. + + + The color of the current. + + + + + Gets or sets the index of the current color. + + + The index of the current color. + + + + + Gets or sets the current normal vector. + + + The current normal vector. + + + + + Gets or sets the current texture coordiate. + + + The current texture coordiate. + + + + + Gets or sets the current raster position. + + + The current raster position. + + + + + Gets or sets the color of the current raster. + + + The color of the current raster. + + + + + Gets or sets the index of the current raster color. + + + The index of the current raster color. + + + + + Gets or sets the current raster texture coordiate. + + + The current raster texture coordiate. + + + + + Gets or sets the current edge flag. + + + The current edge flag. + + + + + The Disk class wraps both the disk and partial disk quadrics. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + Gets or sets the inner radius. + + + The inner radius. + + + + + Gets or sets the outer radius. + + + The outer radius. + + + + + Gets or sets the start angle. + + + The start angle. + + + + + Gets or sets the sweep angle. + + + The sweep angle. + + + + + Gets or sets the slices. + + + The slices. + + + + + Gets or sets the loops. + + + The loops. + + + + + A Shadow object can be added as a child of a polygon. + + + + + Initializes a new instance of the class. + + + + + Render to the provided instance of OpenGL. + + The OpenGL instance. + The render mode. + + + + This function calculates the neighbours in a face. + + + + + Casts a real time 3D shadow. + + The OpenGL object. + The lights. + + + + This is part of the shadow casting code, it does a shadowpass for the + polygon using the specified light. + + The OpenGL object. + The light casting the shadow. + An array of bools. + + + + Are the face neighbours calculated? + + + + + The size of the shadow in each direction. + + + + + Gets the parent polygon. + + + + + Gets or sets the size of the shadow. + + + The size of the shadow. + + + + + A spotlight has a direction and a spot cutoff. + + + + + Initializes a new instance of the class. + + + + + This function sets all of the lights parameters into OpenGL. + + The OpenGL instance. + + + + The spotlight cutoff value (between 0-90 for spotlights, or 180 for a + simple light). + + + + + A Vector describing the direction of the spotlight. + + + + + Gets or sets the direction. + + + The direction. + + + + + Gets or sets the spot cutoff. + + + The spot cutoff. + + + + + This aids the design of the OpenGLCtrl + + + + + Initializes a new instance of the class. + + + + + Remove Control properties that are not supported by the control. + + + + + + The VertexConverter class allows you to edit vertices in the propties window. + + + + + This converts the Material Collection into something more functional. + + + + + The texture editor makes Textures in the properties window much better, + giving them a little thumbnail. + + + + + This converts the Quadric Collection into something more functional, and + allows you to add many types of quadrics. + + + + + This converts the Camera collection into something more usable (design time wise) + by allowing all the types of camera to be added. + + + + + This converts the evaluator collection into something more usable (design time wise) + by allowing all the types of evaluator to be added. + + + + + Initializes a new instance of the class. + + + + + Performs a hit test on the scene. All elements that implement IVolumeBound will + be hit tested. + + The x. + The y. + The elements hit. + + + + This function draws all of the objects in the scene (i.e. every quadric + in the quadrics arraylist etc). + + + + + Renders the element. + + The gl. + The render mode. + + + + Renders the element for hit test. + + The scene element. + The hit map. + Current hit name. + + + + Use this function to resize the scene window, and also to look through + the current camera. + + Width of the screen. + Height of the screen. + + + + Create in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + Destroy in the context of the supplied OpenGL instance. + + The OpenGL instance. + + + + This is the OpenGL class, use it to call OpenGL functions. + + + + + The main scene container - this is the top level element of the Scene Tree. + + + + + The set of scene assets. + + + + + This is the camera that is currently being used to view the scene. + + + + + This is the colour of the background of the scene. + + + + + Gets or sets the open GL. + + + The open GL. + + + + + Gets or sets the scene container. + + + The scene container. + + + + + Gets the assets. + + + + + Gets or sets the current camera. + + + The current camera. + + + + + Gets or sets the color of the clear. + + + The color of the clear. + + + + + Gets or sets a value indicating whether [render bounding volumes]. + + + true if [render bounding volumes]; otherwise, false. + + + + + Gets the current OpenGL that the object exists in context. + + + + + The OpenGL Helper is a class that provides some helper functions for working with OpenGL. + + + + + Initialises the supplied OpenGL instance for high quality rendering. + + The OpenGL instance. + + + + A 4x4 matrix. + + + + + Matrix Library .Net v2.0 By Anas Abidi, 2004. + + The Matrix Library contains Class Matrix which provides many + static methods for making various matrix operations on objects + derived from the class or on arrays defined as double. The + '+','-','*' operators are overloaded to work with the objects + derived from the matrix class. + + + + + Returns a hash code for this instance. + + + A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + + + + + The matrix. + + + + + Matrix object constructor, constructs an empty + matrix with dimensions: rows = noRows and cols = noCols. + + no. of rows in this matrix + no. of columns in this matrix + + + + Matrix object constructor, constructs a matrix from an + already defined array object. + + the array the matrix will contain + + + + Creates a matrix from a column major array. + + The column major array. + The rows. + The columns. + The matrix. + + + + Creates a matrix from a row major array. + + The column major array. + The rows. + The columns. + The matrix. + + + + Creates a matrix from a segment of another matrix. + + The RHS. + The rows. + The cols. + + + + Returns the 2D form of a 1D array. i.e. array with + dimension[n] is returned as an array with dimension [n,1]. + In case of an error the error is raised as an exception. + + + the array to convert, with dimesion [n] + + the same array but with [n,1] dimension + + + + Returns the 1D form of a 2D array. i.e. array with + dimension[n,1] is returned as an array with dimension [n]. + In case of an error the error is raised as an exception. + + + the array to convert, with dimesions [n,1] + + the same array but with [n] dimension + + + + Sets the identity matrix as the identity matrix. It must be N x N (i.e. + square). + + + + + Returns an Identity matrix with dimensions [n,n] in the from of an array. + + the no. of rows or no. cols in the matrix + An identity Matrix with dimensions [n,n] in the form of an array + + + + Returns the summation of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First array in the summation + Second array in the summation + Sum of Mat1 and Mat2 as an array + + + + Returns the summation of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First matrix in the summation + Second matrix in the summation + Sum of Mat1 and Mat2 as a Matrix object + + + + Returns the summation of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First Matrix object in the summation + Second Matrix object in the summation + Sum of Mat1 and Mat2 as a Matrix object + + + + Returns the difference of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First array in the subtraction + Second array in the subtraction + Difference of Mat1 and Mat2 as an array + + + + Returns the difference of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First matrix in the subtraction + Second matrix in the subtraction + Difference of Mat1 and Mat2 as a Matrix object + + + + Returns the difference of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First Matrix object in the subtraction + Second Matrix object in the subtraction + Difference of Mat1 and Mat2 as a Matrix object + + + + Returns the multiplication of two matrices with compatible + dimensions. + In case of an error the error is raised as an exception. + + First array in multiplication + Second array in multiplication + Mat1 multiplied by Mat2 as an array + + + + Returns the multiplication of two matrices with compatible + dimensions OR the cross-product of two vectors. + In case of an error the error is raised as an exception. + + + First matrix or vector (i.e: dimension [3,1]) object in + multiplication + + + Second matrix or vector (i.e: dimension [3,1]) object in + multiplication + + Mat1 multiplied by Mat2 as a Matrix object + + + + Returns the multiplication of two matrices with compatible + dimensions OR the cross-product of two vectors. + In case of an error the error is raised as an exception. + + + First matrix or vector (i.e: dimension [3,1]) object in + multiplication + + + Second matrix or vector (i.e: dimension [3,1]) object in + multiplication + + Mat1 multiplied by Mat2 as a Matrix object + + + + Returns the determinant of a matrix with [n,n] dimension. + In case of an error the error is raised as an exception. + + + Array with [n,n] dimension whose determinant is to be found + + Determinant of the array + + + + Returns the determinant of a matrix with [n,n] dimension. + In case of an error the error is raised as an exception. + + + Matrix object with [n,n] dimension whose determinant is to be found + + Determinant of the Matrix object + + + + Returns the inverse of a matrix with [n,n] dimension + and whose determinant is not zero. + In case of an error the error is raised as an exception. + + + Array with [n,n] dimension whose inverse is to be found + + Inverse of the array as an array + + + + Returns the inverse of a matrix with [n,n] dimension + and whose determinant is not zero. + In case of an error the error is raised as an exception. + + + Matrix object with [n,n] dimension whose inverse is to be found + + Inverse of the matrix as a Matrix object + + + + Returns the transpose of a matrix. + In case of an error the error is raised as an exception. + + Array whose transpose is to be found + Transpose of the array as an array + + + + Returns the transpose of a matrix. + In case of an error the error is raised as an exception. + + Matrix object whose transpose is to be found + Transpose of the Matrix object as a Matrix object + + + + Evaluates the Singular Value Decomposition of a matrix, + returns the matrices S, U and V. Such that a given + Matrix = U x S x V'. + In case of an error the error is raised as an exception. + Note: This method is based on the 'Singular Value Decomposition' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + Array whose SVD is to be computed + An array where the S matrix is returned + An array where the U matrix is returned + An array where the V matrix is returned + + + + Evaluates the Singular Value Decomposition of a matrix, + returns the matrices S, U and V. Such that a given + Matrix = U x S x V'. + In case of an error the error is raised as an exception. + Note: This method is based on the 'Singular Value Decomposition' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + Matrix object whose SVD is to be computed + A Matrix object where the S matrix is returned + A Matrix object where the U matrix is returned + A Matrix object where the V matrix is returned + + + + Returns the LU Decomposition of a matrix. + the output is: lower triangular matrix L, upper + triangular matrix U, and permutation matrix P so that + P*X = L*U. + In case of an error the error is raised as an exception. + Note: This method is based on the 'LU Decomposition and Its Applications' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + Array which will be LU Decomposed + An array where the lower traingular matrix is returned + An array where the upper traingular matrix is returned + An array where the permutation matrix is returned + + + + Returns the LU Decomposition of a matrix. + the output is: lower triangular matrix L, upper + triangular matrix U, and permutation matrix P so that + P*X = L*U. + In case of an error the error is raised as an exception. + Note: This method is based on the 'LU Decomposition and Its Applications' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + Matrix object which will be LU Decomposed + A Matrix object where the lower traingular matrix is returned + A Matrix object where the upper traingular matrix is returned + A Matrix object where the permutation matrix is returned + + + + Solves a set of n linear equations A.X = B, and returns + X, where A is [n,n] and B is [n,1]. + In the same manner if you need to compute: inverse(A).B, it is + better to use this method instead, as it is much faster. + In case of an error the error is raised as an exception. + Note: This method is based on the 'LU Decomposition and Its Applications' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + The array 'A' on the left side of the equations A.X = B + The array 'B' on the right side of the equations A.X = B + Array 'X' in the system of equations A.X = B + + + + Solves a set of n linear equations A.X = B, and returns + X, where A is [n,n] and B is [n,1]. + In the same manner if you need to compute: inverse(A).B, it is + better to use this method instead, as it is much faster. + In case of an error the error is raised as an exception. + Note: This method is based on the 'LU Decomposition and Its Applications' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + Matrix object 'A' on the left side of the equations A.X = B + Matrix object 'B' on the right side of the equations A.X = B + Matrix object 'X' in the system of equations A.X = B + + + + Returns the rank of a matrix. + In case of an error the error is raised as an exception. + + An array whose rank is to be found + The rank of the array + + + + Returns the rank of a matrix. + In case of an error the error is raised as an exception. + + a Matrix object whose rank is to be found + The rank of the Matrix object + + + + Returns the pseudoinverse of a matrix, such that + X = PINV(A) produces a matrix 'X' of the same dimensions + as A' so that A*X*A = A, X*A*X = X. + In case of an error the error is raised as an exception. + + An array whose pseudoinverse is to be found + The pseudoinverse of the array as an array + + + + Returns the pseudoinverse of a matrix, such that + X = PINV(A) produces a matrix 'X' of the same dimensions + as A' so that A*X*A = A, X*A*X = X. + In case of an error the error is raised as an exception. + + a Matrix object whose pseudoinverse is to be found + The pseudoinverse of the Matrix object as a Matrix Object + + + + Returns the Eigenvalues and Eigenvectors of a real symmetric + matrix, which is of dimensions [n,n]. + In case of an error the error is raised as an exception. + Note: This method is based on the 'Eigenvalues and Eigenvectors of a TridiagonalMatrix' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + + The array whose Eigenvalues and Eigenvectors are to be found + + An array where the eigenvalues are returned + An array where the eigenvectors are returned + + + + Returns the Eigenvalues and Eigenvectors of a real symmetric + matrix, which is of dimensions [n,n]. In case of an error the + error is raised as an exception. + Note: This method is based on the 'Eigenvalues and Eigenvectors of a TridiagonalMatrix' + section of Numerical Recipes in C by William H. Press, + Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, + University of Cambridge Press 1992. + + + The Matrix object whose Eigenvalues and Eigenvectors are to be found + + A Matrix object where the eigenvalues are returned + A Matrix object where the eigenvectors are returned + + + + Returns the multiplication of a matrix or a vector (i.e + dimension [3,1]) with a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to multiply the array + Array which is to be multiplied by a scalar + The multiplication of the scalar and the array as an array + + + + Returns the multiplication of a matrix or a vector (i.e + dimension [3,1]) with a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to multiply the array + Matrix which is to be multiplied by a scalar + The multiplication of the scalar and the array as an array + + + + Returns the multiplication of a matrix or a vector (i.e + dimension [3,1]) with a scalar quantity. + In case of an error the error is raised as an exception. + + Matrix object which is to be multiplied by a scalar + The scalar value to multiply the Matrix object + + The multiplication of the scalar and the Matrix object as a + Matrix object + + + + + Returns the multiplication of a matrix or a vector (i.e + dimension [3,1]) with a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to multiply the Matrix object + Matrix object which is to be multiplied by a scalar + + The multiplication of the scalar and the Matrix object as a + Matrix object + + + + + Returns the division of a matrix or a vector (i.e + dimension [3,1]) by a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to divide the array with + Array which is to be divided by a scalar + The division of the array and the scalar as an array + + + + Returns the division of a matrix or a vector (i.e + dimension [3,1]) by a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to divide the array with + Matrix which is to be divided by a scalar + The division of the array and the scalar as an array + + + + Returns the division of a matrix or a vector (i.e + dimension [3,1]) by a scalar quantity. + In case of an error the error is raised as an exception. + + The scalar value to divide the Matrix object with + Matrix object which is to be divided by a scalar + + The division of the Matrix object and the scalar as a Matrix object + + + + + Returns the cross product of two vectors whose + dimensions should be [3] or [3,1]. + In case of an error the error is raised as an exception. + + First vector array (dimension [3]) in the cross product + Second vector array (dimension [3]) in the cross product + Cross product of V1 and V2 as an array (dimension [3]) + + + + Returns the cross product of two vectors whose + dimensions should be [3] or [3x1]. + In case of an error the error is raised as an exception. + + First vector array (dimensions [3,1]) in the cross product + Second vector array (dimensions [3,1]) in the cross product + Cross product of V1 and V2 as an array (dimension [3,1]) + + + + Returns the cross product of two vectors whose + dimensions should be [3] or [3x1]. + In case of an error the error is raised as an exception. + + First Matrix (dimensions [3,1]) in the cross product + Second Matrix (dimensions [3,1]) in the cross product + Cross product of V1 and V2 as a matrix (dimension [3,1]) + + + + Returns the dot product of two vectors whose + dimensions should be [3] or [3,1]. + In case of an error the error is raised as an exception. + + First vector array (dimension [3]) in the dot product + Second vector array (dimension [3]) in the dot product + Dot product of V1 and V2 + + + + Returns the dot product of two vectors whose + dimensions should be [3] or [3,1]. + In case of an error the error is raised as an exception. + + First vector array (dimension [3,1]) in the dot product + Second vector array (dimension [3,1]) in the dot product + Dot product of V1 and V2 + + + + Returns the dot product of two vectors whose + dimensions should be [3] or [3,1]. + In case of an error the error is raised as an exception. + + First Matrix object (dimension [3,1]) in the dot product + Second Matrix object (dimension [3,1]) in the dot product + Dot product of V1 and V2 + + + + Returns the magnitude of a vector whose dimension is [3] or [3,1]. + In case of an error the error is raised as an exception. + + The vector array (dimension [3]) whose magnitude is to be found + The magnitude of the vector array + + + + Returns the magnitude of a vector whose dimension is [3] or [3,1]. + In case of an error the error is raised as an exception. + + The vector array (dimension [3,1]) whose magnitude is to be found + The magnitude of the vector array + + + + Returns the magnitude of a vector whose dimension is [3] or [3,1]. + In case of an error the error is raised as an exception. + + Matrix object (dimension [3,1]) whose magnitude is to be found + The magnitude of the Matrix object + + + + Checks if two Arrays of equal dimensions are equal or not. + In case of an error the error is raised as an exception. + + First array in equality check + Second array in equality check + If two matrices are equal or not + + + + Checks if two matrices of equal dimensions are equal or not. + In case of an error the error is raised as an exception. + + First Matrix in equality check + Second Matrix in equality check + If two matrices are equal or not + + + + Checks if two matrices of equal dimensions are equal or not. + In case of an error the error is raised as an exception. + + First Matrix object in equality check + Second Matrix object in equality check + If two matrices are equal or not + + + + Checks if two matrices of equal dimensions are not equal. + In case of an error the error is raised as an exception. + + First Matrix object in equality check + Second Matrix object in equality check + If two matrices are not equal + + + + Tests whether the specified object is a MatrixLibrary.Matrix + object and is identical to this MatrixLibrary.Matrix object. + + The object to compare with the current object + This method returns true if obj is the specified Matrix object identical to this Matrix object; otherwise, false. + + + + Returns a matrix as a string, so it can be viewed + in a multi-text textbox or in a richtextBox (preferred). + In case of an error the error is raised as an exception. + + The array to be viewed + The string view of the array + + + + Returns a matrix as a string, so it can be viewed + in a multi-text textbox or in a richtextBox (preferred). + In case of an error the error is raised as an exception. + + The Matrix object to be viewed + The string view of the Matrix object + + + + Returns the matrix as a string, so it can be viewed + in a multi-text textbox or in a richtextBox (preferred). + In case of an error the error is raised as an exception. + + The string view of the Matrix object + + + + Set or get an element from the matrix + + + + + Set or get the no. of rows in the matrix. + Warning: Setting this property will delete all of + the elements of the matrix and set them to zero. + + + + + Set or get the no. of columns in the matrix. + Warning: Setting this property will delete all of + the elements of the matrix and set them to zero. + + + + + This property returns the matrix as an array. + + + + + Gets the matrix as a row major array. + + + + + Gets the matrix as a row major array. + + + + + Gets the matrix as a column major array. + + + + + Gets the matrix as a column major array. + + + + + The polygon settings. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the enable cull face. + + + The enable cull face. + + + + + Gets or sets the enable smooth. + + + The enable smooth. + + + + + Gets or sets the cull faces. + + + The cull faces. + + + + + Gets or sets the front faces. + + + The front faces. + + + + + Gets or sets the polygon draw mode. + + + The polygon draw mode. + + + + + Gets or sets the offset factor. + + + The offset factor. + + + + + Gets or sets the offset bias. + + + The offset bias. + + + + + Gets or sets the enable offset point. + + + The enable offset point. + + + + + Gets or sets the enable offset line. + + + The enable offset line. + + + + + Gets or sets the enable offset fill. + + + The enable offset fill. + + + + + The line attributes. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the width. + + + The width. + + + + + Gets or sets the smooth. + + + The smooth. + + + + + This class has all the settings you can edit for hints. + + + + + Initializes a new instance of the class. + + + + + Sets the attributes. + + The OpenGL instance. + + + + Returns true if any attributes are set. + + + True if any attributes are set + + + + + Gets or sets the perspective correction hint. + + + The perspective correction hint. + + + + + Gets or sets the point smooth hint. + + + The point smooth hint. + + + + + Gets or sets the line smooth hint. + + + The line smooth hint. + + + + + Gets or sets the polygon smooth hint. + + + The polygon smooth hint. + + + + + Gets or sets the fog hint. + + + The fog hint. + + + + + The ArcBall camera supports arcball projection, making it ideal for use with a mouse. + + + + + Initializes a new instance of the class. + + + + + This is the class' main function, to override this function and perform a + perspective transformation. + + + + + The arcball used for rotating. + + + + + Gets the arc ball. + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll new file mode 100644 index 0000000000000000000000000000000000000000..9a1eb4eaa9cc8de1ba7187142b57c1dfee982ca2 GIT binary patch literal 22016 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 RE#g}IMD#yD|NnX5e**ue;0^!) literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml new file mode 100644 index 00000000..7f050db4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml @@ -0,0 +1,209 @@ + + + + SharpGL.Serialization + + + + + A Format class has the functionality to load data from a certain type of file. + + + + + Load the data from the specified file stream. The data + should be loaded into a scene object. Also, for consistency + the ObjectLoaded event should be fired every time an object + (such as a polygon or material) is loaded. + + The path. + The scene or null if loading failed. + + + + Saves the scene to the specified stream. + + The scene. + The path. + True if saved correctly. + + + + This property returns an array of file types that can be used with this + format, e.g the CaligariFormat would return "cob", "scn". + + + + + This gets a filter suitable for a file open/save dialog, e.g + "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". + + + + + The SharpGL XML format. + + + + + Load the data from the specified file stream. The data + should be loaded into a scene object. Also, for consistency + the ObjectLoaded event should be fired every time an object + (such as a polygon or material) is loaded. + + The path. + + The scene or null if loading failed. + + + + + Saves the scene to the specified stream. + + The scene. + The path. + + True if saved correctly. + + + + + This property returns an array of file types that can be used with this + format, e.g the CaligariFormat would return "cob", "scn". + + + + + This gets a filter suitable for a file open/save dialog, e.g + "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". + + + + + This is the one chunk that reads no scene object, use it to skip + past unknown chunks. + + The Reader to read from. + The object that has been read. + + + + This function writes an object to the stream. + + The writer to write to. + The object to write. + + + + This function reads the chunk header. + + The Reader to read from. + + + + Writes the data. + + The writer. + The scene object. + + + + This function reads a polygon. + + + + + + + The serialization engine is a singleton that allows + scene objects and their contents to be saved and loaded. + + + + + Singleton instance. + + + + + Prevents a default instance of the class from being created. + + + + + Composes this instance. + + + + + Determines whether [is format valid for path] [the specified file format]. + + The file format. + The path. + + true if [is format valid for path] [the specified file format]; otherwise, false. + + + + + Gets the format for path. + + The path. + + + + + Loads the scene. + + The path. + + + + + Saves the scene. + + The scene. + The path. + + + + + The file formats, composed via MEF. + + + + + Gets the instance. + + + + + Gets the file formats. + + + + + Gets the filter. + + + + + This property returns an array of file types that can be used with this + format, e.g the CaligariFormat would return "cob", "scn". + + + + + This gets a filter suitable for a file open/save dialog, e.g + "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". + + + + + This function reads the chunk and bangs the data in it into the scene. + + The file stream to read from. + The scene to put data into. + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll new file mode 100644 index 0000000000000000000000000000000000000000..00b94b3bf44f8dac0ef0b25372285d4c7f9a597a GIT binary patch literal 355840 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

8)6XHJ8 zRK|7skoSG|t5tvH&lSSyLo)==?>?cIB;O~laqWlu>&$Cq*}~rQ^!>(eE@OndmRq=u zC+}Rfq+*4ht5$BY-N)Zr_T4#W?q%D!md)GewyMwSd<1`PfHb5Snd9YvD%wh;jNwAW3)Ty2>NGnbTo`-E++;(S#;#;YF`ODEKM)hYY>|I#1*oGJQqgXvF*Ip{3gbX(`TZ@hnWDMZ<> zu4VIH6Wyp>j_Wu?U%PWm=TFM?;OynBeLW^IS3PxaRjk6USDd?EI)YxW;oVR5dbN9- zwnMIS-4K3ehpoWwlXng-_rBVfLv`~8?vJ$m5k7mY*YbMyw!jj)pF z8je#$aqouK4X_- z9_EiI+aNl^o<&D$6^WQXBDsM-!d{YZx!F0&J(h2|xjD)$%eUOj9OWL)x7>^zk0@{Zxl`&X-&ds(^HGo9n>{eeh-1gKAf& zny;9Hxz^mP=7=-U?Z%n;e9cIw;Oj2#4HvgVIA40SH^T1ZqdPpYnc@xho2oz}-)nLA zciQ;HER2qNy6m?^ILx4Z#uRg^zU@+Or;FR=;@&aN%)z@xI*sf$&J^5Zq*L%cE)$>@T>6tCYJhRz{>9F&}W;*$qsb%EnVaqSvN**adCfi?9i8R18d(^F-t32jb zQb=(EkDH>xe&uSvE`hNp0xc`BDgmtUh>fY)xTe(_b^#5N|e*@!{sd#Ez6jb7GpY5 zfQ)r3=_=#gO1jD-ZY6~jvsKg-EzrihmUXwqT+6!K;;vXr%ZXw5~`i{a10QPRqF`;3o@kB*PAKQ=MO@bAY)IQK65CpsS7X6WBC%yayZJT8V` z)5LW;pJtpWS<6_bWV&&pWNl-el68y|CF>gNl%)6M{CL6_C9g2nDOuk*QL=%nZD{O- zJj>QTYmSOYe;TW9jTQ- zZ?*CpuRT?c-f|sa%A1beU}UZ!opS`~jUWR}c@w0Ik-36&%@L$8f($n0O^|Lz<_gk1 zN01v4nI7#Vz>VD`=kJ3xn> z8$Iu@`gKCSWpcDQ)&$StZ#SM|M$pe2GjiVR=p!H5&DG~VEdFMz3cg?-M_5J%C6~-@ z&NA=)e4J@etkO(lb98UK@n)j#Fw$8t6GFQjL64iVq6-rXvQAr*Tua_rkag-$HYIt^ zy;kd-b3T7WlG?SVP`O$*?OMEt-J^2J!98q_$~iwgdeB64TA6Abo!9)@$Wn2fHttn9 zr;T|k=d|&ViRZL2&A1S4OjmK7Htth7r;P_x&S~Qj6VGWQ+qe*I+@<0;ZQQSNP8$nV z&S~RO6VEKEyWQjrH#yTy&N5Q0sM)S|uB)BzY8M!rV+AkD$1l#uKb((Wl8=8ZAHURi zG0tVK_HkFc+|{mewJTihldg89t6k-4SG!u#hiT$Ar+>mmKSO)U)S`7*&};6sqI5XV zVe3qJF|$t>!mf8M>u#TME$ePKxRw=mLY~>OpEY&Dn5&JZv>5wyu6C2LymuCK9zMxY zz7)MDF_!8TabA;DEIzLxeE=>Nj7!%4jI}rQDY~!v?NRhIC~xXoN=G5RlG4%kIPzt= zX3+>=q(3S;Ch-9kCniaw48u09$2gx8@!6YApAKT~u*YwqBWB-vMdh4*>n&5u>|4*f z$rp^w75_yQ(b*SYS2-vCJEoS2|B{ipLT$?tYDbPxyG<=|LSJ^ZuNs@Hg{>;4)7kAR z=X7?bsU=!?&DFkPY>rLz&3ydZ`S@M=_;>U1d-Cz`<>TKsKKPng{)}QT9nSqT3b%3} zxRfh+zdB$VACv2Pwm&t;CgeIsA5A)Fj^=vr;ix%6*PP3HQ(sX5=aJUA;eTzanT7a` zkyoM*_6c(G$28xXGET7XT-^7@iN$l$*c{8`2jfNQAB}a|`qjn#W?Zh>`Q04J(cU@Z zMSJIs<+=1){fX*lp%JnE#5&desp0fizHcSdf2s7J`m}Scv~jOm z*4VUh^v`nB_tGBqeIS3Qzs*T$`tu_6y`oorze9b$cG^Jth?}<#y)QRky?yPcA5f^z z&Z(cD6{WWIZW-%MRlA~}cSWDS>|$TXzCGx@NWV3j%27{B_|l^y(|z&2+TO%8>Tg>g zc`yA}jQ&%xYSMqT>U%Rw7PI_WgQ&?`)x4R5olF^T<_%6J&YRgQnDI_gg}wSSGJ&)4 zmcM#Z+UpVNeqVY-q-xBoe~z3vAXg3Av=f5mZ_`oIOK1lEq%huWHSo0Srj?-|3Gz3) z9EGS(%Z-~%FQOR{I8UY1`oR{3^##r;&2y!GE+pm(Q>A{c>r55hBV+kYQBlh~S6HHfAP_QPSiNvL8jay4h86^;r_G=y2-Tq-c+liW!d+rPfbw9BQsu^iEuL1uE*M= z8l|t);@R|4uOl^(T0*5dsZ>do%226NDs{a|C8*R5DpgvgI;&KoN_A1GB$eu_Qe{-C zn@W{csqQM3tWrHxDn+Gws#H0Z>ZMZURjRj2RZyuuDpgUX`l?i_O7&BzN-A}uN>x^= z{wh^Pr3O$c?L%*7GdgQo9Vp{XJw-n2CY8+0P>X;kH#3o@E{iAArq6-KrrqrI*|Buk z8)+9&pm%5EiAibey;FuzWxWLGBh9htN!r*I=y-K6AIMTg(ypb?tZ)n;$DlJ4pasrn zh>utHM(Bcc%5GH^l;8x3p+Uh362pRm6C{QQ1t&<12ntRt5?w)3#imcGs>5DA%%R@Q zanz-(+gO#Lq&LYft~#l%Yd=35@y`~p`s{zzC8Y;nkBY^5{dR2?K!s-Qx38dlb?+1o z$>UNBH!w_DE}?7l)#KFzx67*#YEHZXFC~-G=Ii=_k(A@|D5zuGJdNY%lCV8gK$nf6 zF%_j;U^snKKQ~qPIQq+!{H3c?uT(#6n@UuVNKEwFF{-*9r@r%{#KhE8Yp-S3R3*}m z<~i3@bum2zKKmuL!5Ywe0-Xyr`n3Av=tF~J?PLzt)a$jI(|Y+hYi$%AtAI0blh=Fu zP_N~ktG;o8tmJ4quKY0N)i>>{D^IaoDyp@@2@f)gZK2L&fcv>NK7f?v+L5>Vj}_%(aj)mf!2oKu006e!wGRkI;{6xXQkx6{>u%ntOul&^$Oln7i)&M|*cD}fele1TTX$Uqxr zbl^HBw-jj4Y1)C?(a>T7Eots!oN1@7M9_U}Ag>Ne2d<&g-YE@YEuR^TO*hNf^cE3; z=D7~4KIns0A_6V>U_+{zV$OB1<({fE!2J3u9cjFx5_FN@$whQAx|bnnqR9s#ql} zh3c2Irgb1>mE&|`R(Y_3KBgXxvMP#nsz_H7>B^i=$g08|M;{&@n^jdDuf}P+A+=rI zo5;t<(MJl$((GC@6BB)rJfvLT?5b2;57RqEjn-B-D84aeUP-CAs6Zn^R8rPD+JB=e zR?B)?F)?esLcDK()-&vjXT7XgA?p==csoJw@lkd)3Q(;GKS%QIB09>hPKt#tllN9e zpIr4t+Eu7n+QYhID2e+dceOqpuI|mW-eWy9TNb-RRVPt~)L{ z9h$4y>h@HdZck1SHtBWHe7HA3>U6FL9=BUwN4f&KP=_)b)34)mcTszi@qiB4RiC6`d?KsQw)Rf*JS`c*EvwtMETlOgJ;w5;>gU8W8?fEx?e?Fm7VkAv%7IQ)z=)4S~@_^bA*oMI#Jr@K3h)N9H$Ir#k8vPCM=)4 z2p^xkydijqJR5TQbB9ppGDnE~PbgZ>_pIVN%*^LHOdo^*YOw@L(G5%Ib6wY8Wz%|5 zAH(?M)ndu{uu9Kx>fEF)$HRVg_4r`(h98l|nMmFYy*~Y-!%r6| zZ(?G%pmnB78dIHK;SWW?8YW<3@HIjTy+(M6#!Ow#br12zNAe%5%~I8l7O6gtKIuI+ zlU~=yPNpkB$z1z$te^L1zuuqy*q{A+fA$CWXMaV#Kl}CmOoz?>On24$vBy(3^=ZK%CJjBQjs zBhngBpKC8cC#sg3^2n@og@`O$fnO4-8?<^|KsV@SG~|->Ya7F}(&+4$w34!FGJRP! zn2}jF(Hl|HO7u=m3-&P4PNRBRH7OtAouZ(h!o3mnQtdW6L~om@zDx}Eg`1_l}9Mb;Elf$n~a2+V2UWNs!CROFt z$>Nt~oFJi28w*aXM0Gxk+yqZQtO|lBwpQIcw(?lC66uS6E@4fmU#DK3M)exkZ>&tD zHHy9;uM=Tap?^>%qi%$?yOzhQ(tZ565o3n&_LFd<&!V45TUB~?x8~mDQ?ECyD(!l9 zpkZ3eD1YKQ%C{O7xS8_m%S%^4@9C@PUrnLRg=!5fdM`w^-h%#nkY2CQ3kr)~eOROD z;`NbhOaD!Xv8+#sQS_fGtKL;qzl)*XX;kklUPJ#WPtU$wW({Rjp2As!>6=Q^YZv;W z;GCoPU#ubZEo%V%=eI^Wsj*J#ZYMS0NkufWtdk8@jXkst>C{0==_sDpE$ffh)X~zX zgRZiZDqhZma&|S36+{2|t%gpjos)XRNv*B!u^yuT{MHU9^_i18>!ga-2$oB8QZ1d- zO-?GyNiA_wn<=IHvdc;RLa9&aKfe`c2UE2vl}!Ilw_4J7^+oU2P^t_4=eHI(sf|u* z52e(+#9HNQ21nk@New_M*1DTg6X-v`HIKgQIsE`f{nmabb&gVcHp-_3Pbd@6}5)=mqjXbvleVtuo)-JYBn>4S;yu}YHKT-ox*Hmb3~Z! zY|aX^gH0s$Qhlj7JK4~W2pqGU4ZUIPn7wQ|3A2xldX=fZRGb5B0>T_-bFVN**en(1 zI2-yGD4aMa*z6VNBpdpJ%1)V6Z0K)*I_3-Y!-js%#xdpC6r(*}eW_VZWm8?4 zs%+{DL%)DReZE?lbT%2n)MG;*@N*(JWOJJ^P1w+9k(@Hk*envJ1snRbf>Wjq8~U-Z zW7@O%T$l_tXNBp)CSKik=u3^X2b=1`^kGA9=s0Eiv$;W-L2L#KGlWg1FvHo*6lN5g zCBlql^NcX#*}NvqBsTkmnabvCVY1o$AX~KqH z;X7rTu^A{#3pSa;v|)3fFzwka6DEVrCSkg;*(FR5HlGR8hs|kW`m^!VGqUg56Ea2=b{!faquS(r_1Y74WKO;cgE zvAJHD?Q8}MvxChTVRo{aCd_U&bA;K;=3!y>u~{X|0XEMIbC}IL!W?0YiA`%^ zwzBCW%r-UygxSt!tS~#++#}3RHV+H4o6S05_Of|dn0;*C7v=z)Bf=bJb6S`qZ0MsN z&iou_LvJQK<^-F{!klD7KeThooMJ;iEp^NpHob*8%Z5I);gmVgX0k9B*~}5fic$N| zIzepO>1FnHob*O zXERcmdTg?UX~<^2FiqI35T+TM&BC-`^R_T;*nBEXdp6$*lfmY^FkRTh(T|ALm%37V zu&E$SA2wGA)1OT{VFt13FU$}&w+l0z%}ilNu~{n2ST>u48P8^yFq7Eq7iKD(uZ78G z^P4a;*jyB57MrM&X6$p>BnY#BO>JQovuPvD5;nbrS;l6VFe}*HBg|?xPYSb+%|>B1 zuz6RQO>B+|vz5&s!fay`Tgr@UJDXHtcCe{0%uY6KgxSremoR(T3>Rh}n<>H^U^8Es z!)%@u<_Mdu!W?Jwt}rLqd@jsMHa`nji zRr}8^!uZ%s5GI<;yy{JPjNN8a zOqg^w<%Oxorj{@b*<2+|6E^LHX~w3nFfG`O5~dBCyM$@a<`H2s*sK+%3!81i^kB1F zm_BR{3)7#?x55l!^S3ZV*pyOl?_z$2v#BV|C^n6S8Ox@FFyqP5O;=&ou^A=I z1~%EkY-01EFk9Jd7G@ipkA&II=Ak!)%@w<_Md&g*ndVYhg~X@u)urj2@n3Q&yN$Z0ZSfhD|GB&axRO%y~9bg}KOP zjxbi7+JDvv<74xNFwty26s8E9&xI+@=Cm*gZ2lFd44Y!=M|>D*IX0DrNoCVWn5t}U z5XNS6i!kYI?i8jToB6^tWV2eBCTw07rWu=$glWO%gfMN`To9%`n_}wY_!w6Pn`**z zVbfHY9&EY@(}&Hi!t`e|MVLWs76>zh%~Qe*XY;Bsqu6{b%vd(x2{WF}MPVkfDWQIi z0^^#>riL)tY?=u(gH1PKX0aJ2%v?5E!Yp93NSMWJ)(NwO&1=FeWAlkHE7+VAW;L5j z!mMLcM*RtJjB5j%`oe5tlOfDjHY0@D#%884+u5uVW(S+sh1tnwzc9PmoDya)8-E4U z!+mU0g*m{csW6AxbP(nUo4&#vXER)w6Kp04bCS(GVNS7GDa;u*FAH;)&4RPl<|Vq&_w^go$QztuRH{^bn>vn~}mKu(?Z^GHjLzQ;y9>VN%)b5~eDf zBf{8h&I*&xCN9;Cq8^(n!Zc*lRG21gx(U;a&1hj-u$duD8#WIK)1J**VKUfk6Q&EB z_k`)e<_lr^u=!b-{%kG@Gl)&`N)~^q`{@uim4q42rhzb{*t8L5ESp}!jAt`Um`QBz z6lN-$*}`PAStiU3HXDSQ#pVrR=Cb)nm<4RU6lO7-pM_b%M*p=6{VcJJO=4v;8!OmU z6J|A=D}`Cdri(Be*bEb96Pt;`Y-KZBm~Ctx5oSA^wZiOR^MWut+3XT#H=8en*~{iP zVfL}{RWTzyz^0TihuKsU<_Mc>ggMTpvoI&v+$_vVHdBN-#b%x`XV@$k<}917!klNb zN0^Ij4hv%yRr}BP!uZ&n6DFEXWK}cvB5V?bDbA*fFbQnx3sZ(oOJT~f=_*Vro58|V zWpleQHk-SINoTWAn0joU6s94Y&B8Qc^QJJ(*c=k31)HCRX~QO>nwgFEY|0Ch!KSe= zUD&h}rU#pW!t`M?QJDU0<_R;1%@e{5VY6A7;cVU!W)z#xg&E7{7h%S;iKuSIHHl3b zVWzT47bcrcOJQcP=_$-CHn#~gm(4U`7O;6xn8j??3bTaGc43yW*(b~jHs1=fn$2Ir ztYZ^j!;EwTo65p$V$)cdt!%CrW*eJZgxSvKPGNSic|e$*Y@QNkH=Eal*~{jDF#Fj2 zAj|j<0b!W?IFwJ;~xbP?txn<2uSVsoc3XV^R-%vm;TggMXVRbei& zIUtM`ulAo`h4HZ|R@00knoVV4im+)QOmQ~tgh^o2N0>5f)JLb)m%4YCWAlJ8schB@ zQB8nuVS2EMuVwn&hfOtM`m<>z%pf-Xgc-snAk1(!Gldz&<`H4Wve_cccs6^4nZ)Kx zVWzVAU6^b(MbgbEX0WL&%q%un3p1C^jlwKoGe(%jZ0-?e37e(DEMv1tm=$dH3bUHc zcfzb=W7Rf&-oPeVm`!XN3$vBYAYrz#886IsHcN!r!Dh2CJK5|NW;dIo!t7=9yD z$j}X@wDo3G<6>T_H5{g>^##mWm>4owbD8OmIR`V>F-4=V=EzH6N?XY=s~l53x*5mW z=+wF*ntq>_dbop(?sH2rYFzsq(=NIrnbcT5PbuiOE4Q^Iz{&?rap6J!^MzyHg*oY%4`9wY<{-=^$9x78cSUf1zJw|5nCD{jj8$>W7MOI$ya?0S zG23BUI%XG47su>_8RD1&FrysvEzCs6`~b7aF&AK#JLVG12FG|~^(bC)OeD;^j){jk z?3g5&9~@I2=1($eWzye^QifJ$O#R?GtPWGdF*RZbbD0ig^m?{qhZT#UD{dcss$O4% zwPQ1LnfkGJP_0=FEbBV@ocQD57Gej=?`n3b&9MwYdhev7vXeIEbGM!mAjQ@%5mYY5%|4hOTrrQl|87x+1N28_B= z$14ri1e<~x;4R=Z@L_NZxDPxH#x~Y*Yl8K_CSX@^1UMO-2d)5L1m6e01EZSg_?5xd z;6QLBI1#)Dd;nYut_7b5-vHkS4}mAZU%^XY+*P_CWx#4+eXu#00rmxlf|+18I1hXb zTnlam-vmDdzW`5ye}GX-gos`d~}23pfxQ17?A9!DZkE za69-Rcmj-Qq1&qnUIX?8$AJ%k8^O21!{B+aOiLXv9c%_>fc?Qy;8bufxD4C?ZU^^* zUxKH>f5GCda9+UrU`KEecsKYsxCwj{JOM_w*6~unYrw(aSa2FR7kmtS3fuy|4!#3^ z0v-o{2LA?Q+UWL^z-nLvuqD_P912bW=Yq?@XTcrdC*b$s1u&_tZnrMj2D}BF39bZR z0QZB(!PB7kIvuY(*ci+JZvnHxC&1^xH^7g;W8g2~zhG25-A-|^0$2xZ3HAfWgEPS; z;CgU7_#t>4{0;QA*X<>PwZLZJ4d6g90Nw>Y2(AX-2M>bB!JoiCz=RIE-FjdKI2@b` z&IVV5+ra(ccc9f#$14Xm0Xu@Xfp>rl!FAxr;O}6iPC8x-@D}i1@Nw`R@CaBmL)U8p zb_Q<&v%xjsW^g;W8~g-33Z4Xi2mb-1uh;FB1j~Wdz=mL3uqQYK91q?DJ_xP_Uj+|> zzk<;>=yuD4^}%*vUvMOt1ug`i2HymafPaD|JL~v$!7kwK;B;^SxDI?9{2crR^mWnk zlE5p#)?hzyEVuxC4tx_l0-gg?y6U(M!4BY1@GkHPa09pv+y#CD9s^H-7r>Zqx}8L@ zD%b#Q4fX*?gR{WZ;2!V@covN7uH)ALuK@>x_khoUuY-rc)1beHj#Crt0NxHR1h;?( zz(2sEJ$3zb@LI4RI2~LKz78G-tzNo*GI%xE7t99dfRBJ%z<3N*SApBX@4ym$b^SE371$rV16&9`2kr%b1dH_3aq57r zz?;FD;M3rT;BR2kjk^9--~cciTn)Ye?ghUA{{~C<*Kw`@Gr-~CEO0rv0ellY0R9Ae z2IzQ|z{X&2@HTKVcrUmBdJ9H1WpDQfNQ~b z!Be1ru#S@s-T)2)CxG+8jo`=NSup8l9j7Tc0L%uLgKvQQ!Qa55x9Iv+!KPpba40wf zTnerSUjz4p--74CxFMJ?uo2i1ya^l!&IFf%Tfp7mXW&oZB{2S0-A)Ct0oWSs4h{jQ zfRBSaz~kU0Fmb4k+W^b}Zw04;OTaDQhv1K(f0&L_1-uIE42}lpgPXxm!C%3s;W|!v z@LF&XcssZN+yWi|&x7Sh=r~Qm&fpMm3b+Vd1#SiRfu}+LZRi(R4{QVW0mp+2z^&jR z@B&zFq>gtjI2@c0z5;#=Mvv0v>w~Sqp5QQWD!34Q27Dd-7(4;~3C51b_`oZ`wqRc{ z6PyJu17896f!~1_!4hM1{HkD6Fax{^91CWH3&0iN2JkiTL+}{*D;N>b?Ue>=fLDQ? zz=7Z-a3Q!3dyA)_5{a+i@;aFFTvBG?{;0k2G|Z90p1Tj1#SoTgXh77 zaXQYGU;9_tK_z8F( zEOv*kp9Z!EZv*Fmo4~`MZ-TC8gB`)q;5={{_zd_8xCcB8eh;1lBPZ(k31Ahl0oWSs z4&DN0g7<(Af~&yi!MDLrz;D3c!H7w^{Ze2RumRW_><-=nW`g&COTgE_L*PGPwL5h? zZNUII6MPmt0G2BW9yc$L7b!M@-`a3Qz>d==aSeg^&wda`uf6fg~J0=5VHgJZ$j;A(IO_$7EA zEHO>TPY16D$AVMA`@yB)bKtw+SK#lUe>&zDYzp=UCxc7Dx4<93;@P@>Bd{Ad8oVET z9{duFxl7l(1{?#<2A>B{fJN`tnW@Op3vco(<=d>#A}ya<+`spDM* z-U3bl=Yvmy?||Qf@%QQa4Z#86Bya(^0sIX79kgfZ`n|#X!42Sk@Lw?geqBBZtO(Ww zuK=5XEx`_8H?TiA49oF4pm(I1Ic4oC!V*t_NQS z_k*8-UxD9)r@=o#>jB-bSTF@l2d@SDfMdZ~;M3qv@LSMYpyL(?D}eRE4Dd#91egUr z0og0F(_g2%xNV2Q=L zooZlHFax|9oDR+dSAbiZHC^!zx z2IqlG!KcBO!S}&q;BTOR8O|SA6TAv+2lfKTfHT46;EUk9;9>A2cn*wwT(?&qYy@5p z-U?0t?*o^Do55Y+7vK-zpJ2)5x}7wz6?hXk5u61+2EG7(03HKRfq#OYCv^Ncuryc^ ztO+&%uL0YEUBUj~FfbFG4lV>&f}6oT;4$z#7_kE96RZNJfmeYo!LDFma1b~Y91TtY zv%&e`6W~VhMesFn4|ov#8N39>J*oR!7OV=^2CoELf?dGD;COHfI0KvuJ_IfUSA(0u zo#2PyA@CUZJ@_m54;Zyl_q!Na7OVuOgAKuE;B{a(Z~!;(=4M}l{N)4>P9r@`031K?>edadqPIj|ns2J8cl0cU`V!PVgN;9KBl z;3?3vPPdZ?)&^UFeZkS-UEm|&GvJ%xm*8Ju($hNr6<`N&FgOW(0Ne=f0r!E2z;D1` zzzbmHdfiR}SP@JEn}Qv{KHx}j8n_5t4!#J!3w{lr17n}j?Uo1Yft|pc!71Qk@Hub~ z_%-+sn6yF1tqZmT2ZNKrMc@W-7x*n0`K*pp18fft1@8f$0AB?Ug1>?Z8+DupU`y~u za6GsG+z7r8{s6{3r{mNHTY^2o5nvX$2wV&91doG1ga3lXHtF~k!FpgTum?C6oC?kX z7lX^er@<}YtKcs1L+}vz9rzpg57AquS9bBux?k17Yrrnxt>83p3AhFP2s{d&2LA?Q zx9Irg!8%|ous1jY%mN<*p8;P5-v_?{e**so;rGT}-j^GGzCb$aR4t@ci0WX53 zw(7W5!E3;-V1IBJI1!u+t^hZIJHP|rci^93^b5MZvS1o`HJAYo0LOsS!G+)|@CEQ) z@H6ly@E@?)i@M!PU<0r%*c%)HP66kEPk@`jx4}=r@4>&oxR-Q$<-xjOORzh5D>#wZ z!Rnqplj*UJ5f7G4v@X4^;v`xLJ2lh5Yrz3v7Pt&t5AFoN1pfpRcIkNa!5-iwa4Gl( zcpQv)N7t*yq<<4*pURi8I{j=}!{}eD7)%^VoJbs7qmp$mF_XBEIH`uu8vl#>y%?W0 z3tUFbp!`bkX>bd1ES29$e63Ee?4!gE^!qK}gJ-~V;6*Uv4E?*6b$ex(0ILzz@5NjR zwgh{C!@!B)Z18b#Blr$@82k?W2Q2-oZYQ0XNbO$@UJni;s^8-o1x^9)0~djhf*Zis z!1uu~!PDTsVAO9qerd2eSQl&pwg$U`gTMed5xfVS2QCAj0bd0_1doG%fKk8e{=|dH zpba(v+kw5o;ozO%Z17=l75FUpD!3c`4Ezy14@RHW{V4-h2OEOT!3?lBI2^nK%mx>N zE5R+`E8tG>Bk&vW576_6?oR?(3v3E@0SAI(z$xJU;1cjDa2vP}JPQ5@{td>T)9u?} z1F$*R5$p~Q0&fSi!Fk|v@LBK`a1VG0JOTa&djG^cfK|XcU<>dDus=8qoB-YpE(9M3 zH-c|~AAm=}Q{V+K>b&kxX|OU_4{Q#$1G|C)!O`HI;7ssA@G0;m@E!0o@JH}3F#0du zpHg6TurYWY*aI8{-Udzv?*`|9kAv&M?cm4YSKyD}UtrV)-JjxMWv~|56zl}v1l|r# z1LuGbf~&#j!5!cM@C5iP_zxKUH_jKB3f2ajfE~cz;6QLJI2oJ+E(JG$FM~V5gWw79 zchGZD_opbB2v!AagN?xUU>9&8I2xP;&IMP1FMzwigW$K|Z$x$9y9CDlqw|Si6|gSY z6l@1}1#bk0fSKSu;6m_ma5MNO_z8Fd{24q8dN1jI#e?O++Thh-2XGKL9-IlT0Jnng zfnS2(gBQRe|LS%tfepZxV0Z9Va1uBNTmx(UxKH=zd^r8kD~-w4y*>&1Dk>E z!0zBs@J^=RDn)-`ea}SsJkz{R1$Kz!qQ!use7YcpEq#oDR+g9|oTU zp99|jKLn40KY-^zug^ozcYdoVQS~c{sQOt2yaN3HY&`sX=xW`zrtxJp=#||QycL`P z-UmJkJ`27Hegqx^e*`aq#ps_OQ}HW+b-}h^Kk#<&UT`7!6!;Rj8~hCX9{h``f4^Rh zE7tF^mQuS3U`5adn}F@X9^fEw1UMed1|I;Ig6qL;;9l@k@C5iPcoB?>()}yRH2p45 z`Tf-I+Tb-{Td*5A02~2M2JZ%EfeXRMn11VNqFUdZbiVkD#6xtQzD3L+{{eWIcpc@x z22X-#z)QpqbUZFvvn)}SuS8UFY_J}974ZnQ(+a#E{zh;ZI1#)LT&U@+*A(|LXs}|*l)iCR${R#R@F%5fV_aU!102~62W}5Q1Q$Ci; zO$4WccY}+-CE%0bR;G#bD&>n&oE_k9@I&wuaQ+YUdY#IBf&90@<`cqWvPf@KuMYaAE)%vS1;;8l4nEc-qUoo<%W^u4AsK%>~t8pq;fww_5 z56ag;zA1Pe*o|rC=O)TGqw+(+ao}`t0k|A|mTBt0O!<~n|8;N|_&#`)Y096W{B=~` z6R%kWOa!Zdb-`=F>zO7_f68~FID?qR-%9x|S-%y!yLD zD*p}gYF|?MDzpzNj{jEkR~$bCul6f-{1SXZahG;xEK5e{2BZkj4rABQw%HvRsw5)4Zs%Q^`M3M9fa}r zfxiU|fYZVG;BxR;@Fj2u_yITtaStGW8oUG+Ev5Tk5v&0=0GorIz~0~x@OE$-I0sw; zt^v1zZ-9Hj&%htSzri92x?knNI$(3K3pf}Y2i^ld2rdIRfUkmk!6V?0;GbY5{iDKa z-IN3?fpx(qU~BLOupf8}I1;=aoCw|x&IKO^p8(f`TfsNLJ>Ws`ICvWT2aHeD{jUsO z1$F{&0Vjd8z?I;0;LG5f;QQbK@F;i^JPUe~bo<4@3Se!p8Q2c&2KEPsfp>y)z{kPo zz*oU{!TsP7@O$ttFs=;N6<8O%8f*vl0*8SU!27_3;8JiixDz}Co@Sc+k+-bJ>PPFU z2-EoTlpjdGI#`EkjyIzG5IU~zKZ@!;qp0o&ifW%8BAzcgQTY+%yMcYdLEtcO40s1P zm1)|&hw@`6&K&STa2dD;d>-5Zz7HM+&oE8g$YhU|NpVYns+~;H|JUes!6Z6fmX0fy z2W_x6coldp*a~b5b^tqry}&`>XmApk#WelAi}G1&{GfV1&l3Gq`@!9GTL`!`g@-^{y635l3xuz%QWNMO8JGVKGS&hy!$YD^}MU7o_7`1^RA+L-c?l3yNc?0 zS5ZChJ}lbbL2;Lo-vxdE9t73v4|V()@~1#`-j<3ue^Gt~mGh@)CV*++HB8fgb-k{k z^6Gk3>_o@cAfEbpr~2E8>&f>duXr;UV4Byr!PmKy$*b41_keT2oIfY_Ti@9FeFMDS zwYE_?_5Q+}#BRj*LHBa|QZ4$L8NGyh7fbJG9!7oz<>M*;74qx&xYzmt`AvM>YyF1& zHp-W>BCHF@@1lGXuVD^C zeiY@KQGSHZm${qrt!ReEbN()CH?97ul((wz_^e};zn}h!=2tq8@`={pmDTZumZzr2 zTGlAhI*am)UZTH)TQp9AQRJM$DysD1(8|9DDKc-Z*n$G`2`I=UFD+Bqs zZS?p5%T};fBVV5Kzm~0PRjsbe+m!#eY#nP8@>fzmKKUxEY7Kq7J>^r9TUk?)?@sw@ z^ryKtAwPohwUawpCy<{``9{e%SoLgOe?H}}P3~@uM}8UC?`^FU`P#|-tRu)jPsguI z9$+=Bsq4Q<`7X(~SlP&bLiv>B;nrc~zo&fPlc4n_5UubKk_!^$0g6Swj$qx^4BKMwaz2olk(M)7g*`(y1vTS zPJYlDg#2jAPfdQ<+J<~KoKzFP9r)@qTjoxH(1jQk5+ z{yD2^9bNwoF2B|4Bl5MAU$W*Rzn_jTO@77Nhx`%BuS$O1imt2ce?$42)|*y62E+x{lMC2={M0s|Ke9e>?&smYL zn-b?qrR!M5|AN}TGNq`ekH|--6!**!`D;>2dbW#v>6Fr*lOo?HCCQW8$i%ChlI+P4 z`A#Y2JTpYTZc0VZCggvl_PeE2@|+d<=#*-n)GKv7b-Z6n4bKpfFP&1$vq0o;PO0rV zAo7({uAsMYO#RzZ8hF}>eBG4Bp0UXPMe)a_T;fkvq9u5r(}2zi~Nj~8$4C7GWF}GboX>YKKfP5nwQekGgjmuOzGuWfP6VV z-rKWD-x}i?FY@zJ0-nVp|3b=G&vuc2@c(di=W#aG ze;mi}Znz7{g!?^rnSIW^GmVBsF_@G!gbGPWHI`IJ)>0-^Mi|Oc8AXvLiX@cn7YQkp ztt=@^*(Ei~@B6u*ueZ~8{(C;&_jS&>6L*%z8S%9Jfbxh{^!H(ay;=i4{&?xn#54BR z7OxXS?ENg>B!=4OSX?Sb*f(0dU5vC}vA9HxvKtMrAAh%a!QRp01ESbI$l@d7CHq2) zPl$2$trnjVFWX%O*N=BejJKy-d_|PlyISltCfY|>T+x_hUuJO?V~Ty3@|*Jc-(*a+ z*J#AY|42G)Ot&|;xKzxv7g?NcylJ0iafx`_{;9<=W0w86#RtS}ds5@;$FF6)W3OlN z2{FgsNqLPt|0XflKGEV*G0(ol;_YI-{kX*?Vxc{$iA}zZu~ENUEV4JY_<&eq?{4uC zvD7}z;uB(-{Zr-5vaf3_w;xsBneYlb-NluTe^|PqvC`f^`Gj<#@tM7!@7 z4UMh#qsoQS?Tl^q?56zqd!#!V-`e{rKbY`t`x51T(%p@{_M^&!r5hUi?N#pL{zd8B z-~oG~@>J=^jDz-$%I`@R8b|EK%B!X88b|F*ls8LH7r)vsD({o-Z=AH(yPJ=HI?;m>mXAlhBh=l|OPS8^2tDGMrc8aM z&|{9R%5?peLcJZfcGvq#p?;1!%G6g1J?SV?c70*9RSgYr%u&8E;lYkW%Bcwta~SvX z@oteeZO=KHDmRgKi02)HEKU+HILegU%Du7}?bu=2lf_GpE0*09V;wo|`S^6aJn^!F z?m|lcJ-SNQ6|XubTAU;%I96NSP)u}Ov^ZImI-(t}_pQWKM<e7p!PbjV+I0H=z@ z4!S$(wLMQPadfgcHT02#?oN7bkB3$`c37MrTIslAasALLN5=j9__2xet#Q<`c!2oA zL3b^sF!1c$cifxW|78i?e9B*2jCw4hDTO1F4@1VPt zUOQiYXpbY>>ALHO_BmQBPnFlxICQ`WbBMba-CHJnqFzmhIABF>G%^jY)f;x9I;nq&O^%7Ul9e)8V_IZr;8@euFBMp2;Jo@Q>H#uv~+G&re1!1;k<0=Q$-tRdUrk^ z^{Jwrvz;>a`JwjC5z5r(hdMgvDbw}mhwgXoQl>sX)X8b@u)Pjq#5 zvN#^<<}9|jeyF>1i86gWd@0n^c~rUQI{JL#QD=>weEesnXBb7!=F0T?T@vc!9HLCG z-=(2`&Lzt9`adJ|r1PROy?(zF8t82N2p^C71)(9%LCVxG2n~16Q>K1F=sD*BW$G7% zUT{|F#r>=DdUAus&ZZVOH^w@LC{Iu9uQ(T4+}tQ}9#Z~5?n{k{&T5bH@yIWQN}bIu zo^QPF9AWXtq3KS#Ybd?HKar1L6?)5gQF*O&Pch3`?=jwYNv{jN>nv72DSbuEbFNmt zC~evnIFBkFn5>JyQC3 zXovHV@&xHWL;Ice`tbg4!iSx7mrv@KN@oO*IX7CI8$9W}th`z7_V6iZ)4u%pebNQN z^UiU~za{!h&eay@2LE!NRd#Qn@6TOvHt)y1A>BFXaLrS$E!`_v(RIk;jG)g|?FoK7 z?R|rlU9Bz74OVrHQf?*pTZ752t;&x{4+sWbbhl1=elJKD1f#AZ<>}HH!F1P~%AZK* z2D4l{ly^#x2*zC5PjY`kdQ7mEYl?F7FX{Vp^<0OPJ4t5*8@j4J#g8ZF1{=GYD?goh z{GF~T%FiVp-`urX`Srx(Te+?%FP5GeY~yPDG#_u3^t-|Kt|7|*lQwPlxyqD(Nceu& zX60X{57vCZc8q$Fjs#xSIv$$A%==$B_Jh9AGV<`8} z$bL!i6W4g<66rO;FI<!|V`>7RppU7d#WenI+d@QCYE z<-lh8e(?#{apkCViTKS$ceSMV7r9jY?#foKpV&{inp<2dPP>Yf+si%QcE&Z);u3Mz zwZ!7(;+$)b#iioB>#}k;*_Q_|xN42$^FJ*;TU>G#DHlsG5P!RtC{LHJEUvl^S)45F zZr^j>79SBey60GYLfquuXz>|Q-F?O4OCsntMqNMt6(QUmEp{4V_aKWa8WHzGi>nx^ z?ybse<@3MENOM_sMLs?q?|`W7ZfbEYqmFx!#V15v_Y~zT^6{I*ZSJiWmx|lnzgxUr+~H0i&Bv$5 zmxuy)Q;T3|nLE9hk6%N&uF=BXPT5Sj zm3xHpZPE>md))Js@06|-ZsY!4`CjRQV0(A1m-u)+6TaU)NO`byccY7Yp7LnvhDKNS zF6GJ6xxt6rNn^O5C%w+-?ryBSTDq?Bh`XQimV_U5PgCA6-Oza4y;1pB=|ZE(eNp+M zv}x<(HpcStZCmJkeckPpeF^t>7hBxic-sA`a#-%BZIJtr^3BpCjc44xaeTZxqzjF~ z?gq-O68jK$k#Y~|s^OvTdCE^qo3@eeZOSi7XV{)|A5xw!U1&V#uJSS;e}3Zequg}Y zPWtowX~HkKyDM)^_(k_P<%7~YjnVE;m4B1oYrNz>tNf?*A!D4o&MSO8=hyW8p7HKc z%GAeUWBQ(psP?>s1=pFYVW$GQFxo*1K zB|RTHzauoy-CUXaN}&br5z5q83N3aoQKr69XsP?CrLPoP=B`n~$Ez%lS2eW4-BCFu z;Z^R5%C!^z!cBLRr1Re;oe|vNwoSP1+~Ak)I?4~q-3Wi>9;Dox9v|N3{#5yS=^4hi z?&Hc+rSrl&-OXR)usBIva2HwJQ2gO8vp88? zc5k(~mH6B3ntc6udEy^;E#=?k@!N~5?m-qO38$yb;x5ANIcjmTsOYIu%EzO=kMMdr zTAU{;dqye$BX<$H!L!ifRB@wckHvW++2fkR$D_xmhN^qoSsV`;o)H%3hr*tD7S|6& zJ-d`EZ>964dTdkqc;o>h-P79QBw>1nSUg`v$14_fJVh4g ziTa)?7RN((c-C5+A8P3N-QxP8MxGjP@bRMZ`WlCtc%D+eP1>|I^Gs82pKx=}TIK%I z4Z|%wu4&vqFI{Nd3lre+lIS( zp0YS2*wZsdc~hc))N{q+l}2Artr^_Y-ZtFdGtT0S;2_Ux<->AcX*}yWt9(T|BRI^H zK9l?E+h`x@p}PsvpMP>jaFl1fa&76{;AqcUGAJ-x+VAcZfGp?bW)xoU1%)#j8lGJIzP0+vrKtS!Ye(8ly^vvG*)?h zWqiDo(vOE%dpapQz9Fyk%u$v0&Ur4VD{p1;>yeHBB?0Hl9xU~HLZJy1_j zLGO>_p6I)LyqeOc?S$tp<=WDPwv(QY%B`e(gidG5HEg=;>XuoFHdJvr=#o!`o@=fg>GRq3*DMK~xu zH(UwMmR=C{!M7y#8{vkDJ{fKAoX7hW!XI$R50D}6D13%o_TJX{CfEp3n73LlhC ziqwNoN(UnK;fvDAkp}QpX%T4%SNu+XJc=}it4SXVH-RJ4r^8L*xO8^pF1W6AUZgo( zD1B?B1$>WmgGg(*vvgtP9{3UI)8TvJ{?aWY?cpKP<>C9`(bC()55OhTNs$NPY0~W@ zUEz16lOx^XMbcd&J>V76sgXzF_0olr$KY+!r^9{Vz0y4+ec_|hd66gKv(kMcPr>EV z4I+c!3Onie&%ifI&kYZS)1(JPhQs;N!y?bajig6Mis5$B6C$s|J)~zuO5tau=R~H% zFH4t&XTwvZmqgxy-;w?#G6()R@%Z=PFQnH*-iN=IULTnU?@2uV1Ncb73*bMcH%Au2 zu3dCJAHp|Ce-l~qAO8?p21n(7DDvrld@{1;KfV}Q{~!Mw+4LVLMYqDa@_1_^-@^5z zZ-{;ex0F5|-UZ(;T^8OAKb-LQ@IdJr(I4QUnnz22AHKd%k}ePL!Q;!M_lNhwi=~qy z``|Uw>m&Q&uM_=`@IGlH`V)LS(I0~Ul-?XU3_EwrKmXCAaAoP4;S;bS9gm)bP3c>r zzr(jn*NC2h@6_B%dVKi$-d?(X^c)`FMS4l(0^CEoar6(kw{%(fPxu+>X3@*=^V0W5 z|Ak+X{v>i0o+f>N)Sh(h zZ$t~=%0I~ezR^NBTe?T|Zn%MT?`R9So%GyrYxn``!)@S4q~}N5!ULqg54VShOP7Z` zz%NPf4|jwoNGC<^gQrQ)4BrpWmQId5056bU8tnuxlTM9vhCi2H6X^nPmOdSR5Z)S$m*^|-Iq8ehDezy?&Xl)d_g?w^os`+| z4bnHH%z;DFBIN_vlwK8G0^cg#BlOe{_tTqOFAdz2wX?HPRcKE zp>%_k<8V9a@!{X#ZqiF4r{I2x{R})Zv7dt{NE^`$@C@nw;XmN_r00e&!OIelzYK4b zJ{|rW-Ys1tS`Hu9d_nV7%@y~{pASj7-iM{j!vErU@r19!1=2O5@*m)+uh&{7_Upc1 zdVR!>y_a-(*a;7mHli;01?i-S2c9S$k5+)+mQIdTgcnKQlTry@C7l}a!CRy+hW+p! z>GE(D_?Wakas&K_bW)@m>^eYy9+Tm!(#eq;aEi2u)P(b-QzHgkAl)(&f?G?Mhg0AO zrMHJu;oj0okxY1qbo)paJVrV>5{IWscZuY{?@FgeYQY~#mxXVEzmV>blK&q+oKhd& zD)*L=#_%rbJ}FJ%AEmd4?}mSo9+1)!J}uoo(i*-bJuIaid{w$jq&-~WNBQ-B%KdN^ z=~q%Z!6E6EkGJSkc%k(E@U!qr>7>XIc$4(Z@KAV{baG@Ed_;O_ zbU1uQIyEu^{zrO!WF%baCp!Q0a1CiAIttE^PKvw;*Orb)N5hS!lOr#|ZKUr>83R8k zof;Vj_m;jGei6Ve{@Db_q@LTX%>FwdS;eVu)BJaT7gY@U)UATsHa^!tDQ@TrJ9$Z^GHL?(HB0V6o z=s$ivWhvZ2?yI89;fJJqL_dX#q}NAR!2_gwM?Z&0O3zAJ2alD0I=T^_EWIka34T+$ zM|2DPzV!O&Hh8IY@8}MAwe))_JK?XSKTg^IAFoR}3V$#6Rnb%MuhKoDXW>7k*GDhF z6%Nt)F2OaVx2OCCXG`x(p?{#s-|wp@eKA}SzDwF3@xkq-*GDSD4@sAYZ-9GC8_}xp zAZht}4v&(KN0Z@KrIRDo;Wwo3NvQ$9Bb^!v!i%LZh6TJ*x;z|)|0ivaMBp9LNs(0e zfOH^|1|O47j%30Yq(vkP{#QCR5`!xpra$j-I9a+poCl{!Zx7dkbEK0Zb>Mo^?IX9s zcScefNyF_k>yGW--3gE}22SghE$FHZ{2@jTg`$#kR1?jQTR`5jW<0-A-x1?J} z?t$ked@sC0`gF>D@c*PQr*wh8k#?s(0`HTqk=hSFCLK?G2L40(_SEO#3PJ)ggbpO;D@C@l^Q)j{R zrC&^a5B^xXZR!W`=h7W4-YWe{>H_SC68j?fqV&Yn#jxXN>X*XR68;Fzl%AgYFKeGObO(!HO!#x`lN0^|E=zbVyfEQ)@Mj6Hhc_j>0sc;UUg}2p zC+VfBU%|gif1bJnz9PLNbw6C~sQh@HdJxV?_y}BI`bg?8mEN6WlW${ebhkSB|EDW` zYVnEGla;n9w@K{3S2|+xxzy8@E-QDE`(LSND~Y*$ynfPA+l5Mb%0s11+r>&vEq0{+ zQK_@?^KuW^E>(I$`IUtKtn`BN8`6cw_jTpH(#u6n?+409rSok;Fa1^=I^P-Ts7-jkQ@$ddBn*v2DZuQo+*lE=DcC)yOahrFH#k)m4@0%8%Gw$#%v-pT;F3i1dngw+MC`YWv|>{3cckWZShBGW!{;}HRS$T+8pnv7H>$K z=iP1b*0hD*^A_(;TjH&}kgu2epVF3jP31J{_tI8+8!G2WA4~hp+upKY605zBDd#1g z?;0=t_96QF*+4$tw0-WKpxj3KblMl*ca$HHF0`%lexm%KbU=EGa<9a`-ut6+zr?=Y zdrtXT>E&XBmwt;8osV29HhODXoNxP|H`n44@ujzk@{98EVPli`ev3=RSKdArryE~WtpNewtG>dc6 z|M4zTZcN7yUiEIUSpIu3-(KYwa$jk7 zn(s&DLDH8*hVP>CC+p=kNtmPYI zac;1-?-k`4^6{P0>-y#>zbD-@{SM!1i~FWG^6gSyl{o*MzLOT`2JiOSKH}^9TJD8L z3tzIugVJ01V#+(@Zrbkg6)5kMUTU=QbyPkkyY z(c+2ekNYYvIge_0_gGRXpKqZt?8&Cw&hoXUM)+@M+&bi$6#o?Nwi0Wx7kMX&dirsoX^Fg|-qO{dO)oUK{CBQQ~`AxwCYMnBaR!`B7=p_L^_H za<5y+6Mc&;{waNuZ=-U5`S@SbC;QGRKO=oUeWuU<37?PrPx@?Mj`A?+q>T4{T`jJj zvDEjf^7C@f%vj}{ZSh{?bKgqkadOYiSm)bq@ogEKeCL!W$-P%_o3FwOK0i4lxWgB+ zxNmT$ueQax!S8)7l<97%rfsk9A&Z-2?DIXXJVPF@RP6V?WO0c&;G3>ISMG(zkG>_! zi=->r4*GT|f3AF1`77x&;-Js-DPJ%7k~rcETD(d8?5kyQsrc2`)Z*>pn6Hb)CE}#7 zzw!=wyxrnAU$JFBAWr+HS$ssC@h!IaggEb8ue?|G^53iY_E9o53VvAqRsOMj3abWwJCy$?Q z6#A2u2TSMMn)*#;y328)ahJcq;&(He`8z0&O7t!KMapy+kujl<7V$)PE(tD5JIikn#cPPcqv2{i}IDDs9?2`BNB^ zy^Ftvvh5^Y&x8K1%3f(x`YGjV(mOJ``d?B`lm0%Vn}3FKe!|`TA1dFKczjR)M&+&*Br}Nk84E zgx+6t{7vF1|7nZ2i-CUE=hye$Vz6J{0u7HpB8K{FS==mbgul7P2WyV!9DE< zYtHtY7MEwt^%q!t&UoK{zs1hX1^&Jkw@q8*A8oNWbE$utGTn{&#>|iXt1YgPxy=8g z@|eW+E%*On@xhua{Z-cT_0hgvtnn8qmq>3CYyHnzyj^VYPf;$F`#IxF|3c-N(shk3 z{&mU=6R-bU{ktuWWN!1HP@X3rpP9McZ-(Y4LOEzxbC}d_w%{ziM&VIOeam;rj8?jT3&;;+XN9zrf;J#wmXXi#Lfg z{@xaE7w7%YTfAHR;h$>p5pmhSz~W|U<^By8AFO%Rzu)3>hBI)%;sF*W!%eO@YTP?i;Kbpx@3(?@xMsZqNvnDxZ_?m>CJo zw|J$I8u-HEUcrpOZi_R5*@53I?i-8;?EmBA)A4eHHwUUKUzUC_^Oit8W#@15`$L)a z14R}O&MXW}RSw9#SFlxJfyJXU+XU8GoDsY?@Pow@GCKxNS==}HK*0GWUk@E`MrM~l zO^fBf*9+uXJU6p@;4Wn$AHOv7kw7nHQ+iEipTH#L+oU&%fr0le-Yy0Q)+#rV``4L6 z17|J%Df7iZzfF8St>hjyUJATmaj6&^SYdIxF)pyx;+XMD;IPF9#P~q<&DW1t%P0xt zD7Tl#KOtTV^t9}o#Kgc5i?@r?zyym+#Or~L7Vj2s1ol~cM9c`BRqiT}-z@E|K+;!y z{zs+d>uDgW++X^fF*i_8`B~|{D z18bG(>)~HBKMNdJepl|lWv&V&Z{h1%EG>c?1Ggxzk?tJa5@@TuRr>GDZv*|5zm=|J z`#vyUd9QRpx=i_~v@`36z;fk368ql324&Ch^84>u`vQBFZ;%eyehi#ajwbw5!2UH~ zU!HW;tb>8-$_=DzW*rISDK|^(zXs^v_0iwg2NL~>KxgG137-r+q1;pT z(!Nc)VbqzOy z`qr$Z%Ht9qleoWc`>aZp7b`cGd$+8rl{c`H-j*JbRlV}p%AZQ#Xscd%kMaiPUzB$! zpI1Jhyn8!c{}^@u;Odoa2~VmqPX2bd8c}Ka=2ZJQc|P`+_P}ZS^IsFLB|RZ41UHbL zk(H+P>DZ|^ZJ99jWm#D;_c5)HW2gRD&0LuJ`B}AL?(fk02H2@TSF-@7ennPunEQ@e ze;;=0uhx73rv9s}o-p@MYW-8#sSgAPz|knb4{_fxrnEIUT z<1qJUwf-D->e~e`z|`NKeHrHds@BUJh9~|$^WR?)bimY~%1VN{ucFMa596|Kz)t7y z9J~>xzFBq<<~~j9)3H-;S`vx1p z)c4441ase1>+ix&eQvNBOnrsymN55iwZ0v8>TeCUhpE3Y`vI8yZd(5^cIpQNd%)E9 z%YGc@{zFH~0!neTD22 znET0EUy7aj5y7c2^~17f!rZ^B^>eUOKPLDdO#Qg*#W44uYW+&=)K3nsf~lXDy%y$v zlh$v>PJKpj3ru}^);5^?@3ej=cItD3yJ6}pWbc8w|559I!p_%!2X&9G!`uh8USOwQ{(c0Q`m(Gr%zcX1r()+m9p*j*=002NP3+vqVeWHa?(?+1 z7Ix}C2tm;WN$?Js`Y*Ga!rZsj`gYic0v;4pVzF%X?tjqwJ=m#F68m843(NyB_lLCpFm~!Ii=ScYTbRGV+@H|;lh~?#s3Q3U=yK#lJB1MW(Ilwa?GEcPU?c{c~fd-V_yJ>Ia$? zVeb7}AHYt1o~Qy-KhmrUbAOZ8SI16$T~QOJew=B*+^1-LDt79VL^@1;ftd+&AJh6c zcIq37T$uV&vlh(#ty*6fJN3z;9!z})^LCi~0c8^7FypDJN5GZ zu`u;TW*eCM_FCToJN2!^eK7U&%}y})4{3cj?9}Ip?lAQu&7Ls#k7@nm*r{(Xdc)K& zGoOIDAE@<%uv4ET2E)`Bm_uOhM`-;>?9_J=&%@NOHAlnTzpVAIV5eT*e-Wm>gE;}_ zezMk=VyC{Rm2kg`j z7kgpq&zV2L-2bBWzhb98SsaI{?_i#Uxj(J-XRuS>E_e>6{`TxkF!%px{lD0$PZjc8 zcIxYK>WfSV%)LkX+UtJ>?9>;FiZJ#6ngN*mWUapmJN0>@22A}(GYE4Z*7^u`>Ptil zOuaXj3Ui;K^_keIFBRD^^~o_4<~~R3bFuUJ^I$%IEtvb-T3-h{pT925=f4f+{&uau z13UH8MMIeSNURCWeKW0Zj-C41q9sgyJk|#0zN6OPhn@Nb;sKcY`mwGs_m60OFYMII z-#-LX-@+_{x$md-Phh7$Sv(0--@$wu=KdM2AB>%PLkxkb?`95zxqnXUpT|yps(1mW zzQ`O6b3az=$6=>F-}VYjeY4oBF!vL*{x$5>mxxI)_1@TInER<(|2lT+my2mI_3dKQ zVea45`nRxCUn*w7)F;QvVD8`5`Z?ICFAu&4Q*WB{VeS`e{fF48|4b}}sqY+H26Mks z>p#Oz{W`H4roLBf4b1&otzU;laFC9VGxJM~AzUoiF4V^?7A?bZJK{TqiefB)u$aKY5iiMe6!leE4fb~^tV z;f1MR91FnQ->CJ~uv33Y+yqm)Zb(@fvG-* z$*~zQ_it(a+t{h!F3Mo)hsNH8xu2)?^RZK3A{M~Zdt(b>?myJ}CD^IoEk1&&FODsT zx&KV-S7E3AfLH@l|61&GnEQ2FzaBgFN5n>$`suMvF!x)vej9e`Pl#_|>gU9Ez})ZD z`d!$muWNh{Q=byw19N{s>wm<~{Xv-f!!Y;1X#KC)sh9Tyg{d#gIssFk6aQW7PhqFN z&^QBApC3O5^ZEbK`b*fUH*J?;KL1}Z_gA$3AMDiU2Cu@@SIBlGU;BEJ`wGg}zJ5%? z&V41Adq2#5Rjt1fJN3qysramPe zhq=$w`dZkz&xg6M19M+b>+55uzM*jkOnq5a1DN`pcq6TEjGg*+Mj=dn^Z4B`pTD)% z--Dg{PDWdp`i}7qF!!Ccz6*BlyTaUehq-@D>mSEXeRrcbOnrX5FHC*+_>)@y6n5$x z8UtYJ%d!T-)aS$pYyGp>sm~1#g{iNQJp$(Ie?jYC#7_NVMlnqNWAU*t_v5v`1UvPG z#%nM?|4A_SQ?>qe?9|saroq&w#Am?VzpeGNuv0%>%!a9t#OA`>FVOmh*s1StEQYBc z5dR3~{!^`AiJhPSDwv=D8kqZaTE8AU_ZwmEzl6EpqV->6r+%=p4W|CN_zsx+-CF-W zcIxHNbHmh^W$lHzKcMwLVy8aCb`Yli<@j||KPi4#>yO~^)Q>cd!hHT;VD67={R!-R z{lCH7{|@u@pV9iW*ttIsbAJKm{*u=JiJf}+`(k10^W)_(_gA&vcGIibAJHl{-D+$!cM(uI|6h6 zGtAfjtJWXGPQ5ed1Wdg@=M>ES1+Bk`ozH&>=JWpvbN{#2mt&`Xr|}O=y~w!=bMLJF z-|zpql==IAdkqgveMU}2nEQa%SH@1~KV;khQ(r458RlMSy@8$j<3<>!zClhJ%zaGj z8M!d^{&*hDeQm9;gPr=_qApB*ajZVfeSy|D!cP4;qX|rXi=4Y)?ptYnYwXnj zWwe2*zb~f)%zYQFe-JzM^7nzm)c4Hk4s-vg)<1@w`y!b8zA*PsY5mjKxgQ8~KN#kI zxYm!r&i!*R_bZ^v9!_*JUSqXFhh1Rdd&i#6r`!8Ycw`%=1?A(6? zbH5Yjey`T=!%n?vI{;H(mh~gd{UNPCjGcOi_!*|Yj`<7B{RyogCU$!PLv2KZChX(fU;E)XSeggQ=H4e+F|O z)A~4e>gCU$!PLv2KZCiyRqN|wr(XX28BD$W`7@aN00hUuJvDF=jXo;=I6fw=6;jbZ^ll2erO9!{j8j=F!wvO{#)$) z{CC3q{CC6L@74N!*r^wx12FX;Yo@{6$Fx3ht42z})ZG`UBXx{|V;)5X}8i zt^Wl(^$&)Q!Q7vKsn3a@()!cbsW)wBVd~4W&cS^Ci(3B&_Qdtu{)DN2Iey*T|E2YR zfUlCrI`VFxF%;&#R>#Jd>zE9{TnEH!3L74lf z)~8^n{zW4Vrv8n14CcPJ*4M#KeW6horanJj59Yps);Gk?eIuCrCNTGRY5m>U6TPiD zO#RF8>*l_t*0;jrsUH}+2d3Vh+aBh=v(|UPPJM2$D@=Wb?1y3Qdujcn*r{)BJPuRe zAl?V&{z%^U=CKSb+?VyC{T7!Fhaw)q^){b;Q(#!h`tF$Si7tN9Ad z{Y0&wgq`|!!BUv|+q0*^+|SbbGVIhB8t=f==f~&3+|Sec`PiwyA{M~ZZ-_01x&K(} zmtm)Vy7&a9J`(#3=6gTK^k%?oYwopMkl*p!FBAQ=cEY1XDjN=Q7Ow6|MgV zJNH*%?(O2guitLvYp>rP?A#~8+*gA6`~j`6jGg-%VD4{(xv#GEHLz1JLP41N4{{8c z`>58ZV5dG$q`}mWG&5lCO|6e%r#>FafvF#xb2H3+zSh^qPJR8*tuXb=b8dsVzeDRA zV5k12PytN6$ZZ01f49~*!%qERqXkU;bMe+N_xEajd+gNDFgn82uZZ6dQ@<|WMe85L zPJKz}A(;BC+=pR4|07!83p@3tp~qnAZ^`WqbKhU>9^&_xT z|4!&RnEK|qqhan}(fU`hQ@6p8Uyq&o=Eg>t`Ude$F!x)vej9c^ z|2Ht7|2vrbAGCfCc0T_;n9u(s%>5Cq{~0^=OO0P(>JP<_!`z?J`qS8{e<^epre5S; zfVsb{^?zZfe!fu-Q@<tHN9EoFbKhR;J7DMjKA8JXF!v8> zeK+jXe;4WwQ$Iep7tDPht?!GS`ahtACuxp>MP~R-}EX@5d ztsjn^&p#68^FI%BKU(XHu~UCVjDe}&5PKQseuCD&hMoIKF!xhn?x$=04D8g82)zkY zAIO~zb3ae(=VPaSUuXeL{j}WWF!$@Uem!>TkB2tG)PIos4b1%kt^W}_^?!yA!ql(H z{RQU!l-8fd&iz@K`%5tQ|7!hJ?9^uj?IG)*pYkjh%zZ`WYp;Kmuv4EK^ucug3fYxm z?yG5iGIr|i;p#B;U*{Sy_i0+6j-C2~U?xm`G&=@!UrXz6!OqXWHcWkaR$Z9;JG8z5 zc7FZ^FhBn$F!y(BeKYLTi(m_w`cqkLVeTK$`cBxX?;Pv`Q{ODR2h4pRt?!GS`d+~& zVCwJBehTLP8Lc0To%)R65SaS%tl=>CqqP17?9}%Sj)tl4kv#_H{#C6XkDdD5-~^cZ z3fYrj?qApXH?UKGYj8SD{f*gg!`#o+`uDI?KOi^{roLbHVwn3+w0;G4>I;G^Vd|sV zYhdm-X#Ga))Mo_0gsCsj`U>WLyVie$o%-D1w=ne;vUkDU@74N!*r^{8JOEQaEc*z| z{YkC=4LkK?f~R2W$7TNkbAMIqZQ*OLSJY1qI$-LjWmkZ?4=7)I{i=+e`i$TWF!kkG z)nM*xYJCtp_40n$F!dF(BQW>rTAzWPuRjas>(7C?udVfUu=DlTh57pH!`v5WeIx9A z{Y_xL{-!YZEwsKRcIsyaTf@}P&29&Cf4|m0fSvkxgPmdOmu7c`x$mL%J+V`7+Iqp% zmt{Q)b6=$Oy|HuO7v{bn%>9#E{}guW57rz2Q$HbVFwFf3tsjY<&;LBk=N|=gKU(XH zv2#BL=6)>9{VQ7kDt7KmVD2Zt+)vW_$=IoPh$%4jbUEq3bj#7>y{k>+lg`@LGf4?FdB z#Q~W5appmo`=eU_3wG+0#4(uq0`mmS{VA{`$YEaKY5SZB~G}_i4Q!JDopOREDW9GH-ynPuBXIuv6bk)PSj< zZwi?EsMe=or(S;l7p7i*{}<-o)cP29>f4JPnEGXAEtvbdT7MgM>XSr$nEC?q4w(B! zTHhEu^<6|EO#NE(ZkYSlT7M6A>XSuVnEDRpy)gIpY5o1!sqZN|!PIXxyTaV})cQxT zQ=cjxg{dzxABVZ`tM&b`Q{PAQhpFFV4uH8IqV+?uQ=cb>!_<#7N5b5{p!F|er+$Da zhN(Ylz6^6eQR^pRr#?xP!qgX-Q(^9>YyAxD)DIVL!qlHLXT#jj)B5??sZSOQVCp-V zi(u}TYW+vpsc#ot22+1~_DY!hwOYRpJN2nz15AC9`9GNZue5#(cIu18R+##K&2M4u z_h|iI?9}Ip{V??-%^zXz4{QAq?9?v_9)+p@GW!(F{bjBH3p@2|g5@yvKV&c0wBfvG>1T^;5=s`V+@soxb$gQ>rieKXAc9m?0v-vB%HKL-n7>MNSf zVD8&%eFyB+pAFszQy(Py9FnEK>cG0go~9(0I(F*wZPQ@to5iNX+`p;yZ(--_p9S;vm%-e>tMzlRQ@>oi2UFiJ z_CC!02U@=XJ3s$LFhBprF!xKf{v+(vmj{=@)SKoCnETaQzXm(?v&9!M_3_vSnES7^ zehYT$7l^Ge_4Q-l!rbrC`n}kxm%l$5roM&wBh39_p<({dRE!O#RSUHJJOFS|7wteTgt&>bJNyuF!is+*1_Cw)cXHnr@of438ub!{41FIZCbw_JM|~T z4w(8mv2S7ScWM1@?9^`(Kfu)YkL`oGKdAMGuv1?uj=$9{&n|5fXcVW)n(H~~{X zH1<2p{W+~akDdAwaS^888~X$1{<7Bpg`N7{q8z5aIQB2hy)%_R9$x$S=TheH{~Qn= znEKaZ6=3cwX}uRao&SjN!_-fYRe`xr*7}>UQ-4C#fT^Dos|j;&XnhDf^@T2xu2r-Q?YaZ2F(3*nESW1{%!2kH#Ev%>dUfb z!_?=*=V<+0?9>+;@59vR$LGU*{zY297(4Z*Z3)chUkY=-OzW3pr#?5h0;aw~_Gd8n zUugYW?A))1x&I%`{T8kN8awsPjcqXX4dOds?sseb_t^RQ?}7RG?}fQPp!Gjur+%by z5a#|6O#P(z&su*JJN1ReuQ2ub@#8R`|97oFg`LlT2Iljhh57s!wEiM?>Z^t?!PFnk z{TrtKe6B6+zaPIG%KY)mw7FnDzZ>T3Pty8|*y;QkHZM&5%kk^x>-TGY0FUSQUlo}8 z{CHKE&wrEFSI17hX{!nI^#@_@Ls}ok&V3Z-J_Y7JUF$QjbDsrspAB;#*ZLgn)bBKI zhN%}hwP5b+X#K6&so!hd22-Drb34p^Bdu?Yo%%yYAxwR(oV#J}TWkG2*r`8mw1uf} zkkb+7{z0wpikU-u)g1LWP>)*i6{dAc7H(~B)YyCUe zxt{}b|31w9Lakqfo%;`A?mvRLU!nD%VyC`R=rfr5{yA%4?$>Mm2JGDb59WR|%>6d4 z-;SO89WeJhVea>6{a)W%O-F!g`u4uz>dpZmPlzkr>3hZqf0U&nk2=JUU-^{-&3K1qy+sV^`m zz}!#P`cmxFR~A!Y>RXs^z}(N&`ZuvtpDf;nsqbKx!Q9W$`nlMtH^uuf^#jfMF!zhJ zeld3H^TZOE`jO^GF!!Hm{R-^V*A**a>c^R@VeZ#y{d(-wCy9+P^#$gaF!x)u{%h>i zHx%1o>PyWXF!#H){(J1yCyPBW^&QN8F!w)c{Xy*1w-Se8>gStBVeU_8{YmW9=ZW88 z>PMQVVeZds{RQmQw-1a%GX}MD`Ka< zi}1qKuQe;f+$U@OP1vbV7Byh%JD5S3`>@tWuv6bhq`=hgF*9K9<657Co%%d+Gfe$R zvlh&K9j(6=JM|)T8%+HNIrU-g8)|(4cIs0_W0?9Pvk>O~Zmn;Iov*(I%-7!v=Dw}g zx5J(|f2ci7{p6enVD7tV{lnO)kB54|)Q`=11m^y6tuMk(eSWA9O#Q5!elYh>Y5mjK zsjnXz2vfg2=NXv$p;|u-JM|(o0;c|hoabQfU)1{1*r^{NUV^DVYQ6$yaiK#&U^>ve!kX!fSvkeu@I)dgSi;y{v)mb7(4Z;VmVBG zk+}lqewEg*#!h{)_#CGG|LmO)TpY#u|L5-Z{=oqU9B_ey@aKTTU_ug1qoQIY7Aw}M zw9*QDqNYkMt*BI~(ux*a)U?tzwo#*EMMX^&m0Gk|QL$phiY+RwsA#c`ZLGh~ zGk^Aew{UPIBu2mRdhvetnb~J{W_EUVW}dy>{}nu@>%#s?gZ&@$c(PxS_LQ!Z{dWqU z)^%b3oWXubk0<+O>3`C7vcIBmSl5O9h{674J)Z1WrN5%_0Ntv%LSm|1V%>T_^j_e2cCN zdz;i%|8Ljh>G%cAsq4Z%O4o&bjKMxuk0<*>GTgdO_J=I@=(?~^HQ1-=@npZwm#*t% zziQc1T^IH_27A9APxfnkdAd&aS<3>tF6;{p_WSGc!hVIW3;UJ2F6<95*ssy!$$ovt zT3sjmqn014>%#s>gZ*dqc(T9Wca*M^{lu~gT^IJp8SIbOK`u{$_*yuk?74|E;<%@_(DI z3;QmE{at#zIR4$bE{=b%t_%AI4ffmhcyauPbX^?(5nUJdj~ncNug8nyKcVa5_yf8w z?4L2%KdZ-+{r;&#x=!}?zze!A>_-gtFYEDS|A_AuT_^h;%l@kC!u}0|{kR@4%Kr~t z7v+CT*M$)ia4qX@a9~$icr^k!(vwYPbi}G7^UD!LMuKHi69xuut zt?Q!vvAQno6AktrJ)Z0@@FnXy*?)K05?vSe83y~MdOX=*>dVq~vj54lfUXPsl?MA& zdOX>GDWh1|$^O1&YjmCLuUU4G!Tw-9p6u874$*b8&suhvu8ZRzVX!aL%V??_!I z`&G-zbzRt380?SH;>tw%b+4Z_Ej{j4G{m=AxvR{?nsq18aQ{gXkUD*H1 zVE=19UfAEF>%#svT^IIu8tl9Dc(VVF?>D+G%73@6ll?Wz?lsuor^l21*D~(cb+SKq z`9r!cj{iG@{o{JPuhpzCD+-Q_Rqy0CxEVE?)vPxjZR zjq5tuFWqlK*M%!h9 zb=Cjd^?0(sEW@emWPkngSX~$PNe265J)Z1OOY`bF*$))>bY0kI8|-uRc(Q*aJy+Ms z{`~#-({*9L(qO+zj~C@H)^$<-19V;3uQk{osK=B28sEXXPWD;L4$*aCf4ISZogOdj z%XD4XAF1oY{&NQVqxE>QKg4&8u8aJCUf0RKaM^JN`{VU^QT|F@7xrJ!b#eSEgZ-EE zc(Px|PSSO<|NgR|F6>V>*q@^BPxhy#SL-_2zfpLGt_%A*gZ(*rJlQ{+{taCx`_}!> z*L7k4Erb0*l*!Fewk!_YJ#y}Ex%dUkHr4#*sZ#r@D}-_gZkUpe;wPV$HyQ( zHmJvZ9`;e}b`>ATlgRJwfo!RZ{Qf3z zjMPPbf1{3X75VMfb&=ohz{!07S4~q$e;vCga0b_3cZ&Sq6F7(K&5o3JsC@SXE|Bq} zJog5^E8|!2_>1ry^gMmq|i~f~#*C4MyChG6OK#SBx z{q+X6NnO-mZ(u;`qP`vt#6BbJMSVUNIFjp^JD$ezA6@=f;PYI+#@k{tF>mH$yuO>* zk29}^{zqR>zY+Se*?oF^7xdq*3hEC-e{9v`di)^t{#C!%^;e<)(buo*|AhY3swZ^a zYBsUwS3RZcUg)o`dS2J_pue%|1zj(O{?4kGbo~hEmep_Q`WK)_ul~EP*Fg8Ip3wF4 zq4%$POV=-kzGU^=x_&wIyw(5K^`Ag5Uj3o2Z-IW$>W_5&F6fV~!YvekRDXRu-lXeK zK|gG@Mc0S<{_(p07wErTm7we6+}@+>|AKzp>SSHFSWN7c)fojRiSx-0)l6tVnFVJF zUACu8zQ2X3`?b=Azvax;*)sld6ZJReuFlhS>Tjx-6&9QqlK%b$R~qzR2;I?v>miEm zUvR6`JE6xyzgy~CdHnK%2c_P{h--liR{ohhIo#OW0*j6B}E- zx?tmTJf6K$%-Gwj*AzVb{QtlIVFf4h_-mM{z{EBma9F{!A@QXJ6I_2>UcaRUC%i!R z*Ra|ZxWBDhUvLW7A7|ovKB}Nu>f(Ans-Roy;(9*1AaR)NA7|ovt|&N=>+1TgD5&7N zDo;hhCb_@pKPn1ZUnKiWSU<|QjvZI#*6$`6=*Mu z{Y82w7i36XG^ z#i2i3$G%q3!Sy~9^&bxvf34tuTz}joj(=uB!7JR}(FXe{c4om!sc)A0fl?RulQRnr z=X$e4+)vId_?(Ov?fI;N<7K>P&u0~!B;w`udv?Lu{0T@^KW7(g5;}W3U}8T$;Ov4| zL)vd$!GzFx{L1xpxSmbyH^|#U$YnU^c*=qG@boO~7pODFH2iLl!maENT-s2t;&{gW z-{9fX_n(yeTQY^+`%;hg3Ej`7nFYACu;pB8Y_*I(FhrW!p>n@6xnDV#R`z)=ZR`Xt zP3$Bt&FnNTEv%MHjcw-TvdZ$=*o8dYj`=C&$HAJpbjtLi*i~Ggp5C=QT*GrUWQX*) zw8`}CGJS_k-zn3LlIcdzJKbA(`gXRBONTs;QywRnKT%GLjMwCGgY|OqQr~9NKUE}`Z zI~+I&=3C!;DqYbIgZHArpKpI? zN~iwK$&A<6T*muQe-W<-v%K$GWc_GN)sGm5nB_P! zSTB1f+`=xF=S9_j=y4W4{t{XK%j9v5`V}%<_3NR!y04p=aeN~7i#%MVf2AQG*M!m4 ze#%aqM~l2~YV3MLzHj2Xg^B&NY4_K;;(ryAUifmW{21%wc5ZKG_sDcqJwGh?K9KQBXBpJLSeT7VlO8Yn2NM(f1;dq{N=Miu z4Qa39Rl3nUTw{q`T4j9)=N;;}yK9%q)3@MvuT&n5>ydT4#9{8;h)nYgaQ zm1C}Sjq$sBoL#kBsN);cnM+sW4srj~*h#z|t#TY`)5np!dwqS}_NrZod8>teRrVjX zvb<->_M^r>Vt+Lr3yzm&4>#^NU9Sss95Ei$m>9>Yafi{~!qm9&T{%8d{q{w&JeSGz zRlLe?q~jV@{vXP8)HqoA2~<5A+l`o)S@rg!_A`!K<_Z_rPq5z&y`I8_tA1dv`04$` z-ag)3*WUp$eLl2M>p`j>YWe&o*l&sJe|o=WT>lPNueZzk5bN-o^gjl# z`yN>?RbRbaH#60LDP7EGE&6;`h4;zy`(-*Rd_aaj$EC*p%%zq6P41`4JJ-7X$L$YQ z=U4gf%H;f0Tqi+4rqR!<&SN+~-tPJzRr;bo-g|yeb=+{}dXm>qu)P}h-_!m{wO*>) zSGem!>iB!d&lN1M8t;T2|Ks*=MVh~T)vq<*{O>#dteM+^s^_`$Ip6!Q@K=ZTGmHLG zlh5A-pKDt5zf->ztQXO*Pxrrzaaiy>wXzfC z3$EXV3s>ba=6i*_zQpm(O!Vi$^%pgsU)cCP<^P&1-|D#2*OzB5=bqc&c)YoEabAr1 znZEu#S2}aW@9J@O)y|log-XYmu2EO_<+=Q1qTQ=@6`Y5O@iFc{ydTh*dj3G&_un;) z4_3?jkGkI~UG1-~e^LJ6dfCN19h>eCHSVvT$1{e1TGI(v-rWrkx4xyq)%jKZpbA&V z-Q95Yyo>6;ReMnW7GwB)?-ME=)&A6TUdHFZ#B*OJRwCQ0YFA2E_D31ov(nZ6YF$#T z!-{p);PqpyzY`6|Q@T3d>4xJeT^ui%uJR|;^ZhmXe7{xqE2#V}%zjv3HLNGAbT5*} zSM_E*t|-4|_#IKO96#Xp!F5AXk7~WbB>f-3-*<`e*ZiOJz0OdtH-^#GehcI8R(|nd zc~yH?^C!`N2FLje&SD( z3qKcrS1x~-sMeLOTsO0589sA5|993?W-foQp4B*HaX*^R&%a*ObIIyDoNN6`jDytr zRPcA6%FidRuV6o<)|)-NJ!^74WR=hL1%Iz9){EzFCywiozn`6Mf35W2ihLW78-D*A zxSdtz*Cz98m+RaP{dbD0-b6oRW;yb@RsD_V_e@OmizZeesEs!#EJm05qjN`)Ki^$=Olv&-P~ ztfBi&4_Ebk7*E&2)~WN!>(k6a!!@>^$6Hys+)v#Hg~acSWVrDS?~=Dt*;Y zhwBH7`-yyN`uT}8KGO23^i+FQ^(FeJ>A!PRimYg?&gX& zwr`b=FU`YAbqnj}Qj^a?TiJbF zx3S+Y@cw-~Ju4fK=^x40SMBomBo6i*4|lScxQv?f_`90kUwQgw7FvE2n_sxbUgPOl z_E*=Pv0bQfj*1_b_3|c{7WOum!THI@9Urd0 z2p2xz`{KK@ysH2Ix2y-_eIe5DaQ%cjUvtHO#E)-g_AHtYnB?#COiZ1Bb>38e5GVIj z{cGsB)xwet@oGQ4e~{xG@m`qVc@Lc@EL8Zy|2{S}pOL1o>FdX8yfJe+dwxH4K8?p0 z{ktaTDbwE%quwjDt9F^ZU0}Y$rG@2jsj&jtUPM1_*88`8ZGTm7g|Zx?9*q7V6PqjE zSbxI5V3PC3;5<28c<6aj*Q;6o9gE6m=(?JPsq0Y5Rk9qP;nKnmk>^3JE2(z6Yr0u~ z??z}k3muOBM*4YXKF;2X*Yx*Z%$|=uzn^g)DCW7r_ZQ3+uf}cSzG2bljmB^_PB4b6 z`;IYO?QfiKsQr!MduxA{Pc@$rev{yHcm761i}fa(TyF}#k4KCr zoO>*tJ$3$!ydR{(!J?&oqxlrSZaOp%k9@x|Ndwv`-^Ldzl z+`0Ojx#Eq-G2Z`)_JDe##}rVO(0-9bDSvaqaAWt~=O6 zTsqlfT$*IKS%zC=c=&Y0aUJrwPI+9Dd|#NE_49NsY>-Qhy~w4NjdE#YZ*Xa6lUzF3 zf4FoqbGDdAsOvq7>%nz@(T@gy7iIjNnsI;SClGeQ=dhGrl004-mv}FeL0@jrOALCs z)Q{)V%ueLe!cOBdI3BL!x{aOBrHQHiFOvITF83GvS=qJo+Rw&1`2KeGOM~4VT(>Zh zuBIRV9=V^8X7)gcZel9@acQsWE7UHy-&1lw_57f+7uUn|ajuFt+C3-pv1>BupAdeH z;Chj`Uz(Um*UW}xeqZ4-xZfDpZE}4{-LHdoZ%Mlkq}@kcT3K`swObpD=hDtnxpXj* zo|ENpJ&NteWwaaz1k)AQt3_U~n%+;S{I2A77TxbXSGcOzgSefE8U5x)U5)p}dw@*r z2ySO)N;l5a!}-1y8N zm+KD!E~mf0cdqzI{qRP=#?0xO*v#QUzwFHMyKblEC-apHosXH*+jHgKwd2i|pJ2Rk zy=?c!HR}F2-QWCa_lv9hYNYpJwZ5$UjjF#={fF|WUnu(*jn9x$Kd z{kuuNM|HYx+~25&vo~IM$}ZAym9BCBaN!G`zVbsFpG)|WyuTRz&+0l-&n0Y@`z_S^ zjcR|Pe*WNmbn!U{npdmmKf*o#5dOJ^J@uS}YOltAT(wtYxY}R!J4zbcn;MU*_>cQ} zhPjR(uAdASF2-$UwuN6u7Ir6>!S;R+*Qc+)C_CdihzjqQ=?%&BUgFZq-jM0N&840F zi%SO+$8oa%aXpGz{nXBa>oW5lPtCr6r0adt*YVWz9t*YZti~6SJ|7Zpe|4Wx?R{_S zkv?~#u0wS_ss2CG=TH`EeO-+!j8ffST)h1S*PoTH)}NIgZv8pb?-0&Ev{2zeKUL^) z7dkxX51RQn3m322hw(U}{-W^y$z8SE*Pc_EZ+=w0DLL2kD|5xC%IhGDOA8Bd8Ts=q zyZhXWDu-G}3ghI=?H>Mvteu7__Kj&f6-=Cw_zdk9?i>PtIT+eNUJ}0rSKVK2_H_i3j z#C)GqSTW=H4gM54&J*n;`2F2m*{uz962Cjfr$k>@=CK@i=N6E2LT4St7IxzL%m*`U%DFdX--}_}yWZeq`^jw#$4t z=FEq>pQ`(sah#!^i`~`tckf<$(Xt$_d6z@opKsvxy63;6EUtq{zt8NF<%(Iba*69~ z?(aCO^Bk^zW=|(d<~us#e2eoR{<*?Cr2j;t@c?Qj0yGdI@Ple`}1Uw&gg!aa8^(w}~vsQk}v z=aAQpGve!JPqn+nbZPu)X6n4p)$V8CZ`a%X%*R!~gPGpWX5WAQ?cUh$8r%2G@t^*F z*;wwmzN-=0{_{USs@=`izli)f*w7r~o^btBsJ&D6Q&AE3Q=|O27Ww-TO+FuQW$L*n zb^n@uzxiKBpR|5#_VNd>_u2RR^w*PU@4@#kzGZ0FGsn-rUsBhXG5yf+`HtU%=TVH4 z=bpEV>tp_Q>h~BzM!rs9{EkGZZjsl&7V-73=6|Bzg1?^)H_tcm-)+zTJ0ZsPg3xs4 zKaZR%-@E!<5>@V*?dRXWhRdh=eX^(r`?T+v&(CiD<5QJ>xOu<0PQ$NXhX#|b|7FjqT?%x>4)Nwj=lgBlO0`Vrxg z_p|TG`+<;=_j~HN!Y>^>PePx6zo+~}DqW$^Kb^(=(0mNP&*tk&W~SELRlV+;^)vmu zYN{P2@^&71dsgLK*!HxTzumhYKPmO6zUMZ*KU3{c_{ZiyKHf9!aWTJp_Im%M*6;N1 z5gPkb)s9nm|2qG9@SbhYi}?@d&)z%jec!MD(BF$hK5qS_*v<95!r9{^zdxzx7LMlq zfJJ_fZu<8(W{#i#amwZTrubb9-eb&lD?3ikXH-!Jn1N~~*|nR<>URF8aqq3qOi zh@txY)7e+@Bc78rG4;G`r0Z;-6uWT0znVEb@_B}zw_7s{$o9OP%kb|LiS)Szbzc=S z@_ubGKVse+?!LKLKa2H4>mr|)>uav(k7tjM{Jt&xg`8&y z8Tt51&AXL-s2+Jagk5lbG1Bq2I-Zz!1mB-Cb9m(ERn>zr-I>Eb{&ZD&)pwaf^~leI zYERe5_7JM?{d81$gq(l76!&|J^#5w?dRZ=2KQqTiJ`Pan+{Dwh$nRTd)BMdd$M3tx z`IVubgdX|%7xl95T+iw}8L#J=!y~_*jo;S|)g!Mjb)7wIxbB1=c{=KS7Ej3b_%xRq z`;$y}_V~!#qe@5op4}qf1FPxZftWph{>M?jk5}mmJ@R^amzUqnK9Kbgs?R?i^*vkl zeh!shXn5r9Naah&$on~QpTu|i87%0Hsg4-JpJzGt=% zUN5_vuIeX^?PKQf$n!h1eXw5+J>I^T?s;;&U@V6Sk37HPyamtG-nozN>hXfV_ZQcX zx{n2~XXS?sji2vzHvjyI_HAZI$m>2-kGwxO+8r4tJrN%Hd7e34P5)}}54{7>$YmDtUG=Bd5qiVOI=}d3eq4E3Padvh5pvEo2{}CK_2|e=u zTBQ?j7!L`3{^=~{hy0h*e~+N*S)Cu{-<&x-^8QEJFYNhK-|d>-u0*~U^Jnx!s`C(f zel>Qn;kueRKJtD^9cRy+@5THsbp0;WdD_>~3EPh4{6y8`?E6JNK33`NYxS_N z-&fT08{+utIiKKjC!yhy&qwx7y3_M1`~s1`7e$os<4>nfo?js&_qRv-{DSd(i08pH zb`$SUm4AJDJ@r!8v&Tn%{i}4;bs+qw z%Acd^ZSOyqpz803vb>>s()8%>!JHa z-VW7qL;a<}ae8QY9PFIXigZWhB)kym}l|N;-(CcBL>F&98jhT<5=26q@N3Eaj z?tDuecY6AZ^^ZEi`{Bhrc6$9RRQ)g1d}1*jI$z<}%NOhC|5p8|agCVY1b_E2b9m(U zLuKF2$0Zj1J0vrQ&p+MWeXdN+=N6xTq4utx1G2E0pQ{M2bBOv1w_oJrFjfD`ue|vD z1)T>=SpWTepAS&;fY9-5a9$T09{KgRn69`#sNYfDAp1AferFDkynbi4H?f(+_q}w* zdtWtnvz(6_^Bo!=`TSe-_h$J!1od4jrAIzLRqub9`F%6^UXpz8#?0}N=U1hp`Zu+H zy{F$tqpr_d`Q8vw|H11%G(7V5Bj%52`~18{zAmNmBkUG_T`{yD3zjo9Jo0j?{N66F zYw_MvjfwZ42GgH8KJxaV>aj;&C!u=e?OF9ZLPmaGdgXak>ph`*ljosd*3-=4^G|m`ru!V18v8SsR`xf;ac18y^6`#pSL!{w;yRrB{oCSu z1y1>UvnY0zd=JpVrnmT=E!AJE@8*>8de-Fo%7Wkd5&d`YJ`vgek^39fc~$+icrWzy z@9o@SXa|w)KmUA$_M^f6FEl*z>ra(0)PCX8RrMg&>lVM8HP`Q1_tyCc*N&f@XFC@A z&%Yh3cA@eS?)xfp9u1EREI?R)0<$j7n9^RIrNIdk~F(=LqVUi@y9Sl2K2T=1M;n$w~dsw^r zeV1LeQ|)Kp{LV=5`d075kM#KfRjzoseiEujz8<6O7VBsB`pZmmeNw*z68^la?|+DTvCa8jtv!4FEY|Pdso#D7yB?|@ zX1@Lw^B?ZLcdFj@%>7MWpP!uipRXUs#K(1u-%*`wzN6Y%xcXiEjw&7#Vh$#rqj1Xa zct3L_(BD0C{CwA$ zg1^_=ThB#_b!0O;CR3~ngzAxBKgv$6M~CW>r!(`q-QxG1)c1rJ>qoTHaO3gC`dO@> z-TB^>cu#^^K38Uu_Y+OOpUfT~d4HeA#~Wsr$EAg>A3yZ`EY^>)e$={y@p*ZnM}GaN?~hy~`?pYi z@28{6BV^>)v#JmEKAqpmdGhtLT(ieV-fydP#QP@}zx$)czoK4({uSXzncE+)>Ql^1 zg1_gSIXv?D;mr2I{DmGb@^sbpvH1NqF`nJm&bxXKNa*-}%Fh_?`clUg*I97hJac&D?Qv#%6Pr0a@^r(sH!=PXws&KD6!FvBhpMk|^&`%s znTd5o^r`&3Dn0Ucq3qN;bErQ5bQbd??r+BNsH#^{Ka1ZN5$$bP+t(+h{`TB^Hy8GL zRrR@;Uv-@>RQ-Nh(+TazRJ*}_Os<=#dYpZ~$bWyT()+a5=R%ch_WGVaPT1Gp2m49S z|KfS1@z1{Z-I9emFUI-H-v0iH=m&$>air`0yK1NWjN& zo6o3p-Zl8Mg&z4hQTZ=dOMgSCzW38n*Uk3raM2dsKtz z&c0vd?N9xVRlS#4_`NlDoV>rx9v^wVsB}d7!S`$K>G%6zC;KHKBkv#8edCXL} zs8}}(K8O5i{|@J}D6#IW-eW2HGmYKy4!xhl%GCRjMZ8(>@6Pm-or&$Pedu=|O!{|& z!iDed@y?O?7Wp@`h7jGP>uO%o$m8+6H}7{X@;&+*Ym#=e$6MJWX;e=(_6IKQ@;xUG z_I+u8wM@TV>eoyCXIxs?FS*p%tup>D8ULV+|GkVK;?gSDNo`E{r|fKmhdbEcxOB2N zxr}1};xd{I+bMr8wv+27M&&VOnwgd>&aW!p7oeLmEqeHAA@RbF{1-+)ROo%u#?Iz; zcJ@s!9qc0lpm>13`vs+TC1!eunuk4qOjn9CS; zB$u(Qic1p{=Tk{DuV0oaaz)n_EdA1 z^6=^3MO5vog~v~CSF^{5A5Vn4PQ!((>$itr4;H;YQQ^k+qu#&wRery;$?u2TnXq@T zH+VWuHp!)lSu*MTMBXpWUTzcHQ~ln9PRgg5ZQ}i`g|%?0+H>Uj50^i6-HLcs&l+o$ z?IYCAqK7LxwV&}kei#t-OLC(*o}Fy2cb*J+4gRxO97?f{oysmjg;3*`Ex06k@7An@0aosDW8z?87W`nvS<0LQvW-bgT)_k`KMy1iSm=l;<;SM zmPqO3@#|QY>FQ_`I}*L%Ik+2Men6J#a|I^$>Z+BduS4E?fQRqbl7G1AM(EoQINbDe z$d@3uLQWju)8lVX#WlF*aMOJV&syWs(|;KHtE-MPjX{2H&8a5SekPX43Rx87No!V` zk|9rBb0*JM3Om=d0($M5LY|*4f zSjv75ma$)fMiwUH!}~|iB{rdTQIzIvaKu!+{OZ6 z7uz4~W~;y+_8D+HD*=1i;b0#-66|M3g9B^>ILN*L4zVwT!|W^I2&(}{*_q%N`#Lzz z&Ic!0131aP15U9^!5!=ha3^a8ndur(GyNEJm~I4JrcTgpx*7DCZUw!jJ3*hR8_YD_ z5Bg0HfdSKFV47Mq?0*P31cOH3nRsp(a)%=9`~Zh8}}FinCROz(r0rvHFd zrjNjlCe4icH#xx?Q!H3(N(AdnUa;Pj4sJ4KgAJy9u+dZqHknp}&89VAi|Jsn)l>?$ znbw2trq6*Lrend)rb@8W^d)eM=@f9Q>2z?LsTS-qodb58&I5Z)7lPYOjbN|o60py7 zIoNNy3LG%CfrF;&z#-EO;IQc?aKy9)95vknj+yQN$4z&G6Q&+;()3$!%Je9>!}NP_ zr)dCW=4U|7{3p<1ehGA$M?tswHPB=J2k14w1NzKUV5a#4&~N@97%*EbsDHBqEHcM{ z#pVQXtvLlOG5f$$a~4=;&I8NM%fJeA5xBv809a{02&^(625vN$fz{@tz#8-C!CLbP zV4b-NtT&$wZZe++HkiK#Hk#|eCiA&qv-twB#r$os)!YQOnZF0No38{r%vXb(&Fx^P z`Fe1R`Dfr(^Dn_|=B;3t`F60|{2Q>xd>^>oydCT{KLYld9|!x*e*g!}gW#a~d2q=5 zXK>j33OHgO14qq&2gl5BgX89Zf)nN);H3FOaLR1fQ2%B-xYO(cnI#_7EXkn5k_Ngg znV{Q}3wkX3fnLiB&}S(IGc5;#e#@a?z;XmwXekGaEXRPwmgB*-mJ`7e%SN!&aw=G6 z`6^g$IUB67)Pox=-vlcy7lBoli@}YSX0Y1weXz#zL$KEJBe2fW0oGf73U0Fe0&KAS z8f>&|1Dh;&fz6hC!4}JdV5_AUY_t3hY_~iKc37SUH(Q3lPRonn7Rz72t(L!m+brW? zm*p+6+wvaRWBE6@-LezxwV14^e~S(5w?u;j7B@I(Ndku~so=0>DL7*BgQJ!LaLlqC z9Jj0nCoF5hNy{PNlw}>b!}3{hr=S;5U(6xgZ7fm<{WxK&#MZqqWrE-eS_)&gLUwm-OCTLt!Np8@-{ z60l!8930S&1P8UF!69t}IIMjE9MQfEj%r^4$Fv%7Tssq-(7p~%YUhJfS_8O4`wqBM zyA)*BD?rWK3OcOUfG+EgLAUir&|~ccz1EvSpY>KS(|RZ9w|0X8>-}J%^&zmx`WRSj z?FZLdp8`v)&w{1a7r-*>2v}}?6|Atn4sNi%307Js!7A(f;703zz-sG9V2xF?qyDW< zu+AC_)>{+7O;#`1U`+=bt=V9cH6LuY7J@C-m0+uN4cKNq7;Lwef*scN;AZRRz)tJ2 z;1+8oxYhb4aGUiMu*-Tn*ln!^d#vYx+pXt;z19oCK5HY`Z@mN@uwD)hTCW0!tZm@1 z^*V6GdILCWy$Kw%ZUM)ww}2DYJHScn-Qbk92i#$$7Q55>TWmAiqo8K{J?O9vfG*oJ zpxZ{htH<^yYupDYn{1y48*C?l zjkYSV$wnibW*d!gT5L4pYPHdbtIb9uu67%ZxH@b!;@WIG8T)tIP6M~tz6Nf!)q&fv zB!c?4(O9V4Mq{BK8;ymw+h{D*Yok$9pN&RM{kC(l|A6fRaM1Q`aLCpK4%@y5j@YgQ zM{QSwW43m1+;%-UVfz_4Y5OHOW!nnwu-y*swEYHT_WMB1z8!Sf9|2wV$3eIK51_|B z2zu?$gFgG8!A$!rpx-_Q2JC+a3+-=%MfQJ!#r7TGTKk7!iQVi({oCzencW4J+vC9s zdosAeo(5LhGr=l*F1XRYA6RW)0oK@y!CL!)V4eL?u-<+IxXE4)HrS5=8|}w~P4*MP zX8T64#eOQ-YNva5o1I39?RFX^cGzi@xY%z;Q8H=%CSEk%LBe#SR+Xt##1ouEas3yHW>@?#diAx+`}y zWB&@r_rVPg8c$X_Xgpcvpz-8J2aPAI9W>m4+n+~lC~WP^jo zu8j^FyEZv!?Aq+0v1^Ni#;&an8oRbRXzbeVps{O*ctK%2o zHpj2QF2^>o+i@4zM(0UjwUfr!HO^{m*E-Jt>zrqS_0DgAo1B}#2IsfHM(20I zCg){fvy(>bElwJ-w>oLW-sYqcd%Kgy;T=vIhi`V$_`K8Eg8jERX_UUzN#piyP8yAO zIcYTB?W9q6kCR5-+nqG(?sd|ryU+OpSoJ%v1qYlz0SBF%!6E0*!C~jGz!B$d;Ha|; z9CO|Sjyq|rKH;RX`lOS_>Qhb{tM72qSbe9H#_BAJ#_C!Wjny4dG*)*-(OBIbMPqeO z6phurQ8ZTfMbTJ2Gm6IQ{wNx&2cl^1P#8sXhoUH&I}}IJ++l4Ljp0k89zY&SqaFs! zqWZw{s3*XRC>rZ-h@!D>WfYBdtDV-$^bo1$o}+Z;t>-IgdC>$XPGShp>T#=7lMG}i5iqOtDgD7s&FM$!Fx zOB9WJw?@&pcUu&Vd%L1&+}j;REBe2nJDO$_o@km)c%xY~>Oa~FW=2PW{^&R`5bXgAqnCh1(HUTIbPl*S zIsleL?+=znuL8@WKLeIWmw*+~hl3lUj|3~Dj|QuvH-HRvZw5P~ zZw0qR-wAGw?gqC--w$?0KLmD1KL++h_k-J`p8|WMp9TA(UjX}~N5FyTSHZ#P*TJFa zH^JfPNpK|keQ-4TKj2vON8ot0=0g2PJHg55Sa2#j5!?~&1$RcLgUpo;YA%|iIb1Y5 zbGc|V?sn1a%;Tcjnb$@09iNNlJDDz;)A?OAn+v#T?o;TZIcAZI=9tAUnq#hY(HyhH zMRUwj7tJxtTr|flchMZP!bNk;4KA8vR=Q}8S>>WR=0+FIF{@oP$E+ED;#vu|y4HYgu7kmLS1H)xS`Th^eGcq& z9Sd%8Rf1bxG-ui7qB%>K>q`jfcAWzDxK0PRyK2E+7tLk*Tr`*Icb$Wf0oQrppzA_# z$khlAyXcNT;-XpbDBm9A+v6^pBY3W_deYG=tmeq8S{Ep&6VOLo+x> z%q2+86>~Z0j=2i-#I%9l7@FDnVrXWU8FL*%{4qCxftZ`X!k8^!QOqr1am*dy+L*h+ zl9(Q_H0HNpS>OaN-HpRq%%`pjJOH2yb8sh`oVzR*Ym^`o}W*N9SrU>keIRM-e za}c;S<}h$uOc~e}a}?Me^Lel*<^*tiOcmH0b28W$a~jwm^EGfFrVbp8ITsv?xd0rF z`8GHb(*%yjd=DIpxe^?Yxf+~^X$L1`t_P=Leg^J{`6akBW-G{IZwIy5-++$T`#@Lh zcF-OB2M2;OLNAeSei2y$I|R_Z7j_$OJZqu zSsF{T%d%LSU6#kvoU|gA=A;{9X_i_UOEcE0SelP)j2*;Ls$-uAYhwQl*2ca9*2Rv2 z^|5~kH^sgUHpKoDY>eFjHpPAjHpiM{QU9@aur<~Nw(&IEV`+}l5gU(?&9TW~XKWg{ zB{mb>8k-Ali`@_G;z#f1N9l=OfspO7#b9sjfnZZ9urBU*V13+^;HJ2z z!G^dYurcmMuqo~@U^72fOB~f(Yuw+!wzzSyJ?<^ABknzLbKJkd&bXc6mN-)!>Oal~ zZi|ZsyW-qncU%(K6PF5Z=V|uFEyZ?UoFD9uD*y-LmV<+FtHGhTwcv2vA>c^dI&d`Z zv*1`<1vnme95@m8MQ}3iBycLO8r%_g2DmfsEReas0c!3|pu_zw(B-D{?sk6{+aC92 zpx503`rJPNGu_vMe)mtnfO|7o=>9oa{?7j_L>+S+e-1mT`?gzj!_rqYhyAP~z zKLKuV{}HToKL=L1X}x`;o7UT_-NOi}alZ`Kx@qmb&P{9Y_3pnSWRv?1u)#e6HoD&h zo812bo8A8fTih5nvsSkiY;#9}?d~|R!|ee#yO)5S?hJ5?I|tnA4uIR-`-5HXRbaRK zGhmOq1l;aE9PD);3HG^<2K(I`zybFcz(Mzy!6Eloz+ra{IO0AN9Cd#k9CM!!j=LMc z3HNuvN%y7Tl=}*Bhr1Qr>AnVJ@jnK&_!~h-d?)CNzZrDL-wJx-?*zT^-Jmc2elRos zA*KS*P4W3)Lwq6F7{3y1ieCdZ#~%!~#Fv7t z@$131_|Jju@yCK4@s;4__%DH-@uz@W;!g*+#@B+|;?DuQ;?D!S<1Ykz;v2#3@t1(T z@t1>r@mGQU@onHh{B_`9{0-nx{7v9+{1$K|{uXdF{tj>~{%&wQz6YF$|1CHf|0p;W z|9fyp`~bK!{uz)Z{0Y<&UIHBnqo6C{HPD^#573kF4(Lso0(}V|fSC#Z1N{k>1k`_m z11wC40gDn6z~Y1yaBYGQEJ?@$OB3?IvV>(|c|s9bk#GRGA>kmfGT|_=DxnPAm~a$W zo$z_ECgB9IHlYfvOE?*-D!aBIRZ!EFg!!LEec!S00LfISKKf!h`oj9dlKIQw__9p%t>`UAU_9vP= zsQ*M8IG7j>4kfz5;lw0xBrz2nOFTnp|n@f_kbHc4}jI4hrt?8A6V;o0<81= z5v=z-2X68VgAJaS!A8$t!6wfeV6$feZ1KDcwtD^rwt4;wwtH9->fd7pH+!PMPEQ=T z#p40DdX|9OJQ-k@CkO2I&^V{Z6TtR%&;DSqXBF7z`3%_aDFFvOhl7KjBf%lh(crLW z132RO0yygVGC1b>3OMem0Vh0Xf|H)FgHxXK!5y9kaHr=xAWOOw)RL|M9Z9XAE9n~0 zo%CbSlXN5KP3i=FNjHO;Ni;6xi;}v*;-ve*wMh?wB}tEgrAhr@ zS<+KrdD63BMbZo4hNKa&GU-*YD(Q7_W73;obr-QvowP0V;IbeU%dEh|Oh2UUPBRG_F2{@c|IXIGZ6*!vI z2970N2aYG*08S*`1WqPx0jH8~0e2+b0q#t?8)V5npqBhw(2@Ko=t}-Q=uRF0J;~32 z-sC@lzT}s{%;ZtfpZppaNd5;{nEVb{lsp9%Cw~C0P5vKPl59yq{UTY1PE&^+k4*+YE4+86w4+HCy%fL;^M}ZB=p9dS0PXL>e ztH9>ulfjnc)4_>n zUS1o0yf*rIZ44xzioec3h8BV?cAtStIMtRMQ@tPS={x-rVc>PTB`k6{@LdXtY zOFMZju@tH$E#-TlBZcb9m2xHMPN5p}q)?4{Q>ey#DO6*bDO6+r6soa63YD%fg}e+! zDdc4+P9ZPD+7$9Kl%$ZCp)`fO3}q?gWhhS}FGEGj)v(==(hgRpTn|>I{0!Wf@=LHf zWh+>dLSB#B6!Lo1rQD8?`jp>*oA?nMI2%*$Lr7D~cCb0+5wIoYaj-Sz4`5r$AlT0L z>`0**&E}Nn5z?9RXK+i(E8y0YF>qVT-@&ewx54g|e}X+JJHYKJAEv~x-W01B?LQ?J z>`zGq2U5J?U`jeTl#&e&r{sepDTUx@%1Ur7WeqrAeK>doKqA-mAbuZyQ+Ty$&qq z`>*Bum+<{d`Tk{m|8l;6h4%*RxxsrASn1sYR(Wp$H+t^?tG#!FHQpYu*85wq&ig1> z@BKZv$vXfxc%K0qy?+9myf1;x-chi{`x@Bl{Ri0QeFtp!PJtcX55Udd|AC!e%M#ST z*8y(z#(>+r31F8u1?=|vz#eZFxZRrv_Ij6recmFl-+KT!;5`T&^d1HddCS0I?@{20 z_w(SW_XKdvTLq4LPX;Hvr-75+uYptEI&g>gTyUrN0+22FHmEIW0v$`f2fCJA3A&eD z4SJTegWe_AFNtNoB|if*m)r+#Tk^-{v8;=Sbn}p&C2t^P`;z}Gx3bi|PbXs$iHgw_E@me4xD=n`577+XT?0OLz&6=Grutu{<9q5168 z5}FV0SVE(qol6dl)fh`nSfMd3)dMu^g2kyvfNN9#9OGamspZ%%O+5xIOZ_2i%Tv?9iqzu~vLW?E zurhTcSe1GzxG}XEvDK+x#db~Vg?RR?HuY?5*QM5j^{L+kH>F+#Hl$t*Hl{X%O{w1p zn^P}_ZAMyXpE%n!6 zSL&nKzdLmswtG_V0=K8$3-+cy2==A+g8iw#0|!!{1P4=}28U9Iz~R&v!I9LzfTO8@ z1IJRw!SU3$z=_mnkn&{ed)S^z{WrKHbtkwp)l}qQEDf$=rlm!Ljx;yuN=pLWX{n$m zZ7JwY^Mk&$0x&aeIp|MY4F-5@VcJ@37o{Bn7N@NP*QR|IEJ>>XOVf@6%hJ9GmZzNr zR-{#f8`91IE7Q&btI`HhZyPzQ)4qX_nzZK;Qk#~HTB=Lif$jRVx4}(m{{$P-HesK} zG#6r<(!Pc5=CtpEEoqm5t!XV_TiOr6_Oxrkj`J=_>`r?C>`8kV+@974_NF}n_NDz1>`!|R97r1m2h&~#htmFz{0yi4726|eZ-Ap| z6W|yRA5VK1+Y@R30w>eHirh}6{TJIi(%4GWf0`A9D+ttlaiGKJ0bRZ&pxc)LdVD#c z*B1bNzWu>W-zw1W`wSTHm4Jo5!@(lokzld!XmG7>16bnw0$A$%GFayO3Rv!=Cn_s^ zHQ3(ZI}@z*eI2awoeysGHGtK=?|?PF?<2RhzDu!P=eq)|_qBqXeAj>tz8`~)z8k?N zUnkh?yBTcp-3qq)?gZO>-C(=#ez3!5M{1jWAEK^0eP(QL@%gxcv`7*&S-#5W- z-$U5H$M+bx-M1e?dVRk~>+SOmfc?IHgb(DbOp&j$VJ`CuTu5G+hz2^OWV0gKZqhilWRC6uHejF8gw(p4BUq|;ryJe~T_ zigfBfH>A@VW@S3{qE+d%hPjcmI-OQBYtm^Yvo@W2*Sd6is-!-ho+{atPEVCIq|;L+ zjp^^9Pi{)DS&4gAI`zOU={IA$HT{0DE&WcgogcS@A9pi9ZYK}f!b7(5kZn9CT|6h< zJP$oQ58L^ky?oC;zGpu_)&LJ5FngkWtrWG)iNpPj!b$k z!j(x!ac5GVJ(>3-)|>ed=*xTz%*>>+`!lI@0d7^8*^ls|%%{M$nUv>}Ov-I(CY7-) zlk!>4)2zs(8rYCYt)()PYOgAj^1m^YN>rUmbzYN6wb#%09N_5;@_mLlhxwi(nRFIL zGpW>LJhgG2+5|t=B;TIOq%*REr?xYb>Xv0ue#*1Rsv?WLDjTxMt5TUoUX`jW@~Tv4 zQLbvT$g5JDMP8M&%-u;tgbA|XLlBry(f#G@hqyn-YlxCzAW;s^k>o88OWmZ zGMGj6Ka@rFKb%Frl~JCDF`kEUo`;Dn>X#;YPNuS`U)qsHJ<`rB>XBGBzS5Z0=jh=Dw9|@~sqQlW(Osn|v#4v&pwo!uKr8Ca+3)HhEPl zvdOEmA)CA^mD%J~smdm=N_94QJ!-Pa$5ES2zK{BB^0REpz6)%~z87rFeh_TR?gg8( ze+RZ?KMA&GKMl5J4}tC3FM=J}e*rtQ>3nU;rt`Hmo6gs^Y&u_E*>t|Tv*~>GWYhWD zo=xYgkC(SUo9cWZ`)}Z2Hu+_SvdJ$q%yT%x^ER4Iewnds^2?0#JWphkUuH6!{4!J7 z{4ymuM!xc%gd@%YIXdXKFQ(2Nt$rsb$CtpmXpL{V*e)7dM`^gv6;wN8BtDk%^ zZGQ5_wEM{y)8Qvy%w|9NVmkfgi`n8QU(8lN`C_*D$rsb*CtpmrpL{Vre)7d^_meNC z*H6BfK0oC7Wv%$7Xz#ca(ZU(B{V^2K!JkuRn@k9;vbdE|@f%_DzwUmp3R2lB}CGMGo6m!UlJ zyo}^g>mALb);pF*t#>?+TJJ<2wce>by2I|sBfrefJo3x1eDcd^`Q(>zGX8w>%LMYtFH@LLewm_t^2-$GlV4_SKKW%z^2sk#mQVdy zc|P@H75UVURpyg-rYfJjGaK{CJ5!xc-kF+w^3K%elXs>rpS&~m`Q)A1luzE7hJ5nQ zH0G0crYWDiGtK$rooUG@?@Vhxd1u=4$ve}LPhObK`Q(M^%qK6*)_iK!+w!SZcjZ&7 z?#`!H-IGtPdV4;#>fU^6)qVNYs{8Y)RS)D-s~*g!Ry~wYt$H}0TJ=aiwd&D)YSm-; z)T$@)$rm%3PrjI`eDcNY%qL$A3y?2H3y?3y6(C=XJ3zh|Z-DOIz5w03GXr$*_6O+R z9SG39yD&ia?xFzQyNd&K?=A_D@1`_BzMHZD`EJSs z>Hv+VY69e^s|}E!t}Z}+y7~b5=^6sm#u@|E#+m|u#GJYX>0ss?pjD%`0AKkDd^MJS za(y>`znCRuKIAg9t%26p_l@dRp z=INWHq@Pvu@=94MWwn$|Qg%w&E9E0nj!KE2Jo9uir7V?lR7%YPS1-zipZv4SOc&yJ zL_(HISuJIgl$}!cN;xVeUR@#Vr7V@QTFNFVJEiQEa#TvZvO(BOSt@0M`tEFs`vQx@lDMzJbG16YjQYovY zY?885$yl*}uau)wvN)NJl%-NuOW7o4rF!lx&r>m$FpKYAKtf z?3A)s%26p9e(6u;%apQI$|fm0r98a?KPg3jeVLTMl+tpH2>+XuM;tHutJ9^-a+pNF zE9I$DULxhsrF=w6lT+;9`G%0aQjSWAA0LbUP|8v%tEFs`vQx@lDMzJbf0yY?xz?Sw z{+Z*REPet1mg5JC3-G@`{tr3+kHrpVW9yDY2hV^v0Jf5fjgER z-2i@Rgo~NoZpS6b?y%!RV|UtdS>d-wao}BcH~1TSJb1S~0qnLXg7?@x;Jx-F@IHGo z*kext@3(uw2kcA02koigc6%E5Te}Z@$esy4Z1;os4buUu*Br5?ea)}eyl{~9;8)9D zD|@Hx{jv|rwDr#Qx$DcIwxA~9$9q`H=OF1g>Ub|o{jZSS%Td>m^V$C>wD5k|&9_|ZqfFfHX1pPV zj(5A1q4}fwwBX+i(!Ukk8feD99osh0jDIJ#9iSQi(b$dx&G?VOwhJ`lKMvcmpc()1 z*miR!pi9E{4LGl}CSm)>))eq3)+JzvH4VJpnht&tyA=FSY!>+6*c@9cr!#H^LZUcbaVrrX%^4H78sV`Zaus&~w%wo^&kTPCJS6Tw zgdECQ8h0>44&yvL?hu5p1I_G+xWlkr2AbLWxWlo1Bxq)zjXMI{<)9hQ2CoO};yw$W z6L%E&^|+%E`wh^HXM>Ny_POB6W=96<7;nW$z`qaw1^6$<|HTK~eZU6?e0I$VYtq-R zUC&IfYA+7b`)ru$Z`!MJ>ox5yx%Gx-c}B$kT}zN#Z)&M>>n$xHx8BiK%B^>`L*&*! zwQ{-jzP|Nued`0QQpWyQ+bFj_)XtP!A88lJEtB;!xn;4o$t|n(Cb?y|-X^!4)_deu zw6#}m#aN$|TXELsks7CYHNqwI>7o1 zx%CwR+TVC$oD>k#Wxa_cbbi*oC5>zLd+!a6Cp)?5E8w?1pNKPO6glr>Rq z9sU0(dlvv#&$3QD1(Jx!B4PzZ4kDIX5z1V8qm+_KGBe?1l4+7Tm)06{W^(3)lQWqn znR9{dB2;863${hI7MW|4)V5wLT5wX@Ti^%`?+}_LgeRJ?n z`JH)g@BM!H-sGR7)JlFCCr7p{_D%H;Slv>O0D78O-tx^Z`zo^s|`FALFW&Sp$ zy7@bl>gDfNYCZpHrTY0VD7Be?RH;G!ai5f!9?d^lsbh{B<$qXZS2=3ps2xY0aMY>% z^VP*G^A{?0b^c{ay(+&?saNN_N?ntmDD~R>DWzVQzecHR^Vci&`uwje^@jX!D|KD| zLrPtrzgwv{=Rc#=4f!uA^_KjjO1(Az*n1_tH|C$D)Z6kuq}1E<=O}ek{zXc?GhbHf zUHQFA-JEYJ_3r%TO1&rFQ|gxdK&kiTca*v{|0<=jM z^M9h$hw>j&>W=(IsFO{g&nPsMdS+q2QqL;%lzMjI#T)(spU#$x4+9&s3^hI7g{!;XI|53JXfr3Js<97OqfgrEo;4X5qL}mlb|isdnLw zO05;%s?`3%yOcUu_#LILDEy&PR~GJ4s$2MkQoX|Glv*$RgHrv%BT8)+&iIU^XyB-$ zg(s`*SmEhPjS6QgbyZu5hnX*A^a7>h*<(m3l+r+e%$mc>HH29oHB3DD~#T^OU-w@Dioo zQrN51TMPS?y0NgK)Y}RZrQTk6wNf_~enF{s7Jf~scNK0?>gK`+m3nvK&y{*l;nPap zQg}$I_Z1#d>ej;J{zhVYTjBeZdVk^BN`0Vku2Q!bUZT_o3w5PFRJcN^I|>7(K3q7d z)JFd$d{L=S75+)7 z`wIW2)MpFdR_gvj@qS6$=L_Gf)B}ZQD)nIDY^A86s}k5(Za7O^^L-NmHKAkcBQ^mxJ#*T7e1-f8O1Ls_1NOq zl*$*srBt!_-Jg>bJ-+xfrJhhcOQ|Oo=ahO<@uf;Vx!6$ZDa9+4IZ!%!N! zvr0Xqc)e23EWTZ-XBFS8)U%6!pwx4UcPVvN@m{6QE`C9&bBh10)bonpQtJ7|CwyLF ze{S(wC+FQI;sg>d%D%C80RH@4x)h_kt7XMb#c17`NN?lp} zF{Qf23zg~>t4ggGTT1ndS1Pqx94Iv?PL(=Z{28T=6<@E^sQ4D8t}4DmsY&s-mD(xZ zuGER*ol2c5{-si{EdGsBR~H{r>Q%*um3npYKa{$r_}vdkie6hhQ>oV#pRLrj#h*~> z^~DR7dPA|S)OE$CQr8zRSL)5h!%E%YsJ9f4tL&}CSA)VX${9Bne?h6Y72l@R+l#-Y z)J???DD}?bol3o{c#l#y7eAxayNeGg^`7D*O5IW{enG-`U-9Wm-C8_bsoRPdD)s*2 z%ar;+@h6qKy*O6tgTO;jhDRoEjSCsm2@!d*&qKvD(}fZM%-5SJWZ*k zJ=n^oT^{>HdF&G9 zu}7504pAQaLwW2D<*_T2&wU^86yW=TGl3rfo(en-cslTdz%zg!0-g!%0iFf?Fz{^P zM}X%5KMI@$JQp|{_%Yxd;KzaI0Y3peA9w+9F7QHN2ABorfO+6N;C$c$;6mUc;6=d2 zz>9%PfR_N50xtzhzyeSPDnJ!j1eSnhpa#4Q*bCHw6`%n$fmPr#paryn4zLF71NH+4 zfP=v0z!ktx0#^b*1$2R*2716DU>(>1`oLje6F344fR_VDfgx}V*aAktHgFX%1}4B1 z*a40MCxDZ{Dc}{rD}nzCTn+p;;8noS0IvpK16%|AEbv<3=YZD%{~fp%_<7*cnk2$z*~V|0d53-6?hx)YrxxqUk7di-T}N5_zmD) zz;6OK1HT2l8~C5Vdw}->w*bElybt&t;8x&wf!l!J1Ktn(KJWqHe*w1xe*k8O|;Jbk*0N(>V5%@2_lYs99o(y~+@D$+tfir<00G;awy{4nrr;75Sx06z+x1w0ox8~8Ec9N@=+=K((fJRf)ga4zsdU;v`#2Y`dX<-irdPXbp0KLvDwp9XrsAz&TY0Q$gTU=uh341kvdM}Z-5 z4A=rjz&3CdFa{>T6xacd11Er!z$xGrz$=0O3S15RH{eyk&j7CmUISbM{4DTV;OBtX z0skGi7WjGK^}zoC-T=H2xDNOQ;CkRqz?*?z1a1I+33vHr>;3L4F0(S!c8@LPjGvK4Zp96OTe*t_9_&>ls zz+VC%2mT891n^1VUf{2RPXV6>?gKspd=~f{;C|q9z~_O#1s(vt06Yl%9q>iq?}3Ma zF9BZ${sH(3@Q=V(fqw$N2K+Pdb>Lrshk<_u9s&Lhcog`*z&C*Z2YeIwci>yVe*oVG za*sj#2Oa}F7I++x2MRzD_%7h_z;^>r0KNx!BJf{;Cjs9JJQ?^t;3>fO17`w106Z0V z8t`=B2Z3h*KLk7z*aJKZ_+jALz>fgW0e%!X3wSPYHt=J>Ilzwt&jWq}cs}p~;9TH^ zzzi@8%mMSjdBFL=1;B;CMZk-Ii-8vdmjEvTE(Kl+lz;`G3{-$Bum~&x%Rmiy8L$_q z11mrSXacLiWk3sP107%u*az$f4gd#%%YiF^pMFgDF+JcAunuehec&*#2^<05^q9xx z-u#%C^OS8ach?7Un7RD*d6xi}0_EHfonOtJd;V7`39JJHU1x_QQ#inUf{F91HePTSAmCtZvfv0@-IRi0G0Ne=N1l$bV0^A1N4%`9U3ET~Q9C*UThzIag0H15+ zo&%f%oC}->Tnvun}C~vTY%eu+krcP zJAu1_j{~0q?gt(Oz6^W~cm((+aK?*K4}m8FPXV3|JPSArcpfkVTmW1Glz|%11lE8n zfF7_390Ml6Dd1JWYk}7T*8^_>-UhrAcsKAq;Qhb{fe!tzz2X20UrTA3fu$S3w#!M0C))aD)2Dy4dB~A{v{}X;K{&KfoB5G z0nP!=1vZumZG!gFqMP14n_YfD^#gz%{_Nz;(b4z>UC7z|Fudz-_?oz#YJy zz}>*dflmSV0}ldU2EGP70(=uV<5I*2I1jiOC;>~r3eW})0$rdF90jfdP5@T}*8tZ7 z*8w*GHv%^SHv_i-w*j{UcK~++cLN^>J_XzlJP3Rl_!{sC@J-;1m!dubPXwLr@`a6j-M@MYj@z$3snfiub|f8dG0Q-G%f&jQW@ zo(IeT7XX(4WuOK$fi>U?pa*OM$AAfN3V0RpTHy7-^}t(zw*l`2-VMADct7w#;KRUO zz{h}30QUi(2fhe=1^7DfDDW-du@#g*@Fd_&;2FTPfwO_<19QMdz@<6v{ z)`0;q0(O8`05aFS>Mz(B4s(m6t!Z;-Ivi~Et6S6YDN}}u#nJd!ZyHJ_x#o6% zYpI^w94-v|TN~xka5Ofideu&EIv8z%uZ(*qTD`5!es$PC*58^=AnWu`){gZy`*Rgx z+B=6lUmk6rfU?SPp@zHRHvSM*CL_}vO#pO{#I-8KXfDXsjUM}f!-Z;fz7Y9K`I7d;8 zDDDXj$BHu`p|C7;Vi!D@L+r%qI113U``ais6s3d@&k_;~cX=?Gjy6%k5}sq7j}}^5 zV_~ffwvP2qihH3`juT>b={$r>=S8bO=}$uq3!J*NJ{=tIqvB3?##Bq&y<^+MetC4f zKSoW5pgcOZJ?>8?{f(&lr^Q+ulGa*v0&${=WN6Y}nH%PnAxDbi6vAiV-eNggd}Z5bv8EQLWo7wZ6qWqpJr2Wn%zhnrQ$Tp^(gXu zHWjDYbev{Wahjc^f}2alX)Yb7xm29y(s7zg#c3`br@2&|=F)MRPsM3I9jEzJoaWPU znoq@PJ{_m|RGj8HPW4f5qciSpO}0mq{z`8;9-O2wGsG6(3~MU3gqW;(NLt+4T9>|M zN)3=pn1-X$c-%YXB1Mv5Y+4-+wx+(9fV+f*iZ~WgCL|0?I7I~hUyT-`s|+8CW!9Zk5$2sny{XDNRIE>=?PyprSPS&C7> zMJ~BVa7yV7JR5~6y?|FnVM^=w$|y`}^-KM&%Xa$XL7#M${t#0o&(|hIpMqwgzd2w- zVyaskCdcr=Bqz?8=AoDOX{du~ERwQWK-Mno96rpoSArClqJa2#rZ#bQLR5Ow9>s=T zW1LbRp(I5sy=~`q4I{kgoUv=c7E^Jcb%0{eU4%_kgKmQQ12Lv3x2OHB^}(>Y9ayL= z(Y>g2r8hYm*p{Z#-ue+tw>LOPD0?6p4-VBw>o!HEDZpUZcShxLzc=l#j&1TIyi-fA zdbRL@ItsBen9yWvUw=I9pOm1v|3liUTf1qHjWYU+1K2vr+ScGO76U5c)b%$ca4F(x zDt&OPv9-cbwzhS6R3B}MU*d;Z2$x~d9_@_RsXK?S8kZm|y^wn{&ziqsK5(B4lTc>P zLRpsEpd!^KzAS1JR}S^T)={qzv5WlLBq(1^#tgN6rDp@0X9p_hQQ7RNJ23lz=81yY z2l5$Cn>h#>>1WJIsF~rko12i4?#JAO8X3xER;79oMZt(j<`nyS!@)*W<-_dfsb(yo z_8UnkyJA7gglcDG!b3zT;n5%#Bz@s>iA*@RB1tkJnH7d6JOspoWI$Z#kx42bp6f*> zsT9pOcw`NY<{MmAu_(hKkJGW04ATi&hHoST);no;Ql7*_3CFsdywi!7} z=Dy4|Ba@7D$lw)Qr831&AfjqLdorV9&z;O@0JA4036b;pEX%oUO9_ZKFKC>h#*O}K zVKf@{ds~ApRU+`Ut!aM~!#?xU$&;my1Vq**BHkc|hku?!Q^&s8?{6IHtsjK~Q-Lh8 zAL4mmhkS5@{z7j;eRIm$K1^W;TbnvU?52jx@(}B0P9XV96BF!9Yz$}zr8jJ0pNWT2 z#4Jl3mS4@6R-%iqag|L9(>0(rL%9?A$?L*M!kuj-;Wbetnc=ByB$`c&=F+11v`9MS z*soL*tV!n_S*4pw4e?5LJ2gZsB}2?oGDIycOSSS^y7krO)6EYuZfqzMZ5rY`)vHBp zpU_M&9^^Bm>QXXW8Odg4B!iWato3dvG2T(YY2v*z(qR|GO)#Z8MG}cUQWHrz!;(TV zEu;O8Wzxx30iQD9aUd`_Otlo=wlS;R+9bxWacf(XX>V)2Pn~VJ&JE>=qnk{xjt9rk z){ghFw>9mJ(UWZSb^A;^mGkFaH={FZ+k+jPKTlbMk~!8t#B+G~teatBO{@%#4<@`- zjJ-42C8Nm^;tto*q?|h^+FMS}(w%~);1OdpZxSMS-Bqq0=m>ASUvm`^QJzGb(<1h} z!|kOSTzcM>`r+fdss>IK?mLS)%E^0{AxillIdEDZgxiC)-CRpSLNTi;4t9B+Z--NE zyz2Pwy1{8w&RNF3@{Eg0hSK86=}x3U!izPjnC_w;XpEqiI)XKkWSRJy5C+k3TfQ!M zC&>yttqg*e-D2mFuvxw&H0Fi#T)YUqi?^pmAM8+zfSVUrz<{^bC8B88x71po>Yv^Y z7DcpYI=vQci3S z9}*9eQjJ(btkF+OvyC+?62^zKjdiq47+c4l5Kl7WJjwQXCp(3hW@q}clN}SxGqcUJ zjMC)=ONSSEw;7zP&@DlA60zuLj>t&sZ>tVel z85h^HdXr>aT#xEal5uf8sb57)?T&WOMdUZog||I);bcNii=~i9|KdgHT*NApy8U!< z7i_7Ez`1e_(6ZQT=-8}3)@=0$58{C&Mb92Yq{k1!_!9`>vA*Y%2jLKiopj^GJ4i@FqL|sFJQ8M95!Y@a!^|jUbmUMHY=Gr&5-o(a*Qd;-Hty+tLJmF zbtWPjg;lIR@VU8)G>I7BVu5nit>dm&v9(a9N{cQ_r)7|-ik(p(Gu$n_r1G>*<1iCW zt+k+Y%ZQZKqik*3ZR~m4b*xXjx0>g}3ri2uu=WJrhvLB3P#kz2inX$722%ZqPq?L; zAms4K+zX@Aeyvjeih&5CZBN_7l-aU)YF7?=>wOW|CUO`eJFOz4sHLSc0Se_hqemsq zkcOi6bVQdI#djny)VX?R>xSAS*!uMmN(m)Cf!IeUEi51DuOAJ>?P+hiqYeVG?ljxZ zVp?PSd1;Mp1qYfinJ(>tUWR_U%$&*u?sZz&@CMw(8(aCN_?$7Q#;9JigT6P z0+!!&!kDec(rs=ww^}<;tuHoPE2U1Q+Agmi4#~nVp9AD{A*2jZwG@0Cf z9zxc0vgm71PYwH%>dA=B;h=Le5mjz~qf)My+U@Fr+(NChQd+Gw7MrcU;dGM250P>cFt^T?E=$CPXIIcCY)kHR_JXBwJ+Ioe_~DIDY+b3E&3zjN04Th1%*OH8{z=XFj68vm%&Ia8}A zu~v5n>d98rK%pJ)pROwTCX+ihSs#sugG0IYsmZi|EGO%s995nicXR8#3EIZ6zlm-! zSHpY^n~rqvEQfXNPM@QL0_iSS$~klx{FnKb^7uUlr1Koe>0J$*64IEl>bulnHP5D{~SyQ1KV1w+FhtMDz(N^7hgvq@YPazZ@0a-w%V<& zl$NS(Cu6p|T&*oFcf{u`)3pXmlg1X7hS6#sIM|J4##O4Ton`Xh1p8a1)ozOT-$dY`KXlj^2h$ zle%Uj6lYj2tSv59Tij8J+kkXFclVX*Ygrz3YYl2%L7{fbYYSC$Hmjk`I>{`Z$~ zHBR|~(5X{5s!OHQsGVzWG1dgruCvw7_2s7zo7JmP2W&x*L+W0Pw*utGPRep~Wwlks zx}nl-EiI%a+;h2zt8uN_=q{tnh@#~^l99st@}%P`_gjs%l`w2GlGPEHb`Y~Ht@Vvq zkyNVE&(^DrO1IMPSV|UH&~BAu0aczQO?gc6#kEG6bA#KRORO}*?pj;h@nvh()%gG(B8 ze3#B~2x4{`gHr1tt+E#D&60G5fivr36Y(Pp^tzaPU=Y~FMq=8vX2ISgpYS>eYJ}rB z?;XdrgJ$t&r!-qB%{B|oCf9cQ>x_+IYh&140>F-C5IDFXaByrXT}!KrX8{mRduD33I+)D&eTP&waFVT#V9R9;4jNY=C0I^)&i&k%8g_kL)pwVP|LGOfFu-!gNS{%Nfv zOFs472@`&~+NqwRCfD|%gT@Tp=3S(r%2&sNZ4KiyHKaCraLyI&NVUTxkuLF8d2}l` zF=^^HTeYPc+t-`>F`n0}iybmu!(isQsH<#M7s(=$@hlwiZ|_a1c;GY*?|#c(gdgxl zs5=ZvF>gEQh^muyP6}a*K6C&@H6f_+}Hq#PHy9bIyxsKhNN)7e8QLgex5=pqHjwBrQNWz&B zNjSNYgnR2q!lOzg;ceO^K+}HgQB|=^)@-nwaubuu1057g zX^90g==!?gDjUyDIWzoH15@dwWJv_x*Dm_^{Uua*&fZQ9qY=$r$qXe|nw#Z14boGk zne$DkRMwz`Zne53V+`eoOj4~+ua^$$3YKTYv!v0dc|kh|SLoZ9y-HNdmURZk$r|$yNc#YgG(awcMVv|Cau=s(7biqVs{hWAw@^N z!W$Fq?ozdZotBQYgp61Qrqm&$@p08Jp<%V)TZ{UYGTH}8cS$JK^j5uE+K23o)4GcT zmoqZLak@iK0&$jUMk;)Vu&Xj!({amQt8r4PX*&{a+tC48y3k2Ih0ekIU=%zs(o>}i zO{N5LD(D}UTGeVJ6f9utD&%Pl3GAt33VG}yC)h}BGpevDnk;OBCNsP2`IdBKG{K0c zV!Vmu#Zi;AX=hS6M+J}+^1y@Cx>=&k8AFN88$*fA9YcxDA48d?jDij2VJ<|`@mZ3J zsi`C`nXV*KnJSB2rZS9Xra>5A*-zPDk}*rTMzb3W77n78}ld&fZN$1R^V2(`>ZSwfUiwR{s!l#F>1ioNk}`D3m!_1?LS4qn22mYtNvJ6_IM z574|Lrx6EOQm-b1HDJagEu*>e332m^9l<{aCsVM$V;JmhBkB2~7 zFH^X!rEc5P3lW3(JJp2&y%aGEF;@!Nne#(uF}ILl(QA5RJ>8?={i@!LQ%IZ}2~$F} zYJB`jX|tJQnF;~fwMYv=o!EIDX4IJS)#^C4N*dAWQ@dNLysT8l&JSi~+Mvk2D^IU7TsB1ScS5BW~}vapVb5-LD<2koo9CBX)~G&q4%cDq@#7Cooj#dBBhFMU+kjQ8yG1q#a(Y< zWa|7)3{#^UE0@qGNjGQGI^DM5lNjp4u&(2dtcBe;O;j5-1+GMAGFxf1SF2?@gpbwH zO@S^R1&9`bdR-tbM@^y=r=-2VIFM3N<>M;_PD2uRdBIw@B_&eo%?8s+`Z{!`K%P-? z;=r>*xv{TVU*pq=-EAn}u=Cie(RL~^u}55mcUAnS!eKAe^7Nra;c$s-dO`&q>sdNO zxy%u=G;*mT!z)|lW;v3D2F(Ssw7lxrO({qByJ_ods7AE=#Ov!U&(T0=UkBrC+7B(N zC^06(0Jm3%=wuITAHqqQUy^&1{NxPH#jJ3X6TW_?+H`qjP!_ ziA`v;jIBaBEYl7|I`x#;3#7KGwHIskOvzmxOlg7|n9}+Bmr@0_FQrS=y_6n3=3eVo zP)oVjkpV)vI29@kT}kiJY2sjjW>4lB`XbtLrA~>u01X)1Y&ghothK4H%FsKhq-l3o zkzNkTqJZeQ67$fC1&lx)N!_jvf>^7;#7=Nks^k0%G4k`Z4&`SO{A_}sOYrjv{=5W# zeuBRs!C#o*FG}zjH4_m`#&9MX#hGLrXOfYeNyZXuk3=ZRc+MmvI+Kj)Y%->^$(YV2 zV>+9R>1;Blv&opwCSy9AjOlDLrnAYI&Lv|y=VBUP!R1TZ@-Q)~ z8`gEs4`buTA{JqrlQV1FTlS4gL^Em8Y+8iwChZ%#oU{-fWGHOnpt;njL;$PH8EjOzS8W>h52Z_>%828POdkaJ3jhAqmi3@^?kMKep>~p&)x#f(3qhnAmuF)G zyUIZOo7INiJyb8G*0trP0Bs9c4z;V8S>xp_Yg`(=q*$|nYQ||T=zi7dEofKQXJd9a ziG0j9(s;-eUvDT|&?3}Z%CXShRF1`DD?OR|>#hZxox2)rf^ZUNmyAtktpoe#bgdV8 z+zEE0Oq+C-xXEnAtJ~H*;A(lQh;I>_nUs<3aZ78&+IF*P51Lh zVW$n*@^tsh)mD0ZhlMU!o4{YPHVK=EIIcE&Mi~n+@ZiF=xz!ZVXk@KX&Gn`=Ur3Eb z99}GTavL z(cDSqQa1A@p*0&_FG%pth3cI>-(S@b?JlcxYy#)n1kSm;AL!gTiF4#6&Xr^!-F~%b znuJgCc?-rQ_~22aXA)kVC1mhP?ph>`;o+_dIu_2bXL0OEODMWgYc5qs(;t7iHlYme z*(NlJE4K-4;`VJqE61H^+7g9!QZ09B?N07#wS3en*BBCZT8X2Zx@O`hA6gvR%UN@X zrE-l4ZmGZ5?<35otnM)!7BlrS;W$koVRN!xA?XuWHj8ka116=J4K5FBKr}lrO~#J< zZdP=7tU8Oz?yeISaS|=?U{0BB(AnR_63x%-lS!v?NQ?pIca^@pq9Z2keqd`w{Woo5 zq@)~){B|jgr0|78^!FH&-b$cxZd;JLDP3xpYqg|1)5*-pT-31CY_0Lukc&@Pc3FCJ zi&Y9;AI~xgy*Q1T`P8Z6rfCb`0sG<)eaKLoOZ7a%BJ^N)EAxkLUE&4>?$=trh3?Z@ zbEiJ14MOL;8ksNB=re;(sLX|Wnb2kgny@hU*qES=R=(gxw>GoG-p$B-u~_V8mldD? zjBUM%V=&AdPFE(?#=Z;-i`g2k^t8GfzdBuPbt&}w8QC3(bU1FqTUfWJu^Z=NhU{#LaJ`s6G)p zf2N`OMEv}ThUoo)hVqGw^T!#gPh_1x%uszI^ZZeU>J!=L4>CmW&oPvD`KO(*4&>UE zQ~gy%`aY5`bAM%?XK}8k1EM*s}G2FVO3__-Hl29Mi#mILS1*9P4Lk_)tGfA$wF=8h|z-~!$S7sy<2SuzPO z(8$)IJNc&rjcBLQX`e3xaT|q@sEaZuMZQo6f*61#|d`}U28VN_S{sOk|=uZQ$F7ikGb$vaGrswfCe(KZdU zxRf#3!4R%&sg81ylWRygLpcYT;tvC<$T%PC%_hIM#td!cGl#$OMIhN3Bi{i=lEo6& z1r&9K{U*Yj;cgif4!OXW_)YqYMnr$;k_RVUWqRX061$5aX&dg@N$l>B#5R$bn2fL@ zu?q_wGb%W0DS3$F2>!cRs<)Zor$Vr?&H%)j_#@SlGooCUKh5eQKUU)2nXEKdO7d=!b-}Lfn1JVl zlu{GO&QvI|?uj?!xCWZ748y)bCgdr<)&4trXh)x6EYz*3=u_01yr`p3NU4F{*W=QY z*Mj-!;DE<$C+7Tnz`6-Z^P$8;z|yBWubAZtI(g+e?^Phn^h!oG=h{X&d<0Gt_>|l~ z!^uNO_}&W(@PT+oCz>+0;MrpF1YM>p39Fpu+<18+ne3g!$Io5wB0aw8#M%OzZ4u+% z>y&QB^fod}MEuvJau7$utIjimFHLQqFX^U)3*-3qgT#D7ARnf3EclZroV?(b7+UyP z$MME{@CN!ot#KrdRSs zGW$eZ49b{P<83N?GFXK69;8fO5+*i#F|Uo^#mxLNGY$&pIq|z_$;Tv5^Uh?TB9c;P zeka~xi;^p6Wv=SDJ#lhxQ!k<^Z{-HL3<8`Zq`;YjT^vtntcyvAy-yN$!V@nv_g_qu}Ij7FtQV;)|BXo!X-_n zH!`>8n4z&(c@`=QeP@UdHR#K8zCwccHt5XBzNaF0+QG|f^7cYu(6_r+3tc}Ln^OBW zXI4q@K|z-*eJJ2I9tyZrL&0SnA6d;{eo(_G-<6NcovckV_FCo!G>>3A_ADXe{wpDq z3s%lQcFPZCdprJQAmQH4DcVhecVTS6j?;lt zg=__$i%BUYl^F_2YKB76o1u_IJB6MIwfCcJXrj->rNVl90T1D|q{CNPtGPdTv&dZ2 zZ(cwXI_BTO;BpG3nD#6+=#>@DT$%yLA@d1V6fR5RP+7$OTbN$rLu6SL9@RfLg(OD1 zd5ViP-u7}$-sTk6KL)~EgY*?T*%Ct^ffIdsv$@jc?u99yw(C}*nG0(UWTVh@%$Z6$ zRQ^8-eQoOT?;-DpXZ?LSD_8YhLR&-n1` zai-C-5tS8&aF+YR*=)fa$}A`JSR_^v)JNLT!a#{n5o3pOP+2)xT0>{%mpZ7*Gdfnz zOFn_;R5~tUY#A&!6nM?cp2YH5=RB6r?IQPq>n5@{RDoH{CZanVMRzt%+pMb(adeY% zi*8bGu}I2&WD?Pxwd+l0F@xn44qp9&lrxKE?J7TmtyOV#Hp5b7p{3=gyvJvpEccV! zOmD=Lsnk+Hxr5_5>*5^dGSDPL5GCBow5^P@Z_PZ05(HLdt!oNr1Kei(?nxJ7# zL`!4+1dpV&L5b}>%z+aM+JMLB0A!;iZ&u+&TLdLyT4RwOn^^h>gA!`7?hWcM9MBe* ze9kPdnKg8S^?G&E{Pa#j-DNT1u41du@$m{{^B!0K9rCZ088}wT%x6U zvJ_uMv&8M*?5$SWOTAe}O8PR9{?Z4D^miW?_foLpz4RYcL$I761Dwd{4Flr1WH=Od z&2xK<>v#Z5Djd9(6BKL4bkEpUI-$&!Mi-n5i|lua@m zg+RX|#}dwc{v4em@Au1eZX;6|dk9mF`85$8yz~o4dArmmL|KO~a!RF_U$EOmzm19z zZN;bxet{%I?y7OZp7JEa+$uS@pLsH1ieGGJN`C7?Na?Qa{VTS1?TcMFPF#65;Zg#L zJ;3!=x_mZEac~apMp`7K>!@TJyEkbnXfc)_D53$8Z&Z?pj$w}+$0>1~c;{J8No%gV zgmV&(D|#AskH0*y;V=7uzw%2WM3|+-0uo6l5zcY9!~-bFya!!x=sdyAN{YVKVw%S$ z=LWjM(RHd>@?17)%2}E6z?DEsFfoBRD^`Iz8LdFIPk#Ae-yENBmFL$Mx+)S{<#UT&HEDRVJipit*beSk zt5FA)kNkgxg_kIwY@FVFh{Bk1k6Jt~Ncz=xF?C$pXH_K7mNp@&++@qRL^mcF9 zpHBN5U06+b#(k3S$DlVk(cA7G!LKr#U;{t*+8y_{Hv3)tyfFP7`-D_cfx$zPMTMoZ zu%J{F7Ltmx3P@GS!clP)K6PBd-4pmG%~NjaXS(2;m+6K-E;mh-B&y_@3aQ7Ls>ru6 zGr~BB@-UE49)}TXq9DS|4ZRBGu~(rc@+zxP!dPeN!yvQtanM;7Q52GeA3INKBd1XX z(H5OqLJ3`%vk6t0Qwdd8N)jf?*e29+&R{W=Sjdx$@qNlr6W!Ac6*ll^dFLkpSz0#{ z$Wrf3B+9?r47sU!@TGQ zsW*$1aL5mVt8R6IMUpVX?!(pB({UvoP9ibVl9i1JN$cGtu@{vLDa}_0l$^W zFBa*~ORBijtkcV9eB7@hbKm64f(aqwuh+v83fUOiC$Ws;VXyC{V_3qK(xvKU^y!aR zF5tH#sAj1D(!qFM&g4~TcaDs;cWS&j$`bR{AXe;smwq(C8)+vN3lUJlOg^DcSXqz> zTMaiMWglpfVG*X60Hm&Rma%>=p{MmpXitlrkf*gs$kR?<$kSRzdHc*lGC>!pyQ%5< zCA=k;R#VRG>Xwu#momL~kJ@@K8`#jHJv=HSY<1S_dM9lS=h)c6r<<&(;+RDoU^jF* zMJ~ahkQ5k$3KR&W1_c7CLV@6-RK#c(I*w{8uDpJZZBnu2-|dWTQt{>0 zcWjf2G5@G}Y?F#J|Gar*!@qGJOHvukzjhwmq_UWQ_dK>qWitN)dTf)*X8tYo$cBFq zJ(i^MnSbCpwn^plTq@3UseGPG#d+?6T)nn{7dH;#S_*zwvhG+Eey%pDo}Bi#CWFz| z;?CCk6o1=0+uI{7kv4L*t>dGk{ggqjldBBav^PHW)3dn>RzI7)X+MYcQtZ_vw=nE) zZInmD(OAgpRXaTjBv--WsYPq2sx6&5{gbt0z0E#uhJtMG95Svv+CG((z{5`O(6FCl zznNU^jeE!X)BgDI@hs_pq}!*weQv2g-Hmg8iBE`(g{D3P5@gbFhtjk-7$S6Ryp%@? z8Ma*lS?D==moR1zGUT*(LorU6CxqT}7`OY|$P{FgL@k%##mD8rWIDq7_Za!)n8=@% z!Pc?fNzx1DmCin=Hm&|7@FmBrs!FIc$NMNrURAey$F_(4@(9cE-X@jfvF&kxGU;yw z^&lrZ1aDUR2U{DX6RV@iY|fGBnEG3n?exck{)8LCZ}@MtqqYOYh$8$=;i(OX>I{QEbJUUj5twGGVKd9p-_yhP1HjERC?21 zPDqp;bMQSDtn{|k%^E7N(ay~0kQY(TAr_qL)={~fr%V?QC%HEIx%I)Yx$U$niONc4 zE4|54XIGj|d+SHqM|v9+5K<1ocyOpbT922V0v9JA)ym-y7Ao4v*@iO_FFL9FkqZfCa5*Lih8v~jH^oA`=csTBu_9TU2fz>Rp z6IHbq6-X^EPBUE0y}ve3O=#-h6v<|I_h z9R+=(KO-R3(`8e0j=kYE|6)z#8U5B|$LvB)Vx!q7FMbbzwoG?*mQ==0u}c^Kt{HD( z(_LGOPs&0!vQKLx+u5fz(M|2s+E8S|JlrKNr#0cIoYq2O;!T1j1{ZC>yUMEyS$sr{ zGja7>jGSDmwp-hfWA9D8!XaI-$RU>JkK7wL&SsM&h?Wublvl>;g2d5^VkRY-O-bfb zl6jJ(*E4h2RL+vm?joN_%Y9Fp^2$^hzL`oqj8}l<&*m^=Wh4s94IYmDl8F?ys-cWE zS_f7VC6-H($ObJEZVuUzs{rJ6Vu3_vu_y?Ki#(kCleJqgaZx#ri^QOQ8cx{BRkWO9LAavw?qosZ`Ct)1 zuKZNrn@Y$hutZmT-`<)T-b3tnk%nb8b6wA9r=;HNGKNP=vUSR{)~S4wJQYc#Q) zs8oZrsiE2O&W!3}OXZRo8_vWyy`g}U5(+rwp2wt* zb5{~jqf;Tf<=qAqXa;SCtkTu3<1VYY+*D4PIE*zYn+!)A6k4|GaIA{GjCC>RQw5L1 zj8wBw6l7(3%R%kKHNT0XtqBqadmzMeuV+J>ZE;Y~C!X1!NN>GQ!rDZZMlz)*2}LF; zlTIL%PRJA;VoDYY+S3tjBZ}!X)VKnYLA^E!))f|sgh=8L2rUXpQTa%J{b(R;PkYlH zHV%Zkc#*kzS}t?rv|QFGfjmrc;jWU>&4$fkX?=a?82ue?AL;Sx6ZF`2 zyHWKggAEi8Sx^>fHiG5RlKvtOZJkTp6s1LCIzUnX%Dv&Rj@^2QjhqloYjyi;@n9iO zLQPZYZ%>aHQ{z>*y48lty21A9u(#DGnoe!z4teUhBR4$dg@>IG2QcP*;3+TUNVD$~ zFWm7V?Hmfk-iI9=;h4WW-j5yc$-MJp-g`0cVmrU#JeYT}o%gYwcVW%@pypjj^Fcs9 zw(~)3=XbmhL2T!JY(cs>@XnVe2;)2U(|bcppmy2JZl78moa_%J9()wWyBavHAje*S zV+|+pGwrlY>~@C3MfA*2OKYWyML`IsHBkhpH(CR^4r#oZmOVAN(mgsy$)bijL=M7r zC=>!1X{X9qpQ5ZwZFOU_zc}n|LT;qb7n4wS>PDdvaoFfV*knVSPW5;X*+z#pEcYDy z`DN1pZRxqd%08#qnrsss+3_-kD6fcfw#`Ss?-3ool;f+P4#CslEz9S-=$49U+{E z>JN+9Yo@3J5W-n;*T*vH`D$B(X#-oeVv3T&aCE%CA@c`vKCx|kqO}p$CdfM8)5V&f zYRbxJqd%lL1snzGS&Ci2Ii+*NnZy>(loNu*T;G>9ar*}wJQPx7_!Iy><4CqfBlKW; ziUI;FYc9$<&v9VTQG!{qIaqJfIF0Ja{R#agBmCuFg8nMMG#*Hw0~ynS+-ym%_Sy#6 zub@5HNI_|IG-ZZFm-3MqY?t`>dyax^^iOChG;n&-8}b-$B>AK?rQFCs%wC8?&T%!N z_!t>jQ>{=jH%6g-^=yu(M@Fz&?M)_~BjeG|CiQXFfH?qTqwX@uo!wq2fjKS= zODd*Qg<(mxG!@rM&xB!doph=wEUuAG6{U;oqfCs1EKuLjYQ1wI-tA<%89p|%e0 z(}|(5WE+92l#%42(t!mhOvMxjBLizHS`~9<3(Zx?NN>&6N5z5PbKY;MIBMekmP#XH zt};e?zqz`oIPjaRii){Nl=gnh8db!;itHQoPtcuCByWc&?{2ocgUPXHcrfPt-dXLB zC)?a@(SW$KI#@sIMxLGeXmqs1zG1hMFLA+SjrLBB;oi!ozdL;4XQm=sP!w5_%!U%o zN-o>!ZHx!&q?c7_AW%}K5A20XP*ZdsxucRME~agvC#7qq@Jgk$>TFL>@qB-$d}=u0 zYZ?^P02fg37Zq}f6}YkO?IV3$Ie-E&>)>XhkCt)tm$z?phCmihhV%R>ZYr5fio`gq zNfUZV622few{dHWW~1z@B%L^v83hv>AdZcl@gdz}#r+eQNgk%e9OL%R_^_=0cbG5l zjE{3-DP{qkwCmtD2l)*%BUeuhoeK^u<^msR8qJ4(xTe9CX`L4hJM1b<4H6j3u(ZUr zE86tpi$1c+<+s|hHrk?XHrZqgQW|AKxb>zRZ??adGh%{cTH0pgewHnqb@3$r)jpB8$k- zW0BMj(;hKF>KzDP-QcfPJ-0P8lXK)Old>m6LfMfaiUSl&CTDYry%^nzk$o8Kx8SCd z?X}oW3x-U|Ul1-MQLEh^3us>@uq|txIsI|8xLH~c~Z%g6_wO}zb`-=L-DSF z?gRK;0Kc%$NeaV7yI-P=5V{Xv*z+ zBdiL5rv`>U)VlD;X3j>UX9nrp6Bz5X(TxWj8QSC*w>K=Cbv_|~XvrfK=95YsHez7J zLR>kK}W846y)L>GI&gEzyW73$8{fKUirg%PL(?koy0WQR& z>mT6MmOjA3At^qkrjv=mR&Uz3fV_kUO;nBPTqU1I(iT=c!eFI4*c!>?K)0g#Ex!8)o zZC=IITKbNkY*^4fh~QW7RkD}!1HaV+f z)2Vn}fqn<2BIX)fd6|(?$YT1bh^{;cM?ugpZP0hpUc$e$;YIsby8IKI^uS#}msVGq zT|6KUACqeFKpn4BvRJk4z2yaYP=j7)B~6(g8K}PuAC%)cOfTTq>sY-?FTF_~R9Mg1 zQC@%ummJcG=? ztYBQL>b$}i@VKgh*O=GD76rmqs|WcN0HXP4l33cQbH!WeNNkm@)R#hS6)(VtJpGo# z0$yJyuhhj#dnqAlms?HxG+t7xW|R%JGCN#jFDunj#j*qs>f=}GEgcm+{nu)8+?AxK zju)Dx7Uw~wx(}~zNcNI{;Hg*wfqYXR2vDhFFCcKCwVJEA5RXSH;g|e^l2Da49-^Sv z646~<65*XjLD6VM|#E2yR{z^{K)7xpemp;Zsy(a6vod}zIha`Ta0s&-Ha zWu%CF0!L~kmz$lvRn8d5Yq(Ue@|9Wx7wKz_#ik16bwy>UQUqijUqW}5Nq`z!S+3SA zu4$OS+6R=JKp*b16fV0KGRjzr6WVr=c>M4sH3hB-|&1az3boNKWth)<9vkgjlow7GQc#TzV( z&GH&o-ul8?r_*dy7V72tUW$?lG=r3t7_B6YO`yigsxgv@UT2^7WGk4fmGE-8R8itw zw*n?;zTi+%*(uj%@Ki(S;XL{g5=0Ras<|ul@}RH{t*y}DS19n#-?HT@OZdf1HO14k zfv!Vu?2;eVQX74v~DN*m=c0*x}hRw+}*B066v zjdD;Xjq-90L%dY|M%n6!t2ADuHNgoa8yaP+DS;CcIVVx|ffLFAOJ$?HiZPO#9$vXk z)5ep39&}VvYqL!A zA8)nb2}<9u;MZnk_JPMHFhz5fL0BvQ)h7MS5Q>k9g%%!-L2Kgdz)P2sFH9hQ^ui@9 z(N(n$Qcbl8vH(3|FhsGafnNyJshT;XmoL;0ba)3FJO<-&X!baj`zFx5k8)mK9>%LT zlCj+9h|K3Snk0U93%?ggL4t9e6Vs9!kbXb`V~GNZPpW7FC~mF)g`8$QzU#!#)a}

+ A FontOutline entry contains the details of a font face. + + + + + Gets or sets the HDC. + + + The HDC. + + + + + Gets or sets the HRC. + + + The HRC. + + + + + Gets or sets the name of the face. + + + The name of the face. + + + + + Gets or sets the height. + + + The height. + + + + + Gets or sets the list base. + + + The list base. + + + + + Gets or sets the list count. + + + The list count. + + + + + Gets or sets the deviation. + + + The deviation. + + + + + Gets or sets the extrusion. + + + The extrusion. + + + + + Gets or sets the font outline format. + + + The font outline format. + + + + + The font outline format. + + + + + Render using lines. + + + + + Render using polygons. + + + + + This class wraps the functionality of the wglUseFontOutlines function to + allow straightforward rendering of text. + + + + + Draws the text. + + The gl. + Name of the face. + Size of the font. + The deviation. + The extrusion. + The text. + + + + The cache of font outline entries. + + + + + The OpenGL class wraps Suns OpenGL 3D library. + + + + + Treats each vertex as a single point. Vertex n defines point n. N points are drawn. + + + + + Treats each pair of vertices as an independent line segment. Vertices 2n - 1 and 2n define line n. N/2 lines are drawn. + + + + + Draws a connected group of line segments from the first vertex to the last, then back to the first. Vertices n and n + 1 define line n. The last line, however, is defined by vertices N and 1. N lines are drawn. + + + + + Draws a connected group of line segments from the first vertex to the last. Vertices n and n+1 define line n. N - 1 lines are drawn. + + + + + Treats each triplet of vertices as an independent triangle. Vertices 3n - 2, 3n - 1, and 3n define triangle n. N/3 triangles are drawn. + + + + + Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices. For odd n, vertices n, n + 1, and n + 2 define triangle n. For even n, vertices n + 1, n, and n + 2 define triangle n. N - 2 triangles are drawn. + + + + + Draws a connected group of triangles. one triangle is defined for each vertex presented after the first two vertices. Vertices 1, n + 1, n + 2 define triangle n. N - 2 triangles are drawn. + + + + + Treats each group of four vertices as an independent quadrilateral. Vertices 4n - 3, 4n - 2, 4n - 1, and 4n define quadrilateral n. N/4 quadrilaterals are drawn. + + + + + Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertices presented after the first pair. Vertices 2n - 1, 2n, 2n + 2, and 2n + 1 define quadrilateral n. N/2 - 1 quadrilaterals are drawn. Note that the order in which vertices are used to construct a quadrilateral from strip data is different from that used with independent data. + + + + + Draws a single, convex polygon. Vertices 1 through N define this polygon. + + + + + Determines whether a named extension function is supported. + + Name of the extension function. + + true if the extension function is supported; otherwise, false. + + + + + Invokes an extension function. + + The extension delegate type. + The arguments to the pass to the function. + The return value of the extension function. + + + + The set of extension functions. + + + + + Specify a three-dimensional texture subimage. + + The target. + The level. + The internalformat. + The width. + The height. + The depth. + The border. + The format. + The type. + The pixels. + + + + Texes the sub image3 DEXT. + + The target. + The level. + The xoffset. + The yoffset. + The zoffset. + The width. + The height. + The depth. + The format. + The type. + The pixels. + + + + Render primitives from array data. + + The mode. + The start. + The end. + The count. + The type. + The indices. + + + + Set the Accumulation Buffer operation. + + Operation of the buffer. + Reference value. + + + + Set the Accumulation Buffer operation. + + Operation of the buffer. + Reference value. + + + + Specify the Alpha Test function. + + Specifies the alpha comparison function. Symbolic constants OpenGL.NEVER, OpenGL.LESS, OpenGL.EQUAL, OpenGL.LEQUAL, OpenGL.GREATER, OpenGL.NOTEQUAL, OpenGL.GEQUAL and OpenGL.ALWAYS are accepted. The initial value is OpenGL.ALWAYS. + Specifies the reference value that incoming alpha values are compared to. This value is clamped to the range 0 through 1, where 0 represents the lowest possible alpha value and 1 the highest possible value. The initial reference value is 0. + + + + Specify the Alpha Test function. + + Specifies the alpha comparison function. + Specifies the reference value that incoming alpha values are compared to. This value is clamped to the range 0 through 1, where 0 represents the lowest possible alpha value and 1 the highest possible value. The initial reference value is 0. + + + + Determine if textures are loaded in texture memory. + + Specifies the number of textures to be queried. + Specifies an array containing the names of the textures to be queried. + Specifies an array in which the texture residence status is returned. The residence status of a texture named by an element of textures is returned in the corresponding element of residences. + + + + + Render a vertex using the specified vertex array element. + + Specifies an index into the enabled vertex data arrays. + + + + Begin drawing geometry in the specified mode. + + The mode to draw in, e.g. OpenGL.POLYGONS. + + + + Begin drawing geometry in the specified mode. + + The mode to draw in, e.g. OpenGL.POLYGONS. + + + + This function begins drawing a NURBS curve. + + The NURBS object. + + + + This function begins drawing a NURBS surface. + + The NURBS object. + + + + Call this function after creating a texture to finalise creation of it, + or to make an existing texture current. + + The target type, e.g TEXTURE_2D. + The OpenGL texture object. + + + + Draw a bitmap. + + Specify the pixel width of the bitmap image. + Specify the pixel height of the bitmap image. + Specify the location of the origin in the bitmap image. The origin is measured from the lower left corner of the bitmap, with right and up being the positive axes. + Specify the location of the origin in the bitmap image. The origin is measured from the lower left corner of the bitmap, with right and up being the positive axes. + Specify the x and y offsets to be added to the current raster position after the bitmap is drawn. + Specify the x and y offsets to be added to the current raster position after the bitmap is drawn. + Specifies the address of the bitmap image. + + + + This function sets the current blending function. + + Source factor. + Destination factor. + + + + This function sets the current blending function. + + The source factor. + The destination factor. + + + + This function calls a certain display list. + + The display list to call. + + + + Execute a list of display lists. + + Specifies the number of display lists to be executed. + Specifies the type of values in lists. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT, OpenGL.2_BYTES, OpenGL.3_BYTES and OpenGL.4_BYTES are accepted. + Specifies the address of an array of name offsets in the display list. The pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of type. + + + + Execute a list of display lists. + + Specifies the number of display lists to be executed. + Specifies the type of values in lists. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT, OpenGL.2_BYTES, OpenGL.3_BYTES and OpenGL.4_BYTES are accepted. + Specifies the address of an array of name offsets in the display list. The pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of type. + + + + Execute a list of display lists. Automatically uses the GL_UNSIGNED_BYTE version of the function. + + The number of lists. + The lists. + + + + Execute a list of display lists. Automatically uses the GL_UNSIGNED_INT version of the function. + + The number of lists. + The lists. + + + + This function clears the buffers specified by mask. + + Which buffers to clear. + + + + Specify clear values for the accumulation buffer. + + Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. + Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. + Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. + Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. + + + + This function sets the color that the drawing buffer is 'cleared' to. + + Red component of the color (between 0 and 1). + Green component of the color (between 0 and 1). + Blue component of the color (between 0 and 1)./ + Alpha component of the color (between 0 and 1). + + + + Specify the clear value for the depth buffer. + + Specifies the depth value used when the depth buffer is cleared. The initial value is 1. + + + + Specify the clear value for the color index buffers. + + Specifies the index used when the color index buffers are cleared. The initial value is 0. + + + + Specify the clear value for the stencil buffer. + + Specifies the index used when the stencil buffer is cleared. The initial value is 0. + + + + Specify a plane against which all geometry is clipped. + + Specifies which clipping plane is being positioned. Symbolic names of the form OpenGL.CLIP_PLANEi, where i is an integer between 0 and OpenGL.MAX_CLIP_PLANES -1, are accepted. + Specifies the address of an array of four double-precision floating-point values. These values are interpreted as a plane equation. + + + + Specify a plane against which all geometry is clipped. + + Specifies which clipping plane is being positioned. Symbolic names of the form OpenGL.CLIP_PLANEi, where i is an integer between 0 and OpenGL.MAX_CLIP_PLANES -1, are accepted. + Specifies the address of an array of four double-precision floating-point values. These values are interpreted as a plane equation. + + + + Sets the current color. + + Red color component (between 0 and 255). + Green color component (between 0 and 255). + Blue color component (between 0 and 255). + + + + Sets the current color. + + Red color component (between 0 and 255). + Green color component (between 0 and 255). + Blue color component (between 0 and 255). + Alpha color component (between 0 and 255). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color to 'v'. + + An array of either 3 or 4 float values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 int values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 int values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 double values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 byte values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 unsigned int values. + + + + Sets the current color to 'v'. + + An array of either 3 or 4 unsigned short values. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component. + + + + Sets the current color. + + Red color component (between 0 and 1). + Green color component (between 0 and 1). + Blue color component (between 0 and 1). + Alpha color component (between 0 and 1). + + + + This function sets the current colour mask. + + Red component mask. + Green component mask. + Blue component mask. + Alpha component mask. + + + + Cause a material color to track the current color. + + Specifies whether front, back, or both front and back material parameters should track the current color. Accepted values are OpenGL.FRONT, OpenGL.BACK, and OpenGL.FRONT_AND_BACK. The initial value is OpenGL.FRONT_AND_BACK. + Specifies which of several material parameters track the current color. Accepted values are OpenGL.EMISSION, OpenGL.AMBIENT, OpenGL.DIFFUSE, OpenGL.SPECULAR and OpenGL.AMBIENT_AND_DIFFUSE. The initial value is OpenGL.AMBIENT_AND_DIFFUSE. + + + + Define an array of colors. + + Specifies the number of components per color. Must be 3 or 4. + Specifies the data type of each color component in the array. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT and OpenGL.DOUBLE are accepted. + Specifies the byte offset between consecutive colors. If stride is 0, (the initial value), the colors are understood to be tightly packed in the array. + Specifies a pointer to the first component of the first color element in the array. + + + + Copy pixels in the frame buffer. + + Specify the window coordinates of the lower left corner of the rectangular region of pixels to be copied. + Specify the window coordinates of the lower left corner of the rectangular region of pixels to be copied. + Specify the dimensions of the rectangular region of pixels to be copied. Both must be nonnegative. + Specify the dimensions of the rectangular region of pixels to be copied. Both must be nonnegative. + Specifies whether color values, depth values, or stencil values are to be copied. Symbolic constants OpenGL.COLOR, OpenGL.DEPTH, and OpenGL.STENCIL are accepted. + + + + Copy pixels into a 1D texture image. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the internal format of the texture. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specifies the width of the texture image. Must be 0 or 2^n = (2 * border) for some integer n. The height of the texture image is 1. + Specifies the width of the border. Must be either 0 or 1. + + + + Copy pixels into a 2D texture image. + + Specifies the target texture. Must be OpenGL.TEXTURE_2D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the internal format of the texture. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specifies the width of the texture image. + Specifies the height of the texture image. + Specifies the width of the border. Must be either 0 or 1. + + + + Copy a one-dimensional texture subimage. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the texel offset within the texture array. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specifies the width of the texture image. + + + + Copy a two-dimensional texture subimage. + + Specifies the target texture. Must be OpenGL.TEXTURE_2D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the texel offset within the texture array. + Specifies the texel offset within the texture array. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specify the window coordinates of the left corner of the row of pixels to be copied. + Specifies the width of the texture image. + Specifies the height of the texture image. + + + + Specify whether front- or back-facing facets can be culled. + + Specifies whether front- or back-facing facets are candidates for culling. Symbolic constants OpenGL.FRONT, OpenGL.BACK, and OpenGL.FRONT_AND_BACK are accepted. The initial value is OpenGL.BACK. + + + + This function draws a sphere from the quadric object. + + The quadric object. + Radius at the base. + Radius at the top. + Height of cylinder. + Cylinder slices. + Cylinder stacks. + + + + This function deletes a list, or a range of lists. + + The list to delete. + The range of lists (often just 1). + + + + This function deletes the underlying glu nurbs renderer. + + The pointer to the nurbs object. + + + + This function deletes a set of Texture objects. + + Number of textures to delete. + The array containing the names of the textures to delete. + + + + Call this function to delete an OpenGL Quadric object. + + + + + + This function sets the current depth buffer comparison function, the default it LESS. + + The comparison function to set. + + + + This function sets the current depth buffer comparison function, the default it LESS. + + The comparison function to set. + + + + This function sets the depth mask. + + The depth mask flag, normally 1. + + + + Specify mapping of depth values from normalized device coordinates to window coordinates. + + Specifies the mapping of the near clipping plane to window coordinates. The initial value is 0. + Specifies the mapping of the near clipping plane to window coordinates. The initial value is 1. + + + + Call this function to disable an OpenGL capability. + + The capability to disable. + + + + This function disables a client state array, such as a vertex array. + + The array to disable. + + + + Render primitives from array data. + + Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. + Specifies the starting index in the enabled arrays. + Specifies the number of indices to be rendered. + + + + Specify which color buffers are to be drawn into. + + Specifies up to four color buffers to be drawn into. Symbolic constants OpenGL.NONE, OpenGL.FRONT_LEFT, OpenGL.FRONT_RIGHT, OpenGL.BACK_LEFT, OpenGL.BACK_RIGHT, OpenGL.FRONT, OpenGL.BACK, OpenGL.LEFT, OpenGL.RIGHT, OpenGL.FRONT_AND_BACK, and OpenGL.AUXi, where i is between 0 and (OpenGL.AUX_BUFFERS - 1), are accepted (OpenGL.AUX_BUFFERS is not the upper limit; use glGet to query the number of available aux buffers.) The initial value is OpenGL.FRONT for single- buffered contexts, and OpenGL.BACK for double-buffered contexts. + + + + Specify which color buffers are to be drawn into. + + Specifies up to four color buffers to be drawn into. + + + + Render primitives from array data. + + Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. + Specifies the number of elements to be rendered. + Specifies a pointer to the location where the indices are stored. + + + + Render primitives from array data. + + Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. + Specifies the number of elements to be rendered. + Specifies the type of the values in indices. Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.UNSIGNED_SHORT, or OpenGL.UNSIGNED_INT. + Specifies a pointer to the location where the indices are stored. + + + + Draws a rectangle of pixel data at the current raster position. + + Width of pixel data. + Height of pixel data. + Format of pixel data. + Pixel data buffer. + + + + Draws a rectangle of pixel data at the current raster position. + + Width of pixel data. + Height of pixel data. + Format of pixel data. + Pixel data buffer. + + + + Draws a rectangle of pixel data at the current raster position. + + Width of pixel data. + Height of pixel data. + Format of pixel data. + Pixel data buffer. + + + + Draws a rectangle of pixel data at the current raster position. + + Width of pixel data. + Height of pixel data. + Format of pixel data. + Pixel data buffer. + + + + Draws a rectangle of pixel data at the current raster position. + + Width of pixel data. + Height of pixel data. + Format of pixel data. + The GL data type. + Pixel data buffer. + + + + Flag edges as either boundary or nonboundary. + + Specifies the current edge flag value, either OpenGL.TRUE or OpenGL.FALSE. The initial value is OpenGL.TRUE. + + + + Define an array of edge flags. + + Specifies the byte offset between consecutive edge flags. If stride is 0 (the initial value), the edge flags are understood to be tightly packed in the array. + Specifies a pointer to the first edge flag in the array. + + + + Flag edges as either boundary or nonboundary. + + Specifies a pointer to an array that contains a single boolean element, which replaces the current edge flag value. + + + + Call this function to enable an OpenGL capability. + + The capability you wish to enable. + + + + This function enables one of the client state arrays, such as a vertex array. + + The array to enable. + + + + This is not an imported OpenGL function, but very useful. If 'test' is + true, cap is enabled, otherwise, it's disable. + + The capability you want to enable. + The logical comparison. + + + + Signals the End of drawing. + + + + + This function ends the drawing of a NURBS curve. + + The nurbs object. + + + + Ends the current display list compilation. + + + + + This function ends the drawing of a NURBS surface. + + The nurbs object. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + Domain coordinate. + + + + Evaluate from the current evaluator. + + Domain coordinate. + + + + Evaluates a 'mesh' from the current evaluators. + + Drawing mode, can be POINT or LINE. + Beginning of range. + End of range. + + + + Evaluates a 'mesh' from the current evaluators. + + Drawing mode, fill, point or line. + Beginning of range. + End of range. + Beginning of range. + End of range. + + + + Generate and evaluate a single point in a mesh. + + The integer value for grid domain variable i. + + + + Generate and evaluate a single point in a mesh. + + The integer value for grid domain variable i. + The integer value for grid domain variable j. + + + + This function sets the feedback buffer, that will receive feedback data. + + Size of the buffer. + Type of data in the buffer. + The buffer itself. + + + + This function is similar to flush, but in a sense does it more, as it + executes all commands aon both the client and the server. + + + + + This forces OpenGL to execute any commands you have given it. + + + + + Sets a fog parameter. + + The parameter to set. + The value to set it to. + + + + Sets a fog parameter. + + The parameter to set. + The values to set it to. + + + + Sets a fog parameter. + + The parameter to set. + The value to set it to. + + + + Sets a fog parameter. + + The parameter to set. + The values to set it to. + + + + This function sets what defines a front face. + + Winding mode, counter clockwise by default. + + + + This function creates a frustrum transformation and mulitplies it to the current + matrix (which in most cases should be the projection matrix). + + Left clip position. + Right clip position. + Bottom clip position. + Top clip position. + Near clip position. + Far clip position. + + + + This function generates 'range' number of contiguos display list indices. + + The number of lists to generate. + The first list. + + + + Create a set of unique texture names. + + Number of names to create. + Array to store the texture names. + + + + This function queries OpenGL for data, and puts it in the buffer supplied. + + The parameter to query. + + + + + This function queries OpenGL for data, and puts it in the buffer supplied. + + The parameter to query. + + + + + Return the coefficients of the specified clipping plane. + + Specifies a clipping plane. The number of clipping planes depends on the implementation, but at least six clipping planes are supported. They are identified by symbolic names of the form OpenGL.CLIP_PLANEi where 0 Less Than i Less Than OpenGL.MAX_CLIP_PLANES. + Returns four double-precision values that are the coefficients of the plane equation of plane in eye coordinates. The initial value is (0, 0, 0, 0). + + + + This function queries OpenGL for data, and puts it in the buffer supplied. + + The parameter to query. + The buffer to put that data into. + + + + This function queries OpenGL for data, and puts it in the buffer supplied. + + The parameter to query. + The buffer to put that data into. + + + + Get the current OpenGL error code. + + The current OpenGL error code. + + + + Get the current OpenGL error code. + + The current OpenGL error code. + + + + This this function to query OpenGL values. + + The parameter to query. + The parameters + + + + This this function to query OpenGL values. + + The parameter to query. + The parameters + + + + Use this function to query OpenGL parameter values. + + The Parameter to query + An array to put the values into. + + + + Use this function to query OpenGL parameter values. + + The Parameter to query + An array to put the values into. + + + + Return light source parameter values. + + Specifies a light source. The number of possible lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form OpenGL.LIGHTi where i ranges from 0 to the value of OpenGL.GL_MAX_LIGHTS - 1. + Specifies a light source parameter for light. + Returns the requested data. + + + + Return light source parameter values. + + Specifies a light source. The number of possible lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form OpenGL.LIGHTi where i ranges from 0 to the value of OpenGL.GL_MAX_LIGHTS - 1. + Specifies a light source parameter for light. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return evaluator parameters. + + Specifies the symbolic name of a map. + Specifies which parameter to return. + Returns the requested data. + + + + Return material parameters. + + Specifies which of the two materials is being queried. OpenGL.FRONT or OpenGL.BACK are accepted, representing the front and back materials, respectively. + Specifies the material parameter to return. + Returns the requested data. + + + + Return material parameters. + + Specifies which of the two materials is being queried. OpenGL.FRONT or OpenGL.BACK are accepted, representing the front and back materials, respectively. + Specifies the material parameter to return. + Returns the requested data. + + + + Return the specified pixel map. + + Specifies the name of the pixel map to return. + Returns the pixel map contents. + + + + Return the specified pixel map. + + Specifies the name of the pixel map to return. + Returns the pixel map contents. + + + + Return the specified pixel map. + + Specifies the name of the pixel map to return. + Returns the pixel map contents. + + + + Return the address of the specified pointer. + + Specifies the array or buffer pointer to be returned. + Returns the pointer value specified by parameters. + + + + Return the polygon stipple pattern. + + Returns the stipple pattern. The initial value is all 1's. + + + + Return a string describing the current GL connection. + + Specifies a symbolic constant, one of OpenGL.VENDOR, OpenGL.RENDERER, OpenGL.VERSION, or OpenGL.EXTENSIONS. + Pointer to the specified string. + + + + Return texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE, and OpenGL.TEXTURE_ENV_COLOR. + Returns the requested data. + + + + Return texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE, and OpenGL.TEXTURE_ENV_COLOR. + Returns the requested data. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Return a texture image. + + Specifies which texture is to be obtained. OpenGL.TEXTURE_1D and OpenGL.TEXTURE_2D are accepted. + Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies a pixel format for the returned data. + Specifies a pixel type for the returned data. + Returns the texture image. Should be a pointer to an array of the type specified by type. + + + + Return texture parameter values for a specific level of detail. + + Specifies the symbolic name of the target texture. + Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the symbolic name of a texture parameter. + Returns the requested data. + + + + Return texture parameter values for a specific level of detail. + + Specifies the symbolic name of the target texture. + Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies the symbolic name of a texture parameter. + Returns the requested data. + + + + Return texture parameter values. + + Specifies the symbolic name of the target texture. + Specifies the symbolic name of a texture parameter. + Returns the texture parameters. + + + + Return texture parameter values. + + Specifies the symbolic name of the target texture. + Specifies the symbolic name of a texture parameter. + Returns the texture parameters. + + + + Specify implementation-specific hints. + + Specifies a symbolic constant indicating the behavior to be controlled. + Specifies a symbolic constant indicating the desired behavior. + + + + Specify implementation-specific hints. + + Specifies a symbolic constant indicating the behavior to be controlled. + Specifies a symbolic constant indicating the desired behavior. + + + + Control the writing of individual bits in the color index buffers. + + Specifies a bit mask to enable and disable the writing of individual bits in the color index buffers. Initially, the mask is all 1's. + + + + Define an array of color indexes. + + Specifies the data type of each color index in the array. Symbolic constants OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.INT, OpenGL.FLOAT, and OpenGL.DOUBLE are accepted. + Specifies the byte offset between consecutive color indexes. If stride is 0 (the initial value), the color indexes are understood to be tightly packed in the array. + Specifies a pointer to the first index in the array. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + Set the current color index. + + Specifies the new value for the current color index. + + + + This function initialises the select buffer names. + + + + + Simultaneously specify and enable several interleaved arrays. + + Specifies the type of array to enable. + Specifies the offset in bytes between each aggregate array element. + The array. + + + + Use this function to query if a certain OpenGL function is enabled or not. + + The capability to test. + True if the capability is enabled, otherwise, false. + + + + This function determines whether a specified value is a display list. + + The value to test. + TRUE if it is a list, FALSE otherwise. + + + + Determine if a name corresponds to a texture. + + Specifies a value that may be the name of a texture. + True if texture is a texture object. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + This function sets a parameter of the lighting model. + + The name of the parameter. + The parameter to set it to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The value that you want to set the parameter to. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The parameters. + + + + Set the parameter (pname) of the light 'light'. + + The light you wish to set parameters for. + The parameter you want to set. + The parameters. + + + + Specify the line stipple pattern. + + Specifies a multiplier for each bit in the line stipple pattern. If factor is 3, for example, each bit in the pattern is used three times before the next bit in the pattern is used. factor is clamped to the range [1, 256] and defaults to 1. + Specifies a 16-bit integer whose bit pattern determines which fragments of a line will be drawn when the line is rasterized. Bit zero is used first; the default pattern is all 1's. + + + + Set's the current width of lines. + + New line width to set. + + + + Set the display-list base for glCallLists. + + Specifies an integer offset that will be added to glCallLists offsets to generate display-list names. The initial value is 0. + + + + Call this function to load the identity matrix into the current matrix stack. + + + + + Replace the current matrix with the specified matrix. + + Specifies a pointer to 16 consecutive values, which are used as the elements of a 4x4 column-major matrix. + + + + Replace the current matrix with the specified matrix. + + Specifies a pointer to 16 consecutive values, which are used as the elements of a 4x4 column-major matrix. + + + + This function replaces the name at the top of the selection names stack + with 'name'. + + The name to replace it with. + + + + Specify a logical pixel operation for color index rendering. + + Specifies a symbolic constant that selects a logical operation. + + + + Specify a logical pixel operation for color index rendering. + + Specifies a symbolic constant that selects a logical operation. + + + + This function transforms the projection matrix so that it looks at a certain + point, from a certain point. + + Position of the eye. + Position of the eye. + Position of the eye. + Point to look at. + Point to look at. + Point to look at. + 'Up' Vector X Component. + 'Up' Vector Y Component. + 'Up' Vector Z Component. + + + + Defines a 1D evaluator. + + What the control points represent (e.g. MAP1_VERTEX_3). + Range of the variable 'u'. + Range of the variable 'u'. + Offset between beginning of one control point, and beginning of next. + The degree plus one, should agree with the number of control points. + The data for the points. + + + + Defines a 1D evaluator. + + What the control points represent (e.g. MAP1_VERTEX_3). + Range of the variable 'u'. + Range of the variable 'u'. + Offset between beginning of one control point, and beginning of next. + The degree plus one, should agree with the number of control points. + The data for the points. + + + + Defines a 2D evaluator. + + What the control points represent (e.g. MAP2_VERTEX_3). + Range of the variable 'u'. + Range of the variable 'u. + Offset between beginning of one control point and the next. + The degree plus one. + Range of the variable 'v'. + Range of the variable 'v'. + Offset between beginning of one control point and the next. + The degree plus one. + The data for the points. + + + + Defines a 2D evaluator. + + What the control points represent (e.g. MAP2_VERTEX_3). + Range of the variable 'u'. + Range of the variable 'u. + Offset between beginning of one control point and the next. + The degree plus one. + Range of the variable 'v'. + Range of the variable 'v'. + Offset between beginning of one control point and the next. + The degree plus one. + The data for the points. + + + + This function defines a grid that goes from u1 to u1 in n steps, evenly spaced. + + Number of steps. + Range of variable 'u'. + Range of variable 'u'. + + + + This function defines a grid that goes from u1 to u1 in n steps, evenly spaced. + + Number of steps. + Range of variable 'u'. + Range of variable 'u'. + + + + This function defines a grid that goes from u1 to u1 in n steps, evenly spaced, + and the same for v. + + Number of steps. + Range of variable 'u'. + Range of variable 'u'. + Number of steps. + Range of variable 'v'. + Range of variable 'v'. + + + + This function defines a grid that goes from u1 to u1 in n steps, evenly spaced, + and the same for v. + + Number of steps. + Range of variable 'u'. + Range of variable 'u'. + Number of steps. + Range of variable 'v'. + Range of variable 'v'. + + + + This function sets a material parameter. + + What faces is this parameter for (i.e front/back etc). + What parameter you want to set. + The value to set 'pname' to. + + + + This function sets a material parameter. + + What faces is this parameter for (i.e front/back etc). + What parameter you want to set. + The value to set 'pname' to. + + + + This function sets a material parameter. + + What faces is this parameter for (i.e front/back etc). + What parameter you want to set. + The value to set 'pname' to. + + + + This function sets a material parameter. + + What faces is this parameter for (i.e front/back etc). + What parameter you want to set. + The value to set 'pname' to. + + + + Set the current matrix mode (the matrix that matrix operations will be + performed on). + + The mode, normally PROJECTION or MODELVIEW. + + + + Set the current matrix mode (the matrix that matrix operations will be + performed on). + + The mode, normally PROJECTION or MODELVIEW. + + + + Multiply the current matrix with the specified matrix. + + Points to 16 consecutive values that are used as the elements of a 4x4 column-major matrix. + + + + Multiply the current matrix with the specified matrix. + + Points to 16 consecutive values that are used as the elements of a 4x4 column-major matrix. + + + + This function starts compiling a new display list. + + The list to compile. + Either COMPILE or COMPILE_AND_EXECUTE. + + + + This function creates a new glu NURBS renderer object. + + A Pointer to the NURBS renderer. + + + + This function creates a new OpenGL Quadric Object. + + The pointer to the Quadric Object. + + + + Set the current normal. + + Normal Coordinate. + Normal Coordinate. + Normal Coordinate. + + + + This function sets the current normal. + + The normal. + + + + Set the current normal. + + Normal Coordinate. + Normal Coordinate. + Normal Coordinate. + + + + This function sets the current normal. + + The normal. + + + + Set the current normal. + + Normal Coordinate. + Normal Coordinate. + Normal Coordinate. + + + + This function sets the current normal. + + The normal. + + + + Set the current normal. + + Normal Coordinate. + Normal Coordinate. + Normal Coordinate. + + + + This function sets the current normal. + + The normal. + + + + Set the current normal. + + Normal Coordinate. + Normal Coordinate. + Normal Coordinate. + + + + This function sets the current normal. + + The normal. + + + + Set's the pointer to the normal array. + + The type of data. + The space in bytes between each normal. + The normals. + + + + Set's the pointer to the normal array. + + The type of data. + The space in bytes between each normal. + The normals. + + + + This function defines a NURBS Curve. + + The NURBS object. + The number of knots. + The knots themselves. + The stride, i.e. distance between vertices in the + control points array. + The array of control points. + The order of the polynomial. + The type of data to generate. + + + + This function sets a NURBS property. + + The object to set the property for. + The property to set. + The new value of the property. + + + + This function defines a NURBS surface. + + The NURBS object. + The sknots count. + The s-knots. + The number of t-knots. + The t-knots. + The distance between s vertices. + The distance between t vertices. + The control points. + The order of the s polynomial. + The order of the t polynomial. + The type of data to generate. + + + + This function creates an orthographic projection matrix (i.e one with no + perspective) and multiplies it to the current matrix stack, which would + normally be 'PROJECTION'. + + Left clipping plane. + Right clipping plane. + Bottom clipping plane. + Top clipping plane. + Near clipping plane. + Far clipping plane. + + + + This function creates an orthographic project based on a screen size. + + Left of the screen. (Normally 0). + Right of the screen.(Normally width). + Bottom of the screen (normally 0). + Top of the screen (normally height). + + + + This function draws a partial disk from the quadric object. + + The Quadric objec.t + Radius of the inside of the disk. + Radius of the outside of the disk. + The slices. + The loops. + Starting angle. + Sweep angle. + + + + Place a marker in the feedback buffer. + + Specifies a marker value to be placed in the feedback buffer following a OpenGL.PASS_THROUGH_TOKEN. + + + + This function creates a perspective matrix and multiplies it to the current + matrix stack (which in most cases should be 'PROJECTION'). + + Field of view angle (human eye = 60 Degrees). + Apsect Ratio (width of screen divided by height of screen). + Near clipping plane (normally 1). + Far clipping plane. + + + + This function creates a 'pick matrix' normally used for selecting objects that + are at a certain point on the screen. + + X Point. + Y Point. + Width of point to test (4 is normal). + Height of point to test (4 is normal). + The current viewport. + + + + Set up pixel transfer maps. + + Specifies a symbolic map name. + Specifies the size of the map being defined. + Specifies an array of mapsize values. + + + + Set up pixel transfer maps. + + Specifies a symbolic map name. + Specifies the size of the map being defined. + Specifies an array of mapsize values. + + + + Set up pixel transfer maps. + + Specifies a symbolic map name. + Specifies the size of the map being defined. + Specifies an array of mapsize values. + + + + Set pixel storage modes. + + Specifies the symbolic name of the parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel storage modes. + + Specifies the symbolic name of the parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Set pixel transfer modes. + + Specifies the symbolic name of the pixel transfer parameter to be set. + Specifies the value that pname is set to. + + + + Specify the pixel zoom factors. + + Specify the x and y zoom factors for pixel write operations. + Specify the x and y zoom factors for pixel write operations. + + + + The size of points to be rasterised. + + Size in pixels. + + + + This sets the current drawing mode of polygons (points, lines, filled). + + The faces this applies to (front, back or both). + The mode to set to (points, lines, or filled). + + + + This sets the current drawing mode of polygons (points, lines, filled). + + The faces this applies to (front, back or both). + The mode to set to (points, lines, or filled). + + + + Set the scale and units used to calculate depth values. + + Specifies a scale factor that is used to create a variable depth offset for each polygon. The initial value is 0. + Is multiplied by an implementation-specific value to create a constant depth offset. The initial value is 0. + + + + Set the polygon stippling pattern. + + Specifies a pointer to a 32x32 stipple pattern that will be unpacked from memory in the same way that glDrawPixels unpacks pixels. + + + + This function restores the attribute stack to the state it was when + PushAttrib was called. + + + + + Pop the client attribute stack. + + + + + Restore the previously saved state of the current matrix stack. + + + + + This takes the top name off the selection names stack. + + + + + Set texture residence priority. + + Specifies the number of textures to be prioritized. + Specifies an array containing the names of the textures to be prioritized. + Specifies an array containing the texture priorities. A priority given in an element of priorities applies to the texture named by the corresponding element of textures. + + + + This function Maps the specified object coordinates into window coordinates. + + The object's x coord. + The object's y coord. + The object's z coord. + The modelview matrix. + The projection matrix. + The viewport. + The window x coord. + The Window y coord. + The Window z coord. + + + + Save the current state of the attribute groups specified by 'mask'. + + The attibute groups to save. + + + + Save the current state of the attribute groups specified by 'mask'. + + The attibute groups to save. + + + + Push the client attribute stack. + + Specifies a mask that indicates which attributes to save. + + + + Save the current state of the current matrix stack. + + + + + This function adds a new name to the selection buffer. + + The name to add. + + + + This set's the Generate Normals propery of the specified Quadric object. + + The quadric object. + The type of normals to generate. + + + + This function sets the type of texture coordinates being generated by + the specified quadric object. + + The quadric object. + The type of coordinates to generate. + + + + This sets the orientation for the quadric object. + + The quadric object. + The orientation. + + + + This sets the current drawstyle for the Quadric Object. + + The quadric object. + The draw style. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + + + + This function sets the current raster position. + + The coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + + + + This function sets the current raster position. + + The coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + + + + This function sets the current raster position. + + The coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + + + + This function sets the current raster position. + + The coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + W coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + W coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + W coordinate. + + + + This function sets the current raster position. + + X coordinate. + Y coordinate. + Z coordinate. + W coordinate. + + + + Select a color buffer source for pixels. + + Specifies a color buffer. Accepted values are OpenGL.FRONT_LEFT, OpenGL.FRONT_RIGHT, OpenGL.BACK_LEFT, OpenGL.BACK_RIGHT, OpenGL.FRONT, OpenGL.BACK, OpenGL.LEFT, OpenGL.GL_RIGHT, and OpenGL.AUXi, where i is between 0 and OpenGL.AUX_BUFFERS - 1. + + + + Reads a block of pixels from the frame buffer. + + Top-Left X value. + Top-Left Y value. + Width of block to read. + Height of block to read. + Specifies the format of the pixel data. The following symbolic values are accepted: OpenGL.COLOR_INDEX, OpenGL.STENCIL_INDEX, OpenGL.DEPTH_COMPONENT, OpenGL.RED, OpenGL.GREEN, OpenGL.BLUE, OpenGL.ALPHA, OpenGL.RGB, OpenGL.RGBA, OpenGL.LUMINANCE and OpenGL.LUMINANCE_ALPHA. + Specifies the data type of the pixel data.Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.BYTE, OpenGL.BITMAP, OpenGL.UNSIGNED_SHORT, OpenGL.SHORT, OpenGL.UNSIGNED_INT, OpenGL.INT or OpenGL.FLOAT. + Storage for the pixel data received. + + + + Reads a block of pixels from the frame buffer. + + Top-Left X value. + Top-Left Y value. + Width of block to read. + Height of block to read. + Specifies the format of the pixel data. The following symbolic values are accepted: OpenGL.COLOR_INDEX, OpenGL.STENCIL_INDEX, OpenGL.DEPTH_COMPONENT, OpenGL.RED, OpenGL.GREEN, OpenGL.BLUE, OpenGL.ALPHA, OpenGL.RGB, OpenGL.RGBA, OpenGL.LUMINANCE and OpenGL.LUMINANCE_ALPHA. + Specifies the data type of the pixel data.Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.BYTE, OpenGL.BITMAP, OpenGL.UNSIGNED_SHORT, OpenGL.SHORT, OpenGL.UNSIGNED_INT, OpenGL.INT or OpenGL.FLOAT. + Storage for the pixel data received. + + + + Draw a rectangle from two coordinates (top-left and bottom-right). + + Top-Left X value. + Top-Left Y value. + Bottom-Right X Value. + Bottom-Right Y Value. + + + + Draw a rectangle from two coordinates, expressed as arrays, e.g + Rect(new float[] {0, 0}, new float[] {10, 10}); + + Top-Left point. + Bottom-Right point. + + + + Draw a rectangle from two coordinates (top-left and bottom-right). + + Top-Left X value. + Top-Left Y value. + Bottom-Right X Value. + Bottom-Right Y Value. + + + + Draw a rectangle from two coordinates, expressed as arrays, e.g + Rect(new float[] {0, 0}, new float[] {10, 10}); + + Top-Left point. + Bottom-Right point. + + + + Draw a rectangle from two coordinates (top-left and bottom-right). + + Top-Left X value. + Top-Left Y value. + Bottom-Right X Value. + Bottom-Right Y Value. + + + + Draw a rectangle from two coordinates, expressed as arrays, e.g + Rect(new float[] {0, 0}, new float[] {10, 10}); + + Top-Left point. + Bottom-Right point. + + + + Draw a rectangle from two coordinates (top-left and bottom-right). + + Top-Left X value. + Top-Left Y value. + Bottom-Right X Value. + Bottom-Right Y Value. + + + + Draw a rectangle from two coordinates, expressed as arrays, e.g + Rect(new float[] {0, 0}, new float[] {10, 10}); + + Top-Left point. + Bottom-Right point. + + + + This function sets the current render mode (render, feedback or select). + + The Render mode (RENDER, SELECT or FEEDBACK). + The hits that selection or feedback caused.. + + + + This function sets the current render mode (render, feedback or select). + + The Render mode (RENDER, SELECT or FEEDBACK). + The hits that selection or feedback caused.. + + + + This function applies a rotation transformation to the current matrix. + + The angle to rotate. + Amount along x. + Amount along y. + Amount along z. + + + + This function applies a rotation transformation to the current matrix. + + The angle to rotate. + Amount along x. + Amount along y. + Amount along z. + + + + This function quickly does three rotations, one about each axis, with the + given angles (it's not an OpenGL function, but very useful). + + The angle to rotate about x. + The angle to rotate about y. + The angle to rotate about z. + + + + This function applies a scale transformation to the current matrix. + + The amount to scale along x. + The amount to scale along y. + The amount to scale along z. + + + + This function applies a scale transformation to the current matrix. + + The amount to scale along x. + The amount to scale along y. + The amount to scale along z. + + + + Define the scissor box. + + Specify the lower left corner of the scissor box. Initially (0, 0). + Specify the lower left corner of the scissor box. Initially (0, 0). + Specify the width and height of the scissor box. When a GL context is first attached to a window, width and height are set to the dimensions of that window. + Specify the width and height of the scissor box. When a GL context is first attached to a window, width and height are set to the dimensions of that window. + + + + This function sets the current select buffer. + + The size of the buffer you are passing. + The buffer itself. + + + + Select flat or smooth shading. + + Specifies a symbolic value representing a shading technique. Accepted values are OpenGL.FLAT and OpenGL.SMOOTH. The default is OpenGL.SMOOTH. + + + + Select flat or smooth shading. + + Specifies a symbolic value representing a shading technique. Accepted values are OpenGL.FLAT and OpenGL.SMOOTH. The default is OpenGL.SMOOTH. + + + + This function draws a sphere from a Quadric Object. + + The quadric object. + Sphere radius. + Slices of the sphere. + Stakcs of the sphere. + + + + This function sets the current stencil buffer function. + + The function type. + The function reference. + The function mask. + + + + This function sets the current stencil buffer function. + + The function type. + The function reference. + The function mask. + + + + This function sets the stencil buffer mask. + + The mask. + + + + This function sets the stencil buffer operation. + + Fail operation. + Depth fail component. + Depth pass component. + + + + This function sets the stencil buffer operation. + + Fail operation. + Depth fail component. + Depth pass component. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Array of 1,2,3 or 4 Texture Coordinates. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + + + + This function sets the current texture coordinates. WARNING: if you + can call something more explicit, like TexCoord2f then call that, it's + much faster. + + Array of 1,2,3 or 4 Texture Coordinates. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Array of 1,2,3 or 4 Texture Coordinates. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Array of 1,2,3 or 4 Texture Coordinates. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the current texture coordinates. + + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + Texture Coordinate. + + + + This function sets the texture coord array. + + The number of coords per set. + The type of data. + The number of bytes between coords. + The coords. + + + + This function sets the texture coord array. + + The number of coords per set. + The type of data. + The number of bytes between coords. + The coords. + + + + Set texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a single-valued texture environment parameter. Must be OpenGL.TEXTURE_ENV_MODE. + Specifies a single symbolic constant, one of OpenGL.MODULATE, OpenGL.DECAL, OpenGL.BLEND, or OpenGL.REPLACE. + + + + Set texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE and OpenGL.TEXTURE_ENV_COLOR. + Specifies a pointer to a parameter array that contains either a single symbolic constant or an RGBA color. + + + + Set texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a single-valued texture environment parameter. Must be OpenGL.TEXTURE_ENV_MODE. + Specifies a single symbolic constant, one of OpenGL.MODULATE, OpenGL.DECAL, OpenGL.BLEND, or OpenGL.REPLACE. + + + + Set texture environment parameters. + + Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. + Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE and OpenGL.TEXTURE_ENV_COLOR. + Specifies a pointer to a parameter array that contains either a single symbolic constant or an RGBA color. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. + Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. + Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. + Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. + + + + Control the generation of texture coordinates. + + Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. + Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. + Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. + + + + This function sets the image for the currently binded texture. + + The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. + For mip-map textures, ordinary textures should be '0'. + The format of the data you are want OpenGL to create, e.g RGB16. + The width of the texture image (must be a power of 2, e.g 64). + The width of the border (0 or 1). + The format of the data you are passing, e.g. RGBA. + The type of data you are passing, e.g GL_BYTE. + The actual pixel data. + + + + This function sets the image for the currently binded texture. + + The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. + For mip-map textures, ordinary textures should be '0'. + The format of the data you are want OpenGL to create, e.g RGB16. + The width of the texture image (must be a power of 2, e.g 64). + The height of the texture image (must be a power of 2, e.g 32). + The width of the border (0 or 1). + The format of the data you are passing, e.g. RGBA. + The type of data you are passing, e.g GL_BYTE. + The actual pixel data. + + + + This function sets the image for the currently binded texture. + + The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. + For mip-map textures, ordinary textures should be '0'. + The format of the data you are want OpenGL to create, e.g RGB16. + The width of the texture image (must be a power of 2, e.g 64). + The height of the texture image (must be a power of 2, e.g 32). + The width of the border (0 or 1). + The format of the data you are passing, e.g. RGBA. + The type of data you are passing, e.g GL_BYTE. + The actual pixel data. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + This function sets the parameters for the currently binded texture object. + + The type of texture you are setting the parameter to, e.g. TEXTURE_2D + The parameter to set. + The value to set it to. + + + + Specify a two-dimensional texture subimage. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies a texel offset in the x direction within the texture array. + Specifies the width of the texture subimage. + Specifies the format of the pixel data. + Specifies the data type of the pixel data. + Specifies a pointer to the image data in memory. + + + + Specify a two-dimensional texture subimage. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. + Specifies a texel offset in the x direction within the texture array. + Specifies a texel offset in the y direction within the texture array. + Specifies the width of the texture subimage. + Specifies the height of the texture subimage. + Specifies the format of the pixel data. + Specifies the data type of the pixel data. + Specifies a pointer to the image data in memory. + + + + This function applies a translation transformation to the current matrix. + + The amount to translate along the x axis. + The amount to translate along the y axis. + The amount to translate along the z axis. + + + + This function applies a translation transformation to the current matrix. + + The amount to translate along the x axis. + The amount to translate along the y axis. + The amount to translate along the z axis. + + + + This function turns a screen Coordinate into a world coordinate. + + Screen Coordinate. + Screen Coordinate. + Screen Coordinate. + Current ModelView matrix. + Current Projection matrix. + Current Viewport. + The world coordinate. + The world coordinate. + The world coordinate. + + + + This is a convenience function. It calls UnProject with the current + viewport, modelview and persective matricies, saving you from getting them. + To use you own matricies, all the other version of UnProject. + + X Coordinate (Screen Coordinate). + Y Coordinate (Screen Coordinate). + Z Coordinate (Screen Coordinate). + The world coordinate. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + Specifies the coordinate. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + Specifies the coordinate. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + Specifies the coordinate. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + + + + Sets the current vertex (must be called between 'Begin' and 'End'). + + An array of 2, 3 or 4 floats. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + W Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + W Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + W Value. + + + + Set the current vertex (must be called between 'Begin' and 'End'). + + X Value. + Y Value. + Z Value. + W Value. + + + + This function sets the address of the vertex pointer array. + + The number of coords per vertex. + The data type. + The byte offset between vertices. + The array. + + + + This function sets the address of the vertex pointer array. + + The number of coords per vertex. + The data type. + The byte offset between vertices. + The array. + + + + This sets the viewport of the current Render Context. Normally x and y are 0 + and the width and height are just those of the control/graphics you are drawing + to. + + Top-Left point of the viewport. + Top-Left point of the viewport. + Width of the viewport. + Height of the viewport. + + + + Produce an error string from a GL or GLU error code. + + Specifies a GL or GLU error code. + The OpenGL/GLU error string. + + + + Return a string describing the GLU version or GLU extensions. + + Specifies a symbolic constant, one of OpenGL.VERSION, or OpenGL.EXTENSIONS. + The GLU string. + + + + Scale an image to an arbitrary size. + + Specifies the format of the pixel data. + Specify the width of the source image that is scaled. + Specify the height of the source image that is scaled. + Specifies the data type for dataIn. + Specifies a pointer to the source image. + Specify the width of the destination image. + Specify the height of the destination image. + Specifies the data type for dataOut. + Specifies a pointer to the destination image. + + + + Create 1-D mipmaps. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the number of color components in the texture. Must be 1, 2, 3, or 4. + Specifies the width of the texture image. + Specifies the format of the pixel data. + Specifies the data type for data. + Specifies a pointer to the image data in memory. + + + + Create 2-D mipmaps. + + Specifies the target texture. Must be OpenGL.TEXTURE_1D. + Specifies the number of color components in the texture. Must be 1, 2, 3, or 4. + Specifies the width of the texture image. + Specifies the height of the texture image. + Specifies the format of the pixel data. + Specifies the data type for data. + Specifies a pointer to the image data in memory. + + + + Draw a disk. + + Specifies the quadrics object (created with gluNewQuadric). + Specifies the inner radius of the disk (may be 0). + Specifies the outer radius of the disk. + Specifies the number of subdivisions around the z axis. + Specifies the number of concentric rings about the origin into which the disk is subdivided. + + + + Create a tessellation object. + + A new GLUtesselator poiner. + + + + Delete a tesselator object. + + The tesselator pointer. + + + + Delimit a polygon description. + + Specifies the tessellation object (created with gluNewTess). + Specifies a pointer to user polygon data. + + + + Delimit a contour description. + + Specifies the tessellation object (created with gluNewTess). + + + + Specify a vertex on a polygon. + + Specifies the tessellation object (created with gluNewTess). + Specifies the location of the vertex. + Specifies an opaque pointer passed back to the program with the vertex callback (as specified by gluTessCallback). + + + + Delimit a contour description. + + Specifies the tessellation object (created with gluNewTess). + + + + Delimit a polygon description. + + Specifies the tessellation object (created with gluNewTess). + + + + Set a tessellation object property. + + Specifies the tessellation object (created with gluNewTess). + Specifies the property to be set. + Specifies the value of the indicated property. + + + + Specify a normal for a polygon. + + Specifies the tessellation object (created with gluNewTess). + Specifies the first component of the normal. + Specifies the second component of the normal. + Specifies the third component of the normal. + + + + Set a tessellation object property. + + Specifies the tessellation object (created with gluNewTess). + Specifies the property to be set. + Specifies the value of the indicated property. + + + + Delimit a NURBS trimming loop definition. + + Specifies the NURBS object (created with gluNewNurbsRenderer). + + + + Delimit a NURBS trimming loop definition. + + Specifies the NURBS object (created with gluNewNurbsRenderer). + + + + Describe a piecewise linear NURBS trimming curve. + + Specifies the NURBS object (created with gluNewNurbsRenderer). + Specifies the number of points on the curve. + Specifies an array containing the curve points. + Specifies the offset (a number of single-precision floating-point values) between points on the curve. + Specifies the type of curve. Must be either OpenGL.MAP1_TRIM_2 or OpenGL.MAP1_TRIM_3. + + + + Load NURBS sampling and culling matrice. + + Specifies the NURBS object (created with gluNewNurbsRenderer). + Specifies a modelview matrix (as from a glGetFloatv call). + Specifies a projection matrix (as from a glGetFloatv call). + Specifies a viewport (as from a glGetIntegerv call). + + + + Get a NURBS property. + + Specifies the NURBS object (created with gluNewNurbsRenderer). + Specifies the property whose value is to be fetched. + Specifies a pointer to the location into which the value of the named property is written. + + + + Gets the error description for a given error code. + + The error code. + The error description for the given error code. + + + + Called before an OpenGL call to enable error checking and ensure the + correct OpenGL context is correct. + + + + + Called after an OpenGL call to enable error checking. + + + + + This function transforms a windows point into an OpenGL point, + which is measured from the bottom left of the screen. + + The x coord. + The y coord. + + + + Creates the OpenGL instance. + + Type of the render context. + The drawing context width. + The drawing context height. + The bit depth. + The parameter. + + + + + Creates the OpenGL instance using an external, existing render context. + + The width. + The height. + The bit depth. + The window handle. + The render context handle. + The device context handle. + True on success + + + + Makes the OpenGL instance current. + + + + + Makes no render context current. + + + + + Blits to the specified device context handle. + + The device context handle. + + + + Set the render context dimensions. + + The width (in pixels). + The height (in pixels). + + + + GDIs the coordinateto open GL coordinate. + + The x coordinate. + The y coordinate. + + + + Draws the text. + + The x. + The y. + The r. + The g. + The b. + Name of the face. + Size of the font. + The text. + + + + Draws 3D text. + + Name of the face. + Size of the font. + The deviation. + The extrusion. + The text. + + + + The current OpenGL instance. + + + + + The render context provider. + + + + + Set to true if we're inside glBegin. + + + + + The fontbitmaps object is used to allow easy rendering of text. + + + + + The FontOutlines object is used to allow rendering of text. + + + + + Gets the render context provider. + + The render context provider. + + + + Gets the vendor. + + The vendor. + + + + Gets the renderer. + + The renderer. + + + + Gets the version. + + The version. + + + + Gets the extensions. + + The extensions. + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + The extra parameter. + + + + + Destroys the render context provider instance. + + + + + Sets the dimensions of the render context provider. + + Width. + Height. + + + + Makes the render context current. + + + + + Blit the rendered data to the supplied device context. + + The HDC. + + + + Gets the render context handle. + + + + + Gets the device context handle. + + + + + Gets or sets the width. + + The width. + + + + Gets or sets the height. + + The height. + + + + Gets or sets the bit depth. + + The bit depth. + + + + Gets a value indicating whether GDI drawing is enabled for this type of render context. + + true if GDI drawing is enabled; otherwise, false. + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + + + + + Destroys the render context provider instance. + + + + + Sets the dimensions of the render context provider. + + Width. + Height. + + + + Makes the render context current. + + + + + Blit the rendered data to the supplied device context. + + The HDC. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + The render context handle. + + + + + The device context handle. + + + + + The width. + + + + + The height. + + + + + The bit depth. + + + + + Is gdi drawing enabled? + + + + + Gets the render context handle. + + + + + Gets the device context handle. + + + + + Gets or sets the width. + + The width. + + + + Gets or sets the height. + + The height. + + + + Gets or sets the bit depth. + + The bit depth. + + + + Gets a value indicating whether GDI drawing is enabled for this type of render context. + + true if GDI drawing is enabled; otherwise, false. + + + + Initializes a new instance of the class. + + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + + + + + Destroys the render context provider instance. + + + + + The DIB Section object. + + + + + Gets the DIB section. + + The DIB section. + + + + Useful functions imported from the Win32 SDK. + + + + + Initializes the class. + + + + + Gets the current render context. + + The current render context. + + + + Make the specified render context current. + + The handle to the device context. + The handle to the render context. + + + + + Creates a render context from the device context. + + The handle to the device context. + The handle to the render context. + + + + Deletes the render context. + + The handle to the render context. + + + + + Gets a proc address. + + The name of the function. + The address of the function. + + + + The wglUseFontBitmaps function creates a set of bitmap display lists for use in the current OpenGL rendering context. The set of bitmap display lists is based on the glyphs in the currently selected font in the device context. You can then use bitmaps to draw characters in an OpenGL image. + + Specifies the device context whose currently selected font will be used to form the glyph bitmap display lists in the current OpenGL rendering context.. + Specifies the first glyph in the run of glyphs that will be used to form glyph bitmap display lists. + Specifies the number of glyphs in the run of glyphs that will be used to form glyph bitmap display lists. The function creates count display lists, one for each glyph in the run. + Specifies a starting display list. + If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To get extended error information, call GetLastError. + + + + The wglUseFontOutlines function creates a set of display lists, one for each glyph of the currently selected outline font of a device context, for use with the current rendering context. + + The h DC. + The first. + The count. + The list base. + The deviation. + The extrusion. + The format. + The LPGMF. + + + + + Link two render contexts so they share lists (buffer IDs, etc.) + + The first context. + The second context. + If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. + To get extended error information, call GetLastError. + + + + Specifies that a window created with this style accepts drag-drop files. + + + + + Forces a top-level window onto the taskbar when the window is visible. + + + + + Specifies that a window has a border with a sunken edge. + + + + + Windows XP: Paints all descendants of a window in bottom-to-top painting order using double-buffering. For more information, see Remarks. This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. + + + + + Includes a question mark in the title bar of the window. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message. The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the child window. + WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles. + + + + + The window itself contains child windows that should take part in dialog box navigation. If this style is specified, the dialog manager recurses into children of this window when performing navigation operations such as handling the TAB key, an arrow key, or a keyboard mnemonic. + + + + + Creates a window that has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter. + + + + + Windows 2000/XP: Creates a layered window. Note that this cannot be used for child windows. Also, this cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. + + + + + Arabic and Hebrew versions of Windows 98/Me, Windows 2000/XP: Creates a window whose horizontal origin is on the right edge. Increasing horizontal values advance to the left. + + + + + Creates a window that has generic left-aligned properties. This is the default. + + + + + If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the vertical scroll bar (if present) is to the left of the client area. For other languages, the style is ignored. + + + + + The window text is displayed using left-to-right reading-order properties. This is the default. + + + + + Creates a multiple-document interface (MDI) child window. + + + + + Windows 2000/XP: A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. + To activate the window, use the SetActiveWindow or SetForegroundWindow function. + The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style. + + + + + Windows 2000/XP: A window created with this style does not pass its window layout to its child windows. + + + + + Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed. + + + + + Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE styles. + + + + + Combines the WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW, and WS_EX_TOPMOST styles. + + + + + The window has generic "right-aligned" properties. This depends on the window class. This style has an effect only if the shell language is Hebrew, Arabic, or another language that supports reading-order alignment; otherwise, the style is ignored. + Using the WS_EX_RIGHT style for static or edit controls has the same effect as using the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles. + + + + + Vertical scroll bar (if present) is to the right of the client area. This is the default. + + + + + If the shell language is Hebrew, Arabic, or another language that supports reading-order alignment, the window text is displayed using right-to-left reading-order properties. For other languages, the style is ignored. + + + + + Creates a window with a three-dimensional border style intended to be used for items that do not accept user input. + + + + + Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE. + + + + + Specifies that a window created with this style should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function. + + + + + Specifies that a window created with this style should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted. + To achieve transparency without these restrictions, use the SetWindowRgn function. + + + + + Specifies that a window has a border with a raised edge. + + + + The window has a thin-line border. + + + The window has a title bar (includes the WS_BORDER style). + + + The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with the WS_POPUP style. + + + Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window. + + + + Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. + If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window. + + + + The window is initially disabled. A disabled window cannot receive input from the user. To change this after a window has been created, use the EnableWindow function. + + + The window has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar. + + + + The window is the first control of a group of controls. The group consists of this first control and all controls defined after it, up to the next control with the WS_GROUP style. + The first control in each group usually has the WS_TABSTOP style so that the user can move from group to group. The user can subsequently change the keyboard focus from one control in the group to the next control in the group by using the direction keys. + You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. + + + + The window has a horizontal scroll bar. + + + The window is initially maximized. + + + The window has a maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified. + + + The window is initially minimized. + + + The window has a minimize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified. + + + The window is an overlapped window. An overlapped window has a title bar and a border. + + + The window is an overlapped window. + + + The window is a pop-up window. This style cannot be used with the WS_CHILD style. + + + The window is a pop-up window. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the window menu visible. + + + The window has a sizing border. + + + The window has a window menu on its title bar. The WS_CAPTION style must also be specified. + + + + The window is a control that can receive the keyboard focus when the user presses the TAB key. + Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style. + You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. + For user-created windows and modeless dialogs to work with tab stops, alter the message loop to call the IsDialogMessage function. + + + + The window is initially visible. This style can be turned on and off by using the ShowWindow or SetWindowPos function. + + + The window has a vertical scroll bar. + + + + A FontBitmap entry contains the details of a font face. + + + + + This class wraps the functionality of the wglUseFontBitmaps function to + allow straightforward rendering of text. + + + + + Draws the text. + + The gl. + The x. + The y. + The r. + The g. + The b. + Name of the face. + Size of the font. + The text. + + + + Cache of font bitmap enties. + + + + + Initializes a new instance of the class. + + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + The parameter + + + + + Destroys the render context provider instance. + + + + + Sets the dimensions of the render context provider. + + Width. + Height. + + + + Blit the rendered data to the supplied device context. + + The HDC. + + + + Makes the render context current. + + + + + The window handle. + + + + + Initializes a new instance of the class. + + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + + + + + + Gets the internal DIB section. + + The internal DIB section. + + + + AccumOp + + + + + The alpha function + + + + + The OpenGL Attribute flags. + + + + + The begin mode. + + + + + BlendingDestinationFactor + + + + + The blending source factor. + + + + + + + + + + The Clip Plane Name + + + + + The Cull Face mode. + + + + + + + + + + The Data Type. + + + + + + + + + + The depth function + + + + + The Draw Buffer Mode + + + + + Error Code + + + + + FeedBackMode + + + + + The Feedback Token + + + + + The Fog Mode. + + + + + + + + + + GetMapTarget + + + + + The Front Face Mode. + + + + + The hint mode. + + + + + The + + + + + The hint target. + + + + + LightName + + + + + LightParameter + + + + + The Light Model Parameter. + + + + + The Logic Op + + + + + The matrix mode. + + + + + The pixel transfer parameter name + + + + + The Polygon mode. + + + + + Render as points. + + + + + Render as lines. + + + + + Render as filled. + + + + + Rendering Mode + + + + + ShadingModel + + + + + The stencil function + + + + + The stencil operation. + + + + + GetTextureParameter + + + + + Texture target. + + + + + The render context type. + + + + + A DIB section - offscreen but NEVER hardware accelerated. + + + + + A Native Window - directly render to a window, the window handle + must be passed as the parameter to Create. Hardware acceleration + is supported but one can never do GDI drawing on top of the + OpenGL drawing. + + + + + A Hidden Window - more initial overhead but acceleratable. + + + + + A Framebuffer Object - accelerated but may not be supported on some card. + + + + + Render context provider for working with an external render context + + + + + The window handle. + + + + + Initializes a new instance of the class. + + The existing window handle. + The handle to the existing render context. + The handle to the existing device context. + + + + Destroys the render context provider instance. + + + + + Blit the rendered data to the supplied device context. + + The HDC. + + + + Makes the render context current. + + + + + Initializes a new instance of the class. + + + + + Creates the render context provider. Must also create the OpenGL extensions. + + The OpenGL context. + The width. + The height. + The bit depth. + The parameter. + + + + + Destroys the render context provider instance. + + + + + Sets the dimensions of the render context provider. + + Width. + Height. + + + + Blit the rendered data to the supplied device context. + + The HDC. + + + + Makes the render context current. + + + + + The window handle. + + + + + + + + + + Creates the specified width. + + The width. + The height. + The bit count. + + + + + Resizes the section. + + The width. + The height. + The bit count. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + + + + This function sets the pixel format of the underlying bitmap. + + The bitcount. + + + + Destroys this instance. + + + + + The parent dc. + + + + + The bitmap handle. + + + + + The bits. + + + + + The width. + + + + + The height. + + + + + Gets the handle to the bitmap. + + The handle to the bitmap. + + + + Gets the bits. + + + + + Gets or sets the width. + + The width. + + + + Gets or sets the height. + + The height. + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..e6580dbd01c12eba20ae37c2a30ed50a115a7cbc GIT binary patch literal 19252 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 + + + SharpGLforWPF + 2.1.0 + SharpGL for WPF + Dave Kerr + Dave Kerr + http://sharpgl.codeplex.com/ + false + SharpGL wraps the popular OpenGL library. This package installs SharpGL and the WPF controls. + SharpGL wraps the popular OpenGL library. This package installs SharpGL and the WPF controls. + + Copyright © Dave Kerr 2013 + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll new file mode 100644 index 0000000000000000000000000000000000000000..124d2a5898959e94e66a2e6ff98ae6938f292866 GIT binary patch literal 24576 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 veQQm&*5eS7rvR{EzQ{vj+YTA-zvH literal 0 HcmV?d00001 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml new file mode 100644 index 00000000..1c0007f0 --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml @@ -0,0 +1,341 @@ + + + + SharpGL.WPF + + + + + This class handles conversion to and from various bitmap types. + + + + + Converts an HBitmap the bitmap to a bitmap source. + + The hbitmap. + A BitmapSource. + + + + Convert a DIB section to a BitmapSource. + + The dib section. + The BitmapSource. + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Returns the cached ResourceManager instance used by this class. + + + + + Overrides the current thread's CurrentUICulture property for all + resource lookups using this strongly typed resource class. + + + + + Interaction logic for OpenGLControl.xaml + + + OpenGLControl + + + + + Initializes a new instance of the class. + + + + + Handles the SizeChanged event of the OpenGLControl control. + + The source of the event. + The instance containing the event data. + + + + When overridden in a derived class, is invoked whenever application code or + internal processes call . + + + + + Handles the Tick event of the timer control. + + The source of the event. + The instance containing the event data. + + + + Called when the frame rate is changed. + + The object. + The instance containing the event data. + + + + A single event args for all our needs. + + + + + The OpenGL instance. + + + + + The dispatcher timer. + + + + + A stopwatch used for timing rendering. + + + + + The last frame time in milliseconds. + + + + + The frame rate dependency property. + + + + + The render context type property. + + + + + Called when [render context type changed]. + + The o. + The instance containing the event data. + + + + The DrawFPS property. + + + + + InitializeComponent + + + + + Occurs when OpenGL should be initialised. + + + + + Occurs when OpenGL drawing should occur. + + + + + Occurs when the control is resized. This can be used to perform custom projections. + + + + + Gets or sets the frame rate. + + The frame rate. + + + + Gets or sets the type of the render context. + + The type of the render context. + + + + Gets or sets a value indicating whether to draw FPS. + + + true if draw FPS; otherwise, false. + + + + + Gets the OpenGL instance. + + + + + Interaction logic for SceneTree.xaml + + + SceneTree + + + + + InitializeComponent + + + + + If the count of a collection is zero, this converter returns collapsed. + + + + + Converts a value. + + The value produced by the binding source. + The type of the binding target property. + The converter parameter to use. + The culture to use in the converter. + + A converted value. If the method returns null, the valid null value is used. + + + + + Converts a value. + + The value that is produced by the binding target. + The type to convert to. + The converter parameter to use. + The culture to use in the converter. + + A converted value. If the method returns null, the valid null value is used. + + + + + Interaction logic for SceneView.xaml + + + SceneView + + + + + Initializes a new instance of the class. + + + + + Handles the SizeChanged event of the SceneView control. + + The source of the event. + The instance containing the event data. + + + + When overridden in a derived class, is invoked whenever application code or + internal processes call . + + + + + Handles the Tick event of the timer control. + + The source of the event. + The instance containing the event data. + + + + Called when the frame rate is changed. + + The object. + The instance containing the event data. + + + + The dispatcher timer. + + + + + A stopwatch used for timing rendering. + + + + + The last frame time in milliseconds. + + + + + The frame rate dependency property. + + + + + The DrawFPS property. + + + + + The Scene Dependency Property. + + + + + Called when [scene changed]. + + The o. + The instance containing the event data. + + + + The camera dependency property. + + + + + Called when [camera changed]. + + The o. + The instance containing the event data. + + + + InitializeComponent + + + + + Gets or sets the frame rate. + + The frame rate. + + + + Gets or sets a value indicating whether to draw FPS. + + + true if draw FPS; otherwise, false. + + + + + Gets or sets the scene. + + + The scene. + + + + + Gets or sets the camera. + + + The camera. + + + + diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config new file mode 100644 index 00000000..103e29ed --- /dev/null +++ b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 5b96a77bb241bb0bb6403038d80694ee055483b8 Mon Sep 17 00:00:00 2001 From: Jochem Date: Fri, 9 May 2014 16:40:37 +0100 Subject: [PATCH 2/8] Added the method and constants that are required to use Vertex Array Objects (VAO) and Pixel Buffer Objects (PBO). Note that this is the first methods that I've added, so it might not work (even though no errors were found during the test). Confirmation required! --- .../Core/SharpGL/OpenGLExtensionsJOG.cs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs diff --git a/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs new file mode 100644 index 00000000..a6140836 --- /dev/null +++ b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGL +{ + public partial class OpenGL + { + + #region Missing constants + public const uint GL_COPY_READ_BUFFER = 0x8F36; + public const uint GL_COPY_WRITE_BUFFER = 0x8F37; + public const uint GL_UNIFORM_BUFFER = 0x8A11; + public const uint GL_HALF_FLOAT = 0x140B; + public const uint GL_INT_2_10_10_10_REV = 0x8D9F; + public const uint GL_COLOR_ATTACHMENT0 = 0x8CE0; + public const uint GL_ACTIVE_ATOMIC_COUNTER_BUFFERS = 0x92D9; + public const uint GL_ACTIVE_UNIFORM_BLOCKS = 0x8A36; + public const uint GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 0x8A35; + public const uint GL_COMPUTE_WORK_GROUP_SIZE = 0x8267; + public const uint GL_PROGRAM_BINARY_LENGTH = 0x8741; + + public const uint GL_COMPUTE_SHADER = 0x91B9; + public const uint GL_TESS_CONTROL_SHADER = 0x8E88; + public const uint GL_TESS_EVALUATION_SHADER = 0x8E87; + + public const uint GL_ATOMIC_COUNTER_BUFFER = 0x92C0; + public const uint GL_DRAW_INDIRECT_BUFFER = 0x8F3F; + public const uint GL_DISPATCH_INDIRECT_BUFFER = 0x90EE; + public const uint GL_QUERY_BUFFER = 0x9192; + public const uint GL_SHADER_STORAGE_BUFFER = 0x90D2; + + public const uint GL_MAP_READ_BIT = 0x0001; + #endregion Missing constants + + #region Missing DLL Functions + private delegate IntPtr glMapBufferRange(uint target, int offset, int length, uint access); + #endregion Missing DLL Functions + + #region Missing Wrapped OpenGL Functionspublic void Accum(uint op, float value) + public IntPtr MapBufferRange(uint target, int offset, int length, uint access) + { + return (IntPtr)InvokeExtensionFunction(target, offset, length, access); + } + + #endregion Missing Wrapped OpenGL Functions + + + + + public void BufferData(uint target, uint[] data, uint usage) + { + var dataSize = data.Length * sizeof(uint); + IntPtr p = Marshal.AllocHGlobal(dataSize); + var intData = new int[data.Length]; + Buffer.BlockCopy(data, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, p, data.Length); + InvokeExtensionFunction(target, dataSize, data, usage); + Marshal.FreeHGlobal(p); + } + + public void BufferData(uint target, byte[] data, uint usage) + { + var dataSize = data.Length * sizeof(byte); + IntPtr p = Marshal.AllocHGlobal(dataSize); + var byteData = new byte[data.Length]; + Buffer.BlockCopy(data, 0, byteData, 0, dataSize); + Marshal.Copy(byteData, 0, p, data.Length); + InvokeExtensionFunction(target, dataSize, data, usage); + Marshal.FreeHGlobal(p); + } + } + +} From 9d4690e92422732947a12765afc565e516df8cb7 Mon Sep 17 00:00:00 2001 From: Jochem Date: Fri, 9 May 2014 16:44:00 +0100 Subject: [PATCH 3/8] Removed a sample because of being to large. --- .../SharpGLBase/Events/ModelSelectedEvent.cs | 23 - .../Events/ModelSelectedEventArgs.cs | 24 - .../Extensions/CommonExtensions.cs | 33 - .../Extensions/GlmNetExtensions.cs | 409 -- .../SharpGLBase/IO/IFileModel.cs | 20 - .../SharpGLBase/ManifestResourceLoader.cs | 32 - .../SharpGLBase/Primitives/Axis.cs | 222 - .../SharpGLBase/Primitives/AxisVBO.cs | 178 - .../SharpGLBase/Primitives/Lines.cs | 195 - .../SharpGLBase/Primitives/Model3DBase.cs | 386 - .../Primitives/ModelComponents/Face.cs | 71 - .../Primitives/ModelComponents/Mesh.cs | 175 - .../Primitives/ModelComponents/Vertex.cs | 71 - .../Primitives/PrimitivesGlobal.cs | 23 - .../SharpGLBase/Primitives/SquareGrid.cs | 154 - .../SharpGLBase/Primitives/SquareGridVBO.cs | 155 - .../SharpGLBase/Properties/AssemblyInfo.cs | 36 - .../SharpGLBase/Scene/ModelView.cs | 112 - .../SharpGLBase/Scene/Normal.cs | 48 - .../Scene/OpenGLHitTestExtensions.cs | 20 - .../SharpGLBase/Scene/OpenGLScene.cs | 292 - .../SharpGLBase/Scene/Projection.cs | 157 - .../SharpGLBase/Scene/Shaders.cs | 85 - .../SharpGLBase/Scene/TransformableBase.cs | 312 - .../SharpGLBase/Shaders/ExtShaderProgram.cs | 160 - .../Shaders/Parameters/IMVPNParameters.cs | 17 - .../Parameters/IMaterialShaderParameters.cs | 20 - .../Shaders/Parameters/IShaderParameterIds.cs | 15 - .../Parameters/ISingleLightParameters.cs | 13 - .../Shaders/Parameters/PerPixelParameters.cs | 61 - .../Parameters/SimpleShaderParameters.cs | 72 - .../Shaders/Parameters/ToonParameters.cs | 62 - .../SharpGLBase/Shaders/PerPixel.frag | 24 - .../SharpGLBase/Shaders/PerPixel.vert | 18 - .../SharpGLBase/Shaders/SimpleShader.frag | 9 - .../SharpGLBase/Shaders/SimpleShader.vert | 19 - .../SharpGLBase/Shaders/Toon.frag | 54 - .../SharpGLBase/Shaders/Toon.vert | 18 - .../SharpGLBase/SharpGLBase.csproj | 134 - .../SharpGLBase/VertexAttributes.cs | 18 - .../SharpGLBase/packages.config | 4 - .../SharpGLTest/App.config | 18 - .../SharpGLViewerSample/SharpGLTest/App.xaml | 8 - .../SharpGLTest/App.xaml.cs | 17 - .../SharpGLTest/MainWindow.xaml | 14 - .../SharpGLTest/MainWindow.xaml.cs | 181 - .../SharpGLTest/MainWindowViewModel.cs | 314 - .../SharpGLTest/MyScene.cs | 205 - .../SharpGLTest/Properties/AssemblyInfo.cs | 55 - .../Properties/Resources.Designer.cs | 63 - .../SharpGLTest/Properties/Resources.resx | 117 - .../Properties/Settings.Designer.cs | 26 - .../SharpGLTest/Properties/Settings.settings | 7 - .../SharpGLTest/Shapes/FlatShadedCube.cs | 73 - .../SharpGLTest/Shapes/MyTrefoilKnot.cs | 160 - .../SharpGLTest/Shapes/SmoothShadedCube.cs | 68 - .../SharpGLTest/SharpGLTest.csproj | 133 - .../SharpGLTest/packages.config | 6 - .../SharpGLViewerSample.sln | 27 - .../GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg | Bin 17026 -> 0 bytes .../GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec | 17 - .../GlmNet.0.0.2.0/lib/net40/GlmNet.XML | 281 - .../GlmNet.0.0.2.0/lib/net40/GlmNet.dll | Bin 13824 -> 0 bytes .../GlmNet.0.0.2.0/lib/net40/GlmNet.pdb | Bin 44544 -> 0 bytes .../SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg | Bin 282901 -> 0 bytes .../SharpGLCore.2.1.0.nuspec | 15 - .../lib/SharpGL.SceneGraph.dll | Bin 143360 -> 0 bytes .../lib/SharpGL.SceneGraph.xml | 6188 ----------------- .../lib/SharpGL.Serialization.dll | Bin 22016 -> 0 bytes .../lib/SharpGL.Serialization.xml | 209 - .../SharpGLCore.2.1.0/lib/SharpGL.dll | Bin 355840 -> 0 bytes .../SharpGLCore.2.1.0/lib/SharpGL.xml | 4451 ------------ .../SharpGLforWPF.2.1.0.nupkg | Bin 19252 -> 0 bytes .../SharpGLforWPF.2.1.0.nuspec | 20 - .../SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll | Bin 24576 -> 0 bytes .../SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml | 341 - .../packages/repositories.config | 5 - .../Samples/WPF/SimpleShaderSample/App.xaml | 8 - .../WPF/SimpleShaderSample/App.xaml.cs | 16 - .../WPF/SimpleShaderSample/MainWindow.xaml | 11 - .../WPF/SimpleShaderSample/MainWindow.xaml.cs | 112 - .../Properties/AssemblyInfo.cs | 38 - .../Properties/Resources.Designer.cs | 63 - .../Properties/Resources.resx | 117 - .../Properties/Settings.Designer.cs | 26 - .../Properties/Settings.settings | 7 - .../SimpleShaderSample.csproj | 130 - .../Samples/WPF/SimpleShaderSample/app.config | 3 - 88 files changed, 17501 deletions(-) delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.pdb delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.xml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nuspec delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml delete mode 100644 source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml.cs delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.Designer.cs delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.Designer.cs delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj delete mode 100644 source/SharpGL/Samples/WPF/SimpleShaderSample/app.config diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs deleted file mode 100644 index 04e90bc6..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEvent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SharpGLBase.Primitives; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Events -{ - // A delegate type for hooking up change notifications. - public delegate void ModelSelectedEvent(object sender, ModelSelectedEventArgs e); - public class ModelSelectedEventArgs : EventArgs - { - public Point Point { get; set; } - public Model3DBase SelectedModel { get; set; } - - public ModelSelectedEventArgs(Point p, Model3DBase m) - { - Point = p; - SelectedModel = m; - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs deleted file mode 100644 index c60bedf9..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Events/ModelSelectedEventArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Scene.Primitives; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace Scene.Events -{ - - // A delegate type for hooking up change notifications. - public delegate void ModelSelectedEvent(object sender, ModelSelectedEventArgs e); - public class ModelSelectedEventArgs : EventArgs - { - public Point Point { get; set; } - public Model3DBase SelectedModel { get; set; } - - public ModelSelectedEventArgs(Point p, Model3DBase m) - { - Point = p; - SelectedModel = m; - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs deleted file mode 100644 index 3c852484..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/CommonExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Extensions -{ - public static class CommonExtensions - { - public static List ToValueList(this Dictionary> dic) - { - var list = new List(); - foreach (var item in dic) - { - list.AddRange(item.Value); - } - - return list; - } - - public static List ToValueList(this Dictionary dic) - { - var list = new List(); - - foreach (var item in dic) - { - list.Add(item.Value); - } - - return list; - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs deleted file mode 100644 index c08dac0a..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Extensions/GlmNetExtensions.cs +++ /dev/null @@ -1,409 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Extensions -{ - /// - /// Provides matrix and vector extentions primarely for the GlmNET library. - /// - public static class GlmNetExtensions - { - /// - /// Deep copy of the mat4 object - /// - /// The matrix - /// Deep copy of the input matrix. - public static mat4 DeepCopy(this mat4 mat) - { - return new mat4( - new vec4[]{ - mat[0].DeepCopy(), - mat[1].DeepCopy(), - mat[2].DeepCopy(), - mat[3].DeepCopy(), - }); - } - - /// - /// Deep copy of a vec4 object - /// - /// The vector - /// Deep copy of the input vector. - public static vec4 DeepCopy(this vec4 v) - { - return new vec4(v.x, v.y, v.z, v.w); - } - - /// - /// Copies everything except the z-value from the vector v into a new vec3. - /// - /// input vector - /// - public static vec3 ToVec3(this vec4 v) - { - return new vec3(v.x, v.y, v.z); - } - - /// - /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. - /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. - /// If exception is caught, this method will return an empty string( = ""). - /// - /// The matrix. - /// Used for calling Math.Round(m[i][j], round) - /// A readable 4 line string, where each line defines 1 vector - public static string ToValueString(this mat4 m, int round = 3) - { - var txt = ""; - try - { - for (int i = 0; i < 4; i++) - { - var arr = m.to_array(); - var mi = m[i]; - txt += mi.ToValueString(round); - txt += "\n"; - } - } - catch (Exception) - { - txt = ""; - } - return txt; - - } - - /// - /// Create a string from the values in the vec4. - /// - /// The vector. - /// Used for calling Math.Round(v[j], round). - /// A string from the values in the vec4. - public static string ToValueString(this vec4 v, int round = 3) - { - string txt = ""; - for (int j = 0; j < 4; j++) - { - txt += Math.Round(v[j], round) + "\t"; - } - - return txt; - } - - /// - /// Create a string from the values in the vec3. - /// - /// The vector. - /// Used for calling Math.Round(v[j], round). - /// A string from the values in the vec3. - public static string ToValueString(this vec3 v, int round = 3) - { - string txt = ""; - for (int j = 0; j < 3; j++) - { - txt += Math.Round(v[j], round) + "\t"; - } - - return txt; - } - - /// - /// Transposes the mat4. - /// - /// The 4x4 matrix. - /// The Transpose of the matrix. - public static mat4 Transpose(this mat4 m) - { - vec4[] vecs = new vec4[4]; - - for (int i = 0; i < vecs.Length; i++) - { - vecs[i] = new vec4(); - for (int j = 0; j < vecs.Length; j++) - { - vecs[i][j] = m[j][i]; - } - } - - return new mat4(vecs); - } - - /// - /// Concatenates every value in this matrix with it's corresponding value in the other one. - /// - /// This matrix - /// Other matrix - /// The concatenated result. - public static mat4 Concat(this mat4 m, mat4 m2) - { - vec4[] vecs = new vec4[4]; - - for (int i = 0; i < vecs.Length; i++) - { - vecs[i] = new vec4(); - for (int j = 0; j < vecs.Length; j++) - { - vecs[i][j] = m[i][j] + m2[i][j]; - } - } - - return new mat4(vecs); - } - - /// - /// Not sure if this one works 100%, but might be more performant (if it's ever needed). - /// Creates the Inverse of the matrix. - /// - /// A 4x4 matrix. - /// The inversed matrix. - public static mat4 Inverse2(this mat4 mat) - { - int n = 4; - float[,] a = new float[n,n]; - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - { - a[i,j] = mat[j][i]; - } - } - - var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; - var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; - var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; - var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; - var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; - var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; - - var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; - var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; - var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; - var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; - var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; - var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; - - // Should check for 0 determinant - var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); - - var b = mat4.identity(); - - b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); - b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); - b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); - b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); - - b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); - b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); - b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); - b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); - - b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); - b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); - b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); - b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); - - b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); - b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); - b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); - b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); - - return b; - } - - /// - /// Creates the Inverse of the matrix. - /// - /// A 4x4 matrix. - /// The inversed matrix. - public static mat4 Inverse(this mat4 a) - { - int n = 4; - float[][] arrA = new float[n][]; - float[][] arrInverse; - mat4 inverse = mat4.identity(); - - for (int i = 0; i < n; i++) - { - arrA[i] = new float[n]; - for (int j = 0; j < n; j++) - { - arrA[i][j] = a[j][i]; - } - } - - var d = Determinant(arrA, n); - if (d != 0) - { - arrInverse = Cofactor(arrA, n); - - //float[][] to mat4 - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - { - inverse[i, j] = arrInverse[i][j]; - } - } - - //test if result == I - var res = a * inverse; - - - return inverse; - } - else - { - throw new Exception("Matrix can't be inverted, determinant == 0."); - } - } - - /// - /// For calculating Determinant of the Matrix. - /// - /// The matrix. - /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) - /// The determinant. - public static float Determinant(float[][] a, int k) - { - float s=1,det=0; - float[][] b = new float[k][]; - - - for (int idx = 0; idx < b.Length; idx++) - { - b[idx] = new float[k]; - } - - int m,n,c; - if (k==1) - { - return (a[0][0]); - } - else - { - det=0; - for (c=0;c - /// Calculates the Cofactor of a matrix of the order f. - /// - /// The matrix. - /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) - /// The cofactor. - public static float[][] Cofactor(float[][] a, int f) - { - var b = new float[f][]; - var fac = new float[f][]; - - for (int i = 0; i < f; i++) - { - b[i] = new float[f]; - fac[i] = new float[f]; - } - - - int m,n; - for (int q = 0; q < f; q++) - { - for (int p = 0; p < f; p++) - { - m=0; - n=0; - for (int i = 0; i < f; i++) - { - for (int j = 0; j < f; j++) - { - if (i != q && j != p) - { - b[m][n]=a[i][j]; - if (n<(f-2)) - n++; - else - { - n=0; - m++; - } - } - } - } - fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); - } - } - return Transpose(a, fac, f); - } - - /// - /// Finding the transpose of a matrix. - /// - /// The matrix - /// The cofactor. - /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) - /// The transpose. - public static float[][] Transpose(float[][] a, float[][] fac, int r) - { - float[][] b = new float[r][], - inverse = new float[r][]; - float d; - - for (int i = 0; i < r; i++) - { - b[i] = new float[r]; - inverse[i] = new float[r]; - } - - for (int i = 0; i < r; i++) - { - for (int j = 0; j < r; j++) - { - b[i][j]=fac[j][i]; - } - } - d = Determinant(a, r); - for (int i = 0; i < r; i++) - { - for (int j = 0; j < r; j++) - { - inverse[i][j] = b[i][j] / d; - } - } - //The inverse of matrix is : - return inverse; - } - - public static vec3 Substract(this vec3 v1, vec3 v2) - { - return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs deleted file mode 100644 index ce411b88..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/IO/IFileModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using SharpGL.SceneGraph.Assets; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace IO -{ - public interface IFileModel - { - float[] Vertices { get; set; } - float[] Indices { get; set; } - float[] Normals { get; set; } - Material[] Materials { get; set; } - - - IFileModel LoadModel(string path); - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs deleted file mode 100644 index 64494a4c..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/ManifestResourceLoader.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO; -using System.Reflection; - -namespace SharpGLBase -{ - /// - /// A small helper class to load manifest resource files. - /// - public static class ManifestResourceLoader - { - /// - /// Loads the named manifest resource as a text string. - /// - /// Name of the text file. - /// The contents of the manifest resource. - public static string LoadTextFile(string textFileName) - { - var executingAssembly = Assembly.GetExecutingAssembly(); - var pathToDots = textFileName.Replace("\\", "."); - var location = string.Format("{0}.{1}", executingAssembly.GetName().Name, pathToDots); - - var names = executingAssembly.GetManifestResourceNames(); - using (var stream = executingAssembly.GetManifestResourceStream(location)) - { - using (var reader = new StreamReader(stream)) - { - return reader.ReadToEnd(); - } - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs deleted file mode 100644 index 4636e3ee..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Axis.cs +++ /dev/null @@ -1,222 +0,0 @@ -using GlmNet; -using SharpGLBase.Shaders; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGL.Shaders; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - /// - /// Draws an axis in the center of the world. - /// - public class Axis : IRenderable - { - #region fields - private float _axisLength = 4, - _lineThickness = 2; - private Material _materialX, _materialY, _materialZ; - private List> _linesX, _linesY, _linesZ; - #endregion fields - - #region properties - /// - /// The length of each axis. - /// - public float AxisLength - { - get { return _axisLength; } - set { _axisLength = value; } - } - /// - /// The thickness of each axis. - /// - public float LineThickness - { - get { return _lineThickness; } - set { _lineThickness = value; } - } - /// - /// The material of the the X-axis - /// - public Material MaterialX - { - get { return _materialX; } - set { _materialX = value; } - } - /// - /// The material of the the Y-axis - /// - public Material MaterialY - { - get { return _materialY; } - set { _materialY = value; } - } - - /// - /// The material of the the Z-axis - /// - public Material MaterialZ - { - get { return _materialZ; } - set { _materialZ = value; } - } - #endregion properties - - #region constructors - public Axis() - { - _materialX = new Material(); - _materialX.Ambient = Color.Red; - _materialX.Shininess = 1f; - - _materialY = new Material(); - _materialY.Ambient = Color.Green; - _materialY.Shininess = 1f; - - _materialZ = new Material(); - _materialZ.Ambient = Color.Blue; - _materialZ.Shininess = 1f; - - RecalculateShape(); - } - - public Axis(Material matX, Material matY, Material matZ) - { - _materialX = matX; - _materialY = matY; - _materialY = matZ; - - RecalculateShape(); - } - #endregion constructors - - - /// - /// Renders the axis to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - /// Pass the shader so the material color(s) can be applied locally. - public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) - { - // Ensure that we're in design mode (we don't want axis during render) - if (renderMode != RenderMode.Design) - return; - - ValidateBeforeRender(); - - LoadAttributes(gl); - - shader.ApplyMaterial(gl, MaterialX); - gl.Begin(OpenGL.GL_LINES); - PrimitivesGlobal.RenderLines(gl, _linesX); - gl.End(); - - shader.ApplyMaterial(gl, MaterialZ); - gl.Begin(OpenGL.GL_LINES); - PrimitivesGlobal.RenderLines(gl, _linesZ); - gl.End(); - - shader.ApplyMaterial(gl, MaterialY); - gl.Begin(OpenGL.GL_LINES); - PrimitivesGlobal.RenderLines(gl, _linesY); - gl.End(); - - // Undo last attribute changes - PopAttributes(gl); - } - - /// - /// Renders the axis to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - public virtual void Render(OpenGL gl, RenderMode renderMode) - { - // Ensure that we're in design mode (we don't want axis during render) - if (renderMode != RenderMode.Design) - return; - - ValidateBeforeRender(); - - LoadAttributes(gl); - // Draw the lines. - // TODO: Inefficient, consumes a lot of resources. - gl.Begin(OpenGL.GL_LINES); - PrimitivesGlobal.RenderLines(gl, _linesX); - PrimitivesGlobal.RenderLines(gl, _linesY); - PrimitivesGlobal.RenderLines(gl, _linesZ); - gl.End(); - - PopAttributes(gl); - } - - /// - /// Calculates the lines using the current axis properties. - /// - public virtual void RecalculateShape() - { - _linesX = new List>(); - _linesY = new List>(); - _linesZ = new List>(); - - _linesX.Add( - new Tuple( - new vec3(0, 0, 0), - new vec3(_axisLength,0,0)) - ); - - _linesY.Add( - new Tuple( - new vec3(0, 0, 0), - new vec3(0, _axisLength, 0)) - ); - - _linesZ.Add( - new Tuple( - new vec3(0, 0, 0), - new vec3(0, 0, _axisLength)) - ); - } - - /// - /// Pushes and sets some attributes. - /// - /// The GL. - public virtual void LoadAttributes(OpenGL gl) - { - // Push all attributes, disable lighting and depth testing. - gl.PushAttrib(OpenGL.GL_CURRENT_BIT | OpenGL.GL_ENABLE_BIT | - OpenGL.GL_LINE_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); - - gl.DepthFunc(OpenGL.GL_ALWAYS); - gl.LineWidth(_lineThickness); - } - - /// - /// Pops last attributes. - /// - /// The GL. - public virtual void PopAttributes(OpenGL gl) - { - gl.PopAttrib(); - } - - /// - /// Ensures that all required properties are acceptable. - /// - private void ValidateBeforeRender() - { - if (_linesX == null || _linesY == null || _linesZ == null) - { - throw new Exception("Axis aren't calculated."); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs deleted file mode 100644 index 7e251f53..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/AxisVBO.cs +++ /dev/null @@ -1,178 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGLBase.Shaders; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - public class AxisVBO - { - - #region fields - private float _axisLength = 4, - _lineThickness = 2; - private Lines _lineX, _lineY, _lineZ; - #endregion fields - - #region properties - /// - /// The length of each axis. - /// - public float AxisLength - { - get { return _axisLength; } - set { _axisLength = value; } - } - /// - /// The thickness of each axis. - /// - public float LineThickness - { - get { return _lineThickness; } - set { _lineThickness = value; } - } - /// - /// The material of the the X-axis - /// - public Material MaterialX - { - get { return _lineX.Material; } - set { _lineX.Material = value; } - } - /// - /// The material of the the Y-axis - /// - public Material MaterialY - { - get { return _lineY.Material; } - set { _lineY.Material = value; } - } - - /// - /// The material of the the Z-axis - /// - public Material MaterialZ - { - get { return _lineZ.Material; } - set { _lineZ.Material = value; } - } - #endregion properties - - #region constructors - public AxisVBO(OpenGL gl) - { - RecalculateShape(gl); - - _lineX.Material = new Material(); - _lineX.Material.Diffuse = Color.Red; - - _lineY.Material = new Material(); - _lineY.Material.Diffuse = Color.Green; - _lineY.Material.Shininess = 0.1f; - - _lineZ.Material = new Material(); - _lineZ.Material.Diffuse = Color.Blue; - _lineZ.Material.Shininess = 0.1f; - - var lineWidth = 5f; - - _lineX.LineWidth = lineWidth; - _lineY.LineWidth = lineWidth; - _lineZ.LineWidth = lineWidth; - } - - public AxisVBO(OpenGL gl, Material matX, Material matY, Material matZ, float lineWidth) - { - RecalculateShape(gl); - - _lineX.Material = matX; - _lineY.Material = matY; - _lineZ.Material = matZ; - - _lineX.LineWidth = lineWidth; - _lineY.LineWidth = lineWidth; - _lineZ.LineWidth = lineWidth; - } - #endregion constructors - - - public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) - { - // Ensure that we're in design mode (we don't want axis during render) - if (renderMode != RenderMode.Design) - return; - - ValidateBeforeRender(); - - //gl.DepthFunc(OpenGL.GL_ALWAYS); - - shader.UseProgram(gl, () => - { - shader.ApplyMaterial(gl, MaterialX); - _lineX.Render(gl, renderMode, shader); - - shader.ApplyMaterial(gl, MaterialY); - _lineY.Render(gl, renderMode, shader); - - shader.ApplyMaterial(gl, MaterialZ); - _lineZ.Render(gl, renderMode, shader); - }); - - //gl.DepthFunc(OpenGL.GL_LESS); - } - - - - /// - /// Calculates the lines using the current axis properties. - /// - public virtual void RecalculateShape(OpenGL gl) - { - var riseAxisValue = 0f;// .0001f; // Axis didn't combine well with - - var lineX = new List>(); - var lineY = new List>(); - var lineZ = new List>(); - - lineX.Add( - new Tuple( - new vec3(0, riseAxisValue, 0), - new vec3(_axisLength, riseAxisValue, 0)) - ); - - lineY.Add( - new Tuple( - new vec3(0, riseAxisValue, 0), - new vec3(0, _axisLength, 0)) - ); - - lineZ.Add( - new Tuple( - new vec3(0, riseAxisValue, 0), - new vec3(0, riseAxisValue, _axisLength)) - ); - - - _lineX = new Lines(gl, lineX, null); - _lineY = new Lines(gl, lineY, null); - _lineZ = new Lines(gl, lineZ, null); - } - - /// - /// Ensures that all required properties are acceptable. - /// - private void ValidateBeforeRender() - { - if (_lineX == null || _lineY == null || _lineZ == null) - { - throw new Exception("Axis aren't calculated."); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs deleted file mode 100644 index 2eb8092a..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Lines.cs +++ /dev/null @@ -1,195 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGL.Enumerations; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGL.VertexBuffers; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - public class Lines - { - #region fields - private uint _glDrawMode = SharpGL.OpenGL.GL_LINE; - vec3[] _vertices, _normals; - ushort[] _indices; - Material _material; - OpenGL _openGL; - private VertexBuffer _vertexBuffer, _normalBuffer; - private IndexBuffer _indexBuffer; - float _lineWidth = 1f; - #endregion fields - - - #region properties - public vec3[] Vertices - { - get { return _vertices; } - set { _vertices = value; } - } - - public vec3[] Normals - { - get { return _normals; } - set { _normals = value; } - } - - public ushort[] Indices - { - get { return _indices; } - set { _indices = value; } - } - - public uint GlDrawMode - { - get { return _glDrawMode; } - set { _glDrawMode = value; } - } - - public Material Material - { - get { return _material; } - set { _material = value; } - } - - public OpenGL GL - { - get { return _openGL; } - set { _openGL = value; } - } - - public VertexBuffer VertexBuffer - { - get { return _vertexBuffer; } - set { _vertexBuffer = value; } - } - - public VertexBuffer NormalBuffer - { - get { return _normalBuffer; } - set { _normalBuffer = value; } - } - public IndexBuffer IndexBuffer - { - get { return _indexBuffer; } - set { _indexBuffer = value; } - } - - public float LineWidth - { - get { return _lineWidth; } - set { _lineWidth = value; } - } - - #endregion properties - - public Lines(OpenGL gl, List> lines, Material material = null) - { - - var verts = new vec3[lines.Count * 2]; - var normals = new vec3[lines.Count * 2]; - var indices = new ushort[lines.Count * 2]; - - for (int i = 0; i < lines.Count; i++) - { - var i2 = i * 2; - verts[i2] = lines[i].Item1; - verts[i2 + 1] = lines[i].Item2; - - normals[i2] = new vec3(1, 1, 1); - normals[i2 + 1] = new vec3(1, 1, 1); - - indices[i2] = (ushort)i2; - indices[i2 + 1] = (ushort)(i2 + 1); - } - - if (material != null) - Material = material; - - _vertices = verts; - _normals = normals; - _indices = indices; - GlDrawMode = OpenGL.GL_LINES; - - - if (gl != null) - GenerateGeometry(gl); - } - - /// - /// Generates the vertices, normals and indices and creates them for the OpenGL. - /// This method has to be called once before drawing. - /// - /// - public void GenerateGeometry(OpenGL gl) - { - _openGL = gl; - - // Create the index data buffer. - _indexBuffer = new IndexBuffer(); - _indexBuffer.Create(_openGL); - - // Create the vertex data buffer. - _vertexBuffer = new VertexBuffer(); - _vertexBuffer.Create(_openGL); - - _normalBuffer = new VertexBuffer(); - _normalBuffer.Create(_openGL); - } - - public void Render(OpenGL gl, RenderMode renderMode, Shaders.ExtShaderProgram shader = null) - { - - // Binds buffers. - Bind(); - - // Sets the linewidth. - gl.LineWidth(LineWidth); - // Draw the elements. - gl.DrawArrays(GlDrawMode, 0, Vertices.Length); - //gl.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); - - //gl.PopAttrib(); - } - - - - /// - /// Calls VertexBuffer.Bind(gl), IndexBuffer.Bind(gl) and Material.Bind(gl). - /// - /// The OpenGL - public void Bind() - { - if (_openGL == null) - { - throw new ArgumentNullException("OpenGL parameter cannot be null. Call 'GenerateGeomerty(...)' before attempting to bind."); - } - - // Bind the vertex, normal and index buffers. - if (_vertexBuffer != null) - { - _vertexBuffer.Bind(_openGL); - _vertexBuffer.SetData(_openGL, VertexAttributes.Position, Vertices.SelectMany(v => v.to_array()).ToArray(), false, 3); - } - - if (_normalBuffer != null) - { - _normalBuffer.Bind(_openGL); - _normalBuffer.SetData(_openGL, VertexAttributes.Normal, Normals.SelectMany(v => v.to_array()).ToArray(), false, 3); - } - - if (_indexBuffer != null) - { - _indexBuffer.Bind(_openGL); - _indexBuffer.SetData(_openGL, Indices); - } - - if (Material != null) - Material.Bind(_openGL); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs deleted file mode 100644 index f1181457..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/Model3DBase.cs +++ /dev/null @@ -1,386 +0,0 @@ -using GlmNet; -using SharpGLBase.Scene; -using SharpGLBase.Extensions; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGL.VertexBuffers; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using SharpGLBase.Primitives.ModelComponents; -using SharpGLBase.Shaders; - -namespace SharpGLBase.Primitives -{ - public abstract class Model3DBase : TransformableBase, IHasMaterial, IDisposable - { - #region fields - //private ushort[] _indices; - private vec3[] _baseVertices;//, _transformedVertices, _normals; - private VertexBuffer _vertexBuffer, _normalBuffer; - private IndexBuffer _indexBuffer; - private OpenGL _openGL; - private bool _visible = true; - private bool _autoCalculateNormals = true; - private Material _material = new Material(){ Ambient = Color.Red}; - private Mesh _mesh; - private uint _glDrawMode = OpenGL.GL_TRIANGLES; - private int _bufferStride = 3; - #endregion fields - - #region properties - /// - /// The material that has to be applied to this model. - /// - public Material Material - { - get; - set; - } - /// - /// This indices for this model. Used for pointing to a position in the Normals- and Vertices arrays. - /// - public ushort[] Indices - { - get { return _mesh.Indices; } - set { _mesh.Indices = value; } - } - /// - /// The normals for this model. Primarily used for lighting calculations by telling the GL in which direction the surface is facing. - /// - public vec3[] Normals - { - get { return _mesh.Normals; } - set { _mesh.Normals = value; } - } - /// - /// The vertices for this model. - /// - public vec3[] BaseVertices - { - get { return _baseVertices; } - set { _baseVertices = value; } - } - /// - /// The vertices for this model after applying the transformations to it. - /// - public vec3[] TransformedVertices - { - get { return _mesh.Vertices == null ? _baseVertices : _mesh.Vertices; } - set { _mesh.Vertices = value; } - } - /// - /// The normal buffer for binding with the GL. - /// - public VertexBuffer NormalBuffer - { - get { return _normalBuffer; } - set { _normalBuffer = value; } - } - /// - /// The vertex buffer for binding with the GL. - /// - public VertexBuffer VertexBuffer - { - get { return _vertexBuffer; } - set { _vertexBuffer = value; } - } - /// - /// The index buffer for binding with the GL. - /// - public IndexBuffer IndexBuffer - { - get { return _indexBuffer; } - set { _indexBuffer = value; } - } - /// - /// The opengl instance. - /// - public OpenGL OpenGL - { - get { return _openGL; } - } - /// - /// Checks whether this model should be drawn during the next draw-call. Implement this in your Render-method. - /// - public bool Visible - { - get { return _visible; } - set { _visible = value; } - } - /// - /// Checks if the normals can be automatically calculated if they're unavailable or after a transformation. - /// - public bool AutoCalculateNormals - { - get { return _autoCalculateNormals; } - set { _autoCalculateNormals = value; } - } - /// - /// The mode that this model should be drawn with (GL_LINES, GL_TRIANGLES, GL_QUADS,...). - /// - public uint GlDrawMode - { - get { return _glDrawMode; } - set { _glDrawMode = value; } - } - /// - /// The stride between - /// - public int BufferStride - { - get { return _bufferStride; } - set { _bufferStride = value; } - } - #endregion properties - - #region abstract methods - /// - /// Draws the model to the OpenGL. GenerateGeometry(...) has to be called at least once before Draw(...). - /// - /// - /// - /// - /// - //public abstract void Draw(); - public abstract void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null); - - #endregion abstract methods - - /// - /// Call this method to prepare the object for being displayed or fill -BaseVertices, -Indices, -Normals manually. - /// Also provide the OpenGL to automatically call GenerateGeometry. - /// - /// The BaseVertices - /// The Indices - /// The Normals - /// The OpenGL - public void Init(vec3[] vertices, ushort[] indices, vec3[] normals = null, OpenGL gl = null) - { - _baseVertices = vertices; - //_indices = indices; - - - _mesh = new Mesh(indices, _baseVertices, normals); - //_normals = normals; - - if (gl != null) - { - GenerateGeometry(gl); - } - } - - /// - /// Generates the vertices, normals and indices and creates them for the OpenGL. - /// This method has to be called once before drawing. - /// - /// - public void GenerateGeometry(OpenGL gl) - { - _openGL = gl; - - // Create the index data buffer. - _indexBuffer = new IndexBuffer(); - _indexBuffer.Create(_openGL); - - // Create the vertex data buffer. - _vertexBuffer = new VertexBuffer(); - _vertexBuffer.Create(_openGL); - - if (_mesh.Normals != null) - { - _normalBuffer = new VertexBuffer(); - _normalBuffer.Create(_openGL); - } - else if (_autoCalculateNormals) - { - CalculateNormals(); - _normalBuffer = new VertexBuffer(); - _normalBuffer.Create(_openGL); - } - } - - - /// - /// Calls VertexBuffer.Bind(gl), IndexBuffer.Bind(gl) and Material.Bind(gl). - /// - /// The OpenGL - public void Bind() - { - if (_openGL == null) - { - throw new ArgumentNullException("OpenGL parameter cannot be null. Call 'GenerateGeomerty(...)' before attempting to bind."); - } - - // Bind the vertex, normal and index buffers. - if (_vertexBuffer != null) - { - _vertexBuffer.Bind(_openGL); - _vertexBuffer.SetData(_openGL, VertexAttributes.Position, TransformedVertices.SelectMany(v => v.to_array()).ToArray(), false, _bufferStride); - } - - if (_normalBuffer != null) - { - _normalBuffer.Bind(_openGL); - _normalBuffer.SetData(_openGL, VertexAttributes.Normal, _mesh.Normals.SelectMany(v => v.to_array()).ToArray(), false, _bufferStride); - } - - if (_indexBuffer != null) - { - _indexBuffer.Bind(_openGL); - _indexBuffer.SetData(_openGL, _mesh.Indices); - } - - if (Material != null) - Material.Bind(_openGL); - } - - /// - /// When the creation of the new transformation matrix is finished, this matrix must to be applied to every vertex. - /// - public override void RecalculateResultMatrix() - { - base.RecalculateResultMatrix(); - - vec3[] vertices = new vec3[BaseVertices.Length]; - // Apply transformations to each vertex - for (int baseVertIdx = 0; baseVertIdx < BaseVertices.Length; baseVertIdx++) - { - vec3 vec3Vert = BaseVertices[baseVertIdx]; - vec4 vec4Vert = new vec4(vec3Vert.x, vec3Vert.y, vec3Vert.z, 1); - - // vec4 res = base.ResultMatrix * vec4Vert; // Apparently not supported in GlmNET, so we do it manually. - vec4 res = new vec4(); - for (int i = 0; i < 4; i++) // i = collumn for mat4 - { - float val = 0; - for (int j = 0; j < 4; j++) // j = row for mat4 and col for vec4 - { - val += vec4Vert[j] * base.ResultMatrix[j][i]; - } - res[i] = val; - } - vertices[baseVertIdx] = new vec3(res[0], res[1], res[2]); - } - - TransformedVertices = vertices; - //Vertices changed, so normals need to be recalculated - CalculateNormals(); - } - - /// - /// Recalculates the normals. - /// NOTE: this method is virtual. - /// - public virtual void CalculateNormals() - { - _mesh.CalculateNormals(); - - } - - - /// - /// Cleans up OpenGL memory when this element is no longer needed. - /// - public void Dispose() - { - if (_openGL == null) - return; - - List buffersToBeRemoved = new List(); - - if (_indexBuffer != null) - buffersToBeRemoved.Add(_indexBuffer.IndexBufferObject); - if (_vertexBuffer != null) - buffersToBeRemoved.Add(_vertexBuffer.VertexBufferObject); - if (_normalBuffer != null) - buffersToBeRemoved.Add(_normalBuffer.VertexBufferObject); - - _openGL.DeleteBuffers(buffersToBeRemoved.Count, buffersToBeRemoved.ToArray()); - } - - /// - /// Generates and draws the model from scratch for the given GL. Do NOT use this method for each draw-call. - /// This method should only be used for drawing a model once. - /// - /// - /// - public static void GenerateAndDrawOnce(OpenGL gl, Model3DBase model) - { - var verts = model.TransformedVertices.SelectMany(v => v.to_array()).ToArray(); - var normals = model.Normals.SelectMany(v => v.to_array()).ToArray(); - var indices = model.Indices; - var drawMode = model.GlDrawMode; - - - // Create the index data buffer. - var indexBuffer = new IndexBuffer(); - indexBuffer.Create(gl); - - // Create the vertex data buffer. - var vertexBuffer = new VertexBuffer(); - vertexBuffer.Create(gl); - - // Create the normal data buffer. - var normalBuffer = new VertexBuffer(); - normalBuffer.Create(gl); - - - // Bind the vertex, normal and index buffers. - vertexBuffer.Bind(gl); - vertexBuffer.SetData(gl, VertexAttributes.Position, verts, false, 3); - - normalBuffer.Bind(gl); - normalBuffer.SetData(gl, VertexAttributes.Normal, normals, false, 3); - - indexBuffer.Bind(gl); - indexBuffer.SetData(gl, indices); - - gl.FrontFace(OpenGL.GL_CW); - - // Draw the elements. - gl.DrawElements(drawMode, indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); - - - // Clean up - List buffersToBeRemoved = new List(); - - if (indexBuffer != null) - buffersToBeRemoved.Add(indexBuffer.IndexBufferObject); - if (vertexBuffer != null) - buffersToBeRemoved.Add(vertexBuffer.VertexBufferObject); - if (normalBuffer != null) - buffersToBeRemoved.Add(normalBuffer.VertexBufferObject); - - gl.DeleteBuffers(buffersToBeRemoved.Count, buffersToBeRemoved.ToArray()); - } - - - /// - /// Converts an (uint)model.VertexBuffer.VertexBufferObject to a ARGB color. - /// - /// The model. - /// A float[4] containing RGBA values. - public Color GenerateColorFromId() - { - if (VertexBuffer == null) - { - return Color.Black; - } - - // Get the integer ID - var i = (int)VertexBuffer.VertexBufferObject; - - int b = (i >> 16) & 0xFF; - int g = (i >> 8) & 0xFF; - int r = i & 0xFF; - - return Color.FromArgb(255, r, g, b); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs deleted file mode 100644 index 0b90f8c0..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Face.cs +++ /dev/null @@ -1,71 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives.ModelComponents -{ - public class Face - { - #region fields - Vertex[] _vertices; - vec3 _normal; - #endregion fields - - #region properties - public Vertex[] Vertices - { - get { return _vertices; } - } - - public vec3 Normal - { - get { return _normal; } - set { _normal = value; } - } - #endregion properties - - - public Face(Vertex[] vertices) - { - _vertices = vertices; - foreach (var vertex in vertices) - { - vertex.ParentFaces.Add(this); // Establish many-to-many relationship. - } - } - public void CalculateNormal() - { - var v1 = _vertices[0]; - var v2 = _vertices[1]; - var v3 = _vertices[2]; - var edge1 = v2.Vec3-v1.Vec3; - var edge2 = v3.Vec3-v1.Vec3; - var normal = glm.cross(edge1, edge2); - - //for (int i = 0; i < _vertices.Length - 1; i++) - //{ - // vec3 curVert = _vertices[i].Vec3; - // vec3 nextVert = _vertices[(i + 1) % _vertices.Length].Vec3; - - // normal.x += (curVert.y - nextVert.y) * (curVert.z + nextVert.z); - // normal.y += (curVert.z - nextVert.z) * (curVert.x + nextVert.x); - // normal.z += (curVert.x - nextVert.x) * (curVert.y + nextVert.y); - //} - - - if (normal.x == 0 && normal.y == 0 && normal.z ==0) - { - Normal = new vec3(0, 0, 0); - } - else - { - normal.z = -normal.z; - normal.x = -normal.x; - normal.y = -normal.y; - Normal = glm.normalize(normal); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs deleted file mode 100644 index b6747371..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Mesh.cs +++ /dev/null @@ -1,175 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives.ModelComponents -{ - public class Mesh - { - #region fields - Face[] _faces; - vec3[] _vertices, _normals; - ushort[] _indices; - Vertex[] _allVertices; - Dictionary _idxForVertex; - #endregion fields - - #region properties - public Face[] Faces - { - get { return _faces; } - set { _faces = value; } - } - public vec3[] Vertices - { - get { return _vertices; } - set - { - _vertices = value; - UpdateFaceVertices(); - } - } - - public vec3[] Normals - { - get { return _normals; } - set { _normals = value; } - } - public ushort[] Indices - { - get { return _indices; } - set { _indices = value; } - } - #endregion properties - - #region constructors - public Mesh() - { - - } - public Mesh(Face[] faces) - { - _faces = faces; - } - - public Mesh(ushort[] indices, vec3[] vertices, vec3[] normals) - { - var n = 3; - var faces = new List(); - - _indices = indices; - _normals = normals; - _vertices = vertices; - - _idxForVertex = new Dictionary(); - _allVertices = new Vertex[vertices.Length]; - - for (int i = 0; i < indices.Length; i+=n) - { - var idx0 = indices[i]; - var idx1 = indices[i + 1]; - var idx2 = indices[i + 2]; - - #region getVertex(...) function - Func getVertex = idx => - { - if (_idxForVertex.ContainsKey(idx)) - { - return _idxForVertex[idx]; - } - else - { - var vert = new Vertex(idx, - normals == null ? - new vec3() - : normals[idx], vertices[idx]); - _idxForVertex[idx] = vert; - - _allVertices[idx] = vert; - return vert; - } - }; - #endregion getVertex(...) function - - - Vertex v0 = getVertex(idx0); - Vertex v1 = getVertex(idx1); - Vertex v2 = getVertex(idx2); - - - faces.Add(new Face(new Vertex[]{v0,v1,v2})); - - } - - _faces = faces.ToArray(); - - - - if (_normals == null) - { - CalculateNormals(); - } - } - - #endregion constructors - - public void CalculateNormals() - { - //// Set indices to null. - //foreach (var face in _faces) - //{ - // foreach (var vertex in face.Vertices) - // { - // vertex.Index = null; - // } - //} - - //ushort nxtIdx = 0; - //var vertices = new List(); - var normals = new vec3[_allVertices.Length]; - //var indices = new List(); - //foreach (var face in _faces) - //{ - // foreach (var vertex in face.Vertices) - // { - // if (vertex.Index == null) - // { - // //vertex.Index = nxtIdx++; // Set vertex and increase nxtIdx - // //vertices.Add(vertex.Vec3); - // normals.Add(vertex.Normal); - // } - // //indices.Add(vertex.Index.Value); - // } - //} - - foreach (var face in _faces) - { - face.CalculateNormal(); - } - - foreach (var vert in _allVertices) - { - vert.CalculateVertexNormal(); - normals[vert.Index.Value] = vert.Normal; - } - - //Vertices = vertices.ToArray(); - Normals = normals;//.ToArray(); - //Indices = indices.ToArray(); - - } - - public void UpdateFaceVertices() - { - foreach (var idx in _indices) - { - Vertex vert = _idxForVertex[idx]; - vec3 vec3Vert = _vertices[idx]; - - vert.Vec3 = vec3Vert; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs deleted file mode 100644 index 0206fd41..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/ModelComponents/Vertex.cs +++ /dev/null @@ -1,71 +0,0 @@ -using GlmNet; -using SharpGLBase.Extensions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives.ModelComponents -{ - public class Vertex - { - #region fields - ushort? _index = null; - List _parentFaces = new List(); - vec3 _vertex; - vec3 _normal; - #endregion fields - - - #region properties - public ushort? Index - { - get { return _index; } - set { _index = value; } - } - public vec3 Normal - { - get { return _normal; } - set { _normal = value; } - } - - public vec3 Vec3 - { - get { return _vertex; } - set { _vertex = value; } - } - - public List ParentFaces - { - get { return _parentFaces; } - set { _parentFaces = value; } - } - #endregion properties - - public Vertex() { } - - public Vertex(ushort index, vec3 normal, vec3 vertex) - { - _index = index; - _normal = normal; - _vertex = vertex; - } - - - public void CalculateVertexNormal() - { - vec3 normalSum = new vec3(); - foreach (var plane in _parentFaces) - { - normalSum += plane.Normal; - } - - Normal = glm.normalize(normalSum); - } - - public override string ToString() - { - return _vertex.ToValueString(); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs deleted file mode 100644 index 9e043063..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/PrimitivesGlobal.cs +++ /dev/null @@ -1,23 +0,0 @@ -using GlmNet; -using SharpGL; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - public static class PrimitivesGlobal - { - public static void RenderLines(OpenGL gl, List> lines) - { - foreach (var item in lines) - { - vec3 v1 = item.Item1; - vec3 v2 = item.Item2; - gl.Vertex(v1.x, v1.y, v1.z); - gl.Vertex(v2.x, v2.y, v2.z); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs deleted file mode 100644 index 136e905f..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGrid.cs +++ /dev/null @@ -1,154 +0,0 @@ -using GlmNet; -using SharpGLBase.Shaders; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGL.Shaders; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - /// - /// Draws a grid in the center of the world. - /// - public class SquareGrid : IRenderable, IHasMaterial - { - #region fields - private int _directionLineCount; - private float _stepSize, _lineThickness = 0.001f; - private Material _material; - private List> _lines = null; - #endregion fields - - #region properties - /// - /// Gets or sets the amount of lines in each direction. - /// - public int DirectionLineCount - { - get { return _directionLineCount; } - set { _directionLineCount = value; } - } - - /// - /// Distance between 2 lines. - /// - public float StepSize - { - get { return _stepSize; } - set { _stepSize = value; } - } - public float LineThickness - { - get { return _lineThickness; } - set { _lineThickness = value; } - } - - /// - /// The applied material for the grid. - /// - public Material Material - { - get { return _material; } - set { _material = value; } - } - #endregion properties - - public SquareGrid() - :this(10, 1f) - { } - - public SquareGrid(int directionLineCount, float stepSize) - { - _directionLineCount = directionLineCount; - _stepSize = stepSize; - - _material = new Material(); - _material.Ambient = Color.FromArgb(255, 146, 134, 188); // Purple. - _material.Shininess = 1f; - - RecalculateShape(); - } - - /// - /// Renders the grid to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - /// Pass the shader so the material color(s) can be applied locally. - public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) - { - if (renderMode != RenderMode.Design) - return; - - shader.ApplyMaterial(gl, _material); - - Render(gl, renderMode); - } - - /// - /// Renders the grid to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - public void Render(OpenGL gl, RenderMode renderMode) - { - // Ensure that we're in design mode (we don't want axis during render) - if (renderMode != RenderMode.Design) - return; - - - ValidateBeforeRender(); - - // Draw the lines. - // TODO: Inefficient, consumes a lot of resources. - gl.LineWidth(_lineThickness); - gl.Begin(OpenGL.GL_LINES); - PrimitivesGlobal.RenderLines(gl, _lines); - gl.End(); - } - - /// - /// Calculates the lines using the current grid properties. - /// - public void RecalculateShape() - { - _lines = new List>(); - - float min = -StepSize * DirectionLineCount; - float max = StepSize * DirectionLineCount; - for (float x = min; x <= max; x += StepSize) - { - for (float z = min; z <= max; z += StepSize) - { - _lines.Add( - new Tuple( - new vec3(x, 0.0f, min), - new vec3(x, 0.0f, max)) - ); - - _lines.Add( - new Tuple( - new vec3(min, 0.0f, z), - new vec3(max, 0.0f, z)) - ); - } - } - } - - /// - /// Ensures that all required properties are acceptable. - /// - private void ValidateBeforeRender() - { - if (_lines == null) - { - throw new Exception("Grid lines aren't calculated."); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs deleted file mode 100644 index 8c8dbfea..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Primitives/SquareGridVBO.cs +++ /dev/null @@ -1,155 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGLBase.Shaders; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Primitives -{ - public class SquareGridVBO - { - #region fields - private int _directionLineCount; - private float _stepSize, _lineThickness = 1f; - private List> _lines = null; - private Lines _gridLines = null; - #endregion fields - - #region properties - /// - /// Gets or sets the amount of lines in each direction. - /// - public int DirectionLineCount - { - get { return _directionLineCount; } - set { _directionLineCount = value; } - } - - /// - /// Distance between 2 lines. - /// - public float StepSize - { - get { return _stepSize; } - set { _stepSize = value; } - } - public float LineThickness - { - get { return _lineThickness; } - set { _lineThickness = value; } - } - - /// - /// The applied material for the grid. - /// - public Material Material - { - get { return _gridLines.Material; } - set { _gridLines.Material = value; } - } - #endregion properties - - public SquareGridVBO(OpenGL gl) - :this(gl, 10, 1f) - { } - - public SquareGridVBO(OpenGL gl, int directionLineCount, float stepSize) - { - _directionLineCount = directionLineCount; - _stepSize = stepSize; - - RecalculateShape(); - - _gridLines = new Lines(gl, _lines); - - Material = new Material(); - Material.Diffuse = Color.FromArgb(255, 146, 134, 188); // Purple. - Material.Shininess = 1f; - } - - /// - /// Renders the grid to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - /// Pass the shader so the material color(s) can be applied locally. - public void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader) - { - if (renderMode != RenderMode.Design) - return; - - shader.UseProgram(gl, () => - { - shader.ApplyMaterial(gl, Material); - - Render(gl, renderMode); - }); - } - - /// - /// Renders the grid to the gl if it's in DesignMode. - /// - /// The gl - /// The rendermode - public void Render(OpenGL gl, RenderMode renderMode) - { - // Ensure that we're in design mode (we don't want axis during render) - if (renderMode != RenderMode.Design) - return; - - - ValidateBeforeRender(); - - // Draw the lines. - - _gridLines.Render(gl, renderMode, null); - } - - /// - /// Calculates the lines using the current grid properties. - /// - public void RecalculateShape() - { - _lines = new List>(); - List verts = new List(); - - float min = -StepSize * DirectionLineCount; - float max = StepSize * DirectionLineCount; - for (float x = min; x <= max; x += StepSize) - { - for (float z = min; z <= max; z += StepSize) - { - vec3 v1 = new vec3(x, 0.0f, min); - vec3 v2 = new vec3(x, 0.0f, max); - vec3 v3 = new vec3(min, 0.0f, z); - vec3 v4 = new vec3(max, 0.0f, z); - - verts.AddRange(new vec3[] { v1, v2, v3, v4 }); - - - _lines.Add( - new Tuple(v1, v2)); - - _lines.Add( - new Tuple(v3,v4)); - } - } - } - - /// - /// Ensures that all required properties are acceptable. - /// - private void ValidateBeforeRender() - { - if (_lines == null) - { - throw new Exception("Grid lines aren't calculated."); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs deleted file mode 100644 index a093696d..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Scene")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Scene")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c1ec0990-87c3-4af8-93dd-5a0f1160f45b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs deleted file mode 100644 index d2d66ec5..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/ModelView.cs +++ /dev/null @@ -1,112 +0,0 @@ -using GlmNet; -using SharpGLBase.Extensions; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Scene -{ - public enum CameraRotationHandling { SRT, TRS} - /// - /// This class contains all functionality related to the ModelView matrix. - /// - public class ModelView : TransformableBase,INotifyPropertyChanged - { - #region events - - #region propertychanged event - public event PropertyChangedEventHandler PropertyChanged; - public void OnPropertyChanged(string prop) - { - if (PropertyChanged != null) - PropertyChanged(this, new PropertyChangedEventArgs(prop)); - } - #endregion propertychanged event - - #endregion events - - #region fields - CameraRotationHandling _cameraHandling = CameraRotationHandling.SRT; - #endregion fields - - #region properties - /// - /// The ModelView Matrix. - /// - public mat4 ModelviewMatrix - { - get { return ResultMatrix; } - } - - /// - /// Get or set the sequence of the modelview rotation transformation. - /// - public CameraRotationHandling CameraHandling - { - get { return _cameraHandling; } - set { _cameraHandling = value; } - } - #endregion properties - - /// - /// Converts ModelviewMatrix to a float[]. - /// - /// A float[] containing all the values from the initial matrix. - public float[] ToArray() - { - return ModelviewMatrix.to_array(); - } - - /// - /// Converst the this.ToArray() from a float[] to a double[] - /// - /// - public double[] ToDoubleArray() - { - float[] arr = ToArray(); - var newArr = new double[arr.Length]; - for (int i = 0; i < arr.Length; i++) - { - newArr[i] = (double)arr[i]; - } - - return newArr; - } - - /// - /// Modelview needs different sequences of transformations. - /// - public override void RecalculateResultMatrix() - { - if (CameraHandling == Scene.CameraRotationHandling.TRS) - ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix; // rotate around center - else if (CameraHandling == Scene.CameraRotationHandling.SRT) - ResultMatrix = ScalingMatrix * RotationMatrix * TranslationMatrix; // rotate around camera center - - //ResultMatrix = ScalingMatrix * RotationMatrix * TranslationMatrix; // rotate around camera center - //ResultMatrix = TranslationMatrix * ScalingMatrix * RotationMatrix; // rotate around camera center (swap axis) - //ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix; // rotate around own center - //ResultMatrix = RotationMatrix * ScalingMatrix * TranslationMatrix; // rotate around own center (swap axis) - //ResultMatrix = RotationMatrix * TranslationMatrix * ScalingMatrix; // stretches shape (swap axis) - //ResultMatrix = ScalingMatrix * TranslationMatrix * RotationMatrix; // stretches shape (swap axis) - //ResultMatrix = RotationMatrix * TranslationMatrix.Transpose() * ScalingMatrix; // stretches shape (swap axis) - //ResultMatrix = ScalingMatrix * TranslationMatrix.Transpose() * RotationMatrix; // stretches shape (swap axis) - - OnPropertyChanged("ModelviewMatrix"); - } - - /// - /// Allow direct array access to the ModelviewMatrix. - /// - /// Collumn index. - /// The vec4 at this position. - public vec4 this[int col]{ - get - { - return ModelviewMatrix[col]; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs deleted file mode 100644 index 2ef000ec..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Normal.cs +++ /dev/null @@ -1,48 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Scene -{ - /// - /// This class contains all functionality related to the Normal matrix. - /// - public class Normal - { - #region fields - private mat3 _normalMatrix = mat3.identity(); - - #endregion fields - - #region properties - /// - /// The Normal matrix. - /// - public mat3 NormalMatrix - { - get { return _normalMatrix; } - set { _normalMatrix = value; } - } - #endregion properties - - /// - /// Simplify the creation of the normal matrix by using a modelView. - /// - /// - public void CreateFromModelView(ModelView modelView) - { - _normalMatrix = modelView.ModelviewMatrix.to_mat3(); - } - - /// - /// Converts NormalMatrix to a float[]. - /// - /// A float[] containing all the values from the initial matrix. - public float[] ToArray() - { - return _normalMatrix.to_array(); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs deleted file mode 100644 index 2c6b1758..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLHitTestExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using GlmNet; -using SharpGLBase.Primitives; -using SharpGLBase.Shaders; -using SharpGL; -using SharpGL.SceneGraph.Core; -using SharpGL.Shaders; -using SharpGL.Version; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using SharpGLBase.Extensions; -using SharpGL.RenderContextProviders; -using System.Threading.Tasks; -using SharpGLBase.Shaders.Parameters; - -namespace SharpGLBase.Scene -{ -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs deleted file mode 100644 index d2f35a9b..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/OpenGLScene.cs +++ /dev/null @@ -1,292 +0,0 @@ -using GlmNet; -using SharpGLBase.Events; -using SharpGLBase.Primitives; -using SharpGL; -using SharpGL.Enumerations; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Cameras; -using SharpGL.SceneGraph.Core; -using SharpGL.SceneGraph.Primitives; -using SharpGL.Shaders; -using SharpGL.VertexBuffers; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using SharpGLBase.Shaders; -using System.Threading.Tasks; -using System.Threading; -using SharpGL.Version; -using SharpGLBase.Shaders.Parameters; - -namespace SharpGLBase.Scene -{ - /// - /// A Scene object is the central place where everything -that influences the visual result- comes together. - /// - public abstract class OpenGLScene - { - #region fields - ModelView _modelView = new ModelView(); - Normal _normal = new Normal(); - Projection _projection = new Projection(); - ExtShaderProgram _currentShader; - float _performanceScaleValue = 1f; - Size _sceneSize; - Size _viewPortSize; - Point? _modelSelectionPoint = null; - #endregion fields - - #region properties - /// - /// The projection matrix is contained in here. - /// - public Projection Projection - { - get { return _projection; } - set { _projection = value; } - } - /// - /// The modelview matrix is contained in here. - /// - public ModelView ModelView - { - get { return _modelView; } - set { _modelView = value; } - } - /// - /// The normal matrix is contained in here. - /// - public Normal Normal - { - get { return _normal; } - set { _normal = value; } - } - /// - /// The shader that's currently being used for rendering the models. - /// - public ExtShaderProgram CurrentShader - { - get { return _currentShader; } - set { _currentShader = value; } - } - /// - /// A value that will be multiplied to the passed view width and -height during resizing. - /// - public float PerformanceScaleValue - { - get { return _performanceScaleValue; } - set { _performanceScaleValue = value; } - } - /// - /// The size of the scene. ( = ViewPortSize * PerformanceScaleValue) - /// - public Size SceneSize - { - get { return _sceneSize; } - private set { _sceneSize = value; } - } - /// - /// The size of the viewport. - /// - public Size ViewPortSize - { - get { return _viewPortSize; } - private set { _viewPortSize = value; } - } - - public OpenGL GL { get; private set; } - #endregion properties - - #region events - public event ModelSelectedEvent ModelSelected; - public void OnModelSelected(Point p, Model3DBase m) - { - if (ModelSelected != null) - ModelSelected(this, new ModelSelectedEventArgs(p, m)); - } - #endregion events - - /// - /// Should be called before the first Draw-call is being made. Sets the GL. - /// - /// - public virtual void OpenGLInitialized(OpenGL gl) - { - GL = gl; - } - /// - /// Should be called before the first Draw-call is being made. Sets the GL and shader. - /// - /// - public virtual void OpenGLInitialized(OpenGL gl, ExtShaderProgram shader) - { - OpenGLInitialized(gl); - CurrentShader = shader; - } - - /// - /// Redraw the scene. - /// - /// OpenGL viewport - public abstract void Draw(OpenGL gl); - - public virtual void ViewResized(OpenGL gl, double actualWidth, double actualHeight) - { - var viewPortWidth = (float)actualWidth * _performanceScaleValue; - var viewPortHeight = (float)actualHeight * _performanceScaleValue; - - ViewPortSize = new Size((int)actualWidth, (int)actualHeight); - SceneSize = new Size((int)viewPortWidth, (int)viewPortHeight); - - // Create a projection matrix for the scene with the screen size. - Projection.SetFrustum((float)viewPortWidth, (float)viewPortHeight); - - gl.SetDimensions((int)++viewPortWidth, (int)++viewPortHeight); - gl.Viewport(0, 0, (int)++viewPortWidth, (int)++viewPortHeight); - } - - - /// - /// This method let's the Draw(...) know to retrieve the object at the requested location. When an object is found, the ModelSelectedEvent will be triggered. - /// - /// The 2D point relative to the OpenGL viewport. - public void GetModelAtPoint(Point p, IEnumerable models, HitTestMethod method = HitTestMethod.OpenGLHack) - { - if (p != null && models != null && models.Count() > 0) - { - Point correctedPoint = new Point((int)(p.X * _performanceScaleValue), (int)(p.Y * _performanceScaleValue)); - - - // Create an array that will be the viewport. - int[] viewport = new int[4]; - // Get the viewport, then convert the mouse point to an opengl point. - GL.GetInteger(OpenGL.GL_VIEWPORT, viewport); - - - // Take deep copy of everything we need. - var mvCopy = new ModelView() - { - ResultMatrix = ModelView.ModelviewMatrix - }; - var prCopy = new Projection() - { - ProjectionMatrix = Projection.ProjectionMatrix - }; - var nrmlCopy = new Normal() - { - NormalMatrix = Normal.NormalMatrix - }; - - Task t = new Task(() => - { - Model3DBase clickedModel = null; - - if (method == HitTestMethod.OpenGLHack) - { - clickedModel = GetModelAtPointHack(correctedPoint, models, viewport, mvCopy, prCopy, nrmlCopy); - } - - OnModelSelected(correctedPoint, clickedModel); - }); - - t.Start(); - } - } - - - #region HitTest - - public enum HitTestMethod { OpenGLHack }//, RayOBB} - - - /// - /// Source: http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-an-opengl-hack/ - /// It's recommended to read the source before using this algorithm. - /// - /// The OpenGLScene. - /// The 2D point. - /// The drawn models. - /// A factor that affects performance by scaling the size of the temperory viewport. - /// The model on this location or null. - public static Model3DBase GetModelAtPointHack(Point point, IEnumerable models, - int[] viewport, ModelView modelview, Projection projection, Normal normal, float performanceScaleValue = 1) - { - int id = -1; - - int width = (int)(viewport[2] * performanceScaleValue); - int height = (int)(viewport[3] * performanceScaleValue); - int x = (int)(point.X * performanceScaleValue); - int y = height - (int)(point.Y * performanceScaleValue); - - - #region create a temperory gl to prevent flickering - OpenGL gl = new OpenGL(); - - // Create OpenGL. - var openGLVersion = OpenGLVersion.OpenGL2_1; - var renderContextType = RenderContextType.FBO; - gl.Create(openGLVersion, renderContextType, 1, 1, 32, null); - // Set the dimensions and viewport. - gl.SetDimensions(width, height); - gl.Viewport(0, 0, width, height); - - - // Make GL current. - gl.MakeCurrent(); - - gl.Enable(OpenGL.GL_DEPTH_TEST); - //gl.Clear(OpenGL.GL_DEPTH_CLEAR_VALUE); - - #endregion create a temperory gl to prevent flickering - - // Initialize the shader for our new GL. - var esp = Shaders.LoadSimpleShader(gl); - - esp.UseProgram(gl, () => - { - // Set the matrices. - esp.ApplyMVPNMatrices(gl, modelview, projection, normal); - - // render models, using a temperory color - foreach (var model in models) - { - var col = model.GenerateColorFromId(); - esp.ApplyMaterial(gl, new Material() { Ambient = col }); - Model3DBase.GenerateAndDrawOnce(gl, model); // model.Render(gl, RenderMode.HitTest); - } - }); - esp.Dispose(); - - // Wait for GPU to finish. - gl.Flush(); - gl.Finish(); - - - gl.PixelStore(OpenGL.GL_UNPACK_ALIGNMENT, 1); - - uint format = OpenGL.GL_RGBA; - uint type = OpenGL.GL_UNSIGNED_BYTE; - - byte[] data = new byte[40]; - gl.ReadPixels(x, y, 1, 1, format, type, data); - - - // Remove the temperory gl from memory. - gl.RenderContextProvider.Dispose(); - - // Get color id from pixel data. - id = data[0] + data[1] * 255 + data[2] * 65025; // id = r + g * 255 + b * 255². - - // Find model with id. - var resultModel = models.FirstOrDefault(m => m.VertexBuffer.VertexBufferObject == id); - - return resultModel; - } - #endregion HitTest - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs deleted file mode 100644 index d167bac4..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Projection.cs +++ /dev/null @@ -1,157 +0,0 @@ -using GlmNet; -using SharpGL; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Scene -{ - /// - /// This class contains all functionality related to the projection matrix. - /// - public class Projection - { - #region fields - mat4 _projectionMatrix = mat4.identity(); - float _left, _right, _bottom, _top, _nearVal = 2f, _farVal = -1.2f; - vec3 _translationVector = new vec3(); - - #endregion fields - - #region properties - /// - /// The Projection Matrix. - /// - public mat4 ProjectionMatrix - { - get { return _projectionMatrix; } - set { _projectionMatrix = value; } - } - - /// - /// The Left. - /// Used in GlmNET.glm.frustum(...); - /// - public float Left - { - get { return _left; } - set { _left = value; } - } - - /// - /// The Right. - /// Used in GlmNET.glm.frustum(...); - /// - public float Right - { - get { return _right; } - set { _right = value; } - } - - /// - /// The Bottom. - /// Used in GlmNET.glm.frustum(...); - /// - public float Bottom - { - get { return _bottom; } - set { _bottom = value; } - } - - /// - /// The Top. - /// Used in GlmNET.glm.frustum(...); - /// - public float Top - { - get { return _top; } - set { _top = value; } - } - - /// - /// The Near Val. - /// Used in GlmNET.glm.frustum(...); - /// - public float NearVal - { - get { return _nearVal; } - set { _nearVal = value; } - } - - /// - /// The Far val. - /// Used in GlmNET.glm.frustum(...); - /// - public float FarVal - { - get { return _farVal; } - set { _farVal = value; } - } - - - #endregion properties - - - /// - /// Resets the frustum using the current values for NearVal and FarVal. - /// - /// Width of the screen. - /// Height of the screen. - public void SetFrustum(float screenWidth, float screenHeight) - { - SetFrustum(screenWidth, screenHeight, _nearVal, _farVal); - } - - /// - /// Resets the frustum. - /// - /// Width of the screen. - /// Height of the screen. - /// - /// - public void SetFrustum(float screenWidth, float screenHeight, float nearVal = 1, float farVal = 0) - { - float scale = 1 / screenWidth; - screenWidth *= scale; - screenHeight *= scale; - - Left = -screenWidth; - Right = -Left; - Bottom = -screenHeight; - Top = -Bottom; - NearVal = nearVal; - FarVal = farVal; - CalculateFrustum(); - } - - /// - /// Recalculate the frustum from the available properties. - /// - public void CalculateFrustum() - { - _projectionMatrix = glm.frustum(Left, Right , Bottom , Top , NearVal, FarVal); - - glm.translate(_projectionMatrix, _translationVector); - } - - /// - /// Changes the z values from the TranslationVector, resulting in a zoom effect. - /// - /// Zooming distance (positive => zoom in, negative => zoom out) - public void Zoom(float distance) - { - _translationVector.z += distance; - CalculateFrustum(); - } - - /// - /// Converts ProjectionMatrix to a float[]. - /// - /// A float[] containing all the values from the initial matrix. - public float[] ToArray() - { - return _projectionMatrix.to_array(); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs deleted file mode 100644 index 5939a949..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/Shaders.cs +++ /dev/null @@ -1,85 +0,0 @@ -using SharpGLBase.Shaders; -using SharpGL; -using SharpGL.Shaders; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SharpGLBase.Shaders.Parameters; - -namespace SharpGLBase.Scene -{ - /// - /// - /// - public static class Shaders - { - #region fields - // We're going to specify the attribute locations for the position and normal, - // so that we can force both shaders to explicitly have the same locations. - const uint _positionAttribute = 0; - const uint _normalAttribute = 1; - static Dictionary _attributeLocations; - - // The shaders we use. - static Dictionary _allShaders = new Dictionary(); - - #endregion fields - - #region properties - /// - /// Contains all the initialized named shaders. - /// - public static Dictionary AllShaders - { - get { return _allShaders; } - set { _allShaders = value; } - } - #endregion properties - - /// - /// Static constructor. - /// - static Shaders() - { - _attributeLocations = new Dictionary - { - {_positionAttribute, "Position"}, - {_normalAttribute, "Normal"}, - }; - } - - public static ExtShaderProgram LoadPerPixelShader(OpenGL gl) - { - return CreateShader(gl, new PerPixelParameters(), @"Shaders\PerPixel.vert", @"Shaders\PerPixel.frag"); - } - public static ExtShaderProgram LoadToonShader(OpenGL gl) - { - return CreateShader(gl, new ToonParameters(), @"Shaders\Toon.vert", @"Shaders\Toon.frag"); - } - public static ExtShaderProgram LoadSimpleShader(OpenGL gl) - { - return CreateShader(gl, new SimpleShaderParameters(), @"Shaders\SimpleShader.vert", @"Shaders\SimpleShader.frag"); - } - - - /// - /// Create and add a new ShaderProgram from the given sources. - /// Call this function if you decide to add your own shaders. - /// - /// The OpenGL - /// The path to the vertex shader code. - /// The path to the fragment shader code. - /// The name for the shader. - public static ExtShaderProgram CreateShader(OpenGL gl, IShaderParameterIds parameters, string vertexShaderSource, string fragmentShaderSource) - { - // Create the per pixel shader. - ShaderProgram shader = new ShaderProgram(); - shader.Create(gl, - ManifestResourceLoader.LoadTextFile(vertexShaderSource), - ManifestResourceLoader.LoadTextFile(fragmentShaderSource), _attributeLocations); - - return new ExtShaderProgram(shader, parameters); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs deleted file mode 100644 index 94aa479f..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Scene/TransformableBase.cs +++ /dev/null @@ -1,312 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SharpGLBase.Extensions; - -namespace SharpGLBase.Scene -{ - public enum RotationMethod { TurnTableYZ, TurnTableXZ, TurnTableXY, Simple } - /// - /// Contains the rotation, scaling and translation matrices, together with the result produced from multiplying them. - /// Override RecalculateResultMatrix(...) in order to multiply the result matrix to your vectors/matrices whenever a transformation has been done. - /// - public abstract class TransformableBase - { - #region fields - private mat4 _translationMatrix = mat4.identity(); - private mat4 _rotationMatrix = mat4.identity(); - private mat4 _scalingMatrix = mat4.identity(); - private mat4 _resultMatrix = mat4.identity(); - private RotationMethod _rotationMethod = RotationMethod.Simple; - private vec3 _rotatedRadians = new vec3(0, 0, 0); - - #endregion fields - - #region properties - /// - /// Contains the result of all transformations. - /// - public mat4 ResultMatrix - { - get { return _resultMatrix; } - set { _resultMatrix = value; } - } - /// - /// Represents all translations. - /// - public mat4 TranslationMatrix - { - get { return _translationMatrix; } - set { _translationMatrix = value; } - } - /// - /// Represents all rotations. - /// - public mat4 RotationMatrix - { - get { return _rotationMatrix; } - set { _rotationMatrix = value; } - } - /// - /// Represents all scalings. - /// - public mat4 ScalingMatrix - { - get { return _scalingMatrix; } - set { _scalingMatrix = value; } - } - /// - /// Defines the way of rotating, TurnTable is usually more intuitive for camera control. TrackBall provides more freedom. - /// - public RotationMethod RotationMethod - { - get { return _rotationMethod; } - set { _rotationMethod = value; } - } - /// - /// Gets the value of rotation (radians) in each direction. - /// - public vec3 RotatedRadians - { - get { return _rotatedRadians; } - } - #endregion properties - - #region absolute rotation - /// - /// Rotates by angleRadians in the direction(s) v and forces a recalculation of the result matrix. - /// - /// The angle of the rotation in radians. - /// The vector that represents the axis around which should be rotated. - public void RotateAbsolute(float angleRadians, vec3 v) - { - if (angleRadians == 0) - return; - - mat4 tempRotationMatrix = _rotationMatrix; - switch (_rotationMethod) - { - case RotationMethod.TurnTableXY: - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.x, new vec3(1, 0, 0)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.y, new vec3(0, 1, 0)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.y, new vec3(0, 1, 0)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.x, new vec3(1, 0, 0)); - break; - case RotationMethod.TurnTableXZ: - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.x, new vec3(1, 0, 0)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.z, new vec3(0, 0, 1)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.z, new vec3(0, 0, 1)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.x, new vec3(1, 0, 0)); - break; - case RotationMethod.TurnTableYZ: - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.y, new vec3(0, 1, 0)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, -_rotatedRadians.z, new vec3(0, 0, 1)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.z, new vec3(0, 0, 1)); - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, _rotatedRadians.y, new vec3(0, 1, 0)); - break; - default: - tempRotationMatrix = GlmNet.glm.rotate(tempRotationMatrix, angleRadians, v); - break; - } - - _rotationMatrix = tempRotationMatrix; - - - _rotatedRadians.x += v.x * angleRadians; - _rotatedRadians.y += v.y * angleRadians; - _rotatedRadians.z += v.z * angleRadians; - - - RecalculateResultMatrix(); - } - /// - /// Calls RotateAbsolute(angleRadians, new vec3(1, 0, 0)); - /// - /// - public void RotateAbsoluteX(float angleRadians) - { - RotateAbsolute(angleRadians, new vec3(1, 0, 0)); - } - /// - /// Calls RotateAbsolute(angleRadians, new vec3(0, 1, 0)); - /// - /// - public void RotateAbsoluteY(float angleRadians) - { - RotateAbsolute(angleRadians, new vec3(0, 1, 0)); - } - - /// - /// RotateAbsolute(angleRadians, new vec3(0, 0, 1)); - /// - /// - public void RotateAbsoluteZ(float angleRadians) - { - RotateAbsolute(angleRadians, new vec3(0, 0, 1)); - } - - #endregion absolute rotation - - #region absolute translation - /// - /// Translates by the values contained in 'vec'. - /// - /// Translation vector. - public void TranslateAbsolute(vec3 vec) - { - _translationMatrix = GlmNet.glm.translate(_translationMatrix, vec); - RecalculateResultMatrix(); - } - /// - /// Calls TranslateAbsolute(new vec3(distance, 0, 0)); - /// - /// The distance. - public void TranslateAbsoluteX(float distance) - { - TranslateAbsolute(new vec3(distance, 0, 0)); - } - /// - /// Calls TranslateAbsolute(new vec3(0, distance, 0)); - /// - /// The distance. - public void TranslateAbsoluteY(float distance) - { - TranslateAbsolute(new vec3(0, distance, 0)); - } - /// - /// Calls TranslateAbsolute(new vec3(0, 0, distance)); - /// - /// The distance. - public void TranslateAbsoluteZ(float distance) - { - TranslateAbsolute(new vec3(0, 0, distance)); - } - #endregion absolute translation - - #region relative translation - public void TranslateOnRotationMatrix(vec3 vec) - { - ////var tMatrix = GlmNet.glm.translate(mat4.identity(), vec); - ////var invRotMatrix = _rotationMatrix.Inverse(); - ////var resMat = (tMatrix * _rotationMatrix).Transpose(); // - ////var translateVector = new vec3(resMat[3].x, resMat[3].y, resMat[3].z); - - - //float largestRot; - //float totRot = RotatedRadians.x + RotatedRadians.y + RotatedRadians.z; - ////if (RotatedRadians.x > RotatedRadians.y) - ////{ - //// if (RotatedRadians.x > RotatedRadians.z) - //// { - //// // x is largest - //// largestRot = RotatedRadians.x; - //// } - //// else - //// { - //// // z is largest - //// largestRot = RotatedRadians.z; - //// } - ////} - ////else { - //// if (RotatedRadians.y > RotatedRadians.z) - //// { - //// // y is largest - //// largestRot = RotatedRadians.y; - //// } - //// else - //// { - //// // z is largest - //// largestRot = RotatedRadians.z; - //// } - ////} - - //var totMoveDistance = (float)Math.Sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); - - //float addX; - //float addY = 0; - //float addZ; - //if (totRot == 0) - //{ - // addX = vec.x; - // addY = vec.y; - // addZ = vec.z; - //} - //else - //{ - // var scaleX = RotatedRadians.x / totRot; - // var scaleY = RotatedRadians.y / totRot; - // var scaleZ = RotatedRadians.z / totRot; - - // addX = vec.x * scaleX; - // //addY = vec.x * scaleY; - // addZ = vec.x * scaleZ; - //} - //vec3 translateVector = new vec3(addX, addY, addZ); - - - - - ////ResMatDeleteMeLater = resMat; - ////TranslationVecDeleteMeLater = vec; - ////TranslateAbsolute(translateVector); - - //var t = _translationMatrix[3]; - //t.x += translateVector.x; - //t.y += translateVector.y; - //t.z += translateVector.z; - //_translationMatrix[3] = t; - - //RecalculateResultMatrix(); - } - #endregion relative translation - - #region absolute scaling - /// - /// Scales by the values contained in 'vec'. - /// - /// Scaling vector. - public void Scale(vec3 vec) - { - _scalingMatrix = GlmNet.glm.scale(_scalingMatrix, vec); - RecalculateResultMatrix(); - } - /// - /// Calls Scale(new vec3(scale, 1, 1)); - /// - /// - public void ScaleX(float scale) - { - Scale(new vec3(scale, 1, 1)); - } - /// - /// Calls Scale(new vec3(1, scale, 1)); - /// - /// - public void ScaleY(float scale) - { - Scale(new vec3(1, scale, 1)); - } - /// - /// Calls Scale(new vec3(1, 1, scale)); - /// - /// - public void ScaleZ(float scale) - { - Scale(new vec3(1, 1, scale)); - } - #endregion absolute scaling - - /// - /// Multiplies all transformations into the ResultMatrix in folowing sequence 'ResultMatrix = TranslationMatrix * RotationMatrix * ScalingMatrix'. - /// - public virtual void RecalculateResultMatrix() - { - _resultMatrix = _translationMatrix * _rotationMatrix * _scalingMatrix; - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs deleted file mode 100644 index fcf45cac..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/ExtShaderProgram.cs +++ /dev/null @@ -1,160 +0,0 @@ -using SharpGLBase.Scene; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.Shaders; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SharpGLBase.Shaders.Parameters; -using GlmNet; - -namespace SharpGLBase.Shaders -{ - /// - /// An extended ShaderProgram. This includes a shadername - /// - public class ExtShaderProgram : IDisposable - { - #region fields - OpenGL _gl = null; - #endregion fields - - #region properties - /// - /// The shader program. - /// - public ShaderProgram Program { get; private set; } - - /// - /// - /// - public IShaderParameterIds Parameters { get; private set; } - - #endregion properties - - public ExtShaderProgram(ShaderProgram program, IShaderParameterIds parameters) - { - Program = program; - Parameters = parameters; - } - - /// - /// Applies the material to the shader if the "Parameters" are an implementation of "IMaterialShaderParameters". - /// - /// The GL. - /// The material. - public void ApplyMaterial(OpenGL gl, Material m, bool throwException = true) - { - if (!typeof(IMaterialShaderParameters).IsAssignableFrom(Parameters.GetType())) - { - if (!throwException) - return; - - throw new InvalidCastException("'Parameters' does not implement 'IMaterialShaderParameters'." + - "This has to be implemented for this method to know how the shader expects it's parameter names."); - } - - var s = Program; - var prms = Parameters as IMaterialShaderParameters; - - var amb = m.Ambient; - var diff = m.Diffuse; - var spec = m.Specular; - var shini = m.Shininess; - var emit = m.Emission; - - if (prms.AmbientId != null) - s.SetUniform3(gl, prms.AmbientId, amb.R / 255.0f, amb.G / 255.0f, amb.B / 255.0f); - if (prms.DiffuseId != null) - s.SetUniform3(gl, prms.DiffuseId, diff.R / 255.0f, diff.G / 255.0f, diff.B / 255.0f); - if (prms.SpecularId != null) - s.SetUniform3(gl, prms.SpecularId, spec.R / 255.0f, spec.G / 255.0f, spec.B / 255.0f); - if (prms.ShininessId != null) - s.SetUniform1(gl, prms.ShininessId, shini); - if (prms.EmissionId != null) - s.SetUniform3(gl, prms.EmissionId, emit.R / 255.0f, emit.G / 255.0f, emit.B / 255.0f); - } - - /// - /// Applies the Modelview-, projection- and normal matrix to the shaders if the "Parameters" are an implementation of "IMVPNParameters". - /// - /// The GL. - /// The modelview class that contains the matrix. - /// The projection class that contains the matrix. - /// The normal class that contains the matrix. - public void ApplyMVPNMatrices(OpenGL gl, ModelView modelview, Projection projection, Normal normal, bool throwException = true) - { - if (!typeof(IMVPNParameters).IsAssignableFrom(Parameters.GetType())) - { - if (!throwException) - return; - - throw new InvalidCastException("'Parameters' does not implement 'IMVPNParameters'." + - "This has to be implemented for this method to know how the shader expects it's parameter names."); - } - - var prms = Parameters as IMVPNParameters; - - // Set the matrices. - Program.SetUniformMatrix4(gl, prms.ProjectionMatrixId, projection.ToArray()); - Program.SetUniformMatrix4(gl, prms.ModelviewMatrixId, modelview.ToArray()); - Program.SetUniformMatrix3(gl, prms.NormalMatrixId, normal.ToArray()); - } - - /// - /// Sets the light position to the shader if the "Parameters" are an implementation of "ISingleLightParameters" - /// - /// - /// - public void SetLight(OpenGL gl, vec3 lightPosition, bool throwException = true) - { - if (!typeof(ISingleLightParameters).IsAssignableFrom(Parameters.GetType())) - { - if (!throwException) - return; - - - throw new InvalidCastException("'Parameters' does not implement 'ILightingParameters'." + - "This has to be implemented for this method to know how the shader expects it's parameter names."); - } - - var prms = Parameters as ISingleLightParameters; - - // Set the light position. - if (prms.LightPositionId != null) - Program.SetUniform3(gl, prms.LightPositionId, lightPosition.x, lightPosition.y, lightPosition.z); - } - - /// - /// This method binds the shaderprogram to the GL, invokes the function and unbinds the shader. - /// The function should contain everything that has to be loaded with this shader's settings. - /// - /// The GL. - /// The code that has to be executing in this ShaderProgram. - public void UseProgram(OpenGL gl, Action func) - { - _gl = gl; - - // Bind the shader. - Program.Bind(gl); - - - // Invoke logic. - func.Invoke(); - - // Unbind the shader. - Program.Unbind(gl); - } - - /// - /// Deletes the shaderprogram van the GL and clears the parameters of this object. - /// - public void Dispose() - { - Program.Delete(_gl); - Program = null; - Parameters = null; - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs deleted file mode 100644 index af121d71..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMVPNParameters.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - /// - /// Implement this interface for shaders that accept Modelview-, Projection- and/or Normal matrices. - /// - interface IMVPNParameters - { - string ProjectionMatrixId { get; } - string ModelviewMatrixId { get; } - string NormalMatrixId { get; } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs deleted file mode 100644 index bad92027..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IMaterialShaderParameters.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - /// - /// Implement this interface for shaders that have similar input parameters as SharpGL.SceneGraph.Assets.Material. - /// - public interface IMaterialShaderParameters : IShaderParameterIds - { - string LightPositionId { get; } - string DiffuseId { get; } - string AmbientId { get; } - string SpecularId { get; } - string ShininessId { get; } - string EmissionId { get; } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs deleted file mode 100644 index 81f2d7a9..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/IShaderParameterIds.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - /// - /// Convert this type to one of it's child types, to get access to the available parameters of a shader without - /// having to browse through the vert- and frag shader code. - /// - public interface IShaderParameterIds - { - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs deleted file mode 100644 index e2afddd3..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ISingleLightParameters.cs +++ /dev/null @@ -1,13 +0,0 @@ -using GlmNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - public interface ISingleLightParameters - { - string LightPositionId { get; } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs deleted file mode 100644 index b4c1d7a6..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/PerPixelParameters.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - public class PerPixelParameters : IMaterialShaderParameters, IMVPNParameters, ISingleLightParameters - { - public string LightPositionId - { - get { return "LightPosition"; } - } - - public string DiffuseId - { - get { return "DiffuseMaterial"; } - } - - public string AmbientId - { - get { return "AmbientMaterial"; } - } - - public string SpecularId - { - get { return "SpecularMaterial"; } - } - - public string ShininessId - { - get { return "Shininess"; } - } - - - public string EmissionId - { - get { return "Emission"; } - } - - public string ProjectionMatrixId - { - get { return "Projection"; } - } - - public string ModelviewMatrixId - { - get { return "Modelview"; } - } - - public string NormalMatrixId - { - get { return "NormalMatrix"; } - } - - string ISingleLightParameters.LightPositionId - { - get { return "LightPosition"; } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs deleted file mode 100644 index 36cb429d..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/SimpleShaderParameters.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - - public class SimpleShaderParameters : IMaterialShaderParameters, IMVPNParameters - { - public string LightPositionId - { - get { return null; } - } - - public string DiffuseId - { - get { return null; } - } - - public string AmbientId - { - get { return "PickingColor"; } - } - - public string SpecularId - { - get { return null; } - } - - public string ShininessId - { - get { return null; } - } - - - public string EmissionId - { - get { return null; } - } - - public string ProjectionMatrixId - { - get { return "Projection"; } - } - - public string ModelviewMatrixId - { - get { return "Modelview"; } - } - - public string NormalMatrixId - { - get { return "NormalMatrix"; } - } - - string IMVPNParameters.ProjectionMatrixId - { - get { return "Projection"; } - } - - string IMVPNParameters.ModelviewMatrixId - { - get { return "Modelview"; } - } - - string IMVPNParameters.NormalMatrixId - { - get { return "NormalMatrix"; } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs deleted file mode 100644 index b9519c65..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Parameters/ToonParameters.cs +++ /dev/null @@ -1,62 +0,0 @@ -using SharpGLBase.Shaders.Parameters; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SharpGLBase.Shaders.Parameters -{ - public class ToonParameters : IMaterialShaderParameters, IMVPNParameters, ISingleLightParameters - { - public string LightPositionId - { - get { return "LightPosition"; } - } - - public string DiffuseId - { - get { return "DiffuseMaterial"; } - } - - public string AmbientId - { - get { return "AmbientMaterial"; } - } - - public string SpecularId - { - get { return "SpecularMaterial"; } - } - - public string ShininessId - { - get { return "Shininess"; } - } - - - public string EmissionId - { - get { return "Emission"; } - } - - public string ProjectionMatrixId - { - get { return "Projection"; } - } - - public string ModelviewMatrixId - { - get { return "Modelview"; } - } - - public string NormalMatrixId - { - get { return "NormalMatrix"; } - } - - string ISingleLightParameters.LightPositionId - { - get { return "LightPosition"; } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag deleted file mode 100644 index 767309e7..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 130 -in vec3 EyespaceNormal; -in vec3 Diffuse; -out vec4 FragColor; - -uniform vec3 LightPosition; -uniform vec3 AmbientMaterial; -uniform vec3 SpecularMaterial; -uniform float Shininess; - -void main() -{ - vec3 N = normalize(EyespaceNormal); - vec3 L = normalize(LightPosition); - vec3 E = vec3(0, 0, 1); - vec3 H = normalize(L + E); - - float df = max(0.0, dot(N, L)); - float sf = max(0.0, dot(N, H)); - sf = pow(sf, Shininess); - - vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial; - FragColor = vec4(color, 1.0); -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert deleted file mode 100644 index 2039a858..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/PerPixel.vert +++ /dev/null @@ -1,18 +0,0 @@ -#version 130 -in vec4 Position; -in vec3 Normal; - -uniform mat4 Projection; -uniform mat4 Modelview; -uniform mat3 NormalMatrix; -uniform vec3 DiffuseMaterial; - -out vec3 EyespaceNormal; -out vec3 Diffuse; - -void main() -{ - EyespaceNormal = NormalMatrix * Normal; - gl_Position = Projection * Modelview * Position; - Diffuse = DiffuseMaterial; -} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag deleted file mode 100644 index 07bfe630..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 core -out vec4 FragColor; - -uniform vec3 PickingColor; - -void main() -{ - FragColor = vec4(PickingColor, 1.0); -} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert deleted file mode 100644 index ef30074b..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/SimpleShader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 core - -in vec4 Position; -in vec3 Normal; - -uniform mat4 Projection; -uniform mat4 Modelview; -uniform mat3 NormalMatrix; -uniform vec3 DiffuseMaterial; - -out vec3 EyespaceNormal; -out vec3 Diffuse; - -void main() -{ - EyespaceNormal = NormalMatrix * Normal; - gl_Position = Projection * Modelview * Position; - Diffuse = DiffuseMaterial; -} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag deleted file mode 100644 index 1a44be4d..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.frag +++ /dev/null @@ -1,54 +0,0 @@ -#version 130 -in vec3 EyespaceNormal; -in vec3 Diffuse; -out vec4 FragColor; - -uniform vec3 LightPosition; -uniform vec3 AmbientMaterial; -uniform vec3 SpecularMaterial; -uniform float Shininess; - -float stepmix(float edge0, float edge1, float E, float x) -{ - float T = clamp(0.5 * (x - edge0 + E) / E, 0.0, 1.0); - return mix(edge0, edge1, T); -} - -void main() -{ - vec3 N = normalize(EyespaceNormal); - vec3 L = normalize(LightPosition); - vec3 Eye = vec3(0, 0, 1); - vec3 H = normalize(L + Eye); - - float df = max(0.0, dot(N, L)); - float sf = max(0.0, dot(N, H)); - sf = pow(sf, Shininess); - - const float A = 0.1; - const float B = 0.3; - const float C = 0.6; - const float D = 1.0; - float E = fwidth(df); - - if (df > A - E && df < A + E) df = stepmix(A, B, E, df); - else if (df > B - E && df < B + E) df = stepmix(B, C, E, df); - else if (df > C - E && df < C + E) df = stepmix(C, D, E, df); - else if (df < A) df = 0.0; - else if (df < B) df = B; - else if (df < C) df = C; - else df = D; - - E = fwidth(sf); - if (sf > 0.5 - E && sf < 0.5 + E) - { - sf = smoothstep(0.5 - E, 0.5 + E, sf); - } - else - { - sf = step(0.5, sf); - } - - vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial; - FragColor = vec4(color, 1.0); -} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert deleted file mode 100644 index 2039a858..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/Shaders/Toon.vert +++ /dev/null @@ -1,18 +0,0 @@ -#version 130 -in vec4 Position; -in vec3 Normal; - -uniform mat4 Projection; -uniform mat4 Modelview; -uniform mat3 NormalMatrix; -uniform vec3 DiffuseMaterial; - -out vec3 EyespaceNormal; -out vec3 Diffuse; - -void main() -{ - EyespaceNormal = NormalMatrix * Normal; - gl_Position = Projection * Modelview * Position; - Diffuse = DiffuseMaterial; -} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj deleted file mode 100644 index 253de616..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/SharpGLBase.csproj +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Debug - AnyCPU - {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B} - Library - Properties - SharpGLBase - SharpGLBase - v4.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - ..\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll - False - - - ..\..\sharpgl\source\SharpGL\Core\SharpGL\bin\Debug\SharpGL.dll - False - - - ..\..\sharpgl\source\SharpGL\Core\SharpGL.SceneGraph\bin\Debug\SharpGL.SceneGraph.dll - False - - - False - - - False - - - False - - - - - False - - - False - - - False - - - False - - - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs deleted file mode 100644 index c60516b7..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/VertexAttributes.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace SharpGLBase -{ - /// - /// Vertex attributes used globally in the sample. - /// - public static class VertexAttributes - { - /// - /// The position vertex attribute, used for vertices. - /// - public const uint Position = 0; - - /// - /// The normal vertex attribute, used for normals. - /// - public const uint Normal = 1; - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config deleted file mode 100644 index e316866a..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLBase/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config deleted file mode 100644 index 4c77df1f..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml deleted file mode 100644 index c6d52e7c..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs deleted file mode 100644 index ab7a41f0..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/App.xaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; - -namespace SharpGLTest -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml deleted file mode 100644 index 6a8c860b..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs deleted file mode 100644 index 1e58fdd8..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindow.xaml.cs +++ /dev/null @@ -1,181 +0,0 @@ -using SharpGL; -using SharpGL.SceneGraph; -using SharpGL.SceneGraph.Primitives; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using SharpGLBase.Extensions; -using GlmNet; - -namespace SharpGLTest -{ - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window, INotifyPropertyChanged - { - #region events - public event PropertyChangedEventHandler PropertyChanged; - public void OnPropertyChanged(string prop) - { - if (PropertyChanged != null) - PropertyChanged(this, new PropertyChangedEventArgs(prop)); - } - #endregion events - - #region fields - MainWindowViewModel _viewPortViewModel = new MainWindowViewModel(); - #endregion fields - - #region properties - public string OnScreenData { get; set; } - - public MainWindowViewModel ViewPortViewModel - { - get { return _viewPortViewModel; } - set { _viewPortViewModel = value; } - } - - #endregion properties - - - /// - /// Initializes a new instance of the class. - /// - public MainWindow() - { - DataContext = this; - InitializeComponent(); - MouseMove += MainWindow_MouseMove; - MouseWheel += MainWindow_MouseWheel; - MouseDown += MainWindow_MouseDown; - - ViewPortViewModel.Scene.ModelView.PropertyChanged += (sender, args) => - { - if (args.PropertyName == "ModelviewMatrix") - { - var modelviewMatrix = ViewPortViewModel.Scene.ModelView.ModelviewMatrix; - var translationMatrix = ViewPortViewModel.Scene.ModelView.TranslationMatrix; - var scalingMatrix = ViewPortViewModel.Scene.ModelView.ScalingMatrix; - var rotationMatrix = ViewPortViewModel.Scene.ModelView.RotationMatrix; - - string txt = ""; - - txt += "ModelviewMatrix:\n" + modelviewMatrix.ToValueString(); - txt += "\n\nTranslationMatrix:\n" + translationMatrix.ToValueString(); - txt += "\n\nScalingMatrix:\n" + scalingMatrix.ToValueString(); - txt += "\n\nRotationMatrix:\n" + rotationMatrix.ToValueString(); - - - - OnScreenData = txt; - OnPropertyChanged("OnScreenData"); - } - }; - } - - - void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) - { - if (e.LeftButton == MouseButtonState.Pressed) - { - Point p = e.MouseDevice.GetPosition(this); - _viewPortViewModel.PointerClicked(PointedClickedAction.SelectModel, new System.Drawing.Point((int)p.X, (int)p.Y)); - //_viewPortViewModel.CameraLookAt.RotateCameraAroundRelativeX(.1); - } - } - - void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - _viewPortViewModel.MouseScroll(MouseScrollAction.ChangePerspectiveDepth, e.Delta > 0); - } - else - { - _viewPortViewModel.MouseScroll(MouseScrollAction.Zoom, e.Delta > 0); - } - } - - void MainWindow_MouseMove(object sender, MouseEventArgs e) - { - if (_viewPortViewModel.LastPointerLocation != null) - { - long t1 = DateTime.Now.Ticks; - long t2 = _viewPortViewModel.TimeLastPointerLocation.Value; - if ( t1 > t2 + 3000000) - { - _viewPortViewModel.PointerMoveEnd(); - } - } - - if (e.RightButton == MouseButtonState.Pressed) - { - var p1 = e.MouseDevice.GetPosition(this); - if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - } - else - { - _viewPortViewModel.PointerMoved(new System.Drawing.Point((int)p1.X, (int)p1.Y), PointedMovedAction.RotateAroundCenter); - } - } - else if (e.LeftButton == MouseButtonState.Pressed) - { - var p1 = e.MouseDevice.GetPosition(this); - _viewPortViewModel.PointerMoved(new System.Drawing.Point((int)p1.X, (int)p1.Y), PointedMovedAction.MoveRelatively); - } - else - { - _viewPortViewModel.PointerMoveEnd(); - } - } - - /// - /// Handles the OpenGLDraw event of the OpenGLControl control. - /// - /// The source of the event. - /// The instance containing the event data. - private void OpenGLControl_OpenGLDraw(object sender, OpenGLEventArgs args) - { - OpenGL gl = args.OpenGL; - _viewPortViewModel.OpenGLDraw(gl); - } - - /// - /// Handles the OpenGLInitialized event of the OpenGLControl control. - /// - /// The source of the event. - /// The instance containing the event data. - private void OpenGLControl_OpenGLInitialized(object sender, OpenGLEventArgs args) - { - OpenGL gl = args.OpenGL; - _viewPortViewModel.OpenGLInitialized(gl); - } - - private void OpenGLControl_Resized(object sender, OpenGLEventArgs args) - { - var glCtrl = sender as SharpGL.WPF.OpenGLControl; - // Get the OpenGL instance. - var gl = args.OpenGL; - _viewPortViewModel.ViewResized(gl, glCtrl.ActualWidth, glCtrl.ActualHeight); - } - - private void MainWindow_MouseLeave(object sender, MouseEventArgs e) - { - _viewPortViewModel.PointerMoveEnd(); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs deleted file mode 100644 index 1c1252b1..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MainWindowViewModel.cs +++ /dev/null @@ -1,314 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGL.SceneGraph.Cameras; -using SharpGL.SceneGraph.Core; -using SharpGL.SceneGraph.Primitives; -using SharpGL.Shaders; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SharpGL.SceneGraph.Assets; -using SharpGLBase.Scene; -using SharpGLBase; -using SharpGLTest.Shapes; -using SharpGLBase.Primitives; -using System.Drawing; -using SharpGLBase.Events; -using SharpGLBase.Extensions; - -namespace SharpGLTest -{ - public enum PointedMovedAction { RotateAroundCenter, MoveRelatively, RotateAroundEye, ChangePerspectiveDepth } - public enum PointedClickedAction { SelectModel } - public enum MouseScrollAction { Zoom, ChangePerspectiveDepth } - public class MainWindowViewModel - { - #region fields - OpenGL _gl = null; // Permits using gl for methods that aren't called by the Draw-event - MyScene _scene = new MyScene(); - Point? _lastPointerLocation; - Model3DBase _selectedModel = null; - float _rotationSensitivity = 0.01f / 200000f; - float _moveSensitivity = 0.01f; - float _zoomSensitivity = 1.1f; - float _changePerspectiveDepthSensitivity = 0.2f; - long? _timeLastPointerLocation; - #endregion fields - - #region properties - public Point? LastPointerLocation - { - get { return _lastPointerLocation; } - set { _lastPointerLocation = value; } - } - public long? TimeLastPointerLocation - { - get { return _timeLastPointerLocation; } - set { _timeLastPointerLocation = value; } - } - - public float MoveSensitivity - { - get { return _moveSensitivity; } - set - { - if (value <= 0) - throw new InvalidOperationException("Sensitivity has to be more than 0."); - _moveSensitivity = value; - } - } - public float RotationSensitivity - { - get { return _rotationSensitivity; } - set - { - if (value <= 0) - throw new InvalidOperationException("Sensitivity has to be more than 0."); - _rotationSensitivity = value; - } - } - - public float ZoomSensitivity - { - get { return _zoomSensitivity; } - set - { - if (value <= 0) - throw new InvalidOperationException("Sensitivity has to be more than 0."); - _zoomSensitivity = value; - } - } - - public float ChangePerspectiveDepthSensitivity - { - get { return _changePerspectiveDepthSensitivity; } - set { _changePerspectiveDepthSensitivity = value; } - } - - public MyScene Scene - { - get { return _scene; } - set { _scene = value; } - } - #endregion properties - - #region user input - /// - /// If LastPointerLocation == null then LastPointerLocation = pointerLocation - /// Else act on movement between the 2 points. - /// - /// The new point to where the pointer moved - public void PointerMoved(Point pointerLocation, PointedMovedAction action) - { - if (_lastPointerLocation != null) - { - var diffX = _lastPointerLocation.Value.X - pointerLocation.X; - var diffY = _lastPointerLocation.Value.Y - pointerLocation.Y; - var values = new Point(diffX, diffY); - - if (action == PointedMovedAction.RotateAroundCenter) - { - Rotate(values); - } - else if (action == PointedMovedAction.MoveRelatively) - { - MoveRelatively(values); - } - } - _lastPointerLocation = pointerLocation; - _timeLastPointerLocation = DateTime.Now.Ticks; - } - - /// - /// Clears LastPointerLocation. - /// - public void PointerMoveEnd() - { - _lastPointerLocation = null; - _timeLastPointerLocation = null; - } - - public void PointerClicked(PointedClickedAction action, Point point) - { - if (action == PointedClickedAction.SelectModel) - { - Scene.GetModelAtPoint(point, Scene.MaterialForObjects.ToValueList()); - } - } - public void MouseScroll(MouseScrollAction action, bool forward) - { - if (action == MouseScrollAction.Zoom) - { - //_zoomSteps += forward ? -1 : 1; - - //float zoomFactor = (float)Math.Pow(ZoomSensitivity, _zoomSteps); - float zoomDistance = forward ? ZoomSensitivity : -ZoomSensitivity; - Zoom(zoomDistance); - } - else if (action == MouseScrollAction.ChangePerspectiveDepth) - { - ChangePerspectiveDepth(forward ? ChangePerspectiveDepthSensitivity : -ChangePerspectiveDepthSensitivity); - } - } - #endregion user input - - #region camera control. - /// - /// Rotates CameraLookAt around its Center. - /// - /// Y => rotate in Y direction (Azimuth). X => rotate sideways (Zenith) - public void Rotate(Point moveValues) - { - // Convert 2D pointer movement to 3D rotation - - var size = _scene.ViewPortSize; - var constForXY = _rotationSensitivity * (DateTime.Now.Ticks - _timeLastPointerLocation.Value); - var vertRotLimiter = size.Width > size.Height ? size.Width / (double)size.Height : size.Height / (double)size.Width; - - - float rotationRadiansX = (float)(moveValues.Y * constForXY / vertRotLimiter);// / 1000.0f + 1); - float rotationRadiansY = (float)(moveValues.X * constForXY);// / 1000.0f + 1); - Scene.ModelView.RotateAbsoluteX(rotationRadiansX); - Scene.ModelView.RotateAbsoluteY(rotationRadiansY); - //Scene.ModelView.RotateAbsoluteZ(rotationRadiansX); - } - /// - /// Moves camera relatively - /// - /// X => move horizontally. Y => move vertically. - public void MoveRelatively(Point moveValues) - { - // Adapt the moving speed to the zoom amount. - //float moveSensitivity = (float)Math.Pow(ZoomSensitivity, _zoomSteps) * MoveSensitivity; - float moveSensitivity = MoveSensitivity; - - // Convert 2D pointer movement to 3D rotation - float moveX = (float)moveValues.X * moveSensitivity; - float moveY = (float)moveValues.Y * moveSensitivity; - Scene.ModelView.TranslateAbsoluteX(-moveX); - Scene.ModelView.TranslateAbsoluteY(moveY); - //Scene.ModelView.TranslateOnRotationMatrix(new vec3(-moveX, moveY, 0)); - } - - - public void Zoom(float distance, OpenGL gl = null) - { - //Scene.Projection.Zoom(zoomFactor, gl == null ? _gl : gl); - Scene.Projection.Zoom(distance); - } - - public void ChangePerspectiveDepth(float distance) - { - - //TODO - } - #endregion camera control. - - private Model3DBase _shape; - public void AddElements(OpenGL gl) - { - var redMat = new Material(); - var blueMat = new Material(); - var redObjects = new List(); - var blueObjects = new List(); - - - // Set red material - redMat.Ambient = System.Drawing.Color.FromArgb(255, 50, 0, 50); - redMat.Diffuse = System.Drawing.Color.FromArgb(255, 100, 0, 100); - redMat.Specular = System.Drawing.Color.FromArgb(255, 225, 225, 225); - redMat.Shininess = 100f; - // Set blue material - //blueMat.Ambient = System.Drawing.Color.FromArgb(255, 0, 0, 100); - blueMat.Diffuse = System.Drawing.Color.FromArgb(255, 0, 100, 255); - //blueMat.Specular = System.Drawing.Color.FromArgb(255, 100, 0, 255); - //blueMat.Shininess = 0.0001f; - - _shape = new MyTrefoilKnot(gl); - _shape.TranslateAbsoluteZ(3); - // Add some test models to the viewport - var cube = new FlatShadedCube(gl); - //cube.Scale(new vec3(0.5f, -0.5f, -0.5f)); - cube.TranslateAbsoluteX(3); - cube.RotateAbsoluteY(2); - cube.CalculateNormals(); - - var trefoilKnot = new MyTrefoilKnot(gl); - trefoilKnot.RotateAbsoluteZ(1f); - //trefoilKnot.RotateAbsoluteY(4.5f); - //trefoilKnot.ScaleY(1.3f); - trefoilKnot.TranslateAbsoluteY(2); - - blueObjects.Add(_shape); - redObjects.Add(cube); - redObjects.Add(trefoilKnot); - blueObjects.Add(new FlatShadedCube(gl)); - - Scene.MaterialForObjects.Add(redMat, redObjects); - Scene.MaterialForObjects.Add(blueMat, blueObjects); - } - - public void OpenGLInitialized(OpenGL gl) - { - _gl = gl; - Scene.ModelSelected += Scene_ModelSelected; - - //Scene.ModelView.CameraHandling = CameraRotationHandling.TSR; - //Scene.ModelView.RotationMethod = RotationMethod.TurnTableYZ; - Scene.ModelView.CameraHandling = CameraRotationHandling.TRS; - Scene.ModelView.RotationMethod = RotationMethod.TurnTableXZ; - - // Scale down the opengl viewport size in order to increase performance. - //Scene.PerformanceScaleValue = 0.5f; - - //Scene.DrawEdgesOnly = true; - Scene.OpenGLInitialized(gl); - AddElements(gl); - var lp = new vec3(5, 50, 15); - Scene.LightPosition = lp; - - // Move view to best position - Scene.Projection.Zoom(-10); - //Scene.ModelView.TranslateAbsoluteZ(-5); - //Scene.ModelView.RotateAbsoluteY((float)Math.PI); - } - - void Scene_ModelSelected(object sender, ModelSelectedEventArgs e) - { - if (_selectedModel != null) - _selectedModel.Material = null; - - if (e.SelectedModel == null) - return; - - var mat = new Material(); - mat.Diffuse = Color.Silver; - mat.Ambient = Color.Gray; - - - e.SelectedModel.Material = mat; - - - _selectedModel = e.SelectedModel; - } - - public void OpenGLDraw(OpenGL gl) - { - float rotPerTime = (float)(DateTime.Now.Millisecond / 500.0 * Math.PI % (2 * Math.PI)); - - //Scene.ModelView.RotateAbsoluteY(0.1f); - - _shape.RotationMatrix = mat4.identity(); - _shape.RotateAbsoluteY(rotPerTime); - Scene.Draw(gl); - } - - public void ViewResized(OpenGL gl, double width, double height) - { - Scene.ViewResized(gl, width, height); - } - - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs deleted file mode 100644 index 8343bc1e..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/MyScene.cs +++ /dev/null @@ -1,205 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGL.Enumerations; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Core; -using SharpGLBase.Primitives; -using SharpGLBase.Scene; -using SharpGLBase.Shaders; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using SharpGLBase.Extensions; - -namespace SharpGLTest -{ - public class MyScene : OpenGLScene - { - #region fields - AxisVBO _axis; - SquareGridVBO _grid; - vec3 _lightPosition = new vec3(10, 10, 10); - Dictionary> _materialForObjects = new Dictionary>(); - Color _verticalGradientBackgroundColorTop = Color.FromArgb(146, 134, 188); // Light Purple - Color _verticalGradientBackgroundColorBottom = Color.FromArgb(0, 0, 0); // Black - bool _drawEdgesOnly = false; - #endregion fields - - #region properties - /// - /// Top color of the gradient background. - /// - public Color VerticalGradientBackgroundColorTop - { - get { return _verticalGradientBackgroundColorTop; } - set { _verticalGradientBackgroundColorTop = value; } - } - /// - /// Bottom color of the gradient background. - /// - public Color VerticalGradientBackgroundColorBottom - { - get { return _verticalGradientBackgroundColorBottom; } - set { _verticalGradientBackgroundColorBottom = value; } - } - /// - /// Objects grouped by material. Add an object here and it will be presented to the scene. - /// - public Dictionary> MaterialForObjects - { - get { return _materialForObjects; } - set { _materialForObjects = value; } - } - /// - /// Position of the lightpoint. - /// - public vec3 LightPosition - { - get { return _lightPosition; } - set { _lightPosition = value; } - } - /// - /// If true => models will be rendered in Polygon LineMode. - /// - public bool DrawEdgesOnly - { - get { return _drawEdgesOnly; } - set { _drawEdgesOnly = value; } - } - #endregion properties - - - public MyScene() - { - } - - public override void OpenGLInitialized(SharpGL.OpenGL gl) - { - base.OpenGLInitialized(gl); - - // Initialize the grid and axis. - _axis = new AxisVBO(gl); - _grid = new SquareGridVBO(gl); - - // Set the shader. - CurrentShader = Shaders.LoadToonShader(gl); - } - - public override void Draw(SharpGL.OpenGL gl) - { - // Disable dithering ( = smooth color transition). Should have a slight performance impact. - gl.Disable(OpenGL.GL_DITHER); - - // Clear the viewport. - gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); - - // Add gradient background. - SetVerticalGradientBackground(gl, VerticalGradientBackgroundColorTop, VerticalGradientBackgroundColorBottom); - - // Use the shader program. - CurrentShader.UseProgram(gl, () => - { - if (DrawEdgesOnly) - { - // Push the polygon attributes and set line mode. - gl.PushAttrib(OpenGL.GL_POLYGON_BIT); - gl.PolygonMode(FaceMode.FrontAndBack, PolygonMode.Lines); - } - - CurrentShader.ApplyMVPNMatrices(gl, ModelView, Projection, Normal); - - // Set the light. - CurrentShader.SetLight(gl, _lightPosition, false); - - // Render all objects. - foreach (var key in MaterialForObjects.Keys) - { - var objects = MaterialForObjects[key]; - RenderObjectsFromMaterial(gl, key, CurrentShader, objects); - } - - // Add axis. - _axis.Render(gl, RenderMode.Design, CurrentShader); - - // Add grid. - _grid.Render(gl, RenderMode.Design, CurrentShader); - - - // Undo draw edges only. - if (DrawEdgesOnly) - { - // Pop the attributes, restoring all polygon state. - gl.PopAttrib(); - } - }); - } - - public override void ViewResized(SharpGL.OpenGL gl, double actualWidth, double actualHeight) - { - base.ViewResized(gl, actualWidth, actualHeight); - } - - /// - /// Sets the background color, using a gradient existing from 2 colors - /// - /// - private static void SetVerticalGradientBackground(OpenGL gl, Color colorTop, Color colorBot) - { - float topRed = colorTop.R / 255.0f; - float topGreen = colorTop.G / 255.0f; - float topBlue = colorTop.B / 255.0f; - float botRed = colorBot.R / 255.0f; - float botGreen = colorBot.G / 255.0f; - float botBlue = colorBot.B / 255.0f; - - gl.Begin(OpenGL.GL_QUADS); - - //bottom color - gl.Color(botRed, botGreen, botBlue); - gl.Vertex(-1.0, -1.0); - gl.Vertex(1.0, -1.0); - - //top color - gl.Color(topRed, topGreen, topBlue); - gl.Vertex(1.0, 1.0); - gl.Vertex(-1.0, 1.0); - - gl.End(); - } - - /// - /// Renders all objects in MaterialForObjects[materialKey] to the screen, using the given parameters. - /// - /// The OpenGL - /// The material that will be used for the objects. - /// The shader that will be used for this material. - /// The objects to be drawn. - /// True: draw only edges, false: draw faces. - public void RenderObjectsFromMaterial(OpenGL gl, Material material, ExtShaderProgram shader, IEnumerable objects) - { - if (objects == null) - return; - - // Set the variables for the shader program. - shader.ApplyMaterial(gl, material); - - // Bind the vertex buffer arrays. - foreach (var item in objects) - { - // If the object has it's own material, then use this. Else use the material-parameter. - if (item.Material != null) - { - shader.ApplyMaterial(gl, item.Material); - item.Render(gl, RenderMode.Render); - shader.ApplyMaterial(gl, material); - } - else - { - item.Render(gl, RenderMode.Render); - } - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 3f6877e5..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SharpGLTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SharpGLTest")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs deleted file mode 100644 index 8603ab8a..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34011 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SharpGLTest.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLTest.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx deleted file mode 100644 index af7dbebb..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs deleted file mode 100644 index d35925ad..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34011 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SharpGLTest.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings deleted file mode 100644 index 033d7a5e..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs deleted file mode 100644 index 9edd3d92..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/FlatShadedCube.cs +++ /dev/null @@ -1,73 +0,0 @@ -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Cameras; -using SharpGL.SceneGraph.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Drawing; -using GlmNet; -using SharpGLBase; -using SharpGLBase.Primitives; -using SharpGLBase.Shaders; - -namespace SharpGLTest.Shapes -{ - /// - /// A simple cube object - /// - public class FlatShadedCube : Model3DBase - { - #region cube data - readonly vec3[] _vertices = new vec3[]{ - new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), - new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), - new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), - new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), - new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), - new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) - }; - //readonly vec3[] _normals = new vec3[]{ - // new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), - // new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), - // new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), - // new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), - // new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), - // new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), - //}; - readonly ushort[] _indices = new ushort[]{ - 1, 2,0,2,3,0, - 4,6,5, 4,7,6, - 8,10,9, 8,11,10, - 13,14,12, 14,15,12, - 16,18,17, 16,19,18, - 21,22,20, 22,23,20, - }; - #endregion cube data - - public FlatShadedCube(OpenGL gl) - { - base.Init(_vertices, _indices, null, gl); - } - - /// - /// Renders the cube to the screen. - /// - /// - /// - public override void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null) - { - // Load our cube data ClockWise. - gl.FrontFace(OpenGL.GL_CW); - - // Binds buffers. - base.Bind(); - - // Draw the elements. - gl.DrawElements(OpenGL.GL_TRIANGLES, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs deleted file mode 100644 index a7040a89..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/MyTrefoilKnot.cs +++ /dev/null @@ -1,160 +0,0 @@ -using GlmNet; -using SharpGLBase; -using SharpGLBase.Primitives; -using SharpGLBase.Primitives.ModelComponents; -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.VertexBuffers; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using SharpGLBase.Shaders; - -namespace SharpGLTest.Shapes -{ - /// - /// The TrefoilKnot class creates geometry - /// for a trefoil knot. - /// - public class MyTrefoilKnot: Model3DBase - { - #region fields - /// The number of slices and stacks. - private const uint _slices = 128; - private const uint _stacks = 32; - - private static vec3[] _vertices; - private static vec3[] _normals; - private static ushort[] _indices; - #endregion fields - - #region constructor - static MyTrefoilKnot() - { - CreateIndexBuffer(); - CreateVertexNormalBuffer(); - } - - public MyTrefoilKnot(OpenGL gl) - { - Init(_vertices, _indices, _normals, gl); - //base.BaseVertices = _vertices; - //base.Normals = _normals; - //base.Indices = _indices; - //GenerateGeometry(gl); - } - - #endregion constructor - - #region calculate trefoil knot - /// - /// Evaluates the trefoil, providing the vertex at a given coordinate. - /// - /// The s. - /// The t. - /// The vertex at (s,t). - private static vec3 EvaluateTrefoil(float s, float t) - { - const float TwoPi = (float)Math.PI * 2; - - float a = 0.5f; - float b = 0.3f; - float c = 0.5f; - float d = 0.1f; - float u = (1 - s) * 2 * TwoPi; - float v = t * TwoPi; - float r = (float)(a + b * Math.Cos(1.5f * u)); - float x = (float)(r * Math.Cos(u)); - float y = (float)(r * Math.Sin(u)); - float z = (float)(c * Math.Sin(1.5f * u)); - - vec3 dv = new vec3(); - dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); - dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); - dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); - - vec3 q = glm.normalize(dv); - vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); - vec3 ww = glm.cross(q, qvn); - - vec3 range = new vec3(); - range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); - range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); - range.z = (float)(z + d * ww.z * Math.Sin(v)); - - return range; - } - - private static void CreateVertexNormalBuffer() - { - var vertexCount = _slices * _stacks; - - _vertices = new vec3[vertexCount]; - _normals = new vec3[vertexCount]; - - int count = 0; - - float ds = 1.0f / _slices; - float dt = 1.0f / _stacks; - - // The upper bounds in these loops are tweaked to reduce the - // chance of precision error causing an incorrect # of iterations. - - for (float s = 0; s < 1 - ds / 2; s += ds) - { - for (float t = 0; t < 1 - dt / 2; t += dt) - { - const float E = 0.01f; - vec3 p = EvaluateTrefoil(s, t); - vec3 u = EvaluateTrefoil(s + E, t) - p; - vec3 v = EvaluateTrefoil(s, t + E) - p; - vec3 n = glm.normalize(glm.cross(u, v)); - _vertices[count] = p; - _normals[count] = n; - count++; - } - } - } - - private static void CreateIndexBuffer() - { - const uint vertexCount = _slices * _stacks; - const uint indexCount = vertexCount * 6; - _indices = new ushort[indexCount]; - int count = 0; - - ushort n = 0; - for (ushort i = 0; i < _slices; i++) - { - for (ushort j = 0; j < _stacks; j++) - { - _indices[count++] = (ushort)(n + j); - _indices[count++] = (ushort)(n + (j + 1) % _stacks); - _indices[count++] = (ushort)((n + j + _stacks) % vertexCount); - - _indices[count++] = (ushort)((n + j + _stacks) % vertexCount); - _indices[count++] = (ushort)((n + (j + 1) % _stacks) % vertexCount); - _indices[count++] = (ushort)((n + (j + 1) % _stacks + _stacks) % vertexCount); - } - - n += (ushort)_stacks; - } - } - #endregion calculate trefoil knot - - public override void Render(OpenGL gl, SharpGL.SceneGraph.Core.RenderMode renderMode, ExtShaderProgram shader = null) - { - if (base.Visible) - { - OpenGL.FrontFace(OpenGL.GL_CW); - - base.Bind(); - - // Draw the elements. - OpenGL.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs deleted file mode 100644 index 77b9d254..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/Shapes/SmoothShadedCube.cs +++ /dev/null @@ -1,68 +0,0 @@ -using SharpGL; -using SharpGL.SceneGraph.Assets; -using SharpGL.SceneGraph.Cameras; -using SharpGL.SceneGraph.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Drawing; -using GlmNet; -using SharpGLBase; -using SharpGLBase.Primitives; -using SharpGLBase.Shaders; - -namespace SharpGLTest.Shapes -{ - /// - /// A simple cube object - /// - public class SmoothShadedCube : Model3DBase - { - #region cube data - readonly vec3[] _vertices = new vec3[]{ - new vec3(-1.0f, -1.0f, -1.0f), - new vec3(1.0f, -1.0f, -1.0f), - new vec3(1.0f, 1.0f, -1.0f), - new vec3(-1.0f, 1.0f, -1.0f), - new vec3(-1.0f, -1.0f, 1.0f), - new vec3(1.0f, -1.0f, 1.0f), - new vec3(1.0f, 1.0f, 1.0f), - new vec3(-1.0f, 1.0f, 1.0f) - }; - - readonly ushort[] _indices = new ushort[]{ - 0, 4, 5, 0, 5, 1, - 1, 5, 6, 1, 6, 2, - 2, 6, 7, 2, 7, 3, - 3, 7, 4, 3, 4, 0, - 4, 7, 6, 4, 6, 5, - 3, 0, 1, 3, 1, 2 - }; - #endregion cube data - - public SmoothShadedCube(OpenGL gl) - { - base.Init(_vertices, _indices, null, gl); - } - - /// - /// Renders the cube to the screen. - /// - /// - /// - public override void Render(OpenGL gl, RenderMode renderMode, ExtShaderProgram shader = null) - { - // Load our cube data ClockWise. - gl.FrontFace(OpenGL.GL_CW); - - // Binds buffers. - base.Bind(); - - // Draw the elements. - gl.DrawElements(GlDrawMode, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero); - } - } -} diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj deleted file mode 100644 index f067275a..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/SharpGLTest.csproj +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Debug - AnyCPU - {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9} - WinExe - Properties - SharpGLTest - SharpGLTest - v4.0 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll - - - False - ..\..\sharpgl\source\SharpGL\Core\SharpGL\bin\Debug\SharpGL.dll - - - False - ..\..\sharpgl\source\SharpGL\Core\SharpGL.SceneGraph\bin\Debug\SharpGL.SceneGraph.dll - - - False - ..\..\sharpgl\source\SharpGL\Core\SharpGL.WPF\bin\Debug\SharpGL.WPF.dll - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - - - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - - {cffbb91a-c898-45ca-a074-b16f3ffe7f3b} - SharpGLBase - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config deleted file mode 100644 index d001aa11..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLTest/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln b/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln deleted file mode 100644 index 10b20b54..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/SharpGLViewerSample.sln +++ /dev/null @@ -1,27 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLTest", "SharpGLTest\SharpGLTest.csproj", "{4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLBase", "SharpGLBase\SharpGLBase.csproj", "{CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4821D142-7EF2-4B40-A5EE-5F23C5B1F0A9}.Release|Any CPU.Build.0 = Release|Any CPU - {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFFBB91A-C898-45CA-A074-B16F3FFE7F3B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nupkg deleted file mode 100644 index 5f5487064aabfc866ae8cb09cad61f70a805be2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17026 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 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec deleted file mode 100644 index 36821604..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/GlmNet.0.0.2.0.nuspec +++ /dev/null @@ -1,17 +0,0 @@ - - - - GlmNet - 0.0.2.0 - GlmNet - Dave Kerr - Dave Kerr - https://github.com/dwmkerr/glmnet - false - GLM .NET is a .NET version of the popular GLM mathematics library. -

GLM .NET is a .NET version of the popular GLM mathematics library. - - Copyright © Dave Kerr 2014 - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML deleted file mode 100644 index 7e31a995..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.XML +++ /dev/null @@ -1,281 +0,0 @@ - - - - GlmNet - - - - - Represents a 2x2 matrix. - - - - - Initializes a new instance of the struct. - This matrix is the identity matrix scaled by . - - The scale. - - - - Initializes a new instance of the struct. - The matrix is initialised with the . - - The colums of the matrix. - - - - Creates an identity matrix. - - A new identity matrix. - - - - Returns the matrix as a flat array of elements, column major. - - - - - - Multiplies the matrix by the matrix. - - The LHS matrix. - The RHS matrix. - The product of and . - - - - The columms of the matrix. - - - - - Gets or sets the column at the specified index. - - - The column. - - The column index. - The column at index . - - - - Gets or sets the element at and . - - - The element at and . - - The column index. - The row index. - - The element at and . - - - - - Represents a 3x3 matrix. - - - - - Initializes a new instance of the struct. - This matrix is the identity matrix scaled by . - - The scale. - - - - Initializes a new instance of the struct. - The matrix is initialised with the . - - The colums of the matrix. - - - - Creates an identity matrix. - - A new identity matrix. - - - - Returns the matrix as a flat array of elements, column major. - - - - - - Returns the portion of this matrix. - - The portion of this matrix. - - - - Multiplies the matrix by the matrix. - - The LHS matrix. - The RHS matrix. - The product of and . - - - - The columms of the matrix. - - - - - Gets or sets the column at the specified index. - - - The column. - - The column index. - The column at index . - - - - Gets or sets the element at and . - - - The element at and . - - The column index. - The row index. - - The element at and . - - - - - Represents a three dimensional vector. - - - - - Represents a four dimensional vector. - - - - - The glm class contains static functions as exposed in the glm namespace of the - GLM library. The lowercase naming is to keep the code as consistent as possible - with the real GLM. - - - - - Creates a perspective transformation matrix. - - The field of view angle, in radians. - The aspect ratio. - The near depth clipping plane. - The far depth clipping plane. - A that contains the projection matrix for the perspective transformation. - - - - Creates a frustrum projection matrix. - - The left. - The right. - The bottom. - The top. - The near val. - The far val. - - - - - Applies a translation transformation to matrix by vector . - - The matrix to transform. - The vector to translate by. - translated by . - - - - Applies a scale transformation to matrix by vector . - - The matrix to transform. - The vector to scale by. - scaled by . - - - - Represents a 4x4 matrix. - - - - - Initializes a new instance of the struct. - This matrix is the identity matrix scaled by . - - The scale. - - - - Initializes a new instance of the struct. - The matrix is initialised with the . - - The colums of the matrix. - - - - Creates an identity matrix. - - A new identity matrix. - - - - Returns the matrix as a flat array of elements, column major. - - - - - - Returns the portion of this matrix. - - The portion of this matrix. - - - - Multiplies the matrix by the matrix. - - The LHS matrix. - The RHS matrix. - The product of and . - - - - The columms of the matrix. - - - - - Gets or sets the column at the specified index. - - - The column. - - The column index. - The column at index . - - - - Gets or sets the element at and . - - - The element at and . - - The column index. - The row index. - - The element at and . - - - - - Represents a two dimensional vector. - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/GlmNet.0.0.2.0/lib/net40/GlmNet.dll deleted file mode 100644 index c0b1b2efec79562c59fdc7d13c13c5440aa6a6cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13824 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

N5D(*T^4UFg5sAkONtFGxhvi0Axq4gh1 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 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nupkg deleted file mode 100644 index 0f93ceda3aac8d963cd9765f1bc3d3251e63776f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282901 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 + + + SharpGL + + + +

<^P^i5leAfjQ1pca* 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 diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec deleted file mode 100644 index 782c94cc..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/SharpGLCore.2.1.0.nuspec +++ /dev/null @@ -1,15 +0,0 @@ - - - - SharpGLCore - 2.1.0 - SharpGL Core - Dave Kerr - Dave Kerr - http://sharpgl.codeplex.com/ - false - SharpGL Core is the core library for SharpGL. It provides wrappers for all OpenGL functions and also includes the Scene Graph classes. Installed as part of SharpGL for WinForms or SharpGL for WPF. - SharpGL Core is the core library for SharpGL. It provides wrappers for all OpenGL functions and also includes the Scene Graph classes. Installed as part of SharpGL for WinForms or SharpGL for WPF. - Copyright © Dave Kerr 2013 - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.dll deleted file mode 100644 index c450d6d2c3f50d8124d0cd46ceae33d276513a40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143360 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 z�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 D8N|AI diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml deleted file mode 100644 index 9c972588..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.SceneGraph.xml +++ /dev/null @@ -1,6188 +0,0 @@ - - - - SharpGL.SceneGraph - - - - - The Quadric orientation. - - - - - Outside. - - - - - Inside. - - - - - Helps with implementing IHasObjectSpace. - - - - - IDeepCloneable objects can create a deep clone of themselves. - - - - - - Creates a deep clones of this instance. - - A deep clone of this instance. - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - Deeps the clone. - - - - - - The linear transformation - - - - - Gets or sets the transformation. - - - The transformation. - - - - - Freezes the specified instance. - - The gl instance. - The renderable. - - - - Renders the specified gl. - - The gl. - - - - Unfreezes the specified gl. - - The gl. - - - - The display list internally. - - - - - If true, we're frozen. - - - - - Gets a value indicating whether this instance is frozen. - - - true if this instance is frozen; otherwise, false. - - - - - Any element or asset which has an OpenGL context has some - associated OpenGL resource. This means that when it is loaded - from file, it may need to be re-created, or if it is moved - between OpenGL contexts it may need to be re-created. - Any object that has an OpenGL context has a Create method, a - Destroy Method and a CurrentContext property. - - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Gets the current OpenGL that the object exists in context. - - - - - This class has all the settings you can edit for fog. - - - - - The OpenGLAttributeGroup is the base for groups of opengl attributes. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - True if any attributes are set - - - - Pushes the attributes onto the specified OpenGL attribute stack. - - The OpenGL instance. - - - - Pops the attributes off the specified OpenGL attribute stack. - - The OpenGL instance. - - - - The attribute flags for the group. - - - - - Gets the attribute flags. - todo use get only, xmlignore and don't store them - return them on the fly. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the viewport X. - - - The viewport X. - - - - - Gets or sets the viewport Y. - - - The viewport Y. - - - - - Gets or sets the width of the viewport. - - - The width of the viewport. - - - - - Gets or sets the height of the viewport. - - - The height of the viewport. - - - - - Gets or sets the depth range near. - - - The depth range near. - - - - - Gets or sets the depth range far. - - - The depth range far. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable stencil test. - - - The enable stencil test. - - - - - Gets or sets the stencil function. - - - The stencil function. - - - - - Gets or sets the stencil reference. - - - The stencil reference. - - - - - Gets or sets the stencil mask. - - - The stencil mask. - - - - - Gets or sets the index of the stencil clear. - - - The index of the stencil clear. - - - - - Gets or sets the stencil write mask. - - - The stencil write mask. - - - - - Gets or sets the operation fail. - - - The operation fail. - - - - - Gets or sets the operation depth pass. - - - The operation depth pass. - - - - - Gets or sets the operation depth pass. - - - The operation depth pass. - - - - - The standard OpenGL teapot. - - - - - The base class for all elements in a scene. Anything in - the scene tree is a Scene Element. Scene elements can - have children but are very lacking in functionality - - implement - - - - - Traverses this instance. Traversing simply returns - the children and all descendents in the correct order. - - - - - - Traverses this instance. Traversing simply returns - the children and all descendents in the correct order. - This traversal allows for a predicate to be used. - - The predicate for traversal. - - - - - Traverses this instance. Traversing simply returns - the children and all descendents of type T in the correct order. - - The type of object to traverse for. - The full set of T objects in the scene. - - - - Traverses this instance. Traversing simply returns - the children and all descendents of type T in the correct order. - - The type of object to traverse for. - The predicate for traversal. - - The full set of T objects in the scene. - - - - - Traverses to root element. - - - - - - Initializes a new instance of the class. - - - - - Adds a child. - - The child scene element. - - - - Removes the child scene element. - - The child scene element. - - - - Adds an effect. - - The effect. - - - - Removes the effect. - - The effect. - - - - Returns a that represents this instance. - - - A that represents this instance. - - - - - The children of the element. - - - - - The effects. - - - - - Gets the children. - - - - - Gets the effects. - - - - - Gets the parent. - - - - - Gets or sets the name. - - - The name. - - - - - Gets or sets a value indicating whether this instance is enabled. - - - true if this instance is enabled; otherwise, false. - - - - - A Scene Element can implement this interface to enable rendering - functionality. Note that many scene elements (materials etc) are - not actually drawn. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The IHasMaterial interface can be implemented by any scene object - to allow a material to be associated with the object. - - - - - Gets or sets the material. - - - The material. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Draws the specified gl. - - The gl. - The grid. - The scale. - The type. - - - - Gets or sets the grid. - - - The grid. - - - - - Gets or sets the scale. - - - The scale. - - - - - Gets or sets the type of the fill. - - - The type of the fill. - - - - - Material to be used when rendering the teapot in lighted mode. - - - The material. - - - - - Extensions for Array type. - - - - - Flattens the specified array. - - The array type. - The array. - The flattened array. - - - - The Grid design time primitive is displays a grid in the scene. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Creates the display list. This function draws the - geometry as well as compiling it. - - - - - The internal display list. - - - - - The feedback class handles feedback easily and well. It is 100% dependant on - OpenGL so use it with care! - - - - - This function begins feedback, recording the scene etc. End finishes - feedback, and parses the feedback buffer. - - - - - This function stops the collection of feedback data. - - The feedback array. - - - - Override this function to do custom functions on the data. - - Number of values. - - - - An effect is something that can be applied to a scene element which - then changes everything in the tree below it. It can be pushed, to apply it - and popped, to restore OpenGL back to the state without the effect. - - - - - Initializes a new instance of the class. - - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pops the effect off the specified parent element. - - The OpenGL instance. - The parent element. - - - - Gets or sets the name. - - - The name. - - - - - Gets or sets a value indicating whether this instance is enabled. - - - true if this instance is enabled; otherwise, false. - - - - - The Vertex class represents a 3D point in space. - - - - - Initializes a new instance of the struct. - - The x. - The y. - The z. - - - - Initializes a new instance of the struct. - - The vertex. - - - - Sets the specified X. - - The X. - The Y. - The Z. - - - - Implements the operator +. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator -. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator *. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator *. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator *. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator *. - - The LHS. - The RHS. - - The result of the operator. - - - - - Implements the operator /. - - The LHS. - The RHS. - - The result of the operator. - - - - - This finds the Scalar Product (Dot Product) of two vectors. - - The right hand side of the equation. - A Scalar Representing the Dot-Product. - - - - Find the Vector product (cross product) of two vectors. - - The right hand side of the equation. - The Cross Product. - - - - If You use this as a Vector, then call this function to get the vector - magnitude. - - - - - - Make this vector unit length. - - - - - Normalizes this instance. - - - - - The X coordinate. - - - - - The Y coordinate. - - - - - The Z coordinate. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - This class has all the settings you can edit for lists. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - The list base. - - - - - Gets or sets the list base. - - - The list base. - - - - - The Fragment Shader. - - - - - The Shader base class. - - - - - Pops the effect off the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Sets the shader source. - - The source. - - - - Loads the shader source. - - The path to the shader file. - - - - Compiles this instance. - - - - - The internal shader object. - - - - - Gets or sets the shader object. - - - The shader object. - - - - - Gets the current OpenGL that the object exists in context. - - - - - Gets the compile status. - - - - - Gets the info log. - - - - - Gets the source code. - - - - - Initializes a new instance of the class. - - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - A Folder is used to organise scene elements. - - - - - Initializes a new instance of the class. - - - - - This takes the feedback data and turns it into triangles. - - - The number of triangles. - - - - A NURBS Surface is a two dimensional non uniform B-Spline. - - - - - The NURBS class is the base for NURBS objects, such as curves and surfaces. - - - - - This is the base class of all evaluators, 1D, 2D etc. It is also the base class - for the NURBS, as they share alot of common code, such as the VertexGrid. - - - - - A SceneElement can implement IHasObjectSpace to allow it to transform - world space into object space. - - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - Gets the transformation that pushes us into object space. - - - - - Initializes a new instance of the class. - - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The control points. - - - - - Draw points flag. - - - - - Draw lines flag. - - - - - The IHasObjectSpace helper. - - - - - Gets or sets the control points. - - - The control points. - - - - - Gets or sets a value indicating whether [draw control points]. - - - true if [draw control points]; otherwise, false. - - - - - Gets or sets a value indicating whether [draw control grid]. - - - true if [draw control grid]; otherwise, false. - - - - - Gets the transformation that pushes us into object space. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - This is the pointer to the underlying NURBS object. - - - - - The display mode. - - - - - Gets or sets the display mode. - - - The display mode. - - - - - Gets the current OpenGL that the object exists in context. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The s knots. - - - - - The t knots. - - - - - Gets the knots. - - - - - Gets the knots. - - - - - An ArcBall is an effect that pushes an arcball transformation - onto the stack. - - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pops the specified parent element. - - The OpenGL instance. - The parent element. - - - - The arcball. - - - - - Gets or sets the linear transformation. - - - The linear transformation. - - - - - A Scene Element can be volumne bound meaning that it can - participate in hit testing and various optimisations. - - - - - Gets the bounding volume. - - - - - An Asset is something which is used in the scene, but is not in the scene - tree. An example of an asset is a material, which there may be one instance - of which is shared between many objects. - - - - - Returns a that represents this instance. - - - A that represents this instance. - - - - - Gets or sets the id. - - - The id. - - - - - Gets or sets the name. - - - The name. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable normalize. - - - The enable normalize. - - - - - Gets or sets the matrix mode. - - - The matrix mode. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - A ScreenPixel, password around when raytracing. - - - - - The Quadric draw style. - - - - - Points. - - - - - Lines. - - - - - Silhouette. - - - - - Fill. - - - - - A polygon contains a set of 'faces' which are indexes into a single list - of vertices. The main thing about polygons is that they are easily editable - by the user, depending on the Context they're in. - - - - - A SceneElement can implement IRayTracable to allow it to - be raytraced. - - - - - Raytraces the specified ray. If an intersection is found, it is returned, - otherwise null is returned. - - The ray. - The scene. - The intersection with the object, or null. - - - - Scene Elements can be marked as Freezeable. If scene objects - are freezable, they can be frozen, meaning that they are locked. - Generally this means compiling the object's geometry into - a display list. - - - - - Freezes this instance using the provided OpenGL instance. - - The OpenGL instance. - - - - Unfreezes this instance using the provided OpenGL instance. - - The OpenGL instance. - - - - Gets a value indicating whether this instance is frozen. - - - true if this instance is frozen; otherwise, false. - - - - - Initializes a new instance of the class. - - - - - This function is cool, just stick in a set of points, it'll add them to the - array, and create a face. It will take account of duplicate vertices too! - - A set of vertices to make into a face. - - - - Triangulate this polygon. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - This creates a polygon from a height map (any picture). Black is low, - and the colors are high (the lighter the color, the higher the surface). - - Path of the image file. - Number of points along X. - Number of points along Y. - True if sucessful, false otherwise. - - - - This function performs lossless optimisation on the polygon, it should be - called when the geometry changes, and the polygon goes into static mode. - - The amount of optimisation (as a %). - - - - Call this function as soon as you change the polygons geometry, it will - re-generate normals, etc. - - Regenerate Normals. - - - - This function tests to see if a ray interesects the polygon. - - The ray you want to test. - - The distance from the origin of the ray to the intersection, or -1 if there - is no intersection. - - - - - Raytraces the specified ray. If an intersection is found, it is returned, - otherwise null is returned. - - The ray. - The scene. - - The intersection with the object, or null. - - - - - This function subdivides the faces of this polygon. - - If set to true the faces will be smoothed. - The number of faces in the new subdivided polygon. - - - - Freezes this instance using the provided OpenGL instance. - - The OpenGL instance. - - - - Unfreezes this instance using the provided OpenGL instance. - - The OpenGL instance. - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - Creates a new object that is a copy of the current instance. - - - A new object that is a copy of this instance. - - - - - The IHasObjectSpace helper. - - - - - The freezable helper. - - - - - The faces that make up the polygon. - - - - - The vertices that make up the polygon. - - - - - The UV coordinates (texture coodinates) for the polygon. - - - - - The normals of the polygon object. - - - - - Should the normals be drawn? - - - - - The bounding volume helper - used to ease implementation of IBoundVolume. - - - - - Gets or sets the faces. - - - The faces. - - - - - Gets or sets the vertices. - - - The vertices. - - - - - Gets or sets the U vs. - - - The U vs. - - - - - Gets or sets the normals. - - - The normals. - - - - - Gets or sets a value indicating whether [draw normals]. - - - true if [draw normals]; otherwise, false. - - - - - Gets the transformation that pushes us into object space. - - - - - Gets the bounding volume. - - - - - Gets a value indicating whether this instance is frozen. - - - true if this instance is frozen; otherwise, false. - - - - - Material to be used when rendering the polygon in lighted mode. - This material may be overriden on a per-face basis. - - - The material. - - - - - This enumeration describes the linear transformation order. - - - - - Translate > Rotate > Scale - - - - - Rotate > Translate > Scale - - - - - The LinearTransformation class represents a linear transformation, such - as a transformation that moves us from world space into object space. - - - - - Base class for transformations. - - - - - Performs the transformation on the current matrix. - - The OpenGL instance. - - - - Performs the transformation on the current matrix. - - The OpenGL instance. - - - - Creates a new object that is a copy of the current instance. - - - A new object that is a copy of this instance. - - - - - X Component of the Translation. - - - - - Y Component of the Translation. - - - - - Z Component of the Translation. - - - - - X Component of the Rotation. - - - - - Y Component of the Rotation. - - - - - Z Component of the Rotation. - - - - - X Component of the Scale. - - - - - Y Component of the Scale. - - - - - Z Component of the Scale. - - - - - The order of the linear transformation. - - - - - Gets the translation vertex. - - - - - Gets or sets the x component of the translation. - - - The x component of the translation. - - - - - Gets or sets the y component of the translation. - - - The y component of the translation. - - - - - Gets or sets the z component of the translation. - - - The z component of the translation. - - - - - Gets or sets the x component of the rotation. - - - The x component of the rotation. - - - - - Gets or sets the y component of the rotation. - - - The y component of the rotation. - - - - - Gets or sets the z component of the rotation. - - - The z component of the rotation. - - - - - Gets or sets the x component of the scale. - - - The x component of the scale. - - - - - Gets or sets the y component of the scale. - - - The y component of the scale. - - - - - Gets or sets the z component of the scale. - - - The z component of the scale. - - - - - Gets or sets the transformation order. - - - The transformation order. - - - - - An index into a set of arrays. - - - - - Initializes a new instance of the class. - - - - - This is the vertex in the polygon vertex array that the index refers to. - - - - - This is the material coord in the polygon UV array that the index refers to. - - - - - This is the index into the normal array for this vertex. A value of -1 will - generate a normal on the fly. - - - - - Gets or sets the vertex. - - - The vertex. - - - - - Gets or sets the UV. - - - The UV. - - - - - Gets or sets the normal. - - - The normal. - - - - - A particle system is, you guessed it, just a collection of particles. - - - - - Initializes a new instance of the class. - - - - - This function should create and initialise 'count' particles of the correct - type. This is done automatically by default, only override if you want - to change the standard behaviour. - - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - This function ticks the particle system. - - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - The IHasObjectSpace helper. - - - - - Gets the transformation that pushes us into object space. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - The Vertex Shader object. - - - - - Initializes a new instance of the class. - - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - A Ray. - - - - - The light. - - - - - The origin. - - - - - The direction. - - - - - The bounding helper. - - - - - The bounding volume. - - - - - Gets the bounding volume. - - - - - The LookAt camera is a camera that does a 'look at' transformation. - - - - - This camera contains the data needed to perform a Perspective transformation - to the projection matrix. - - - - - The camera class is a base for a set of derived classes for manipulating the - projection matrix. - - - - - Initializes a new instance of the class. - - - - - This function projects through the camera, to OpenGL, ie. it - creates a projection matrix. - - - - - This function is for when you simply want to call only the functions that - would transform the projection matrix. Warning, it won't load the identity - first, and it won't set the current matrix to projection, it's really for - people who need to use it for their own projection functions (e.g Picking - uses it to create a composite 'Pick' projection). - - - - - The camera position. - - - - - Every time a camera is used to project, the projection matrix calculated - and stored here. - - - - - The screen aspect ratio. - - - - - Gets or sets the position. - - - The position. - - - - - Gets or sets the aspect. - - - The aspect. - - - - - Initializes a new instance of the class. - - - - - This is the class' main function, to override this function and perform a - perspective transformation. - - - - - The field of view. - - - - - The near clip. - - - - - The far flip. - - - - - Gets or sets the field of view. - - - The field of view. - - - - - Gets or sets the near. - - - The near. - - - - - Gets or sets the far. - - - The far. - - - - - Initializes a new instance of the class. - - - - - This is the class' main function, to override this function and perform a - perspective transformation. - - - - - This is the point in the scene that the camera is pointed at. - - - - - This is a vector that describes the 'up' direction (normally 0, 0, 1). - Use this to tilt the camera. - - - - - Gets or sets the target. - - - The target. - - - - - Gets or sets up vector. - - - Up vector. - - - - - A simple cube polygon. - - - - - Initializes a new instance of the class. - - - - - This function makes a simple cube shape. - - - - - An intersection. - - - - - Is it intersected? - - - - - The normal. - - - - - The point. - - - - - The closeness. - - - - - The OpenGLAttributes are an effect that can set - any OpenGL attributes. - - - - - Initializes a new instance of the class. - - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pops the effect off the specified parent element. - - The OpenGL instance. - The parent element. - - - - Gets or sets the hint attributes. - - - The hint attributes. - - - - - Gets or sets the list attributes. - - - The list attributes. - - - - - Gets or sets the pixel mode attributes. - - - The pixel mode attributes. - - - - - Gets or sets the polygon stipple attributes. - - - The polygon stipple attributes. - - - - - Gets or sets the scissor attributes. - - - The scissor attributes. - - - - - Gets or sets the stencil buffer attributes. - - - The stencil buffer attributes. - - - - - Gets or sets the texture attributes. - - - The texture attributes. - - - - - Gets or sets the transform attributes. - - - The transform attributes. - - - - - Gets or sets the viewport attributes. - - - The viewport attributes. - - - - - Gets or sets the eval attributes. - - - The eval attributes. - - - - - Gets or sets the accum buffer attributes. - - - The accum buffer attributes. - - - - - Gets or sets the color buffer attributes. - - - The color buffer attributes. - - - - - Gets or sets the current attributes. - - - The current buffer. - - - - - Gets or sets the depth buffer attributes. - - - The depth buffer attributes. - - - - - Gets or sets the enable attributes. - - - The enable attributes. - - - - - Gets the fog attributes. - - - - - Gets the lighting attributes. - - - - - Gets the line attributes. - - - - - Gets the point attributes. - - - - - Gets the polygon attributes. - - - - - This class represent's a grid of points, just like you'd get on a NURBS - surface, or a patch. - - - - - Use this to draw the vertex grid. - - OpenGL object. - Draw each individual vertex (with selection names). - Draw the lines connecting the points. - - - - This function returns all of the control points as a float array, which - is in the format [0] = vertex 1 X, [1] = vertex 1 Y, [2] = vertex 1 Z, - [3] = vertex 2 X etc etc... This array is suitable for OpenGL functions - for evaluators and NURBS. - - An array of floats. - - - - The Scene Container is the top-level object in a scene graph. - - - - - Initializes a new instance of the class. - - - - - Gets or sets the parent scene. - - - The parent scene. - - - - - This camera contains the data needed to perform a Frustum transformation - to the projection matrix. - - - - - Initializes a new instance of the class. - - - - - This is the main function of the camera, perform a Frustrum (in this case) - transformation. - - - - - The left pos. - - - - - The right pos. - - - - - The top pos. - - - - - The bottom pos. - - - - - The near pos. - - - - - The far pos. - - - - - Gets or sets the left. - - - The left. - - - - - Gets or sets the right. - - - The right. - - - - - Gets or sets the top. - - - The top. - - - - - Gets or sets the bottom. - - - The bottom. - - - - - Gets or sets the near. - - - The near. - - - - - Gets or sets the far. - - - The far. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable depth writemask. - - - The enable depth writemask. - - - - - Gets or sets the depth clear value. - - - The depth clear value. - - - - - Gets or sets the depth function. - - - The depth function. - - - - - Gets or sets the enable depth test. - - - The enable depth test. - - - - - Pass this class any SceneObject and it'll send you back a polygon. - - - - - This is the main function of the class, it'll create a triangulated polygon - from and SceneObject. - - The gl. - The object to convert. - A camera that can see the whole object. - - A polygon created from 'sourceObject'. - - - - - A plane. - - - - - Initializes a new instance of the class. - - - - - This finds out if a point is in front of, behind, or on this plane. - - The point to classify. - - Less than 0 if behind, 0 if on, Greater than 0 if in front. - - - - - The position. - - - - - The normal. - - - - - The equation. - - - - - An object that is Bindable is able to set itself into - the current OpenGL instance. This can be lights, materials, - attributes and so on. - Bindable objects must be able to be used without interfering - with later rendering, so as well as simply being bound directly, - they must be able to be pushed and popped. - - - - - Pushes this object into the provided OpenGL instance. - This will generally push elements of the attribute stack - and then set current values. - - The OpenGL instance. - - - - Pops this object from the provided OpenGL instance. - This will generally pop elements of the attribute stack, - restoring previous attribute values. - - The OpenGL instance. - - - - Bind to the specified OpenGL instance. - Remember, this will not push or pop the attribute - stack so will affect ALL subsequent rendering. - - The OpenGL instance. - - - - A Face is a set of indices to vertices. - - - - - Initializes a new instance of the class. - - - - - Returns the plane equation (ax + by + cz + d = 0) of the face. - - The parent polygon. - An array of four coefficients a,b,c,d. - - - - Gets the surface normal. - - The parent. - - - - - This function reverses the order of the indices, i.e changes which direction - this face faces in. - - The parent polygon. - - - - This function generates normals for every vertex. - - The parent polygon. - - - - Returns a that represents this instance. - - - A that represents this instance. - - - - - The indices. - - - - - The neighbor indices. - - - - - Gets the count. - - - - - Gets or sets the indices. - - - The indices. - - - - - Gets or sets the neighbour indicies. - - - The neighbour indicies. - - - - - Gets or sets the material. - - - The material. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the polygon stipple. - - - The polygon stipple. - - - - - The Cylinder class wraps the cylinder quadric. - - - - - Quadric is the base class for all SharpGL quadric objects. - It can be interacted with and it can be rendered. - - - - - Initializes a new instance of the class. - - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Pushes us into Object Space using the transformation into the specified OpenGL instance. - - The OpenGL instance. - - - - Pops us from Object Space using the transformation into the specified OpenGL instance. - - The gl. - - - - This is the pointer to the opengl quadric object. - - - - - The draw style, can be filled, line, silouhette or points. - - - - - The IHasObjectSpace helper. - - - - - Gets or sets the quadric draw style. - - - The quadric draw style. - - - - - Gets or sets the normal orientation. - - - The normal orientation. - - - - - Gets or sets the normal generation. - - - The normal generation. - - - - - Gets or sets a value indicating whether [texture coords]. - - - true if [texture coords]; otherwise, false. - - - - - Gets the transformation that pushes us into object space. - - - - - Gets the current OpenGL that the object exists in context. - - - - - Material to be used when rendering the quadric in lighted mode. - - - The material. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Sphere data. - - - - - Top radius. - - - - - The height. - - - - - The slices. - - - - - The stacks. - - - - - Helps us implement IVolumeBound. - - - - - Gets or sets the base radius. - - - The base radius. - - - - - Gets or sets the top radius. - - - The top radius. - - - - - Gets or sets the height. - - - The height. - - - - - Gets or sets the slices. - - - The slices. - - - - - Gets or sets the stacks. - - - The stacks. - - - - - Gets the bounding volume. - - - - - This class provides a means of working with standard and opengl colours. - Use the ColorNet and ColorGL properties to set or access the colour in either - mode. - - - - - Initializes a new instance of the class. - - - - - This property allows you to access the color as if it was a .NET - color. - - - - - This property accesses the color as an opengl value. - - - - - Gets or sets the R. - - - The R. - - - - - Gets or sets the G. - - - The G. - - - - - Gets or sets the B. - - - The B. - - - - - Gets or sets the A. - - - The A. - - - - - This class has the light settings. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - The Shader base class. - - - - - Pops the effect off the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Attaches a shader. - - The shader. - - - - Detaches the shader. - - The shader. - - - - Links this instance. - - - - - Gets the uniform location. - - The name. - - - - - Sets the full shader source. - - The source. - - - - - Gets or sets the shader object. - - - The shader object. - - - - - Gets the current OpenGL that the object exists in context. - - - - - Gets the attached shaders. - - - - - Gets the compile status. - - - - - Gets the info log. - - - - - The axies objects are design time rendered primitives - that show an RGB axies at the origin of the scene. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Creates the display list. This function draws the - geometry as well as compiling it. - - - - - The internal display list. - - - - - The scene helper can be used to create scene presets, - such as designer, application, etc - - - - - Initialises a modeling scene. A modeling scene has: - - A 'Look At' camera targetting the centre of the scene - - Three gentle omnidirectional lights - - A design time grid and axis. - - The scene. - - - - This is a 1D evaluator, i.e a bezier curve. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - The points. - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The segments. - - - - - Gets or sets the segments. - - - The segments. - - - - - A Linear Transformation is an effect that pushes a linear transformation (translate, scale, rotate) - onto the stack. - - - - - Pushes the effect onto the specified parent element. - - The OpenGL instance. - The parent element. - - - - Pops the specified parent element. - - The OpenGL instance. - The parent element. - - - - The linear transformation. - - - - - Gets or sets the linear transformation. - - - The linear transformation. - - - - - The display list class basicly wraps an OpenGL display list, making them easier - to manage. Remember this class is completely OpenGL dependant. In time this class - will derive from the IOpenGLDependant interface. - - - - - This function generates the display list. You must call it before you call - anything else! - - OpenGL - - - - This function makes the display list. - - OpenGL - The mode, compile or compile and execute. - - - - This function ends the compilation of a list. - - - - - - This camera contains the data needed to perform an orthographic transformation - to the projection matrix. - - - - - Initializes a new instance of the class. - - - - - This is the main function of the class, to perform a specialised projection - in this case, an orthographic one. - - - - - The left pos. - - - - - The right pos. - - - - - The top pos. - - - - - The bottom pos. - - - - - The near pos. - - - - - The far pos. - - - - - Gets or sets the left. - - - The left. - - - - - Gets or sets the right. - - - The right. - - - - - Gets or sets the top. - - - The top. - - - - - Gets or sets the bottom. - - - The bottom. - - - - - Gets or sets the near. - - - The near. - - - - - Gets or sets the far. - - - The far. - - - - - A Texture object is simply an array of bytes. It has OpenGL functions, but is - not limited to OpenGL, so DirectX or custom library functions could be later added. - - - - - Initializes a new instance of the class. - - - - - Pushes this object into the provided OpenGL instance. - This will generally push elements of the attribute stack - and then set current values. - - The OpenGL instance. - - - - Pops this object from the provided OpenGL instance. - This will generally pop elements of the attribute stack, - restoring previous attribute values. - - The OpenGL instance. - - - - Bind to the specified OpenGL instance. - - The OpenGL instance. - - - - This function creates the underlying OpenGL object. - - - - - - - This function creates the texture from an image. - - The OpenGL object. - The image. - True if the texture was successfully loaded. - - - - This function creates the texture from an image file. - - The OpenGL object. - The path to the image file. - True if the texture was successfully loaded. - - - - This function destroys the OpenGL object that is a representation of this texture. - - - - - This function (attempts) to make a bitmap from the raw data. The fact that - the byte array is a managed type makes it slightly more complicated. - - The texture object as a Bitmap. - - - - This is an array of bytes (r, g, b, a) that represent the pixels in this - texture object. - - - - - The width of the texture image. - - - - - The height of the texture image. - - - - - This is for OpenGL textures, it is the unique ID for the OpenGL texture. - - - - - Gets the name of the texture. - - - The name of the texture. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - This is a 2D evaluator, i.e a bezier patch. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - The u. - The v. - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The segments. - - - - - Gets or sets the segments. - - - The segments. - - - - - The RenderMode enumeration is used to identify what kind - of rendering is occuring. - - - - - We are designing. - - - - - We are rendering for a hit test. - - - - - We are rendering. - - - - - The ArcBall camera supports arcball projection, making it ideal for use with a mouse. - - - - - Initializes a new instance of the class. - - - - - This is the class' main function, to override this function and perform a - perspective transformation. - - - - - The OpenGLEventArgs class. - - - - - Initializes a new instance of the class. - - The gl. - - - - The OpenGL instance. - - - - - Gets or sets the open GL. - - The open GL. - - - - The OpenGL Event Handler delegate. - - - - - A NURBS Curve is a one dimensional non uniform B-Spline. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The knots. - - - - - Gets the knots. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the color of the map. - - - The color of the map. - - - - - Gets or sets the map stencil. - - - The map stencil. - - - - - Gets or sets the index shift. - - - The index shift. - - - - - Gets or sets the index offset. - - - The index offset. - - - - - Gets or sets the red scale. - - - The red scale. - - - - - Gets or sets the green scale. - - - The green scale. - - - - - Gets or sets the blue scale. - - - The blue scale. - - - - - Gets or sets the alpha scale. - - - The alpha scale. - - - - - Gets or sets the depth scale. - - - The depth scale. - - - - - Gets or sets the red bias. - - - The red bias. - - - - - Gets or sets the green bias. - - - The green bias. - - - - - Gets or sets the blue bias. - - - The blue bias. - - - - - Gets or sets the alpha bias. - - - The alpha bias. - - - - - Gets or sets the depth bias. - - - The depth bias. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable alpha test. - - - The enable alpha test. - - - - - Gets or sets the alpha test function. - - - The alpha test function. - - - - - Gets or sets the alpha test reference value. - - - The alpha test reference value. - - - - - Gets or sets the enable blend. - - - The enable blend. - - - - - Gets or sets the blending source factor. - - - The blending source factor. - - - - - Gets or sets the blending destination factor. - - - The blending destination factor. - - - - - Gets or sets the enable dither. - - - The enable dither. - - - - - Gets or sets the draw buffer mode. - - - The draw buffer mode. - - - - - Gets or sets the enable logic op. - - - The enable logic op. - - - - - Gets or sets the logic op. - - - The logic op. - - - - - Gets or sets the color of the color mode clear. - - - The color of the color mode clear. - - - - - Gets or sets the color of the index mode clear. - - - The color of the index mode clear. - - - - - Gets or sets the color mode write mask. - - - The color mode write mask. - - - - - Gets or sets the index mode write mask. - - - The index mode write mask. - - - - - A material object is defined in mathematical terms, i.e it's not exclusivly - for OpenGL. This means later on, DirectX or custom library functions could - be added. - - - - - Initializes a new instance of the class. - - - - - Calculates the lighting. - - The light. - The angle. - - - - - Pushes this object into the provided OpenGL instance. - This will generally push elements of the attribute stack - and then set current values. - - The OpenGL instance. - - - - Pops this object from the provided OpenGL instance. - This will generally pop elements of the attribute stack, - restoring previous attribute values. - - The OpenGL instance. - - - - Bind to the specified OpenGL instance. - - The OpenGL instance. - - - - Ambient color. - - - - - Diffuse color. - - - - - Specular color. - - - - - Emission. - - - - - Shininess. - - - - - The texture. - - - - - Gets or sets the ambient. - - - The ambient. - - - - - Gets or sets the diffuse. - - - The diffuse. - - - - - Gets or sets the specular. - - - The specular. - - - - - Gets or sets the emission. - - - The emission. - - - - - Gets or sets the shininess. - - - The shininess. - - - - - Gets or sets the texture. - - - The texture. - - - - - The point settings. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - The size. - - - - - The smooth flag. - - - - - Gets or sets the size. - - - The size. - - - - - Gets or sets the smooth. - - - The smooth. - - - - - The Ray Tracer is an engine that renders a scene using the raytracing mechanism. - - - - - Renders the specified scene. - - The scene. - The camera. - - The scene rendered with raytracing. - - - - - The Sphere class wraps the sphere quadric. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - The radius. - - - - - The slices. - - - - - The stacks. - - - - - The bounding volume helper, used to aid implementation of IVolumeBound. - - - - - Gets or sets the radius. - - - The radius. - - - - - Gets or sets the slices. - - - The slices. - - - - - Gets or sets the stacks. - - - The stacks. - - - - - Gets the bounding volume. - - - - - The Quadric Normals. - - - - - None. - - - - - Flat. - - - - - Smooth. - - - - - A Light is defined purely mathematically, but works well with OpenGL. - A light is a scene element, it can be interacted with using the mouse - and it is bindable. - - - - - Initializes a new instance of the class. - - - - - Pushes this object into the provided OpenGL instance. - This will generally push elements of the attribute stack - and then set current values. - - The OpenGL instance. - - - - Pops this object from the provided OpenGL instance. - This will generally pop elements of the attribute stack, - restoring previous attribute values. - - The OpenGL instance. - - - - This function sets all of the lights parameters into OpenGL. - - The OpenGL instance. - - - - This is the OpenGL code for the light. - - - - - The ambient colour of the light. - - - - - The diffuse color of the light. - - - - - The specular colour of the light. - - - - - The colour of the shadow created by this light. - - - - - True when the light is on. - - - - - The position of the light. - - - - - Should the light cast a shadow? - - - - - Used to aid in the implementation of IVolumeBound. - - - - - Gets the bounding volume. - - - - - Gets or sets the GL code. - - - The GL code. - - - - - Gets or sets the position. - - - The position. - - - - - Gets or sets the ambient. - - - The ambient. - - - - - Gets or sets the diffuse. - - - The diffuse. - - - - - Gets or sets the specular. - - - The specular. - - - - - Gets or sets the color of the shadow. - - - The color of the shadow. - - - - - Gets or sets a value indicating whether this is on. - - - true if on; otherwise, false. - - - - - Gets or sets a value indicating whether [cast shadow]. - - - true if [cast shadow]; otherwise, false. - - - - - A texture coordinate. - - - - - Initializes a new instance of the struct. - - The u. - The v. - - - - The u value. - - - - - The v value. - - - - - Gets or sets the U. - - - The U. - - - - - Gets or sets the V. - - - The V. - - - - - Initializes a new instance of the class. - - - - - Creates the volume from vertices. - - The vertices. - - - - Creates the volume from a spherical volume. - - The centre. - The radius. - - - - Creates the volume from a cylindrical volume. - - The baseline. - The height. - The base radius. - The top radius. - - - - Pads the bounding volume. - - The padding. - - - - Gets the bound dimensions. - - The x size. - The y size. - The z size. - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - This is the main particle class, if you want specialised particles derive from it. - - - - - This function should initialise the particle so that it's ready to tick. - - The random number generator. - - - - This function moves the particle on a stage. - - The random nunber generator. - - - - This function draws the particle. - - - - - - A basic particle. - - - - - Initializes a new instance of the class. - - - - - This function initialises the basic particle. - - - - - - This function 'ticks' the particle, i.e moves it on a stage. - - A random object. - - - - This is the vertex's current position in space. - - - - - This is the velocity, do not modify! - - - - - This is the direction of the particle. - - - - - This shows the potential magnitude of the random effects of the direction. - - - - - This is the gravity affecting the particle. - - - - - Particles colour. - - - - - How much the particles colour can change by each tick. - - - - - The life left of the particle. - - - - - The lifespan of the particle. - - - - - Does the particle only exist once? - - - - - A Sphere particle. - - - - - Initializes a new instance of the class. - - - - - Draws the specified gl. - - The gl. - - - - Extensions to the OpenGL class for use with the Scene Graph types (allowing - vertices, GLColors etc to be used). - - - - - Set the current color. - - The OpenGL instance. - The color. - - - - This is a SharpGL helper version, that projects the vertex passed, using the - current matrixes. - - The gl. - The object coordinates. - - The screen coords. - - - - - Gets the model view matrix. - - The gl. - - - - - Gets the projection matrix. - - The gl. - - - - - Gets the texture matrix. - - The gl. - - - - - Vertexes the pointer. - - The gl. - The size. - The type. - The stride. - The pointer. - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable scissor test. - - - The enable scissor test. - - - - - Gets or sets the scissor X. - - - The scissor X. - - - - - Gets or sets the scissor Y. - - - The scissor Y. - - - - - Gets or sets the width of the scissor. - - - The width of the scissor. - - - - - Gets or sets the height of the scissor. - - - The height of the scissor. - - - - - This class has all the settings you can edit for fog. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable alpha test. - - - The enable alpha test. - - - - - Gets or sets the enable auto normal. - - - The enable auto normal. - - - - - Gets or sets the enable blend. - - - The enable blend. - - - - - Gets or sets the enable cull face. - - - The enable cull face. - - - - - Gets or sets the enable depth test. - - - The enable depth test. - - - - - Gets or sets the enable dither. - - - The enable dither. - - - - - Gets or sets the enable fog. - - - The enable fog. - - - - - Gets or sets the enable lighting. - - - The enable lighting. - - - - - Gets or sets the enable line smooth. - - - The enable line smooth. - - - - - Gets or sets the enable line stipple. - - - The enable line stipple. - - - - - Gets or sets the enable color logic op. - - - The enable color logic op. - - - - - Gets or sets the enable index logic op. - - - The enable index logic op. - - - - - Gets or sets the enable normalize. - - - The enable normalize. - - - - - Gets or sets the enable point smooth. - - - The enable point smooth. - - - - - Gets or sets the enable polygon offset line. - - - The enable polygon offset line. - - - - - Gets or sets the enable polygon offset fill. - - - The enable polygon offset fill. - - - - - Gets or sets the enable polygon offset point. - - - The enable polygon offset point. - - - - - Gets or sets the enable polygon smooth. - - - The enable polygon smooth. - - - - - Gets or sets the enable polygon stipple. - - - The enable polygon stipple. - - - - - Gets or sets the enable scissor test. - - - The enable scissor test. - - - - - Gets or sets the enable stencil test. - - - The enable stencil test. - - - - - Gets or sets the enable texture1 D. - - - The enable texture1 D. - - - - - Gets or sets the enable texture2 D. - - - The enable texture2 D. - - - - - This class has all the settings you can edit for current. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the color of the current. - - - The color of the current. - - - - - Gets or sets the index of the current color. - - - The index of the current color. - - - - - Gets or sets the current normal vector. - - - The current normal vector. - - - - - Gets or sets the current texture coordiate. - - - The current texture coordiate. - - - - - Gets or sets the current raster position. - - - The current raster position. - - - - - Gets or sets the color of the current raster. - - - The color of the current raster. - - - - - Gets or sets the index of the current raster color. - - - The index of the current raster color. - - - - - Gets or sets the current raster texture coordiate. - - - The current raster texture coordiate. - - - - - Gets or sets the current edge flag. - - - The current edge flag. - - - - - The Disk class wraps both the disk and partial disk quadrics. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - Gets or sets the inner radius. - - - The inner radius. - - - - - Gets or sets the outer radius. - - - The outer radius. - - - - - Gets or sets the start angle. - - - The start angle. - - - - - Gets or sets the sweep angle. - - - The sweep angle. - - - - - Gets or sets the slices. - - - The slices. - - - - - Gets or sets the loops. - - - The loops. - - - - - A Shadow object can be added as a child of a polygon. - - - - - Initializes a new instance of the class. - - - - - Render to the provided instance of OpenGL. - - The OpenGL instance. - The render mode. - - - - This function calculates the neighbours in a face. - - - - - Casts a real time 3D shadow. - - The OpenGL object. - The lights. - - - - This is part of the shadow casting code, it does a shadowpass for the - polygon using the specified light. - - The OpenGL object. - The light casting the shadow. - An array of bools. - - - - Are the face neighbours calculated? - - - - - The size of the shadow in each direction. - - - - - Gets the parent polygon. - - - - - Gets or sets the size of the shadow. - - - The size of the shadow. - - - - - A spotlight has a direction and a spot cutoff. - - - - - Initializes a new instance of the class. - - - - - This function sets all of the lights parameters into OpenGL. - - The OpenGL instance. - - - - The spotlight cutoff value (between 0-90 for spotlights, or 180 for a - simple light). - - - - - A Vector describing the direction of the spotlight. - - - - - Gets or sets the direction. - - - The direction. - - - - - Gets or sets the spot cutoff. - - - The spot cutoff. - - - - - This aids the design of the OpenGLCtrl - - - - - Initializes a new instance of the class. - - - - - Remove Control properties that are not supported by the control. - - - - - - The VertexConverter class allows you to edit vertices in the propties window. - - - - - This converts the Material Collection into something more functional. - - - - - The texture editor makes Textures in the properties window much better, - giving them a little thumbnail. - - - - - This converts the Quadric Collection into something more functional, and - allows you to add many types of quadrics. - - - - - This converts the Camera collection into something more usable (design time wise) - by allowing all the types of camera to be added. - - - - - This converts the evaluator collection into something more usable (design time wise) - by allowing all the types of evaluator to be added. - - - - - Initializes a new instance of the class. - - - - - Performs a hit test on the scene. All elements that implement IVolumeBound will - be hit tested. - - The x. - The y. - The elements hit. - - - - This function draws all of the objects in the scene (i.e. every quadric - in the quadrics arraylist etc). - - - - - Renders the element. - - The gl. - The render mode. - - - - Renders the element for hit test. - - The scene element. - The hit map. - Current hit name. - - - - Use this function to resize the scene window, and also to look through - the current camera. - - Width of the screen. - Height of the screen. - - - - Create in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - Destroy in the context of the supplied OpenGL instance. - - The OpenGL instance. - - - - This is the OpenGL class, use it to call OpenGL functions. - - - - - The main scene container - this is the top level element of the Scene Tree. - - - - - The set of scene assets. - - - - - This is the camera that is currently being used to view the scene. - - - - - This is the colour of the background of the scene. - - - - - Gets or sets the open GL. - - - The open GL. - - - - - Gets or sets the scene container. - - - The scene container. - - - - - Gets the assets. - - - - - Gets or sets the current camera. - - - The current camera. - - - - - Gets or sets the color of the clear. - - - The color of the clear. - - - - - Gets or sets a value indicating whether [render bounding volumes]. - - - true if [render bounding volumes]; otherwise, false. - - - - - Gets the current OpenGL that the object exists in context. - - - - - The OpenGL Helper is a class that provides some helper functions for working with OpenGL. - - - - - Initialises the supplied OpenGL instance for high quality rendering. - - The OpenGL instance. - - - - A 4x4 matrix. - - - - - Matrix Library .Net v2.0 By Anas Abidi, 2004. - - The Matrix Library contains Class Matrix which provides many - static methods for making various matrix operations on objects - derived from the class or on arrays defined as double. The - '+','-','*' operators are overloaded to work with the objects - derived from the matrix class. - - - - - Returns a hash code for this instance. - - - A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - - - - - The matrix. - - - - - Matrix object constructor, constructs an empty - matrix with dimensions: rows = noRows and cols = noCols. - - no. of rows in this matrix - no. of columns in this matrix - - - - Matrix object constructor, constructs a matrix from an - already defined array object. - - the array the matrix will contain - - - - Creates a matrix from a column major array. - - The column major array. - The rows. - The columns. - The matrix. - - - - Creates a matrix from a row major array. - - The column major array. - The rows. - The columns. - The matrix. - - - - Creates a matrix from a segment of another matrix. - - The RHS. - The rows. - The cols. - - - - Returns the 2D form of a 1D array. i.e. array with - dimension[n] is returned as an array with dimension [n,1]. - In case of an error the error is raised as an exception. - - - the array to convert, with dimesion [n] - - the same array but with [n,1] dimension - - - - Returns the 1D form of a 2D array. i.e. array with - dimension[n,1] is returned as an array with dimension [n]. - In case of an error the error is raised as an exception. - - - the array to convert, with dimesions [n,1] - - the same array but with [n] dimension - - - - Sets the identity matrix as the identity matrix. It must be N x N (i.e. - square). - - - - - Returns an Identity matrix with dimensions [n,n] in the from of an array. - - the no. of rows or no. cols in the matrix - An identity Matrix with dimensions [n,n] in the form of an array - - - - Returns the summation of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First array in the summation - Second array in the summation - Sum of Mat1 and Mat2 as an array - - - - Returns the summation of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First matrix in the summation - Second matrix in the summation - Sum of Mat1 and Mat2 as a Matrix object - - - - Returns the summation of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First Matrix object in the summation - Second Matrix object in the summation - Sum of Mat1 and Mat2 as a Matrix object - - - - Returns the difference of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First array in the subtraction - Second array in the subtraction - Difference of Mat1 and Mat2 as an array - - - - Returns the difference of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First matrix in the subtraction - Second matrix in the subtraction - Difference of Mat1 and Mat2 as a Matrix object - - - - Returns the difference of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First Matrix object in the subtraction - Second Matrix object in the subtraction - Difference of Mat1 and Mat2 as a Matrix object - - - - Returns the multiplication of two matrices with compatible - dimensions. - In case of an error the error is raised as an exception. - - First array in multiplication - Second array in multiplication - Mat1 multiplied by Mat2 as an array - - - - Returns the multiplication of two matrices with compatible - dimensions OR the cross-product of two vectors. - In case of an error the error is raised as an exception. - - - First matrix or vector (i.e: dimension [3,1]) object in - multiplication - - - Second matrix or vector (i.e: dimension [3,1]) object in - multiplication - - Mat1 multiplied by Mat2 as a Matrix object - - - - Returns the multiplication of two matrices with compatible - dimensions OR the cross-product of two vectors. - In case of an error the error is raised as an exception. - - - First matrix or vector (i.e: dimension [3,1]) object in - multiplication - - - Second matrix or vector (i.e: dimension [3,1]) object in - multiplication - - Mat1 multiplied by Mat2 as a Matrix object - - - - Returns the determinant of a matrix with [n,n] dimension. - In case of an error the error is raised as an exception. - - - Array with [n,n] dimension whose determinant is to be found - - Determinant of the array - - - - Returns the determinant of a matrix with [n,n] dimension. - In case of an error the error is raised as an exception. - - - Matrix object with [n,n] dimension whose determinant is to be found - - Determinant of the Matrix object - - - - Returns the inverse of a matrix with [n,n] dimension - and whose determinant is not zero. - In case of an error the error is raised as an exception. - - - Array with [n,n] dimension whose inverse is to be found - - Inverse of the array as an array - - - - Returns the inverse of a matrix with [n,n] dimension - and whose determinant is not zero. - In case of an error the error is raised as an exception. - - - Matrix object with [n,n] dimension whose inverse is to be found - - Inverse of the matrix as a Matrix object - - - - Returns the transpose of a matrix. - In case of an error the error is raised as an exception. - - Array whose transpose is to be found - Transpose of the array as an array - - - - Returns the transpose of a matrix. - In case of an error the error is raised as an exception. - - Matrix object whose transpose is to be found - Transpose of the Matrix object as a Matrix object - - - - Evaluates the Singular Value Decomposition of a matrix, - returns the matrices S, U and V. Such that a given - Matrix = U x S x V'. - In case of an error the error is raised as an exception. - Note: This method is based on the 'Singular Value Decomposition' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - Array whose SVD is to be computed - An array where the S matrix is returned - An array where the U matrix is returned - An array where the V matrix is returned - - - - Evaluates the Singular Value Decomposition of a matrix, - returns the matrices S, U and V. Such that a given - Matrix = U x S x V'. - In case of an error the error is raised as an exception. - Note: This method is based on the 'Singular Value Decomposition' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - Matrix object whose SVD is to be computed - A Matrix object where the S matrix is returned - A Matrix object where the U matrix is returned - A Matrix object where the V matrix is returned - - - - Returns the LU Decomposition of a matrix. - the output is: lower triangular matrix L, upper - triangular matrix U, and permutation matrix P so that - P*X = L*U. - In case of an error the error is raised as an exception. - Note: This method is based on the 'LU Decomposition and Its Applications' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - Array which will be LU Decomposed - An array where the lower traingular matrix is returned - An array where the upper traingular matrix is returned - An array where the permutation matrix is returned - - - - Returns the LU Decomposition of a matrix. - the output is: lower triangular matrix L, upper - triangular matrix U, and permutation matrix P so that - P*X = L*U. - In case of an error the error is raised as an exception. - Note: This method is based on the 'LU Decomposition and Its Applications' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - Matrix object which will be LU Decomposed - A Matrix object where the lower traingular matrix is returned - A Matrix object where the upper traingular matrix is returned - A Matrix object where the permutation matrix is returned - - - - Solves a set of n linear equations A.X = B, and returns - X, where A is [n,n] and B is [n,1]. - In the same manner if you need to compute: inverse(A).B, it is - better to use this method instead, as it is much faster. - In case of an error the error is raised as an exception. - Note: This method is based on the 'LU Decomposition and Its Applications' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - The array 'A' on the left side of the equations A.X = B - The array 'B' on the right side of the equations A.X = B - Array 'X' in the system of equations A.X = B - - - - Solves a set of n linear equations A.X = B, and returns - X, where A is [n,n] and B is [n,1]. - In the same manner if you need to compute: inverse(A).B, it is - better to use this method instead, as it is much faster. - In case of an error the error is raised as an exception. - Note: This method is based on the 'LU Decomposition and Its Applications' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - Matrix object 'A' on the left side of the equations A.X = B - Matrix object 'B' on the right side of the equations A.X = B - Matrix object 'X' in the system of equations A.X = B - - - - Returns the rank of a matrix. - In case of an error the error is raised as an exception. - - An array whose rank is to be found - The rank of the array - - - - Returns the rank of a matrix. - In case of an error the error is raised as an exception. - - a Matrix object whose rank is to be found - The rank of the Matrix object - - - - Returns the pseudoinverse of a matrix, such that - X = PINV(A) produces a matrix 'X' of the same dimensions - as A' so that A*X*A = A, X*A*X = X. - In case of an error the error is raised as an exception. - - An array whose pseudoinverse is to be found - The pseudoinverse of the array as an array - - - - Returns the pseudoinverse of a matrix, such that - X = PINV(A) produces a matrix 'X' of the same dimensions - as A' so that A*X*A = A, X*A*X = X. - In case of an error the error is raised as an exception. - - a Matrix object whose pseudoinverse is to be found - The pseudoinverse of the Matrix object as a Matrix Object - - - - Returns the Eigenvalues and Eigenvectors of a real symmetric - matrix, which is of dimensions [n,n]. - In case of an error the error is raised as an exception. - Note: This method is based on the 'Eigenvalues and Eigenvectors of a TridiagonalMatrix' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - - The array whose Eigenvalues and Eigenvectors are to be found - - An array where the eigenvalues are returned - An array where the eigenvectors are returned - - - - Returns the Eigenvalues and Eigenvectors of a real symmetric - matrix, which is of dimensions [n,n]. In case of an error the - error is raised as an exception. - Note: This method is based on the 'Eigenvalues and Eigenvectors of a TridiagonalMatrix' - section of Numerical Recipes in C by William H. Press, - Saul A. Teukolsky, William T. Vetterling and Brian P. Flannery, - University of Cambridge Press 1992. - - - The Matrix object whose Eigenvalues and Eigenvectors are to be found - - A Matrix object where the eigenvalues are returned - A Matrix object where the eigenvectors are returned - - - - Returns the multiplication of a matrix or a vector (i.e - dimension [3,1]) with a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to multiply the array - Array which is to be multiplied by a scalar - The multiplication of the scalar and the array as an array - - - - Returns the multiplication of a matrix or a vector (i.e - dimension [3,1]) with a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to multiply the array - Matrix which is to be multiplied by a scalar - The multiplication of the scalar and the array as an array - - - - Returns the multiplication of a matrix or a vector (i.e - dimension [3,1]) with a scalar quantity. - In case of an error the error is raised as an exception. - - Matrix object which is to be multiplied by a scalar - The scalar value to multiply the Matrix object - - The multiplication of the scalar and the Matrix object as a - Matrix object - - - - - Returns the multiplication of a matrix or a vector (i.e - dimension [3,1]) with a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to multiply the Matrix object - Matrix object which is to be multiplied by a scalar - - The multiplication of the scalar and the Matrix object as a - Matrix object - - - - - Returns the division of a matrix or a vector (i.e - dimension [3,1]) by a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to divide the array with - Array which is to be divided by a scalar - The division of the array and the scalar as an array - - - - Returns the division of a matrix or a vector (i.e - dimension [3,1]) by a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to divide the array with - Matrix which is to be divided by a scalar - The division of the array and the scalar as an array - - - - Returns the division of a matrix or a vector (i.e - dimension [3,1]) by a scalar quantity. - In case of an error the error is raised as an exception. - - The scalar value to divide the Matrix object with - Matrix object which is to be divided by a scalar - - The division of the Matrix object and the scalar as a Matrix object - - - - - Returns the cross product of two vectors whose - dimensions should be [3] or [3,1]. - In case of an error the error is raised as an exception. - - First vector array (dimension [3]) in the cross product - Second vector array (dimension [3]) in the cross product - Cross product of V1 and V2 as an array (dimension [3]) - - - - Returns the cross product of two vectors whose - dimensions should be [3] or [3x1]. - In case of an error the error is raised as an exception. - - First vector array (dimensions [3,1]) in the cross product - Second vector array (dimensions [3,1]) in the cross product - Cross product of V1 and V2 as an array (dimension [3,1]) - - - - Returns the cross product of two vectors whose - dimensions should be [3] or [3x1]. - In case of an error the error is raised as an exception. - - First Matrix (dimensions [3,1]) in the cross product - Second Matrix (dimensions [3,1]) in the cross product - Cross product of V1 and V2 as a matrix (dimension [3,1]) - - - - Returns the dot product of two vectors whose - dimensions should be [3] or [3,1]. - In case of an error the error is raised as an exception. - - First vector array (dimension [3]) in the dot product - Second vector array (dimension [3]) in the dot product - Dot product of V1 and V2 - - - - Returns the dot product of two vectors whose - dimensions should be [3] or [3,1]. - In case of an error the error is raised as an exception. - - First vector array (dimension [3,1]) in the dot product - Second vector array (dimension [3,1]) in the dot product - Dot product of V1 and V2 - - - - Returns the dot product of two vectors whose - dimensions should be [3] or [3,1]. - In case of an error the error is raised as an exception. - - First Matrix object (dimension [3,1]) in the dot product - Second Matrix object (dimension [3,1]) in the dot product - Dot product of V1 and V2 - - - - Returns the magnitude of a vector whose dimension is [3] or [3,1]. - In case of an error the error is raised as an exception. - - The vector array (dimension [3]) whose magnitude is to be found - The magnitude of the vector array - - - - Returns the magnitude of a vector whose dimension is [3] or [3,1]. - In case of an error the error is raised as an exception. - - The vector array (dimension [3,1]) whose magnitude is to be found - The magnitude of the vector array - - - - Returns the magnitude of a vector whose dimension is [3] or [3,1]. - In case of an error the error is raised as an exception. - - Matrix object (dimension [3,1]) whose magnitude is to be found - The magnitude of the Matrix object - - - - Checks if two Arrays of equal dimensions are equal or not. - In case of an error the error is raised as an exception. - - First array in equality check - Second array in equality check - If two matrices are equal or not - - - - Checks if two matrices of equal dimensions are equal or not. - In case of an error the error is raised as an exception. - - First Matrix in equality check - Second Matrix in equality check - If two matrices are equal or not - - - - Checks if two matrices of equal dimensions are equal or not. - In case of an error the error is raised as an exception. - - First Matrix object in equality check - Second Matrix object in equality check - If two matrices are equal or not - - - - Checks if two matrices of equal dimensions are not equal. - In case of an error the error is raised as an exception. - - First Matrix object in equality check - Second Matrix object in equality check - If two matrices are not equal - - - - Tests whether the specified object is a MatrixLibrary.Matrix - object and is identical to this MatrixLibrary.Matrix object. - - The object to compare with the current object - This method returns true if obj is the specified Matrix object identical to this Matrix object; otherwise, false. - - - - Returns a matrix as a string, so it can be viewed - in a multi-text textbox or in a richtextBox (preferred). - In case of an error the error is raised as an exception. - - The array to be viewed - The string view of the array - - - - Returns a matrix as a string, so it can be viewed - in a multi-text textbox or in a richtextBox (preferred). - In case of an error the error is raised as an exception. - - The Matrix object to be viewed - The string view of the Matrix object - - - - Returns the matrix as a string, so it can be viewed - in a multi-text textbox or in a richtextBox (preferred). - In case of an error the error is raised as an exception. - - The string view of the Matrix object - - - - Set or get an element from the matrix - - - - - Set or get the no. of rows in the matrix. - Warning: Setting this property will delete all of - the elements of the matrix and set them to zero. - - - - - Set or get the no. of columns in the matrix. - Warning: Setting this property will delete all of - the elements of the matrix and set them to zero. - - - - - This property returns the matrix as an array. - - - - - Gets the matrix as a row major array. - - - - - Gets the matrix as a row major array. - - - - - Gets the matrix as a column major array. - - - - - Gets the matrix as a column major array. - - - - - The polygon settings. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the enable cull face. - - - The enable cull face. - - - - - Gets or sets the enable smooth. - - - The enable smooth. - - - - - Gets or sets the cull faces. - - - The cull faces. - - - - - Gets or sets the front faces. - - - The front faces. - - - - - Gets or sets the polygon draw mode. - - - The polygon draw mode. - - - - - Gets or sets the offset factor. - - - The offset factor. - - - - - Gets or sets the offset bias. - - - The offset bias. - - - - - Gets or sets the enable offset point. - - - The enable offset point. - - - - - Gets or sets the enable offset line. - - - The enable offset line. - - - - - Gets or sets the enable offset fill. - - - The enable offset fill. - - - - - The line attributes. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the width. - - - The width. - - - - - Gets or sets the smooth. - - - The smooth. - - - - - This class has all the settings you can edit for hints. - - - - - Initializes a new instance of the class. - - - - - Sets the attributes. - - The OpenGL instance. - - - - Returns true if any attributes are set. - - - True if any attributes are set - - - - - Gets or sets the perspective correction hint. - - - The perspective correction hint. - - - - - Gets or sets the point smooth hint. - - - The point smooth hint. - - - - - Gets or sets the line smooth hint. - - - The line smooth hint. - - - - - Gets or sets the polygon smooth hint. - - - The polygon smooth hint. - - - - - Gets or sets the fog hint. - - - The fog hint. - - - - - The ArcBall camera supports arcball projection, making it ideal for use with a mouse. - - - - - Initializes a new instance of the class. - - - - - This is the class' main function, to override this function and perform a - perspective transformation. - - - - - The arcball used for rotating. - - - - - Gets the arc ball. - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.dll deleted file mode 100644 index 9a1eb4eaa9cc8de1ba7187142b57c1dfee982ca2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22016 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 RE#g}IMD#yD|NnX5e**ue;0^!) diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml deleted file mode 100644 index 7f050db4..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.Serialization.xml +++ /dev/null @@ -1,209 +0,0 @@ - - - - SharpGL.Serialization - - - - - A Format class has the functionality to load data from a certain type of file. - - - - - Load the data from the specified file stream. The data - should be loaded into a scene object. Also, for consistency - the ObjectLoaded event should be fired every time an object - (such as a polygon or material) is loaded. - - The path. - The scene or null if loading failed. - - - - Saves the scene to the specified stream. - - The scene. - The path. - True if saved correctly. - - - - This property returns an array of file types that can be used with this - format, e.g the CaligariFormat would return "cob", "scn". - - - - - This gets a filter suitable for a file open/save dialog, e.g - "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". - - - - - The SharpGL XML format. - - - - - Load the data from the specified file stream. The data - should be loaded into a scene object. Also, for consistency - the ObjectLoaded event should be fired every time an object - (such as a polygon or material) is loaded. - - The path. - - The scene or null if loading failed. - - - - - Saves the scene to the specified stream. - - The scene. - The path. - - True if saved correctly. - - - - - This property returns an array of file types that can be used with this - format, e.g the CaligariFormat would return "cob", "scn". - - - - - This gets a filter suitable for a file open/save dialog, e.g - "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". - - - - - This is the one chunk that reads no scene object, use it to skip - past unknown chunks. - - The Reader to read from. - The object that has been read. - - - - This function writes an object to the stream. - - The writer to write to. - The object to write. - - - - This function reads the chunk header. - - The Reader to read from. - - - - Writes the data. - - The writer. - The scene object. - - - - This function reads a polygon. - - - - - - - The serialization engine is a singleton that allows - scene objects and their contents to be saved and loaded. - - - - - Singleton instance. - - - - - Prevents a default instance of the class from being created. - - - - - Composes this instance. - - - - - Determines whether [is format valid for path] [the specified file format]. - - The file format. - The path. - - true if [is format valid for path] [the specified file format]; otherwise, false. - - - - - Gets the format for path. - - The path. - - - - - Loads the scene. - - The path. - - - - - Saves the scene. - - The scene. - The path. - - - - - The file formats, composed via MEF. - - - - - Gets the instance. - - - - - Gets the file formats. - - - - - Gets the filter. - - - - - This property returns an array of file types that can be used with this - format, e.g the CaligariFormat would return "cob", "scn". - - - - - This gets a filter suitable for a file open/save dialog, e.g - "Caligari trueSpace Files (*.cob, *.scn)|*.cob;*.scn". - - - - - This function reads the chunk and bangs the data in it into the scene. - - The file stream to read from. - The scene to put data into. - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLCore.2.1.0/lib/SharpGL.dll deleted file mode 100644 index 00b94b3bf44f8dac0ef0b25372285d4c7f9a597a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 355840 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

8)6XHJ8 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

- A FontOutline entry contains the details of a font face. - - - - - Gets or sets the HDC. - - - The HDC. - - - - - Gets or sets the HRC. - - - The HRC. - - - - - Gets or sets the name of the face. - - - The name of the face. - - - - - Gets or sets the height. - - - The height. - - - - - Gets or sets the list base. - - - The list base. - - - - - Gets or sets the list count. - - - The list count. - - - - - Gets or sets the deviation. - - - The deviation. - - - - - Gets or sets the extrusion. - - - The extrusion. - - - - - Gets or sets the font outline format. - - - The font outline format. - - - - - The font outline format. - - - - - Render using lines. - - - - - Render using polygons. - - - - - This class wraps the functionality of the wglUseFontOutlines function to - allow straightforward rendering of text. - - - - - Draws the text. - - The gl. - Name of the face. - Size of the font. - The deviation. - The extrusion. - The text. - - - - The cache of font outline entries. - - - - - The OpenGL class wraps Suns OpenGL 3D library. - - - - - Treats each vertex as a single point. Vertex n defines point n. N points are drawn. - - - - - Treats each pair of vertices as an independent line segment. Vertices 2n - 1 and 2n define line n. N/2 lines are drawn. - - - - - Draws a connected group of line segments from the first vertex to the last, then back to the first. Vertices n and n + 1 define line n. The last line, however, is defined by vertices N and 1. N lines are drawn. - - - - - Draws a connected group of line segments from the first vertex to the last. Vertices n and n+1 define line n. N - 1 lines are drawn. - - - - - Treats each triplet of vertices as an independent triangle. Vertices 3n - 2, 3n - 1, and 3n define triangle n. N/3 triangles are drawn. - - - - - Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices. For odd n, vertices n, n + 1, and n + 2 define triangle n. For even n, vertices n + 1, n, and n + 2 define triangle n. N - 2 triangles are drawn. - - - - - Draws a connected group of triangles. one triangle is defined for each vertex presented after the first two vertices. Vertices 1, n + 1, n + 2 define triangle n. N - 2 triangles are drawn. - - - - - Treats each group of four vertices as an independent quadrilateral. Vertices 4n - 3, 4n - 2, 4n - 1, and 4n define quadrilateral n. N/4 quadrilaterals are drawn. - - - - - Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertices presented after the first pair. Vertices 2n - 1, 2n, 2n + 2, and 2n + 1 define quadrilateral n. N/2 - 1 quadrilaterals are drawn. Note that the order in which vertices are used to construct a quadrilateral from strip data is different from that used with independent data. - - - - - Draws a single, convex polygon. Vertices 1 through N define this polygon. - - - - - Determines whether a named extension function is supported. - - Name of the extension function. - - true if the extension function is supported; otherwise, false. - - - - - Invokes an extension function. - - The extension delegate type. - The arguments to the pass to the function. - The return value of the extension function. - - - - The set of extension functions. - - - - - Specify a three-dimensional texture subimage. - - The target. - The level. - The internalformat. - The width. - The height. - The depth. - The border. - The format. - The type. - The pixels. - - - - Texes the sub image3 DEXT. - - The target. - The level. - The xoffset. - The yoffset. - The zoffset. - The width. - The height. - The depth. - The format. - The type. - The pixels. - - - - Render primitives from array data. - - The mode. - The start. - The end. - The count. - The type. - The indices. - - - - Set the Accumulation Buffer operation. - - Operation of the buffer. - Reference value. - - - - Set the Accumulation Buffer operation. - - Operation of the buffer. - Reference value. - - - - Specify the Alpha Test function. - - Specifies the alpha comparison function. Symbolic constants OpenGL.NEVER, OpenGL.LESS, OpenGL.EQUAL, OpenGL.LEQUAL, OpenGL.GREATER, OpenGL.NOTEQUAL, OpenGL.GEQUAL and OpenGL.ALWAYS are accepted. The initial value is OpenGL.ALWAYS. - Specifies the reference value that incoming alpha values are compared to. This value is clamped to the range 0 through 1, where 0 represents the lowest possible alpha value and 1 the highest possible value. The initial reference value is 0. - - - - Specify the Alpha Test function. - - Specifies the alpha comparison function. - Specifies the reference value that incoming alpha values are compared to. This value is clamped to the range 0 through 1, where 0 represents the lowest possible alpha value and 1 the highest possible value. The initial reference value is 0. - - - - Determine if textures are loaded in texture memory. - - Specifies the number of textures to be queried. - Specifies an array containing the names of the textures to be queried. - Specifies an array in which the texture residence status is returned. The residence status of a texture named by an element of textures is returned in the corresponding element of residences. - - - - - Render a vertex using the specified vertex array element. - - Specifies an index into the enabled vertex data arrays. - - - - Begin drawing geometry in the specified mode. - - The mode to draw in, e.g. OpenGL.POLYGONS. - - - - Begin drawing geometry in the specified mode. - - The mode to draw in, e.g. OpenGL.POLYGONS. - - - - This function begins drawing a NURBS curve. - - The NURBS object. - - - - This function begins drawing a NURBS surface. - - The NURBS object. - - - - Call this function after creating a texture to finalise creation of it, - or to make an existing texture current. - - The target type, e.g TEXTURE_2D. - The OpenGL texture object. - - - - Draw a bitmap. - - Specify the pixel width of the bitmap image. - Specify the pixel height of the bitmap image. - Specify the location of the origin in the bitmap image. The origin is measured from the lower left corner of the bitmap, with right and up being the positive axes. - Specify the location of the origin in the bitmap image. The origin is measured from the lower left corner of the bitmap, with right and up being the positive axes. - Specify the x and y offsets to be added to the current raster position after the bitmap is drawn. - Specify the x and y offsets to be added to the current raster position after the bitmap is drawn. - Specifies the address of the bitmap image. - - - - This function sets the current blending function. - - Source factor. - Destination factor. - - - - This function sets the current blending function. - - The source factor. - The destination factor. - - - - This function calls a certain display list. - - The display list to call. - - - - Execute a list of display lists. - - Specifies the number of display lists to be executed. - Specifies the type of values in lists. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT, OpenGL.2_BYTES, OpenGL.3_BYTES and OpenGL.4_BYTES are accepted. - Specifies the address of an array of name offsets in the display list. The pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of type. - - - - Execute a list of display lists. - - Specifies the number of display lists to be executed. - Specifies the type of values in lists. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT, OpenGL.2_BYTES, OpenGL.3_BYTES and OpenGL.4_BYTES are accepted. - Specifies the address of an array of name offsets in the display list. The pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of type. - - - - Execute a list of display lists. Automatically uses the GL_UNSIGNED_BYTE version of the function. - - The number of lists. - The lists. - - - - Execute a list of display lists. Automatically uses the GL_UNSIGNED_INT version of the function. - - The number of lists. - The lists. - - - - This function clears the buffers specified by mask. - - Which buffers to clear. - - - - Specify clear values for the accumulation buffer. - - Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. - Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. - Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. - Specify the red, green, blue and alpha values used when the accumulation buffer is cleared. The initial values are all 0. - - - - This function sets the color that the drawing buffer is 'cleared' to. - - Red component of the color (between 0 and 1). - Green component of the color (between 0 and 1). - Blue component of the color (between 0 and 1)./ - Alpha component of the color (between 0 and 1). - - - - Specify the clear value for the depth buffer. - - Specifies the depth value used when the depth buffer is cleared. The initial value is 1. - - - - Specify the clear value for the color index buffers. - - Specifies the index used when the color index buffers are cleared. The initial value is 0. - - - - Specify the clear value for the stencil buffer. - - Specifies the index used when the stencil buffer is cleared. The initial value is 0. - - - - Specify a plane against which all geometry is clipped. - - Specifies which clipping plane is being positioned. Symbolic names of the form OpenGL.CLIP_PLANEi, where i is an integer between 0 and OpenGL.MAX_CLIP_PLANES -1, are accepted. - Specifies the address of an array of four double-precision floating-point values. These values are interpreted as a plane equation. - - - - Specify a plane against which all geometry is clipped. - - Specifies which clipping plane is being positioned. Symbolic names of the form OpenGL.CLIP_PLANEi, where i is an integer between 0 and OpenGL.MAX_CLIP_PLANES -1, are accepted. - Specifies the address of an array of four double-precision floating-point values. These values are interpreted as a plane equation. - - - - Sets the current color. - - Red color component (between 0 and 255). - Green color component (between 0 and 255). - Blue color component (between 0 and 255). - - - - Sets the current color. - - Red color component (between 0 and 255). - Green color component (between 0 and 255). - Blue color component (between 0 and 255). - Alpha color component (between 0 and 255). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color to 'v'. - - An array of either 3 or 4 float values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 int values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 int values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 double values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 byte values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 unsigned int values. - - - - Sets the current color to 'v'. - - An array of either 3 or 4 unsigned short values. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component. - - - - Sets the current color. - - Red color component (between 0 and 1). - Green color component (between 0 and 1). - Blue color component (between 0 and 1). - Alpha color component (between 0 and 1). - - - - This function sets the current colour mask. - - Red component mask. - Green component mask. - Blue component mask. - Alpha component mask. - - - - Cause a material color to track the current color. - - Specifies whether front, back, or both front and back material parameters should track the current color. Accepted values are OpenGL.FRONT, OpenGL.BACK, and OpenGL.FRONT_AND_BACK. The initial value is OpenGL.FRONT_AND_BACK. - Specifies which of several material parameters track the current color. Accepted values are OpenGL.EMISSION, OpenGL.AMBIENT, OpenGL.DIFFUSE, OpenGL.SPECULAR and OpenGL.AMBIENT_AND_DIFFUSE. The initial value is OpenGL.AMBIENT_AND_DIFFUSE. - - - - Define an array of colors. - - Specifies the number of components per color. Must be 3 or 4. - Specifies the data type of each color component in the array. Symbolic constants OpenGL.BYTE, OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.UNSIGNED_SHORT, OpenGL.INT, OpenGL.UNSIGNED_INT, OpenGL.FLOAT and OpenGL.DOUBLE are accepted. - Specifies the byte offset between consecutive colors. If stride is 0, (the initial value), the colors are understood to be tightly packed in the array. - Specifies a pointer to the first component of the first color element in the array. - - - - Copy pixels in the frame buffer. - - Specify the window coordinates of the lower left corner of the rectangular region of pixels to be copied. - Specify the window coordinates of the lower left corner of the rectangular region of pixels to be copied. - Specify the dimensions of the rectangular region of pixels to be copied. Both must be nonnegative. - Specify the dimensions of the rectangular region of pixels to be copied. Both must be nonnegative. - Specifies whether color values, depth values, or stencil values are to be copied. Symbolic constants OpenGL.COLOR, OpenGL.DEPTH, and OpenGL.STENCIL are accepted. - - - - Copy pixels into a 1D texture image. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the internal format of the texture. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specifies the width of the texture image. Must be 0 or 2^n = (2 * border) for some integer n. The height of the texture image is 1. - Specifies the width of the border. Must be either 0 or 1. - - - - Copy pixels into a 2D texture image. - - Specifies the target texture. Must be OpenGL.TEXTURE_2D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the internal format of the texture. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specifies the width of the texture image. - Specifies the height of the texture image. - Specifies the width of the border. Must be either 0 or 1. - - - - Copy a one-dimensional texture subimage. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the texel offset within the texture array. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specifies the width of the texture image. - - - - Copy a two-dimensional texture subimage. - - Specifies the target texture. Must be OpenGL.TEXTURE_2D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the texel offset within the texture array. - Specifies the texel offset within the texture array. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specify the window coordinates of the left corner of the row of pixels to be copied. - Specifies the width of the texture image. - Specifies the height of the texture image. - - - - Specify whether front- or back-facing facets can be culled. - - Specifies whether front- or back-facing facets are candidates for culling. Symbolic constants OpenGL.FRONT, OpenGL.BACK, and OpenGL.FRONT_AND_BACK are accepted. The initial value is OpenGL.BACK. - - - - This function draws a sphere from the quadric object. - - The quadric object. - Radius at the base. - Radius at the top. - Height of cylinder. - Cylinder slices. - Cylinder stacks. - - - - This function deletes a list, or a range of lists. - - The list to delete. - The range of lists (often just 1). - - - - This function deletes the underlying glu nurbs renderer. - - The pointer to the nurbs object. - - - - This function deletes a set of Texture objects. - - Number of textures to delete. - The array containing the names of the textures to delete. - - - - Call this function to delete an OpenGL Quadric object. - - - - - - This function sets the current depth buffer comparison function, the default it LESS. - - The comparison function to set. - - - - This function sets the current depth buffer comparison function, the default it LESS. - - The comparison function to set. - - - - This function sets the depth mask. - - The depth mask flag, normally 1. - - - - Specify mapping of depth values from normalized device coordinates to window coordinates. - - Specifies the mapping of the near clipping plane to window coordinates. The initial value is 0. - Specifies the mapping of the near clipping plane to window coordinates. The initial value is 1. - - - - Call this function to disable an OpenGL capability. - - The capability to disable. - - - - This function disables a client state array, such as a vertex array. - - The array to disable. - - - - Render primitives from array data. - - Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. - Specifies the starting index in the enabled arrays. - Specifies the number of indices to be rendered. - - - - Specify which color buffers are to be drawn into. - - Specifies up to four color buffers to be drawn into. Symbolic constants OpenGL.NONE, OpenGL.FRONT_LEFT, OpenGL.FRONT_RIGHT, OpenGL.BACK_LEFT, OpenGL.BACK_RIGHT, OpenGL.FRONT, OpenGL.BACK, OpenGL.LEFT, OpenGL.RIGHT, OpenGL.FRONT_AND_BACK, and OpenGL.AUXi, where i is between 0 and (OpenGL.AUX_BUFFERS - 1), are accepted (OpenGL.AUX_BUFFERS is not the upper limit; use glGet to query the number of available aux buffers.) The initial value is OpenGL.FRONT for single- buffered contexts, and OpenGL.BACK for double-buffered contexts. - - - - Specify which color buffers are to be drawn into. - - Specifies up to four color buffers to be drawn into. - - - - Render primitives from array data. - - Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. - Specifies the number of elements to be rendered. - Specifies a pointer to the location where the indices are stored. - - - - Render primitives from array data. - - Specifies what kind of primitives to render. Symbolic constants OpenGL.POINTS, OpenGL.LINE_STRIP, OpenGL.LINE_LOOP, OpenGL.LINES, OpenGL.TRIANGLE_STRIP, OpenGL.TRIANGLE_FAN, OpenGL.TRIANGLES, OpenGL.QUAD_STRIP, OpenGL.QUADS, and OpenGL.POLYGON are accepted. - Specifies the number of elements to be rendered. - Specifies the type of the values in indices. Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.UNSIGNED_SHORT, or OpenGL.UNSIGNED_INT. - Specifies a pointer to the location where the indices are stored. - - - - Draws a rectangle of pixel data at the current raster position. - - Width of pixel data. - Height of pixel data. - Format of pixel data. - Pixel data buffer. - - - - Draws a rectangle of pixel data at the current raster position. - - Width of pixel data. - Height of pixel data. - Format of pixel data. - Pixel data buffer. - - - - Draws a rectangle of pixel data at the current raster position. - - Width of pixel data. - Height of pixel data. - Format of pixel data. - Pixel data buffer. - - - - Draws a rectangle of pixel data at the current raster position. - - Width of pixel data. - Height of pixel data. - Format of pixel data. - Pixel data buffer. - - - - Draws a rectangle of pixel data at the current raster position. - - Width of pixel data. - Height of pixel data. - Format of pixel data. - The GL data type. - Pixel data buffer. - - - - Flag edges as either boundary or nonboundary. - - Specifies the current edge flag value, either OpenGL.TRUE or OpenGL.FALSE. The initial value is OpenGL.TRUE. - - - - Define an array of edge flags. - - Specifies the byte offset between consecutive edge flags. If stride is 0 (the initial value), the edge flags are understood to be tightly packed in the array. - Specifies a pointer to the first edge flag in the array. - - - - Flag edges as either boundary or nonboundary. - - Specifies a pointer to an array that contains a single boolean element, which replaces the current edge flag value. - - - - Call this function to enable an OpenGL capability. - - The capability you wish to enable. - - - - This function enables one of the client state arrays, such as a vertex array. - - The array to enable. - - - - This is not an imported OpenGL function, but very useful. If 'test' is - true, cap is enabled, otherwise, it's disable. - - The capability you want to enable. - The logical comparison. - - - - Signals the End of drawing. - - - - - This function ends the drawing of a NURBS curve. - - The nurbs object. - - - - Ends the current display list compilation. - - - - - This function ends the drawing of a NURBS surface. - - The nurbs object. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - Domain coordinate. - - - - Evaluate from the current evaluator. - - Domain coordinate. - - - - Evaluates a 'mesh' from the current evaluators. - - Drawing mode, can be POINT or LINE. - Beginning of range. - End of range. - - - - Evaluates a 'mesh' from the current evaluators. - - Drawing mode, fill, point or line. - Beginning of range. - End of range. - Beginning of range. - End of range. - - - - Generate and evaluate a single point in a mesh. - - The integer value for grid domain variable i. - - - - Generate and evaluate a single point in a mesh. - - The integer value for grid domain variable i. - The integer value for grid domain variable j. - - - - This function sets the feedback buffer, that will receive feedback data. - - Size of the buffer. - Type of data in the buffer. - The buffer itself. - - - - This function is similar to flush, but in a sense does it more, as it - executes all commands aon both the client and the server. - - - - - This forces OpenGL to execute any commands you have given it. - - - - - Sets a fog parameter. - - The parameter to set. - The value to set it to. - - - - Sets a fog parameter. - - The parameter to set. - The values to set it to. - - - - Sets a fog parameter. - - The parameter to set. - The value to set it to. - - - - Sets a fog parameter. - - The parameter to set. - The values to set it to. - - - - This function sets what defines a front face. - - Winding mode, counter clockwise by default. - - - - This function creates a frustrum transformation and mulitplies it to the current - matrix (which in most cases should be the projection matrix). - - Left clip position. - Right clip position. - Bottom clip position. - Top clip position. - Near clip position. - Far clip position. - - - - This function generates 'range' number of contiguos display list indices. - - The number of lists to generate. - The first list. - - - - Create a set of unique texture names. - - Number of names to create. - Array to store the texture names. - - - - This function queries OpenGL for data, and puts it in the buffer supplied. - - The parameter to query. - - - - - This function queries OpenGL for data, and puts it in the buffer supplied. - - The parameter to query. - - - - - Return the coefficients of the specified clipping plane. - - Specifies a clipping plane. The number of clipping planes depends on the implementation, but at least six clipping planes are supported. They are identified by symbolic names of the form OpenGL.CLIP_PLANEi where 0 Less Than i Less Than OpenGL.MAX_CLIP_PLANES. - Returns four double-precision values that are the coefficients of the plane equation of plane in eye coordinates. The initial value is (0, 0, 0, 0). - - - - This function queries OpenGL for data, and puts it in the buffer supplied. - - The parameter to query. - The buffer to put that data into. - - - - This function queries OpenGL for data, and puts it in the buffer supplied. - - The parameter to query. - The buffer to put that data into. - - - - Get the current OpenGL error code. - - The current OpenGL error code. - - - - Get the current OpenGL error code. - - The current OpenGL error code. - - - - This this function to query OpenGL values. - - The parameter to query. - The parameters - - - - This this function to query OpenGL values. - - The parameter to query. - The parameters - - - - Use this function to query OpenGL parameter values. - - The Parameter to query - An array to put the values into. - - - - Use this function to query OpenGL parameter values. - - The Parameter to query - An array to put the values into. - - - - Return light source parameter values. - - Specifies a light source. The number of possible lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form OpenGL.LIGHTi where i ranges from 0 to the value of OpenGL.GL_MAX_LIGHTS - 1. - Specifies a light source parameter for light. - Returns the requested data. - - - - Return light source parameter values. - - Specifies a light source. The number of possible lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form OpenGL.LIGHTi where i ranges from 0 to the value of OpenGL.GL_MAX_LIGHTS - 1. - Specifies a light source parameter for light. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return evaluator parameters. - - Specifies the symbolic name of a map. - Specifies which parameter to return. - Returns the requested data. - - - - Return material parameters. - - Specifies which of the two materials is being queried. OpenGL.FRONT or OpenGL.BACK are accepted, representing the front and back materials, respectively. - Specifies the material parameter to return. - Returns the requested data. - - - - Return material parameters. - - Specifies which of the two materials is being queried. OpenGL.FRONT or OpenGL.BACK are accepted, representing the front and back materials, respectively. - Specifies the material parameter to return. - Returns the requested data. - - - - Return the specified pixel map. - - Specifies the name of the pixel map to return. - Returns the pixel map contents. - - - - Return the specified pixel map. - - Specifies the name of the pixel map to return. - Returns the pixel map contents. - - - - Return the specified pixel map. - - Specifies the name of the pixel map to return. - Returns the pixel map contents. - - - - Return the address of the specified pointer. - - Specifies the array or buffer pointer to be returned. - Returns the pointer value specified by parameters. - - - - Return the polygon stipple pattern. - - Returns the stipple pattern. The initial value is all 1's. - - - - Return a string describing the current GL connection. - - Specifies a symbolic constant, one of OpenGL.VENDOR, OpenGL.RENDERER, OpenGL.VERSION, or OpenGL.EXTENSIONS. - Pointer to the specified string. - - - - Return texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE, and OpenGL.TEXTURE_ENV_COLOR. - Returns the requested data. - - - - Return texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE, and OpenGL.TEXTURE_ENV_COLOR. - Returns the requested data. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Return a texture image. - - Specifies which texture is to be obtained. OpenGL.TEXTURE_1D and OpenGL.TEXTURE_2D are accepted. - Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies a pixel format for the returned data. - Specifies a pixel type for the returned data. - Returns the texture image. Should be a pointer to an array of the type specified by type. - - - - Return texture parameter values for a specific level of detail. - - Specifies the symbolic name of the target texture. - Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the symbolic name of a texture parameter. - Returns the requested data. - - - - Return texture parameter values for a specific level of detail. - - Specifies the symbolic name of the target texture. - Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies the symbolic name of a texture parameter. - Returns the requested data. - - - - Return texture parameter values. - - Specifies the symbolic name of the target texture. - Specifies the symbolic name of a texture parameter. - Returns the texture parameters. - - - - Return texture parameter values. - - Specifies the symbolic name of the target texture. - Specifies the symbolic name of a texture parameter. - Returns the texture parameters. - - - - Specify implementation-specific hints. - - Specifies a symbolic constant indicating the behavior to be controlled. - Specifies a symbolic constant indicating the desired behavior. - - - - Specify implementation-specific hints. - - Specifies a symbolic constant indicating the behavior to be controlled. - Specifies a symbolic constant indicating the desired behavior. - - - - Control the writing of individual bits in the color index buffers. - - Specifies a bit mask to enable and disable the writing of individual bits in the color index buffers. Initially, the mask is all 1's. - - - - Define an array of color indexes. - - Specifies the data type of each color index in the array. Symbolic constants OpenGL.UNSIGNED_BYTE, OpenGL.SHORT, OpenGL.INT, OpenGL.FLOAT, and OpenGL.DOUBLE are accepted. - Specifies the byte offset between consecutive color indexes. If stride is 0 (the initial value), the color indexes are understood to be tightly packed in the array. - Specifies a pointer to the first index in the array. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - Set the current color index. - - Specifies the new value for the current color index. - - - - This function initialises the select buffer names. - - - - - Simultaneously specify and enable several interleaved arrays. - - Specifies the type of array to enable. - Specifies the offset in bytes between each aggregate array element. - The array. - - - - Use this function to query if a certain OpenGL function is enabled or not. - - The capability to test. - True if the capability is enabled, otherwise, false. - - - - This function determines whether a specified value is a display list. - - The value to test. - TRUE if it is a list, FALSE otherwise. - - - - Determine if a name corresponds to a texture. - - Specifies a value that may be the name of a texture. - True if texture is a texture object. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - This function sets a parameter of the lighting model. - - The name of the parameter. - The parameter to set it to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The value that you want to set the parameter to. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The parameters. - - - - Set the parameter (pname) of the light 'light'. - - The light you wish to set parameters for. - The parameter you want to set. - The parameters. - - - - Specify the line stipple pattern. - - Specifies a multiplier for each bit in the line stipple pattern. If factor is 3, for example, each bit in the pattern is used three times before the next bit in the pattern is used. factor is clamped to the range [1, 256] and defaults to 1. - Specifies a 16-bit integer whose bit pattern determines which fragments of a line will be drawn when the line is rasterized. Bit zero is used first; the default pattern is all 1's. - - - - Set's the current width of lines. - - New line width to set. - - - - Set the display-list base for glCallLists. - - Specifies an integer offset that will be added to glCallLists offsets to generate display-list names. The initial value is 0. - - - - Call this function to load the identity matrix into the current matrix stack. - - - - - Replace the current matrix with the specified matrix. - - Specifies a pointer to 16 consecutive values, which are used as the elements of a 4x4 column-major matrix. - - - - Replace the current matrix with the specified matrix. - - Specifies a pointer to 16 consecutive values, which are used as the elements of a 4x4 column-major matrix. - - - - This function replaces the name at the top of the selection names stack - with 'name'. - - The name to replace it with. - - - - Specify a logical pixel operation for color index rendering. - - Specifies a symbolic constant that selects a logical operation. - - - - Specify a logical pixel operation for color index rendering. - - Specifies a symbolic constant that selects a logical operation. - - - - This function transforms the projection matrix so that it looks at a certain - point, from a certain point. - - Position of the eye. - Position of the eye. - Position of the eye. - Point to look at. - Point to look at. - Point to look at. - 'Up' Vector X Component. - 'Up' Vector Y Component. - 'Up' Vector Z Component. - - - - Defines a 1D evaluator. - - What the control points represent (e.g. MAP1_VERTEX_3). - Range of the variable 'u'. - Range of the variable 'u'. - Offset between beginning of one control point, and beginning of next. - The degree plus one, should agree with the number of control points. - The data for the points. - - - - Defines a 1D evaluator. - - What the control points represent (e.g. MAP1_VERTEX_3). - Range of the variable 'u'. - Range of the variable 'u'. - Offset between beginning of one control point, and beginning of next. - The degree plus one, should agree with the number of control points. - The data for the points. - - - - Defines a 2D evaluator. - - What the control points represent (e.g. MAP2_VERTEX_3). - Range of the variable 'u'. - Range of the variable 'u. - Offset between beginning of one control point and the next. - The degree plus one. - Range of the variable 'v'. - Range of the variable 'v'. - Offset between beginning of one control point and the next. - The degree plus one. - The data for the points. - - - - Defines a 2D evaluator. - - What the control points represent (e.g. MAP2_VERTEX_3). - Range of the variable 'u'. - Range of the variable 'u. - Offset between beginning of one control point and the next. - The degree plus one. - Range of the variable 'v'. - Range of the variable 'v'. - Offset between beginning of one control point and the next. - The degree plus one. - The data for the points. - - - - This function defines a grid that goes from u1 to u1 in n steps, evenly spaced. - - Number of steps. - Range of variable 'u'. - Range of variable 'u'. - - - - This function defines a grid that goes from u1 to u1 in n steps, evenly spaced. - - Number of steps. - Range of variable 'u'. - Range of variable 'u'. - - - - This function defines a grid that goes from u1 to u1 in n steps, evenly spaced, - and the same for v. - - Number of steps. - Range of variable 'u'. - Range of variable 'u'. - Number of steps. - Range of variable 'v'. - Range of variable 'v'. - - - - This function defines a grid that goes from u1 to u1 in n steps, evenly spaced, - and the same for v. - - Number of steps. - Range of variable 'u'. - Range of variable 'u'. - Number of steps. - Range of variable 'v'. - Range of variable 'v'. - - - - This function sets a material parameter. - - What faces is this parameter for (i.e front/back etc). - What parameter you want to set. - The value to set 'pname' to. - - - - This function sets a material parameter. - - What faces is this parameter for (i.e front/back etc). - What parameter you want to set. - The value to set 'pname' to. - - - - This function sets a material parameter. - - What faces is this parameter for (i.e front/back etc). - What parameter you want to set. - The value to set 'pname' to. - - - - This function sets a material parameter. - - What faces is this parameter for (i.e front/back etc). - What parameter you want to set. - The value to set 'pname' to. - - - - Set the current matrix mode (the matrix that matrix operations will be - performed on). - - The mode, normally PROJECTION or MODELVIEW. - - - - Set the current matrix mode (the matrix that matrix operations will be - performed on). - - The mode, normally PROJECTION or MODELVIEW. - - - - Multiply the current matrix with the specified matrix. - - Points to 16 consecutive values that are used as the elements of a 4x4 column-major matrix. - - - - Multiply the current matrix with the specified matrix. - - Points to 16 consecutive values that are used as the elements of a 4x4 column-major matrix. - - - - This function starts compiling a new display list. - - The list to compile. - Either COMPILE or COMPILE_AND_EXECUTE. - - - - This function creates a new glu NURBS renderer object. - - A Pointer to the NURBS renderer. - - - - This function creates a new OpenGL Quadric Object. - - The pointer to the Quadric Object. - - - - Set the current normal. - - Normal Coordinate. - Normal Coordinate. - Normal Coordinate. - - - - This function sets the current normal. - - The normal. - - - - Set the current normal. - - Normal Coordinate. - Normal Coordinate. - Normal Coordinate. - - - - This function sets the current normal. - - The normal. - - - - Set the current normal. - - Normal Coordinate. - Normal Coordinate. - Normal Coordinate. - - - - This function sets the current normal. - - The normal. - - - - Set the current normal. - - Normal Coordinate. - Normal Coordinate. - Normal Coordinate. - - - - This function sets the current normal. - - The normal. - - - - Set the current normal. - - Normal Coordinate. - Normal Coordinate. - Normal Coordinate. - - - - This function sets the current normal. - - The normal. - - - - Set's the pointer to the normal array. - - The type of data. - The space in bytes between each normal. - The normals. - - - - Set's the pointer to the normal array. - - The type of data. - The space in bytes between each normal. - The normals. - - - - This function defines a NURBS Curve. - - The NURBS object. - The number of knots. - The knots themselves. - The stride, i.e. distance between vertices in the - control points array. - The array of control points. - The order of the polynomial. - The type of data to generate. - - - - This function sets a NURBS property. - - The object to set the property for. - The property to set. - The new value of the property. - - - - This function defines a NURBS surface. - - The NURBS object. - The sknots count. - The s-knots. - The number of t-knots. - The t-knots. - The distance between s vertices. - The distance between t vertices. - The control points. - The order of the s polynomial. - The order of the t polynomial. - The type of data to generate. - - - - This function creates an orthographic projection matrix (i.e one with no - perspective) and multiplies it to the current matrix stack, which would - normally be 'PROJECTION'. - - Left clipping plane. - Right clipping plane. - Bottom clipping plane. - Top clipping plane. - Near clipping plane. - Far clipping plane. - - - - This function creates an orthographic project based on a screen size. - - Left of the screen. (Normally 0). - Right of the screen.(Normally width). - Bottom of the screen (normally 0). - Top of the screen (normally height). - - - - This function draws a partial disk from the quadric object. - - The Quadric objec.t - Radius of the inside of the disk. - Radius of the outside of the disk. - The slices. - The loops. - Starting angle. - Sweep angle. - - - - Place a marker in the feedback buffer. - - Specifies a marker value to be placed in the feedback buffer following a OpenGL.PASS_THROUGH_TOKEN. - - - - This function creates a perspective matrix and multiplies it to the current - matrix stack (which in most cases should be 'PROJECTION'). - - Field of view angle (human eye = 60 Degrees). - Apsect Ratio (width of screen divided by height of screen). - Near clipping plane (normally 1). - Far clipping plane. - - - - This function creates a 'pick matrix' normally used for selecting objects that - are at a certain point on the screen. - - X Point. - Y Point. - Width of point to test (4 is normal). - Height of point to test (4 is normal). - The current viewport. - - - - Set up pixel transfer maps. - - Specifies a symbolic map name. - Specifies the size of the map being defined. - Specifies an array of mapsize values. - - - - Set up pixel transfer maps. - - Specifies a symbolic map name. - Specifies the size of the map being defined. - Specifies an array of mapsize values. - - - - Set up pixel transfer maps. - - Specifies a symbolic map name. - Specifies the size of the map being defined. - Specifies an array of mapsize values. - - - - Set pixel storage modes. - - Specifies the symbolic name of the parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel storage modes. - - Specifies the symbolic name of the parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Set pixel transfer modes. - - Specifies the symbolic name of the pixel transfer parameter to be set. - Specifies the value that pname is set to. - - - - Specify the pixel zoom factors. - - Specify the x and y zoom factors for pixel write operations. - Specify the x and y zoom factors for pixel write operations. - - - - The size of points to be rasterised. - - Size in pixels. - - - - This sets the current drawing mode of polygons (points, lines, filled). - - The faces this applies to (front, back or both). - The mode to set to (points, lines, or filled). - - - - This sets the current drawing mode of polygons (points, lines, filled). - - The faces this applies to (front, back or both). - The mode to set to (points, lines, or filled). - - - - Set the scale and units used to calculate depth values. - - Specifies a scale factor that is used to create a variable depth offset for each polygon. The initial value is 0. - Is multiplied by an implementation-specific value to create a constant depth offset. The initial value is 0. - - - - Set the polygon stippling pattern. - - Specifies a pointer to a 32x32 stipple pattern that will be unpacked from memory in the same way that glDrawPixels unpacks pixels. - - - - This function restores the attribute stack to the state it was when - PushAttrib was called. - - - - - Pop the client attribute stack. - - - - - Restore the previously saved state of the current matrix stack. - - - - - This takes the top name off the selection names stack. - - - - - Set texture residence priority. - - Specifies the number of textures to be prioritized. - Specifies an array containing the names of the textures to be prioritized. - Specifies an array containing the texture priorities. A priority given in an element of priorities applies to the texture named by the corresponding element of textures. - - - - This function Maps the specified object coordinates into window coordinates. - - The object's x coord. - The object's y coord. - The object's z coord. - The modelview matrix. - The projection matrix. - The viewport. - The window x coord. - The Window y coord. - The Window z coord. - - - - Save the current state of the attribute groups specified by 'mask'. - - The attibute groups to save. - - - - Save the current state of the attribute groups specified by 'mask'. - - The attibute groups to save. - - - - Push the client attribute stack. - - Specifies a mask that indicates which attributes to save. - - - - Save the current state of the current matrix stack. - - - - - This function adds a new name to the selection buffer. - - The name to add. - - - - This set's the Generate Normals propery of the specified Quadric object. - - The quadric object. - The type of normals to generate. - - - - This function sets the type of texture coordinates being generated by - the specified quadric object. - - The quadric object. - The type of coordinates to generate. - - - - This sets the orientation for the quadric object. - - The quadric object. - The orientation. - - - - This sets the current drawstyle for the Quadric Object. - - The quadric object. - The draw style. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - - - - This function sets the current raster position. - - The coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - - - - This function sets the current raster position. - - The coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - - - - This function sets the current raster position. - - The coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - - - - This function sets the current raster position. - - The coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - W coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - W coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - W coordinate. - - - - This function sets the current raster position. - - X coordinate. - Y coordinate. - Z coordinate. - W coordinate. - - - - Select a color buffer source for pixels. - - Specifies a color buffer. Accepted values are OpenGL.FRONT_LEFT, OpenGL.FRONT_RIGHT, OpenGL.BACK_LEFT, OpenGL.BACK_RIGHT, OpenGL.FRONT, OpenGL.BACK, OpenGL.LEFT, OpenGL.GL_RIGHT, and OpenGL.AUXi, where i is between 0 and OpenGL.AUX_BUFFERS - 1. - - - - Reads a block of pixels from the frame buffer. - - Top-Left X value. - Top-Left Y value. - Width of block to read. - Height of block to read. - Specifies the format of the pixel data. The following symbolic values are accepted: OpenGL.COLOR_INDEX, OpenGL.STENCIL_INDEX, OpenGL.DEPTH_COMPONENT, OpenGL.RED, OpenGL.GREEN, OpenGL.BLUE, OpenGL.ALPHA, OpenGL.RGB, OpenGL.RGBA, OpenGL.LUMINANCE and OpenGL.LUMINANCE_ALPHA. - Specifies the data type of the pixel data.Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.BYTE, OpenGL.BITMAP, OpenGL.UNSIGNED_SHORT, OpenGL.SHORT, OpenGL.UNSIGNED_INT, OpenGL.INT or OpenGL.FLOAT. - Storage for the pixel data received. - - - - Reads a block of pixels from the frame buffer. - - Top-Left X value. - Top-Left Y value. - Width of block to read. - Height of block to read. - Specifies the format of the pixel data. The following symbolic values are accepted: OpenGL.COLOR_INDEX, OpenGL.STENCIL_INDEX, OpenGL.DEPTH_COMPONENT, OpenGL.RED, OpenGL.GREEN, OpenGL.BLUE, OpenGL.ALPHA, OpenGL.RGB, OpenGL.RGBA, OpenGL.LUMINANCE and OpenGL.LUMINANCE_ALPHA. - Specifies the data type of the pixel data.Must be one of OpenGL.UNSIGNED_BYTE, OpenGL.BYTE, OpenGL.BITMAP, OpenGL.UNSIGNED_SHORT, OpenGL.SHORT, OpenGL.UNSIGNED_INT, OpenGL.INT or OpenGL.FLOAT. - Storage for the pixel data received. - - - - Draw a rectangle from two coordinates (top-left and bottom-right). - - Top-Left X value. - Top-Left Y value. - Bottom-Right X Value. - Bottom-Right Y Value. - - - - Draw a rectangle from two coordinates, expressed as arrays, e.g - Rect(new float[] {0, 0}, new float[] {10, 10}); - - Top-Left point. - Bottom-Right point. - - - - Draw a rectangle from two coordinates (top-left and bottom-right). - - Top-Left X value. - Top-Left Y value. - Bottom-Right X Value. - Bottom-Right Y Value. - - - - Draw a rectangle from two coordinates, expressed as arrays, e.g - Rect(new float[] {0, 0}, new float[] {10, 10}); - - Top-Left point. - Bottom-Right point. - - - - Draw a rectangle from two coordinates (top-left and bottom-right). - - Top-Left X value. - Top-Left Y value. - Bottom-Right X Value. - Bottom-Right Y Value. - - - - Draw a rectangle from two coordinates, expressed as arrays, e.g - Rect(new float[] {0, 0}, new float[] {10, 10}); - - Top-Left point. - Bottom-Right point. - - - - Draw a rectangle from two coordinates (top-left and bottom-right). - - Top-Left X value. - Top-Left Y value. - Bottom-Right X Value. - Bottom-Right Y Value. - - - - Draw a rectangle from two coordinates, expressed as arrays, e.g - Rect(new float[] {0, 0}, new float[] {10, 10}); - - Top-Left point. - Bottom-Right point. - - - - This function sets the current render mode (render, feedback or select). - - The Render mode (RENDER, SELECT or FEEDBACK). - The hits that selection or feedback caused.. - - - - This function sets the current render mode (render, feedback or select). - - The Render mode (RENDER, SELECT or FEEDBACK). - The hits that selection or feedback caused.. - - - - This function applies a rotation transformation to the current matrix. - - The angle to rotate. - Amount along x. - Amount along y. - Amount along z. - - - - This function applies a rotation transformation to the current matrix. - - The angle to rotate. - Amount along x. - Amount along y. - Amount along z. - - - - This function quickly does three rotations, one about each axis, with the - given angles (it's not an OpenGL function, but very useful). - - The angle to rotate about x. - The angle to rotate about y. - The angle to rotate about z. - - - - This function applies a scale transformation to the current matrix. - - The amount to scale along x. - The amount to scale along y. - The amount to scale along z. - - - - This function applies a scale transformation to the current matrix. - - The amount to scale along x. - The amount to scale along y. - The amount to scale along z. - - - - Define the scissor box. - - Specify the lower left corner of the scissor box. Initially (0, 0). - Specify the lower left corner of the scissor box. Initially (0, 0). - Specify the width and height of the scissor box. When a GL context is first attached to a window, width and height are set to the dimensions of that window. - Specify the width and height of the scissor box. When a GL context is first attached to a window, width and height are set to the dimensions of that window. - - - - This function sets the current select buffer. - - The size of the buffer you are passing. - The buffer itself. - - - - Select flat or smooth shading. - - Specifies a symbolic value representing a shading technique. Accepted values are OpenGL.FLAT and OpenGL.SMOOTH. The default is OpenGL.SMOOTH. - - - - Select flat or smooth shading. - - Specifies a symbolic value representing a shading technique. Accepted values are OpenGL.FLAT and OpenGL.SMOOTH. The default is OpenGL.SMOOTH. - - - - This function draws a sphere from a Quadric Object. - - The quadric object. - Sphere radius. - Slices of the sphere. - Stakcs of the sphere. - - - - This function sets the current stencil buffer function. - - The function type. - The function reference. - The function mask. - - - - This function sets the current stencil buffer function. - - The function type. - The function reference. - The function mask. - - - - This function sets the stencil buffer mask. - - The mask. - - - - This function sets the stencil buffer operation. - - Fail operation. - Depth fail component. - Depth pass component. - - - - This function sets the stencil buffer operation. - - Fail operation. - Depth fail component. - Depth pass component. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Array of 1,2,3 or 4 Texture Coordinates. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - - - - This function sets the current texture coordinates. WARNING: if you - can call something more explicit, like TexCoord2f then call that, it's - much faster. - - Array of 1,2,3 or 4 Texture Coordinates. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Array of 1,2,3 or 4 Texture Coordinates. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Array of 1,2,3 or 4 Texture Coordinates. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the current texture coordinates. - - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - Texture Coordinate. - - - - This function sets the texture coord array. - - The number of coords per set. - The type of data. - The number of bytes between coords. - The coords. - - - - This function sets the texture coord array. - - The number of coords per set. - The type of data. - The number of bytes between coords. - The coords. - - - - Set texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a single-valued texture environment parameter. Must be OpenGL.TEXTURE_ENV_MODE. - Specifies a single symbolic constant, one of OpenGL.MODULATE, OpenGL.DECAL, OpenGL.BLEND, or OpenGL.REPLACE. - - - - Set texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE and OpenGL.TEXTURE_ENV_COLOR. - Specifies a pointer to a parameter array that contains either a single symbolic constant or an RGBA color. - - - - Set texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a single-valued texture environment parameter. Must be OpenGL.TEXTURE_ENV_MODE. - Specifies a single symbolic constant, one of OpenGL.MODULATE, OpenGL.DECAL, OpenGL.BLEND, or OpenGL.REPLACE. - - - - Set texture environment parameters. - - Specifies a texture environment. Must be OpenGL.TEXTURE_ENV. - Specifies the symbolic name of a texture environment parameter. Accepted values are OpenGL.TEXTURE_ENV_MODE and OpenGL.TEXTURE_ENV_COLOR. - Specifies a pointer to a parameter array that contains either a single symbolic constant or an RGBA color. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. - Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. - Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function. Must be OpenGL.TEXTURE_GEN_MODE. - Specifies a single-valued texture generation parameter, one of OpenGL.OBJECT_LINEAR, OpenGL.GL_EYE_LINEAR, or OpenGL.SPHERE_MAP. - - - - Control the generation of texture coordinates. - - Specifies a texture coordinate. Must be one of OpenGL.S, OpenGL.T, OpenGL.R, or OpenGL.Q. - Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be OpenGL.TEXTURE_GEN_MODE, OpenGL.OBJECT_PLANE, or OpenGL.EYE_PLANE. - Specifies a pointer to an array of texture generation parameters. If pname is OpenGL.TEXTURE_GEN_MODE, then the array must contain a single symbolic constant, one of OpenGL.OBJECT_LINEAR, OpenGL.EYE_LINEAR, or OpenGL.SPHERE_MAP. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by pname. - - - - This function sets the image for the currently binded texture. - - The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. - For mip-map textures, ordinary textures should be '0'. - The format of the data you are want OpenGL to create, e.g RGB16. - The width of the texture image (must be a power of 2, e.g 64). - The width of the border (0 or 1). - The format of the data you are passing, e.g. RGBA. - The type of data you are passing, e.g GL_BYTE. - The actual pixel data. - - - - This function sets the image for the currently binded texture. - - The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. - For mip-map textures, ordinary textures should be '0'. - The format of the data you are want OpenGL to create, e.g RGB16. - The width of the texture image (must be a power of 2, e.g 64). - The height of the texture image (must be a power of 2, e.g 32). - The width of the border (0 or 1). - The format of the data you are passing, e.g. RGBA. - The type of data you are passing, e.g GL_BYTE. - The actual pixel data. - - - - This function sets the image for the currently binded texture. - - The type of texture, TEXTURE_2D or PROXY_TEXTURE_2D. - For mip-map textures, ordinary textures should be '0'. - The format of the data you are want OpenGL to create, e.g RGB16. - The width of the texture image (must be a power of 2, e.g 64). - The height of the texture image (must be a power of 2, e.g 32). - The width of the border (0 or 1). - The format of the data you are passing, e.g. RGBA. - The type of data you are passing, e.g GL_BYTE. - The actual pixel data. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - This function sets the parameters for the currently binded texture object. - - The type of texture you are setting the parameter to, e.g. TEXTURE_2D - The parameter to set. - The value to set it to. - - - - Specify a two-dimensional texture subimage. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies a texel offset in the x direction within the texture array. - Specifies the width of the texture subimage. - Specifies the format of the pixel data. - Specifies the data type of the pixel data. - Specifies a pointer to the image data in memory. - - - - Specify a two-dimensional texture subimage. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. - Specifies a texel offset in the x direction within the texture array. - Specifies a texel offset in the y direction within the texture array. - Specifies the width of the texture subimage. - Specifies the height of the texture subimage. - Specifies the format of the pixel data. - Specifies the data type of the pixel data. - Specifies a pointer to the image data in memory. - - - - This function applies a translation transformation to the current matrix. - - The amount to translate along the x axis. - The amount to translate along the y axis. - The amount to translate along the z axis. - - - - This function applies a translation transformation to the current matrix. - - The amount to translate along the x axis. - The amount to translate along the y axis. - The amount to translate along the z axis. - - - - This function turns a screen Coordinate into a world coordinate. - - Screen Coordinate. - Screen Coordinate. - Screen Coordinate. - Current ModelView matrix. - Current Projection matrix. - Current Viewport. - The world coordinate. - The world coordinate. - The world coordinate. - - - - This is a convenience function. It calls UnProject with the current - viewport, modelview and persective matricies, saving you from getting them. - To use you own matricies, all the other version of UnProject. - - X Coordinate (Screen Coordinate). - Y Coordinate (Screen Coordinate). - Z Coordinate (Screen Coordinate). - The world coordinate. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - Specifies the coordinate. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - Specifies the coordinate. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - Specifies the coordinate. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - - - - Sets the current vertex (must be called between 'Begin' and 'End'). - - An array of 2, 3 or 4 floats. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - W Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - W Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - W Value. - - - - Set the current vertex (must be called between 'Begin' and 'End'). - - X Value. - Y Value. - Z Value. - W Value. - - - - This function sets the address of the vertex pointer array. - - The number of coords per vertex. - The data type. - The byte offset between vertices. - The array. - - - - This function sets the address of the vertex pointer array. - - The number of coords per vertex. - The data type. - The byte offset between vertices. - The array. - - - - This sets the viewport of the current Render Context. Normally x and y are 0 - and the width and height are just those of the control/graphics you are drawing - to. - - Top-Left point of the viewport. - Top-Left point of the viewport. - Width of the viewport. - Height of the viewport. - - - - Produce an error string from a GL or GLU error code. - - Specifies a GL or GLU error code. - The OpenGL/GLU error string. - - - - Return a string describing the GLU version or GLU extensions. - - Specifies a symbolic constant, one of OpenGL.VERSION, or OpenGL.EXTENSIONS. - The GLU string. - - - - Scale an image to an arbitrary size. - - Specifies the format of the pixel data. - Specify the width of the source image that is scaled. - Specify the height of the source image that is scaled. - Specifies the data type for dataIn. - Specifies a pointer to the source image. - Specify the width of the destination image. - Specify the height of the destination image. - Specifies the data type for dataOut. - Specifies a pointer to the destination image. - - - - Create 1-D mipmaps. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the number of color components in the texture. Must be 1, 2, 3, or 4. - Specifies the width of the texture image. - Specifies the format of the pixel data. - Specifies the data type for data. - Specifies a pointer to the image data in memory. - - - - Create 2-D mipmaps. - - Specifies the target texture. Must be OpenGL.TEXTURE_1D. - Specifies the number of color components in the texture. Must be 1, 2, 3, or 4. - Specifies the width of the texture image. - Specifies the height of the texture image. - Specifies the format of the pixel data. - Specifies the data type for data. - Specifies a pointer to the image data in memory. - - - - Draw a disk. - - Specifies the quadrics object (created with gluNewQuadric). - Specifies the inner radius of the disk (may be 0). - Specifies the outer radius of the disk. - Specifies the number of subdivisions around the z axis. - Specifies the number of concentric rings about the origin into which the disk is subdivided. - - - - Create a tessellation object. - - A new GLUtesselator poiner. - - - - Delete a tesselator object. - - The tesselator pointer. - - - - Delimit a polygon description. - - Specifies the tessellation object (created with gluNewTess). - Specifies a pointer to user polygon data. - - - - Delimit a contour description. - - Specifies the tessellation object (created with gluNewTess). - - - - Specify a vertex on a polygon. - - Specifies the tessellation object (created with gluNewTess). - Specifies the location of the vertex. - Specifies an opaque pointer passed back to the program with the vertex callback (as specified by gluTessCallback). - - - - Delimit a contour description. - - Specifies the tessellation object (created with gluNewTess). - - - - Delimit a polygon description. - - Specifies the tessellation object (created with gluNewTess). - - - - Set a tessellation object property. - - Specifies the tessellation object (created with gluNewTess). - Specifies the property to be set. - Specifies the value of the indicated property. - - - - Specify a normal for a polygon. - - Specifies the tessellation object (created with gluNewTess). - Specifies the first component of the normal. - Specifies the second component of the normal. - Specifies the third component of the normal. - - - - Set a tessellation object property. - - Specifies the tessellation object (created with gluNewTess). - Specifies the property to be set. - Specifies the value of the indicated property. - - - - Delimit a NURBS trimming loop definition. - - Specifies the NURBS object (created with gluNewNurbsRenderer). - - - - Delimit a NURBS trimming loop definition. - - Specifies the NURBS object (created with gluNewNurbsRenderer). - - - - Describe a piecewise linear NURBS trimming curve. - - Specifies the NURBS object (created with gluNewNurbsRenderer). - Specifies the number of points on the curve. - Specifies an array containing the curve points. - Specifies the offset (a number of single-precision floating-point values) between points on the curve. - Specifies the type of curve. Must be either OpenGL.MAP1_TRIM_2 or OpenGL.MAP1_TRIM_3. - - - - Load NURBS sampling and culling matrice. - - Specifies the NURBS object (created with gluNewNurbsRenderer). - Specifies a modelview matrix (as from a glGetFloatv call). - Specifies a projection matrix (as from a glGetFloatv call). - Specifies a viewport (as from a glGetIntegerv call). - - - - Get a NURBS property. - - Specifies the NURBS object (created with gluNewNurbsRenderer). - Specifies the property whose value is to be fetched. - Specifies a pointer to the location into which the value of the named property is written. - - - - Gets the error description for a given error code. - - The error code. - The error description for the given error code. - - - - Called before an OpenGL call to enable error checking and ensure the - correct OpenGL context is correct. - - - - - Called after an OpenGL call to enable error checking. - - - - - This function transforms a windows point into an OpenGL point, - which is measured from the bottom left of the screen. - - The x coord. - The y coord. - - - - Creates the OpenGL instance. - - Type of the render context. - The drawing context width. - The drawing context height. - The bit depth. - The parameter. - - - - - Creates the OpenGL instance using an external, existing render context. - - The width. - The height. - The bit depth. - The window handle. - The render context handle. - The device context handle. - True on success - - - - Makes the OpenGL instance current. - - - - - Makes no render context current. - - - - - Blits to the specified device context handle. - - The device context handle. - - - - Set the render context dimensions. - - The width (in pixels). - The height (in pixels). - - - - GDIs the coordinateto open GL coordinate. - - The x coordinate. - The y coordinate. - - - - Draws the text. - - The x. - The y. - The r. - The g. - The b. - Name of the face. - Size of the font. - The text. - - - - Draws 3D text. - - Name of the face. - Size of the font. - The deviation. - The extrusion. - The text. - - - - The current OpenGL instance. - - - - - The render context provider. - - - - - Set to true if we're inside glBegin. - - - - - The fontbitmaps object is used to allow easy rendering of text. - - - - - The FontOutlines object is used to allow rendering of text. - - - - - Gets the render context provider. - - The render context provider. - - - - Gets the vendor. - - The vendor. - - - - Gets the renderer. - - The renderer. - - - - Gets the version. - - The version. - - - - Gets the extensions. - - The extensions. - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - The extra parameter. - - - - - Destroys the render context provider instance. - - - - - Sets the dimensions of the render context provider. - - Width. - Height. - - - - Makes the render context current. - - - - - Blit the rendered data to the supplied device context. - - The HDC. - - - - Gets the render context handle. - - - - - Gets the device context handle. - - - - - Gets or sets the width. - - The width. - - - - Gets or sets the height. - - The height. - - - - Gets or sets the bit depth. - - The bit depth. - - - - Gets a value indicating whether GDI drawing is enabled for this type of render context. - - true if GDI drawing is enabled; otherwise, false. - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - - - - - Destroys the render context provider instance. - - - - - Sets the dimensions of the render context provider. - - Width. - Height. - - - - Makes the render context current. - - - - - Blit the rendered data to the supplied device context. - - The HDC. - - - - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - - - - - The render context handle. - - - - - The device context handle. - - - - - The width. - - - - - The height. - - - - - The bit depth. - - - - - Is gdi drawing enabled? - - - - - Gets the render context handle. - - - - - Gets the device context handle. - - - - - Gets or sets the width. - - The width. - - - - Gets or sets the height. - - The height. - - - - Gets or sets the bit depth. - - The bit depth. - - - - Gets a value indicating whether GDI drawing is enabled for this type of render context. - - true if GDI drawing is enabled; otherwise, false. - - - - Initializes a new instance of the class. - - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - - - - - Destroys the render context provider instance. - - - - - The DIB Section object. - - - - - Gets the DIB section. - - The DIB section. - - - - Useful functions imported from the Win32 SDK. - - - - - Initializes the class. - - - - - Gets the current render context. - - The current render context. - - - - Make the specified render context current. - - The handle to the device context. - The handle to the render context. - - - - - Creates a render context from the device context. - - The handle to the device context. - The handle to the render context. - - - - Deletes the render context. - - The handle to the render context. - - - - - Gets a proc address. - - The name of the function. - The address of the function. - - - - The wglUseFontBitmaps function creates a set of bitmap display lists for use in the current OpenGL rendering context. The set of bitmap display lists is based on the glyphs in the currently selected font in the device context. You can then use bitmaps to draw characters in an OpenGL image. - - Specifies the device context whose currently selected font will be used to form the glyph bitmap display lists in the current OpenGL rendering context.. - Specifies the first glyph in the run of glyphs that will be used to form glyph bitmap display lists. - Specifies the number of glyphs in the run of glyphs that will be used to form glyph bitmap display lists. The function creates count display lists, one for each glyph in the run. - Specifies a starting display list. - If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To get extended error information, call GetLastError. - - - - The wglUseFontOutlines function creates a set of display lists, one for each glyph of the currently selected outline font of a device context, for use with the current rendering context. - - The h DC. - The first. - The count. - The list base. - The deviation. - The extrusion. - The format. - The LPGMF. - - - - - Link two render contexts so they share lists (buffer IDs, etc.) - - The first context. - The second context. - If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. - To get extended error information, call GetLastError. - - - - Specifies that a window created with this style accepts drag-drop files. - - - - - Forces a top-level window onto the taskbar when the window is visible. - - - - - Specifies that a window has a border with a sunken edge. - - - - - Windows XP: Paints all descendants of a window in bottom-to-top painting order using double-buffering. For more information, see Remarks. This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. - - - - - Includes a question mark in the title bar of the window. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message. The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the child window. - WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles. - - - - - The window itself contains child windows that should take part in dialog box navigation. If this style is specified, the dialog manager recurses into children of this window when performing navigation operations such as handling the TAB key, an arrow key, or a keyboard mnemonic. - - - - - Creates a window that has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter. - - - - - Windows 2000/XP: Creates a layered window. Note that this cannot be used for child windows. Also, this cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. - - - - - Arabic and Hebrew versions of Windows 98/Me, Windows 2000/XP: Creates a window whose horizontal origin is on the right edge. Increasing horizontal values advance to the left. - - - - - Creates a window that has generic left-aligned properties. This is the default. - - - - - If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the vertical scroll bar (if present) is to the left of the client area. For other languages, the style is ignored. - - - - - The window text is displayed using left-to-right reading-order properties. This is the default. - - - - - Creates a multiple-document interface (MDI) child window. - - - - - Windows 2000/XP: A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. - To activate the window, use the SetActiveWindow or SetForegroundWindow function. - The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style. - - - - - Windows 2000/XP: A window created with this style does not pass its window layout to its child windows. - - - - - Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed. - - - - - Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE styles. - - - - - Combines the WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW, and WS_EX_TOPMOST styles. - - - - - The window has generic "right-aligned" properties. This depends on the window class. This style has an effect only if the shell language is Hebrew, Arabic, or another language that supports reading-order alignment; otherwise, the style is ignored. - Using the WS_EX_RIGHT style for static or edit controls has the same effect as using the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles. - - - - - Vertical scroll bar (if present) is to the right of the client area. This is the default. - - - - - If the shell language is Hebrew, Arabic, or another language that supports reading-order alignment, the window text is displayed using right-to-left reading-order properties. For other languages, the style is ignored. - - - - - Creates a window with a three-dimensional border style intended to be used for items that do not accept user input. - - - - - Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE. - - - - - Specifies that a window created with this style should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function. - - - - - Specifies that a window created with this style should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted. - To achieve transparency without these restrictions, use the SetWindowRgn function. - - - - - Specifies that a window has a border with a raised edge. - - - - The window has a thin-line border. - - - The window has a title bar (includes the WS_BORDER style). - - - The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with the WS_POPUP style. - - - Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window. - - - - Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. - If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window. - - - - The window is initially disabled. A disabled window cannot receive input from the user. To change this after a window has been created, use the EnableWindow function. - - - The window has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar. - - - - The window is the first control of a group of controls. The group consists of this first control and all controls defined after it, up to the next control with the WS_GROUP style. - The first control in each group usually has the WS_TABSTOP style so that the user can move from group to group. The user can subsequently change the keyboard focus from one control in the group to the next control in the group by using the direction keys. - You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. - - - - The window has a horizontal scroll bar. - - - The window is initially maximized. - - - The window has a maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified. - - - The window is initially minimized. - - - The window has a minimize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified. - - - The window is an overlapped window. An overlapped window has a title bar and a border. - - - The window is an overlapped window. - - - The window is a pop-up window. This style cannot be used with the WS_CHILD style. - - - The window is a pop-up window. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the window menu visible. - - - The window has a sizing border. - - - The window has a window menu on its title bar. The WS_CAPTION style must also be specified. - - - - The window is a control that can receive the keyboard focus when the user presses the TAB key. - Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style. - You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. - For user-created windows and modeless dialogs to work with tab stops, alter the message loop to call the IsDialogMessage function. - - - - The window is initially visible. This style can be turned on and off by using the ShowWindow or SetWindowPos function. - - - The window has a vertical scroll bar. - - - - A FontBitmap entry contains the details of a font face. - - - - - This class wraps the functionality of the wglUseFontBitmaps function to - allow straightforward rendering of text. - - - - - Draws the text. - - The gl. - The x. - The y. - The r. - The g. - The b. - Name of the face. - Size of the font. - The text. - - - - Cache of font bitmap enties. - - - - - Initializes a new instance of the class. - - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - The parameter - - - - - Destroys the render context provider instance. - - - - - Sets the dimensions of the render context provider. - - Width. - Height. - - - - Blit the rendered data to the supplied device context. - - The HDC. - - - - Makes the render context current. - - - - - The window handle. - - - - - Initializes a new instance of the class. - - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - - - - - - Gets the internal DIB section. - - The internal DIB section. - - - - AccumOp - - - - - The alpha function - - - - - The OpenGL Attribute flags. - - - - - The begin mode. - - - - - BlendingDestinationFactor - - - - - The blending source factor. - - - - - - - - - - The Clip Plane Name - - - - - The Cull Face mode. - - - - - - - - - - The Data Type. - - - - - - - - - - The depth function - - - - - The Draw Buffer Mode - - - - - Error Code - - - - - FeedBackMode - - - - - The Feedback Token - - - - - The Fog Mode. - - - - - - - - - - GetMapTarget - - - - - The Front Face Mode. - - - - - The hint mode. - - - - - The - - - - - The hint target. - - - - - LightName - - - - - LightParameter - - - - - The Light Model Parameter. - - - - - The Logic Op - - - - - The matrix mode. - - - - - The pixel transfer parameter name - - - - - The Polygon mode. - - - - - Render as points. - - - - - Render as lines. - - - - - Render as filled. - - - - - Rendering Mode - - - - - ShadingModel - - - - - The stencil function - - - - - The stencil operation. - - - - - GetTextureParameter - - - - - Texture target. - - - - - The render context type. - - - - - A DIB section - offscreen but NEVER hardware accelerated. - - - - - A Native Window - directly render to a window, the window handle - must be passed as the parameter to Create. Hardware acceleration - is supported but one can never do GDI drawing on top of the - OpenGL drawing. - - - - - A Hidden Window - more initial overhead but acceleratable. - - - - - A Framebuffer Object - accelerated but may not be supported on some card. - - - - - Render context provider for working with an external render context - - - - - The window handle. - - - - - Initializes a new instance of the class. - - The existing window handle. - The handle to the existing render context. - The handle to the existing device context. - - - - Destroys the render context provider instance. - - - - - Blit the rendered data to the supplied device context. - - The HDC. - - - - Makes the render context current. - - - - - Initializes a new instance of the class. - - - - - Creates the render context provider. Must also create the OpenGL extensions. - - The OpenGL context. - The width. - The height. - The bit depth. - The parameter. - - - - - Destroys the render context provider instance. - - - - - Sets the dimensions of the render context provider. - - Width. - Height. - - - - Blit the rendered data to the supplied device context. - - The HDC. - - - - Makes the render context current. - - - - - The window handle. - - - - - - - - - - Creates the specified width. - - The width. - The height. - The bit count. - - - - - Resizes the section. - - The width. - The height. - The bit count. - - - - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - - - - - This function sets the pixel format of the underlying bitmap. - - The bitcount. - - - - Destroys this instance. - - - - - The parent dc. - - - - - The bitmap handle. - - - - - The bits. - - - - - The width. - - - - - The height. - - - - - Gets the handle to the bitmap. - - The handle to the bitmap. - - - - Gets the bits. - - - - - Gets or sets the width. - - The width. - - - - Gets or sets the height. - - The height. - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/SharpGLforWPF.2.1.0.nupkg deleted file mode 100644 index e6580dbd01c12eba20ae37c2a30ed50a115a7cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19252 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 - - - SharpGLforWPF - 2.1.0 - SharpGL for WPF - Dave Kerr - Dave Kerr - http://sharpgl.codeplex.com/ - false - SharpGL wraps the popular OpenGL library. This package installs SharpGL and the WPF controls. - SharpGL wraps the popular OpenGL library. This package installs SharpGL and the WPF controls. - - Copyright © Dave Kerr 2013 - - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.dll deleted file mode 100644 index 124d2a5898959e94e66a2e6ff98ae6938f292866..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 veQQm&*5eS7rvR{EzQ{vj+YTA-zvH diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml deleted file mode 100644 index 1c0007f0..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/SharpGLforWPF.2.1.0/lib/SharpGL.WPF.xml +++ /dev/null @@ -1,341 +0,0 @@ - - - - SharpGL.WPF - - - - - This class handles conversion to and from various bitmap types. - - - - - Converts an HBitmap the bitmap to a bitmap source. - - The hbitmap. - A BitmapSource. - - - - Convert a DIB section to a BitmapSource. - - The dib section. - The BitmapSource. - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Interaction logic for OpenGLControl.xaml - - - OpenGLControl - - - - - Initializes a new instance of the class. - - - - - Handles the SizeChanged event of the OpenGLControl control. - - The source of the event. - The instance containing the event data. - - - - When overridden in a derived class, is invoked whenever application code or - internal processes call . - - - - - Handles the Tick event of the timer control. - - The source of the event. - The instance containing the event data. - - - - Called when the frame rate is changed. - - The object. - The instance containing the event data. - - - - A single event args for all our needs. - - - - - The OpenGL instance. - - - - - The dispatcher timer. - - - - - A stopwatch used for timing rendering. - - - - - The last frame time in milliseconds. - - - - - The frame rate dependency property. - - - - - The render context type property. - - - - - Called when [render context type changed]. - - The o. - The instance containing the event data. - - - - The DrawFPS property. - - - - - InitializeComponent - - - - - Occurs when OpenGL should be initialised. - - - - - Occurs when OpenGL drawing should occur. - - - - - Occurs when the control is resized. This can be used to perform custom projections. - - - - - Gets or sets the frame rate. - - The frame rate. - - - - Gets or sets the type of the render context. - - The type of the render context. - - - - Gets or sets a value indicating whether to draw FPS. - - - true if draw FPS; otherwise, false. - - - - - Gets the OpenGL instance. - - - - - Interaction logic for SceneTree.xaml - - - SceneTree - - - - - InitializeComponent - - - - - If the count of a collection is zero, this converter returns collapsed. - - - - - Converts a value. - - The value produced by the binding source. - The type of the binding target property. - The converter parameter to use. - The culture to use in the converter. - - A converted value. If the method returns null, the valid null value is used. - - - - - Converts a value. - - The value that is produced by the binding target. - The type to convert to. - The converter parameter to use. - The culture to use in the converter. - - A converted value. If the method returns null, the valid null value is used. - - - - - Interaction logic for SceneView.xaml - - - SceneView - - - - - Initializes a new instance of the class. - - - - - Handles the SizeChanged event of the SceneView control. - - The source of the event. - The instance containing the event data. - - - - When overridden in a derived class, is invoked whenever application code or - internal processes call . - - - - - Handles the Tick event of the timer control. - - The source of the event. - The instance containing the event data. - - - - Called when the frame rate is changed. - - The object. - The instance containing the event data. - - - - The dispatcher timer. - - - - - A stopwatch used for timing rendering. - - - - - The last frame time in milliseconds. - - - - - The frame rate dependency property. - - - - - The DrawFPS property. - - - - - The Scene Dependency Property. - - - - - Called when [scene changed]. - - The o. - The instance containing the event data. - - - - The camera dependency property. - - - - - Called when [camera changed]. - - The o. - The instance containing the event data. - - - - InitializeComponent - - - - - Gets or sets the frame rate. - - The frame rate. - - - - Gets or sets a value indicating whether to draw FPS. - - - true if draw FPS; otherwise, false. - - - - - Gets or sets the scene. - - - The scene. - - - - - Gets or sets the camera. - - - The camera. - - - - diff --git a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config b/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config deleted file mode 100644 index 103e29ed..00000000 --- a/source/SharpGL/Samples/WPF/SharpGLViewerSample/packages/repositories.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml b/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml deleted file mode 100644 index b409b1ef..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs b/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs deleted file mode 100644 index 0ab665f0..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Windows; - -namespace SimpleShaderSample -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - } -} diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml b/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml deleted file mode 100644 index c446cd3a..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml.cs deleted file mode 100644 index d0bdac02..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/MainWindow.xaml.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using SharpGL; -using SharpGL.SceneGraph.Primitives; -using SharpGL.SceneGraph.Shaders; -using SharpGL.SceneGraph; - -namespace SimpleShaderSample -{ - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window - { - public MainWindow() - { - InitializeComponent(); - } - - private void OpenGLControl_OpenGLDraw(object sender, OpenGLEventArgs args) - { - OpenGL gl = args.OpenGL; - - // Clear The Screen And The Depth Buffer - gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); - - // Move Left And Into The Screen - gl.LoadIdentity(); - gl.Translate(0.0f, 0.0f, -6.0f); - - program.Push(gl, null); - gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); - - Teapot tp = new Teapot(); - tp.Draw(gl, 14, 1, OpenGL.GL_FILL); - - rotation += 3.0f; - program.Pop(gl, null); - } - - float rotation = 0; - - private void OpenGLControl_OpenGLInitialized(object sender, OpenGLEventArgs args) - { - OpenGL gl = args.OpenGL; - - gl.Enable(OpenGL.GL_DEPTH_TEST); - - float[] global_ambient = new float[] { 0.5f, 0.5f, 0.5f, 1.0f }; - float[] light0pos = new float[] { 0.0f, 5.0f, 10.0f, 1.0f }; - float[] light0ambient = new float[] { 0.2f, 0.2f, 0.2f, 1.0f }; - float[] light0diffuse = new float[] { 0.3f, 0.3f, 0.3f, 1.0f }; - float[] light0specular = new float[] { 0.8f, 0.8f, 0.8f, 1.0f }; - - float[] lmodel_ambient = new float[] { 0.2f, 0.2f, 0.2f, 1.0f }; - gl.LightModel(OpenGL.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); - - gl.LightModel(OpenGL.GL_LIGHT_MODEL_AMBIENT, global_ambient); - gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, light0pos); - gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, light0ambient); - gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, light0diffuse); - gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, light0specular); - gl.Enable(OpenGL.GL_LIGHTING); - gl.Enable(OpenGL.GL_LIGHT0); - - gl.ShadeModel(OpenGL.GL_SMOOTH); - - // Create a vertex shader. - VertexShader vertexShader = new VertexShader(); - vertexShader.CreateInContext(gl); - vertexShader.SetSource( - "void main()" + Environment.NewLine + - "{" + Environment.NewLine + - "gl_Position = ftransform();" + Environment.NewLine + - "}" + Environment.NewLine); - - // Create a fragment shader. - FragmentShader fragmentShader = new FragmentShader(); - fragmentShader.CreateInContext(gl); - fragmentShader.SetSource( - "void main()" + Environment.NewLine + - "{" + Environment.NewLine + - "gl_FragColor = vec4(0.4,0.4,0.8,1.0);" + Environment.NewLine + - "}" + Environment.NewLine); - - // Compile them both. - vertexShader.Compile(); - fragmentShader.Compile(); - - // Build a program. - program.CreateInContext(gl); - - // Attach the shaders. - program.AttachShader(vertexShader); - program.AttachShader(fragmentShader); - program.Link(); - } - - ShaderProgram program = new ShaderProgram(); - } -} diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs deleted file mode 100644 index d4b1707c..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Simple Shader Sample")] -[assembly: AssemblyDescription("Simple Shader Sample for SharpGL")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.Designer.cs deleted file mode 100644 index 6ff6b969..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.239 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SimpleShaderSample.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimpleShaderSample.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx deleted file mode 100644 index ffecec85..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.Designer.cs deleted file mode 100644 index 3f3fc746..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.239 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SimpleShaderSample.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings deleted file mode 100644 index 8f2fd95d..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj b/source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj deleted file mode 100644 index efbca480..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj +++ /dev/null @@ -1,130 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {6DB0A8E3-0385-4B1A-BF61-44F8275909A2} - WinExe - Properties - SimpleShaderSample - SimpleShaderSample - v4.0 - - - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - - - - - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Properties\SharedAssemblyInfo.cs - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - {47BCAA39-EDAD-4404-B6BD-4742B0ABB523} - SharpGL.SceneGraph - - - {53E67055-13D2-4467-BB57-79589AFAC2CD} - SharpGL.WPF - - - {5EF45533-E2C7-46F2-B4A3-B8F36CD406E0} - SharpGL - - - - - \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/SimpleShaderSample/app.config b/source/SharpGL/Samples/WPF/SimpleShaderSample/app.config deleted file mode 100644 index cb2586be..00000000 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - From 6bbc54cb8b6038547e593540a8026479cebf2843 Mon Sep 17 00:00:00 2001 From: Jochem Date: Fri, 9 May 2014 17:11:16 +0100 Subject: [PATCH 4/8] Fix: Accidentally passed the actual data instead of pointer for the glBufferData overloads with uint and byte. --- source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs index a6140836..429912f7 100644 --- a/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs +++ b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs @@ -6,7 +6,7 @@ namespace SharpGL { - public partial class OpenGL + public partial class OpenGL { #region Missing constants @@ -43,7 +43,7 @@ public partial class OpenGL public IntPtr MapBufferRange(uint target, int offset, int length, uint access) { return (IntPtr)InvokeExtensionFunction(target, offset, length, access); - } + } #endregion Missing Wrapped OpenGL Functions @@ -57,7 +57,7 @@ public void BufferData(uint target, uint[] data, uint usage) var intData = new int[data.Length]; Buffer.BlockCopy(data, 0, intData, 0, dataSize); Marshal.Copy(intData, 0, p, data.Length); - InvokeExtensionFunction(target, dataSize, data, usage); + InvokeExtensionFunction(target, dataSize, p, usage); Marshal.FreeHGlobal(p); } @@ -68,7 +68,7 @@ public void BufferData(uint target, byte[] data, uint usage) var byteData = new byte[data.Length]; Buffer.BlockCopy(data, 0, byteData, 0, dataSize); Marshal.Copy(byteData, 0, p, data.Length); - InvokeExtensionFunction(target, dataSize, data, usage); + InvokeExtensionFunction(target, dataSize, p, usage); Marshal.FreeHGlobal(p); } } From 0baa6689595aab3d62273c45f9d7044aa9905166 Mon Sep 17 00:00:00 2001 From: Jochem Date: Mon, 19 May 2014 17:58:09 +0100 Subject: [PATCH 5/8] Added PBORenderContextProvider.cs to give the option to render using Pixel Buffer Objects (Still some issues with it). Removed some GL calls from OpenGLControl and SceneView, that in my opinion should be left by the user, because it might cause confusion (Like OpenGL.GL_DEPTH_TEST). Note that this might require for the samples to be double checked! Added missing constants and function calls to OpenGLExtensionsJOG.cs for review. If approved then they can be added to OpenGL.cs or OpenGLExtensions.cs. Upgraded and added classes to SceneGraph.JOG. This includes a less restrictive and - in my opinion - more OGL natural ShaderProgram.cs, Color.cs,... Added samples to share my experience with OpenGL for the last 2 months. It should mostly follow the OGL 3.3+ conventions, except for the Gradient Backgrounds, who still use deprecated functionalities. The samples which are currently working include "Translucency", "Particle Systems", "Use of materials", "Lines". Note that for the examples, it is required to install GlmNET, which can be easely retrieved from Nuget in Visual Studio. --- .../Core/SharpGL.SceneGraph/JOG/ColorF.cs | 133 ++++++ .../JOG/ManifestResourceLoader.cs | 46 ++ .../Core/SharpGL.SceneGraph/JOG/Material.cs | 77 ++++ .../SharpGL.SceneGraph.csproj | 5 + .../Core/SharpGL.SceneGraph/packages.config | 4 + .../Core/SharpGL.WPF/OpenGLControl.xaml.cs | 50 +- .../Core/SharpGL.WPF/OpenGLControlJOG.xaml | 8 + .../Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs | 388 ++++++++++++++++ .../Core/SharpGL.WPF/SceneView.xaml.cs | 19 + .../Core/SharpGL.WPF/SharpGL.WPF.csproj | 12 +- source/SharpGL/Core/SharpGL/DIBSection.cs | 2 +- source/SharpGL/Core/SharpGL/OpenGL.cs | 15 +- .../Core/SharpGL/OpenGLExtensionsJOG.cs | 1 + .../PBORenderContextProvider.cs | 150 ++++++ .../RenderContextProvider.cs | 1 + .../SharpGL/Core/SharpGL/RenderContextType.cs | 7 +- .../Core/SharpGL/Shaders/ShaderProgramJOG.cs | 356 +++++++++++++++ source/SharpGL/Core/SharpGL/SharpGL.csproj | 5 + .../WPF/JOG/SharpGLLinesSample/App.config | 6 + .../WPF/JOG/SharpGLLinesSample/App.xaml | 8 + .../WPF/JOG/SharpGLLinesSample/App.xaml.cs | 17 + .../JOG/SharpGLLinesSample/GLController.cs | 209 +++++++++ .../SharpGLLinesSample/GlmNetExtensions.cs | 431 ++++++++++++++++++ .../JOG/SharpGLLinesSample/MainWindow.xaml | 11 + .../JOG/SharpGLLinesSample/MainWindow.xaml.cs | 112 +++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../JOG/SharpGLLinesSample/Primitives/Axis.cs | 37 ++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Primitives/SquareGrid.cs | 117 +++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 71 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../ShaderResources/SingleColor.frag | 10 + .../ShaderResources/SingleColor.vert | 15 + .../Shaders/LinesShader/LinesBufferGroup.cs | 134 ++++++ .../Shaders/LinesShader/LinesProgram.cs | 149 ++++++ ...ShaderManagerNormalMaterialParticleTest.cs | 278 +++++++++++ .../SharpGLLinesSample.csproj | 133 ++++++ .../JOG/SharpGLLinesSample/packages.config | 4 + .../WPF/JOG/SharpGLMaterialSample/App.config | 6 + .../WPF/JOG/SharpGLMaterialSample/App.xaml | 8 + .../WPF/JOG/SharpGLMaterialSample/App.xaml.cs | 17 + .../JOG/SharpGLMaterialSample/GLController.cs | 208 +++++++++ .../SharpGLMaterialSample/GlmNetExtensions.cs | 431 ++++++++++++++++++ .../JOG/SharpGLMaterialSample/MainWindow.xaml | 11 + .../SharpGLMaterialSample/MainWindow.xaml.cs | 112 +++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 71 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../ShaderResources/NormalMaterial.frag | 25 + .../ShaderResources/NormalMaterial.vert | 27 ++ .../NormalMaterialShader/NMBufferGroup.cs | 178 ++++++++ .../NormalMaterialProgram.cs | 180 ++++++++ ...ShaderManagerNormalMaterialParticleTest.cs | 278 +++++++++++ .../SharpGLMaterialSample.csproj | 131 ++++++ .../JOG/SharpGLMaterialSample/packages.config | 4 + .../WPF/JOG/SharpGLParticlesSample/App.config | 6 + .../WPF/JOG/SharpGLParticlesSample/App.xaml | 8 + .../JOG/SharpGLParticlesSample/App.xaml.cs | 17 + .../SharpGLParticlesSample/GLController.cs | 213 +++++++++ .../GlmNetExtensions.cs | 431 ++++++++++++++++++ .../SharpGLParticlesSample/MainWindow.xaml | 11 + .../SharpGLParticlesSample/MainWindow.xaml.cs | 112 +++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 63 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 26 ++ .../Properties/Settings.settings | 7 + .../NormalMaterialParticle.frag | 25 + .../NormalMaterialParticle.vert | 46 ++ .../NMPBufferGroup.cs | 246 ++++++++++ .../NormalMaterialParticleProgram.cs | 187 ++++++++ ...ShaderManagerNormalMaterialParticleTest.cs | 278 +++++++++++ .../SharpGLParticlesSample.csproj | 134 ++++++ .../SharpGLParticlesSample/packages.config | 4 + .../JOG/SharpGLTranslucencySample/App.config | 6 + .../JOG/SharpGLTranslucencySample/App.xaml | 8 + .../JOG/SharpGLTranslucencySample/App.xaml.cs | 17 + .../SharpGLTranslucencySample/GLController.cs | 211 +++++++++ .../GlmNetExtensions.cs | 431 ++++++++++++++++++ .../SharpGLTranslucencySample/MainWindow.xaml | 11 + .../MainWindow.xaml.cs | 112 +++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 71 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../NormalTranslucentMaterial.frag | 25 + .../NormalTranslucentMaterial.vert | 27 ++ .../NTMBufferGroup.cs | 178 ++++++++ .../NormalTranslucentMaterialProgram.cs | 180 ++++++++ ...ShaderManagerNormalMaterialParticleTest.cs | 278 +++++++++++ .../SharpGLTranslucencySample.csproj | 131 ++++++ .../SharpGLTranslucencySample/packages.config | 4 + 108 files changed, 10501 insertions(+), 22 deletions(-) create mode 100644 source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs create mode 100644 source/SharpGL/Core/SharpGL.SceneGraph/JOG/ManifestResourceLoader.cs create mode 100644 source/SharpGL/Core/SharpGL.SceneGraph/JOG/Material.cs create mode 100644 source/SharpGL/Core/SharpGL.SceneGraph/packages.config create mode 100644 source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml create mode 100644 source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs create mode 100644 source/SharpGL/Core/SharpGL/RenderContextProviders/PBORenderContextProvider.cs create mode 100644 source/SharpGL/Core/SharpGL/Shaders/ShaderProgramJOG.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/Axis.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/SquareGrid.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/SharpGLLinesSample.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/packages.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NMBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/packages.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NMPBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NormalMaterialParticleProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/SharpGLParticlesSample.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/packages.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NTMBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NormalTranslucentMaterialProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/SharpGLTranslucencySample.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/packages.config diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs new file mode 100644 index 00000000..19b977cb --- /dev/null +++ b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGL.SceneGraph.JOG +{ + public class ColorF + { + #region fields + float[] _argb = new float[4]; + #endregion fields + + #region properties + public float A + { + get { return this[0]; } + set { this[0] = value; } + } + + public float R + { + get { return this[1]; } + set { this[1] = value; } + } + + public float G + { + get { return this[2]; } + set { this[2] = value; } + } + + public float B + { + get { return this[3]; } + set { this[3] = value; } + } + + /// + /// Gets or sets a color by index (0 = Alpha, 1 = Red, 2 = Green, 3 = Blue) + /// + /// + /// + public float this[int i] + { + get + { + return _argb[i]; + } + set + { + _argb[i] = value; + } + } + + public float[] Argb + { + get { return _argb; } + set { _argb = value; } + } + #endregion properties + + #region constructors + public ColorF() + { } + + /// + /// Converts uint to ColorF. Second byte = blue, Thirth byte = green, Last byte = red. + /// + /// + public ColorF(uint colorRGB) + { + // Get the integer ID + var i = colorRGB; + + int b = (int)(i >> 16) & 0xFF; + int g = (int)(i >> 8) & 0xFF; + int r = (int)i & 0xFF; + + IntToFloatColor(255, r, g, b); + } + + /// + /// Converts uint to ColorF. 3th and 4th byte = blue, 5th and 6th byte = green, 7th and last byte = red. + /// + /// + public ColorF(ulong colorRGB) + { + // Get the integer ID + var i = colorRGB; + + int b = (int)(i >> 32) & 0xFF; + int g = (int)(i >> 16) & 0xFF; + int r = (int)i & 0xFF; + + IntToFloatColor(255, r, g, b); + } + + public ColorF(int a, int r, int g, int b) + { + IntToFloatColor(a, r, g, b); + } + + public ColorF(float a, float r, float g, float b) + { + A = a; + R = r; + G = g; + B = b; + } + + public ColorF(System.Drawing.Color color) + : this(color.A, color.R, color.G, color.B) + { } + + + #endregion constructors + + private void IntToFloatColor(int a, int r, int g, int b) + { + A = a / 255.0f; + R = r / 255.0f; + G = g / 255.0f; + B = b / 255.0f; + } + + public uint ToUint() + { + // Get color id from pixel data. + return (uint)(R * 255 + G * 65025 + B * 16581375); // r * 255 + g * 255² + b * 255³. + } + } +} diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ManifestResourceLoader.cs b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ManifestResourceLoader.cs new file mode 100644 index 00000000..3f1ced47 --- /dev/null +++ b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ManifestResourceLoader.cs @@ -0,0 +1,46 @@ +using System.IO; +using System.Reflection; +using System.Resources; +using System.Text; + +namespace SharpGL.SceneGraph.JOG +{ + /// + /// A small helper class to load manifest resource files. + /// + public static class ManifestResourceLoader + { + /// + /// Loads the named manifest resource as a text string. + /// + /// Name of the text file. + /// The contents of the manifest resource. + public static string LoadTextFile(string path, Assembly executingAssembly, bool autoAttachAssemblyName = true) + { + if (executingAssembly == null) + executingAssembly = Assembly.GetExecutingAssembly(); + + var pathToDots = path.Replace("\\", ".").Replace("/", "."); + + + string location; + if (autoAttachAssemblyName) + { + string assemblyName = executingAssembly.GetName().Name; + location = string.Format("{0}.{1}", assemblyName, pathToDots); + } + else + { + location = pathToDots; + } + + using (var stream = executingAssembly.GetManifestResourceStream(location)) + { + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + } + } +} diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/JOG/Material.cs b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/Material.cs new file mode 100644 index 00000000..d10a7f81 --- /dev/null +++ b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/Material.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGL.SceneGraph.JOG +{ + /// + /// + /// + public class Material + { + #region fields + static ColorF _defaultColor = new ColorF(0, 0, 0, 0); + float shininess; + ColorF _ambient, diffuse, specular, emission; + #endregion fields + + #region properties + public ColorF Ambient + { + get { return _ambient; } + set { _ambient = value; } + } + + public ColorF Diffuse + { + get { return diffuse; } + set { diffuse = value; } + } + + public ColorF Specular + { + get { return specular; } + set { specular = value; } + } + + public ColorF Emission + { + get { return emission; } + set { emission = value; } + } + + public float Shininess + { + get { return shininess; } + set { shininess = value; } + } + #endregion properties + + #region constructors + /// + /// Default constructor. No users will be recorded. + /// + public Material() + { + Ambient = _defaultColor; + Diffuse = _defaultColor; + Specular = _defaultColor; + Emission = _defaultColor; + } + public Material(ColorF ambient, ColorF diffuse, ColorF specular, ColorF emission, float shininess) + : this() + { + Ambient = ambient == null? _defaultColor : ambient; + Diffuse = diffuse == null? _defaultColor : diffuse; + Specular = specular == null? _defaultColor : specular; + Emission = emission == null? _defaultColor : emission; + Shininess = shininess; + } + #endregion constructors + + + } +} diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/SharpGL.SceneGraph.csproj b/source/SharpGL/Core/SharpGL.SceneGraph/SharpGL.SceneGraph.csproj index 93df5b3d..80e64d75 100644 --- a/source/SharpGL/Core/SharpGL.SceneGraph/SharpGL.SceneGraph.csproj +++ b/source/SharpGL/Core/SharpGL.SceneGraph/SharpGL.SceneGraph.csproj @@ -30,6 +30,7 @@ prompt 4 false + true pdbonly @@ -64,6 +65,9 @@ Properties\SharedAssemblyInfo.cs + + + @@ -178,6 +182,7 @@ + diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/packages.config b/source/SharpGL/Core/SharpGL.SceneGraph/packages.config new file mode 100644 index 00000000..7bd4d3f8 --- /dev/null +++ b/source/SharpGL/Core/SharpGL.SceneGraph/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/SharpGL/Core/SharpGL.WPF/OpenGLControl.xaml.cs b/source/SharpGL/Core/SharpGL.WPF/OpenGLControl.xaml.cs index 334f159b..818621b7 100644 --- a/source/SharpGL/Core/SharpGL.WPF/OpenGLControl.xaml.cs +++ b/source/SharpGL/Core/SharpGL.WPF/OpenGLControl.xaml.cs @@ -17,6 +17,7 @@ using System.Diagnostics; using SharpGL.SceneGraph; using SharpGL.Version; +using SharpGL.RenderContextProviders; namespace SharpGL.WPF { @@ -31,6 +32,8 @@ public partial class OpenGLControl : UserControl public OpenGLControl() { InitializeComponent(); + // Set default size. + writeableBitmap = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null); SizeChanged += new SizeChangedEventHandler(OpenGLControl_SizeChanged); } @@ -59,16 +62,19 @@ void OpenGLControl_SizeChanged(object sender, SizeChangedEventArgs e) handler(this, eventArgsFast); else { + /// ---- Removed because it only slows down and is deprecated. User should create it's own projection matrix. ---- // Otherwise we do our own projection. - gl.MatrixMode(OpenGL.GL_PROJECTION); - gl.LoadIdentity(); + //gl.MatrixMode(OpenGL.GL_PROJECTION); + //gl.LoadIdentity(); - // Calculate The Aspect Ratio Of The Window - gl.Perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f); + //// Calculate The Aspect Ratio Of The Window + //gl.Perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f); - gl.MatrixMode(OpenGL.GL_MODELVIEW); - gl.LoadIdentity(); + //gl.MatrixMode(OpenGL.GL_MODELVIEW); + //gl.LoadIdentity(); + /// --------------------------------------------------------------------------------------------------------------- } + writeableBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null); } } } @@ -92,13 +98,15 @@ public override void OnApplyTemplate() // Create our fast event args. eventArgsFast = new OpenGLEventArgs(gl); + /// ---- This does not belong here! If user would want this, he'll set it himself. ---- // Set the most basic OpenGL styles. - gl.ShadeModel(OpenGL.GL_SMOOTH); - gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl.ClearDepth(1.0f); - gl.Enable(OpenGL.GL_DEPTH_TEST); - gl.DepthFunc(OpenGL.GL_LEQUAL); - gl.Hint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST); + //gl.ShadeModel(OpenGL.GL_SMOOTH); + //gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); + //gl.ClearDepth(1.0f); + //gl.Enable(OpenGL.GL_DEPTH_TEST); + //gl.DepthFunc(OpenGL.GL_LEQUAL); + //gl.Hint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST); + /// --------------------------------------------------------------------------------------------------------------- // Fire the OpenGL initialised event. var handler = OpenGLInitialized; @@ -183,6 +191,19 @@ void timer_Tick(object sender, EventArgs e) image.Source = newFormatedBitmapSource; } break; + case RenderContextType.PBO: + { + PBORenderContextProvider provider = gl.RenderContextProvider as PBORenderContextProvider; + var width = provider.Width; + var height = provider.Height; + var pixelsPtr = provider.PixelPtr; + var size = provider.Size; + var stride = provider.Stride; + writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), pixelsPtr, size, stride, 0, 0); + + image.Source = writeableBitmap; + } + break; default: break; } @@ -219,6 +240,11 @@ private static void OnFrameRateChanged(DependencyObject o, DependencyPropertyCha } } + /// + /// A writeableBitmap for the PBO. + /// + private WriteableBitmap writeableBitmap; + /// /// A single event args for all our needs. /// diff --git a/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml new file mode 100644 index 00000000..28460514 --- /dev/null +++ b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml @@ -0,0 +1,8 @@ + + + diff --git a/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs new file mode 100644 index 00000000..1b124cee --- /dev/null +++ b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs @@ -0,0 +1,388 @@ +using SharpGL; +using SharpGL.RenderContextProviders; +using SharpGL.SceneGraph; +using SharpGL.Version; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; + +namespace SharpGL.WPF +{ + /// + /// Interaction logic for OGLViewportImage.xaml. + /// + public partial class OpenGLControlJOG : UserControl, INotifyPropertyChanged + { + #region fields + + int _viewportWidth; + int _viewportHeight; + OpenGL _gl = new OpenGL(); + OpenGLVersion _oglVersion = OpenGLVersion.OpenGL2_1; + RenderContextType _renderContextType = RenderContextType.FBO; + WriteableBitmap _writeableBitmap; + + //OGLViewport _viewport; + Stopwatch stopwatch = new Stopwatch(); + DispatcherTimer _timer = new DispatcherTimer(); + TimeSpan _interval = new TimeSpan(0,0,0,0,1000/24); // Set default to 24 frames/sec. + DispatcherPriority _priority = DispatcherPriority.Render; + + OpenGLEventArgs _eventArgsFast; + Queue _frameTime = new Queue(); + + ImageSource _imgSource; + #endregion fields + + #region properties + /// + /// A queue of the last recorded frame times. + /// + public Queue FrameTime + { + get { return _frameTime; } + set { _frameTime = value; } + } + + /// + /// The timer interval. + /// + public TimeSpan Interval + { + get { return _interval; } + set + { + _interval = value; + if (_timer != null) + _timer.Interval = value; + } + } + + /// + /// The last rendered frame that was retrieved by the timer. + /// + public ImageSource ImgSource + { + get { return _imgSource; } + set { _imgSource = value; } + } + + /// + /// The timer that refreshes every frame. + /// + public DispatcherTimer Timer + { + get { return _timer; } + private set { _timer = value; } + } + + /// + /// Start or stop timer. + /// + public bool TimerIsEnabled + { + get { return _timer.IsEnabled; } + set { _timer.IsEnabled = value; } + } + + ///// + ///// The virtual viewport. Call "GetFrame" to get the latest image. + ///// + //public OGLViewport Viewport + //{ + // get { return _viewport; } + // set { _viewport = value; } + //} + /// + /// Whether or not the image has to be refreshed by retrieving an update from the GPU. + /// + public bool RefreshImage { get; set; } + + + + + + + /// + /// A writeableBitmap for the PBO. + /// + public WriteableBitmap WriteableBitmap + { + get { return _writeableBitmap; } + set { _writeableBitmap = value; } + } + public int ViewportWidth + { + get { return _viewportWidth; } + private set { _viewportWidth = value; } + } + + public int ViewportHeight + { + get { return _viewportHeight; } + private set { _viewportHeight = value; } + } + public OpenGL Gl + { + get { return _gl; } + set { _gl = value; } + } + + public OpenGLVersion OglVersion + { + get { return _oglVersion; } + set { _oglVersion = value; } + } + + public RenderContextType RenderContextType + { + get { return _renderContextType; } + set { _renderContextType = value; } + } + #endregion properties + + #region events + /// + /// Occurs when OpenGL should be initialised. + /// + [Description("Called when OpenGL has been initialized."), Category("SharpGL")] + public event OpenGLEventHandler OpenGLInitialized; + + public void OnOpenGLInitialized() + { + if (OpenGLInitialized != null) + OpenGLInitialized(this, _eventArgsFast); + } + + /// + /// Occurs when OpenGL drawing should occur. + /// + [Description("Called whenever OpenGL drawing can should occur."), Category("SharpGL")] + public event OpenGLEventHandler OpenGLDraw; + public void OnOpenGLDraw() + { + if (OpenGLDraw != null) + OpenGLDraw(this, _eventArgsFast); + } + + + /// + /// Occurs when the control is resized. This can be used to perform custom projections. + /// + [Description("Called when the control is resized - you can use this to do custom viewport projections."), Category("SharpGL")] + public event OpenGLEventHandler Resized; + public void OnResized() + { + if (Resized != null) + Resized(this, _eventArgsFast); + } + + + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public OpenGLControlJOG() + { + InitializeComponent(); + DataContext = this; + RefreshImage = true; + } + #endregion constructors + + /// + /// Start the timer. + /// + private void StartTimer() + { + _timer.Start(); + } + + /// + /// Calls Viewport.GetFrame() and updates the ImgSource. + /// + public void Refresh(bool notifyChanged = true) + { + // Update the frame. + ImgSource = GetFrame(); + + // Notify that the frame was updated. + if (notifyChanged) + OnPropertyChanged("ImgSource"); + } + + public ImageSource GetFrame() + { + lock (Gl) + { + Gl.Blit(IntPtr.Zero); + IntPtr hBitmap = IntPtr.Zero; + + switch (RenderContextType) + { + case RenderContextType.DIBSection: + { + DIBSectionRenderContextProvider provider = Gl.RenderContextProvider as DIBSectionRenderContextProvider; + + // TODO: We have to remove the alpha channel - for some reason it comes out as 0.0 + // meaning the drawing comes out transparent. + FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap(); + newFormatedBitmapSource.BeginInit(); + newFormatedBitmapSource.Source = BitmapConversion.HBitmapToBitmapSource(provider.DIBSection.HBitmap); + newFormatedBitmapSource.DestinationFormat = PixelFormats.Rgb24; + newFormatedBitmapSource.EndInit(); + + // Copy the pixels over. + + return newFormatedBitmapSource; + } + case RenderContextType.NativeWindow: + break; + case RenderContextType.HiddenWindow: + break; + case RenderContextType.FBO: + { + FBORenderContextProvider provider = Gl.RenderContextProvider as FBORenderContextProvider; + + // TODO: We have to remove the alpha channel - for some reason it comes out as 0.0 + // meaning the drawing comes out transparent. + FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap(); + newFormatedBitmapSource.BeginInit(); + newFormatedBitmapSource.Source = BitmapConversion.HBitmapToBitmapSource(provider.InternalDIBSection.HBitmap); + newFormatedBitmapSource.DestinationFormat = PixelFormats.Rgb24; + newFormatedBitmapSource.EndInit(); + + // Copy the pixels over. + return newFormatedBitmapSource; + } + case RenderContextType.PBO: + { + PBORenderContextProvider provider = Gl.RenderContextProvider as PBORenderContextProvider; + var width = provider.Width; + var height = provider.Height; + var pixelsPtr = provider.PixelPtr; + if (pixelsPtr == IntPtr.Zero) + return null; + var size = provider.Size; + var stride = provider.Stride; + var rect = new Int32Rect(0, 0, width, height); + WriteableBitmap.WritePixels(rect, pixelsPtr, size, stride, 0, 0); + + return WriteableBitmap; + } + default: + break; + } + + } + return null; + } + + public void Resize(int width, int height) + { + // Lock on OpenGL. + lock (Gl) + { + // Set default size. + WriteableBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null); + + Gl.RenderContextProvider.SetDimensions(width, height); + + // Set the viewport. + Gl.Viewport(0, 0, width, height); + + ViewportHeight = height; + ViewportWidth = width; + } + } + + /// + /// Initialization logic for the GL. + /// + /// + /// + void OGLViewportImage_Loaded(object sender, RoutedEventArgs e) + { + // Set default size. + WriteableBitmap = new WriteableBitmap(50, 50, 96, 96, PixelFormats.Bgra32, null); + + // Lock on OpenGL. + lock (Gl) + { + // Create OpenGL. + Gl.Create(OglVersion, RenderContextType, 1, 1, 32, null); + } + + _eventArgsFast = new OpenGLEventArgs(Gl); + + // Notify that the GL is ready to use. + OnOpenGLInitialized(); + + // Notify to update the view settings. + OnResized(); + + // Synchronise the Image size with the Viewport size. + Resize((int)ActualWidth, (int)ActualHeight); + + this.SizeChanged += OGLViewportImage_SizeChanged; + + // Set the timer. + Timer = new DispatcherTimer(_priority); + Timer.Interval = Interval; + Timer.Tick += Timer_Tick; + + // Start timer. + StartTimer(); + } + + /// + /// Update the Viewport sizes and trigger notification that a resize happened. + /// + /// + /// + void OGLViewportImage_SizeChanged(object sender, SizeChangedEventArgs e) + { + Resize((int)e.NewSize.Width, (int)e.NewSize.Height); + OnResized(); + } + + /// + /// The timer tick. + /// + /// + /// + public virtual void Timer_Tick(object sender, EventArgs e) + { + stopwatch.Restart(); + if (RefreshImage) + Refresh(); + OnOpenGLDraw(); + + stopwatch.Stop(); + + _frameTime.Enqueue(stopwatch.Elapsed.TotalMilliseconds); + if (_frameTime.Count > 10) + _frameTime.Dequeue(); + } + + } +} diff --git a/source/SharpGL/Core/SharpGL.WPF/SceneView.xaml.cs b/source/SharpGL/Core/SharpGL.WPF/SceneView.xaml.cs index 47fcd53d..dc2a0696 100644 --- a/source/SharpGL/Core/SharpGL.WPF/SceneView.xaml.cs +++ b/source/SharpGL/Core/SharpGL.WPF/SceneView.xaml.cs @@ -16,6 +16,7 @@ using System.Diagnostics; using System.Windows.Threading; using SharpGL.SceneGraph.Cameras; +using SharpGL.RenderContextProviders; namespace SharpGL.WPF { @@ -33,6 +34,9 @@ public SceneView() // Handle the size changed event. SizeChanged += new SizeChangedEventHandler(SceneView_SizeChanged); + + // Set default size. + writeableBitmap = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null); } /// @@ -56,6 +60,7 @@ void SceneView_SizeChanged(object sender, SizeChangedEventArgs e) // Resize the scene. Scene.OpenGL.SetDimensions(width, height); Scene.Resize(width, height); + writeableBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null); } } @@ -129,6 +134,18 @@ void timer_Tick(object sender, EventArgs e) // Copy the pixels over. image.Source = newFormatedBitmapSource; } + else if (Scene.OpenGL.RenderContextProvider is RenderContextProviders.PBORenderContextProvider) + { + PBORenderContextProvider provider = Scene.OpenGL.RenderContextProvider as PBORenderContextProvider; + var width = provider.Width; + var height = provider.Height; + var pixelsPtr = provider.PixelPtr; + var size = provider.Size; + var stride = provider.Stride; + writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), pixelsPtr, size, stride, 0, 0); + + image.Source = writeableBitmap; + } // Stop the stopwatch. stopwatch.Stop(); @@ -157,6 +174,8 @@ private static void OnFrameRateChanged(DependencyObject o, DependencyPropertyCha // Start the timer. me.timer.Start(); } + + private WriteableBitmap writeableBitmap; /// /// The dispatcher timer. diff --git a/source/SharpGL/Core/SharpGL.WPF/SharpGL.WPF.csproj b/source/SharpGL/Core/SharpGL.WPF/SharpGL.WPF.csproj index 8607eacd..60305484 100644 --- a/source/SharpGL/Core/SharpGL.WPF/SharpGL.WPF.csproj +++ b/source/SharpGL/Core/SharpGL.WPF/SharpGL.WPF.csproj @@ -33,6 +33,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -72,6 +73,9 @@ Properties\SharedAssemblyInfo.cs + + OpenGLControlJOG.xaml + SceneTree.xaml @@ -82,6 +86,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -131,11 +139,11 @@ - {47BCAA39-EDAD-4404-B6BD-4742B0ABB523} + {47bcaa39-edad-4404-b6bd-4742b0abb523} SharpGL.SceneGraph - {5EF45533-E2C7-46F2-B4A3-B8F36CD406E0} + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} SharpGL diff --git a/source/SharpGL/Core/SharpGL/DIBSection.cs b/source/SharpGL/Core/SharpGL/DIBSection.cs index 96e4c795..988cd05f 100644 --- a/source/SharpGL/Core/SharpGL/DIBSection.cs +++ b/source/SharpGL/Core/SharpGL/DIBSection.cs @@ -37,7 +37,6 @@ public virtual unsafe bool Create(IntPtr hDC, int width, int height, int bitCoun // Create the bitmap. hBitmap = Win32.CreateDIBSection(hDC, ref info, Win32.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0); - Win32.SelectObject(hDC, hBitmap); // Set the OpenGL pixel format. @@ -75,6 +74,7 @@ public void Resize(int width, int height, int bitCount) hBitmap = Win32.CreateDIBSection(parentDC, ref info, Win32.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0); + Win32.SelectObject(parentDC, hBitmap); } diff --git a/source/SharpGL/Core/SharpGL/OpenGL.cs b/source/SharpGL/Core/SharpGL/OpenGL.cs index 945a8c23..5a7551bf 100644 --- a/source/SharpGL/Core/SharpGL/OpenGL.cs +++ b/source/SharpGL/Core/SharpGL/OpenGL.cs @@ -972,7 +972,7 @@ public partial class OpenGL [DllImport(LIBRARY_OPENGL)] private static extern void glDeleteLists (uint list, int range); [DllImport(LIBRARY_OPENGL)] private static extern void glDeleteTextures (int n, uint []textures); [DllImport(LIBRARY_OPENGL)] private static extern void glDepthFunc (uint func); - [DllImport(LIBRARY_OPENGL)] private static extern void glDepthMask (byte flag); + [DllImport(LIBRARY_OPENGL)] private static extern void glDepthMask (uint flag); [DllImport(LIBRARY_OPENGL)] private static extern void glDepthRange (double zNear, double zFar); [DllImport(LIBRARY_OPENGL)] private static extern void glDisable (uint cap); [DllImport(LIBRARY_OPENGL)] private static extern void glDisableClientState (uint array); @@ -2185,7 +2185,7 @@ public void DepthFunc(Enumerations.DepthFunction function) /// This function sets the depth mask. /// /// The depth mask flag, normally 1. - public void DepthMask(byte flag) + public void DepthMask(uint flag) { PreGLCall(); glDepthMask(flag); @@ -6724,10 +6724,13 @@ public virtual bool Create(OpenGLVersion openGLVersion, RenderContextType render break; case RenderContextType.HiddenWindow: renderContextProvider = new HiddenWindowRenderContextProvider(); - break; - case RenderContextType.FBO: - renderContextProvider = new FBORenderContextProvider(); - break; + break; + case RenderContextType.FBO: + renderContextProvider = new FBORenderContextProvider(); + break; + case RenderContextType.PBO: + renderContextProvider = new PBORenderContextProvider(); + break; } // Create the render context. diff --git a/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs index 429912f7..b8c38eec 100644 --- a/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs +++ b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs @@ -33,6 +33,7 @@ public partial class OpenGL public const uint GL_SHADER_STORAGE_BUFFER = 0x90D2; public const uint GL_MAP_READ_BIT = 0x0001; + #endregion Missing constants #region Missing DLL Functions diff --git a/source/SharpGL/Core/SharpGL/RenderContextProviders/PBORenderContextProvider.cs b/source/SharpGL/Core/SharpGL/RenderContextProviders/PBORenderContextProvider.cs new file mode 100644 index 00000000..40d9c656 --- /dev/null +++ b/source/SharpGL/Core/SharpGL/RenderContextProviders/PBORenderContextProvider.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SharpGL.Version; +using System.Windows.Media.Imaging; +using System.Windows.Media; + +namespace SharpGL.RenderContextProviders +{ + public class PBORenderContextProvider : HiddenWindowRenderContextProvider + { + /// + /// Initializes a new instance of the class. + /// + public PBORenderContextProvider() + { + // We can layer GDI drawing on top of open gl drawing. + GDIDrawingEnabled = true; + + } + + /// + /// Creates the render context provider. Must also create the OpenGL extensions. + /// + /// The desired OpenGL version. + /// The OpenGL context. + /// The width. + /// The height. + /// The bit depth. + /// The parameter + /// + public override bool Create(OpenGLVersion openGLVersion, OpenGL gl, int width, int height, int bitDepth, object parameter) + { + this.gl = gl; + + // Call the base class. + base.Create(openGLVersion, gl, width, height, bitDepth, parameter); + + // Request an id for our pixel buffer. + uint[] ids = new uint[1]; + + ids = new uint[1]; + gl.GenBuffers(1, ids); + + pixelBufferID = ids[0]; + + // The writeable bitmap needs to be initialized, so trigger setDimensions for this. + SetDimensions(width, height); + + + return true; + } + + private void DestroyPixelbuffers() + { + // Delete the framebuffer. + gl.DeleteBuffers(1, new uint[] { pixelBufferID }); + + // Reset the IDs. + pixelBufferID = 0; + } + + public override void Destroy() + { + // Delete the render buffers. + DestroyPixelbuffers(); + + + // Call the base, which will delete the render context handle and window. + base.Destroy(); + } + + public override void SetDimensions(int width, int height) + { + // Call the base. + base.SetDimensions(width, height); + + // Recreate the bitmap with the new dimensions. + var bitsPerPixel = 32; + var bytesPerPixel = 4; + Stride = (int)(((width * bitsPerPixel + bitsPerPixel - 1) / bitsPerPixel) * bytesPerPixel); + + + var size = height * width * 4 * sizeof(byte); + + // Don't bother updating if the size is the same already. + if (size == this.size) + return; + + Size = size; + + gl.BindBuffer(target, pixelBufferID); + gl.BufferData(target, Size, IntPtr.Zero, usage); // Reserve space. + gl.BindBuffer(target, 0); + } + + public override void Blit(IntPtr hdc) + { + if (deviceContextHandle != IntPtr.Zero) + { + gl.ReadBuffer(OpenGL.GL_COLOR_ATTACHMENT0); + gl.BindBuffer(target, pixelBufferID); + gl.ReadPixels(0, 0, width, height, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, IntPtr.Zero); + pixelPtr = gl.MapBufferRange(OpenGL.GL_PIXEL_PACK_BUFFER, 0, size, OpenGL.GL_MAP_READ_BIT); + + gl.UnmapBuffer(OpenGL.GL_PIXEL_PACK_BUFFER); + gl.BindBuffer(OpenGL.GL_PIXEL_PACK_BUFFER, 0); + } + } + + protected uint pixelBufferID = 0; + private int size = 0; + private int stride; + protected uint target = OpenGL.GL_PIXEL_PACK_BUFFER; + protected uint usage = OpenGL.GL_DYNAMIC_DRAW; + private IntPtr pixelPtr; + //protected WriteableBitmap writableBitmap; + protected OpenGL gl; + + /// + /// Gets the pointer to the bitmap data. + /// + public IntPtr PixelPtr + { + get { return pixelPtr; } + private set { pixelPtr = value; } + } + + /// + /// The size of the bitmap. + /// + public int Size + { + get { return size; } + set { size = value; } + } + + /// + /// The stride for the bitmap. + /// + public int Stride + { + get { return stride; } + private set { stride = value; } + } + + + } +} diff --git a/source/SharpGL/Core/SharpGL/RenderContextProviders/RenderContextProvider.cs b/source/SharpGL/Core/SharpGL/RenderContextProviders/RenderContextProvider.cs index c6211cfa..03cedc03 100644 --- a/source/SharpGL/Core/SharpGL/RenderContextProviders/RenderContextProvider.cs +++ b/source/SharpGL/Core/SharpGL/RenderContextProviders/RenderContextProvider.cs @@ -21,6 +21,7 @@ public abstract class RenderContextProvider : IRenderContextProvider public virtual bool Create(OpenGLVersion openGLVersion, OpenGL gl, int width, int height, int bitDepth, object parameter) { // Set the width, height and bit depth. + // TODO: consider setting the width and height by calling SetDimensions? Width = width; Height = height; BitDepth = bitDepth; diff --git a/source/SharpGL/Core/SharpGL/RenderContextType.cs b/source/SharpGL/Core/SharpGL/RenderContextType.cs index cba03f43..8e25b15a 100644 --- a/source/SharpGL/Core/SharpGL/RenderContextType.cs +++ b/source/SharpGL/Core/SharpGL/RenderContextType.cs @@ -31,6 +31,11 @@ public enum RenderContextType /// /// A Framebuffer Object - accelerated but may not be supported on some cards. /// - FBO + FBO, + + /// + /// A Pixel Buffer Object - Allow asynchronous data download, so OpenGL can continue working during a download. + /// + PBO, }; } diff --git a/source/SharpGL/Core/SharpGL/Shaders/ShaderProgramJOG.cs b/source/SharpGL/Core/SharpGL/Shaders/ShaderProgramJOG.cs new file mode 100644 index 00000000..433a37f8 --- /dev/null +++ b/source/SharpGL/Core/SharpGL/Shaders/ShaderProgramJOG.cs @@ -0,0 +1,356 @@ +using SharpGL; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGL.Shaders +{ + + /// + /// Provides a more restrictive ShaderProgram builder, + /// utilizes a modern .NET appoach and supports more than 2 kinds of shaders. + /// + public class ShaderProgramJOG + { + #region common program and shader enums + /// + /// Values that are available for the glGetProgram(...) call. + /// + public enum GetProgramActions : uint + { + GL_DELETE_STATUS = OpenGL.GL_DELETE_STATUS, + GL_LINK_STATUS = OpenGL.GL_LINK_STATUS, + GL_VALIDATE_STATUS = OpenGL.GL_VALIDATE_STATUS, + GL_INFO_LOG_LENGTH = OpenGL.GL_INFO_LOG_LENGTH, + GL_ATTACHED_SHADERS = OpenGL.GL_ATTACHED_SHADERS, + GL_ACTIVE_ATOMIC_COUNTER_BUFFERS = OpenGL.GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, + GL_ACTIVE_ATTRIBUTES = OpenGL.GL_ACTIVE_ATTRIBUTES, + GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = OpenGL.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, + GL_ACTIVE_UNIFORMS = OpenGL.GL_ACTIVE_UNIFORMS, + GL_ACTIVE_UNIFORM_BLOCKS = OpenGL.GL_ACTIVE_UNIFORM_BLOCKS, + GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = OpenGL.GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, + GL_ACTIVE_UNIFORM_MAX_LENGTH = OpenGL.GL_ACTIVE_UNIFORM_MAX_LENGTH, + GL_COMPUTE_WORK_GROUP_SIZE = OpenGL.GL_COMPUTE_WORK_GROUP_SIZE, + GL_PROGRAM_BINARY_LENGTH = OpenGL.GL_PROGRAM_BINARY_LENGTH, + GL_TRANSFORM_FEEDBACK_BUFFER_MODE = OpenGL.GL_TRANSFORM_FEEDBACK_BUFFER_MODE, + GL_TRANSFORM_FEEDBACK_VARYINGS = OpenGL.GL_TRANSFORM_FEEDBACK_VARYINGS, + GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = OpenGL.GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, + GL_GEOMETRY_VERTICES_OUT = OpenGL.GL_GEOMETRY_VERTICES_OUT, + GL_GEOMETRY_INPUT_TYPE = OpenGL.GL_GEOMETRY_INPUT_TYPE, + GL_GEOMETRY_OUTPUT_TYPE = OpenGL.GL_GEOMETRY_OUTPUT_TYPE, + } + + /// + /// Values that are available for the glGetShader(...) call. + /// + public enum GetShaderActions : uint + { + GL_SHADER_TYPE = OpenGL.GL_SHADER_TYPE, + GL_DELETE_STATUS = OpenGL.GL_DELETE_STATUS, + GL_COMPILE_STATUS = OpenGL.GL_COMPILE_STATUS, + GL_INFO_LOG_LENGTH = OpenGL.GL_INFO_LOG_LENGTH, + GL_SHADER_SOURCE_LENGTH = OpenGL.GL_SHADER_SOURCE_LENGTH, + } + + /// + /// The available shader types. + /// + public enum ShaderTypes : uint + { + GL_COMPUTE_SHADER = OpenGL.GL_COMPUTE_SHADER, + GL_VERTEX_SHADER = OpenGL.GL_VERTEX_SHADER, + GL_TESS_CONTROL_SHADER = OpenGL.GL_TESS_CONTROL_SHADER, + GL_TESS_EVALUATION_SHADER = OpenGL.GL_TESS_EVALUATION_SHADER, + GL_GEOMETRY_SHADER = OpenGL.GL_GEOMETRY_SHADER, + GL_FRAGMENT_SHADER = OpenGL.GL_FRAGMENT_SHADER, + } + #endregion common program and shader enums + + + #region fields + + #endregion fields + + #region properties + /// + /// The id for this Program. + /// + public uint ShaderProgramId{get; protected set;} + /// + /// The ids of the shaders that are attached to this program. + /// + public Dictionary ShaderIds { get; protected set; } + /// + /// Attribute names and their positions in the shaders. + /// + public Dictionary Attribs { get; protected set; } + /// + /// The uniform names and their positions in the shaders. + /// + public Dictionary Uniforms { get; protected set; } + /// + /// A value that will be true before invoking the Action in UseShader(...) and will be set to false after the Action finished. + /// + public bool ProgramIsBound { get; private set; } + #endregion properties + + #region events + #endregion events + + #region constructors + /// + /// Default constructor. + /// + public ShaderProgramJOG() + { } + + /// + /// Calls Initialize. + /// + /// + /// + /// + public ShaderProgramJOG(OpenGL gl, Dictionary shaderTypeAndCode, + IEnumerable attributeNames, IEnumerable uniformNames) + { + Initialize(gl, shaderTypeAndCode, attributeNames, uniformNames); + } + #endregion constructors + + /// + /// Initialization of the ShaderProgram. + /// Creates the Shaders and the program. + /// Attaches the shaders to the program. + /// Retrieves the attribute and uniform positions that are utilized in this program. + /// + public void Initialize(OpenGL gl, Dictionary shaderTypeAndCode, + IEnumerable attributeNames, IEnumerable uniformNames) + { + ShaderIds = new Dictionary(); + Attribs = new Dictionary(); + Uniforms = new Dictionary(); + + CreateShaders(gl, shaderTypeAndCode); + CreateProgram(gl); + LinkProgram(gl); + AddAttributeIds(gl, attributeNames); + AddUniformIds(gl, uniformNames); + + AssertValid(gl); + } + + /// + /// Calls glUseProgram(ShaderProgramId) -> invokes executeInProgram-Action -> unbinds program using glUseProgram(0). + /// + /// + /// The logic to be executed for this shader program. + public void UseProgram(OpenGL gl, Action executeInProgram) + { + // Bind. + gl.UseProgram(ShaderProgramId); + + // Make sure the program unbinds, even if a problem should occur. + try + { + // Invoke logic. + executeInProgram.Invoke(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + // Unbind. + gl.UseProgram(0); + ProgramIsBound = false; + } + } + + /// + /// Deletes the shaders and the program and sets the ShaderProgramId to 0. + /// + /// + /// + public void DeleteProgram(OpenGL gl, bool deleteShaders) + { + while (ShaderIds.Count > 0) + { + DeleteShader(gl, ShaderIds.First().Key); + } + + gl.DeleteProgram(ShaderProgramId); + ShaderProgramId = 0; + } + + /// + /// Deletes the shader and removes it from the ShaderIds-Dictionary. + /// + /// + /// + public void DeleteShader(OpenGL gl, ShaderTypes type) + { + var shader = ShaderIds[type]; + + gl.DeleteShader(shader); + + ShaderIds.Remove(type); + } + + #region init + /// + /// Creates the shaders. + /// + /// + /// + private void CreateShaders(OpenGL gl, Dictionary shaderTypeAndCode) + { + foreach (var stc in shaderTypeAndCode) + { + CreateShader(gl, stc.Key, stc.Value); + } + } + /// + /// Creates a shader. + /// + /// + /// + /// + private void CreateShader(OpenGL gl, ShaderTypes type, string shaderCode) + { + var id = gl.CreateShader((uint)type); + gl.ShaderSource(id, shaderCode); + gl.CompileShader(id); + ShaderIds.Add(type, id); + } + /// + /// Creates the program and attaches all the shaders to it. + /// + /// + private void CreateProgram(OpenGL gl) + { + ShaderProgramId = gl.CreateProgram(); + + foreach (var shader in ShaderIds) + { + gl.AttachShader(ShaderProgramId, shader.Value); + } + } + + /// + /// Retrieve the attribute locations using the attribute names and add them to Attribs. + /// + /// + /// + private void AddAttributeIds(OpenGL gl, IEnumerable attributeNames) + { + if (Attribs == null) + Attribs = new Dictionary(); + + foreach (var name in attributeNames) + { + var location = gl.GetAttribLocation(ShaderProgramId, name); + Attribs.Add(name, (uint)location); + } + } + + /// + /// Retrieve the uniform locations using the uniform names and add them to Uniforms. + /// + /// + /// + private void AddUniformIds(OpenGL gl, IEnumerable uniformNames) + { + if (Uniforms == null) + Uniforms = new Dictionary(); + + foreach (var name in uniformNames) + { + var location = gl.GetUniformLocation(ShaderProgramId, name); + Uniforms.Add(name, location); + } + } + /// + /// Link the program. + /// + /// + private void LinkProgram(OpenGL gl) + { + gl.LinkProgram(ShaderProgramId); + } + #endregion init + + + #region Diagnostics + public int[] GetProgramResult(OpenGL gl, GetProgramActions action, uint expectedLength) + { + int[] parameters = new int[expectedLength]; + gl.GetProgram(ShaderProgramId, (uint)action, parameters); + return parameters; + } + public int[] GetShaderResult(OpenGL gl, ShaderTypes shaderType, GetShaderActions action, uint expectedLength) + { + int[] parameters = new int[expectedLength]; + gl.GetShader(ShaderIds[shaderType], (uint)action, parameters); + return parameters; + } + + + public bool GetProgramLinkStatus(OpenGL gl) + { + var parameters = GetProgramResult(gl, GetProgramActions.GL_LINK_STATUS, 1); + return parameters[0] == OpenGL.GL_TRUE; + } + + public string GetProgramInfoLog(OpenGL gl) + { + // Get the info log length. + int[] infoLength = GetProgramResult(gl, GetProgramActions.GL_INFO_LOG_LENGTH, 1); + int bufSize = infoLength[0]; + + // Get the compile info. + StringBuilder il = new StringBuilder(bufSize); + gl.GetProgramInfoLog(ShaderProgramId, bufSize, IntPtr.Zero, il); + + return il.ToString(); + } + + public bool GetShaderCompileStatus(OpenGL gl, ShaderTypes type) + { + var parameters = GetShaderResult(gl, type, GetShaderActions.GL_COMPILE_STATUS, 1); + + return parameters[0] == OpenGL.GL_TRUE; + } + + public string GetShaderInfoLog(OpenGL gl, ShaderTypes type) + { + // Get the info log length. + int[] infoLength = GetShaderResult(gl, type, GetShaderActions.GL_INFO_LOG_LENGTH, 1); + int bufSize = infoLength[0]; + + // Get the compile info. + StringBuilder il = new StringBuilder(bufSize); + gl.GetShaderInfoLog(ShaderIds[type], bufSize, IntPtr.Zero, il); + + return il.ToString(); + } + + + public void AssertValid(OpenGL gl) + { + foreach (var shaderId in ShaderIds) + { + if (GetShaderCompileStatus(gl, shaderId.Key) == false) + throw new Exception(GetShaderInfoLog(gl, shaderId.Key)); + } + + if (GetProgramLinkStatus(gl) == false) + throw new Exception(GetProgramInfoLog(gl)); + } + + #endregion Diagnostics + } +} diff --git a/source/SharpGL/Core/SharpGL/SharpGL.csproj b/source/SharpGL/Core/SharpGL/SharpGL.csproj index 02576d84..4e037219 100644 --- a/source/SharpGL/Core/SharpGL/SharpGL.csproj +++ b/source/SharpGL/Core/SharpGL/SharpGL.csproj @@ -35,6 +35,7 @@ false + true pdbonly @@ -54,6 +55,7 @@ SharpGL.snk + @@ -66,9 +68,11 @@ + + @@ -78,6 +82,7 @@ + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml new file mode 100644 index 00000000..74e06e8f --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs new file mode 100644 index 00000000..311083e9 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLLinesSample +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GLController.cs new file mode 100644 index 00000000..a1d3a758 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GLController.cs @@ -0,0 +1,209 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLLinesSample +{ + public class GLController + { + #region fields + LinesProgram _scProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public LinesProgram SCProgram + { + get { return _scProgram; } + set { _scProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + SCProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + SCProgram.Modelview = value; + } + } + + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + // Create a shader program. + SCProgram = new LinesProgram(GL); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + + + AddData(GL); + + GL.Enable(OpenGL.GL_DEPTH_TEST); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + } + public void Draw(object sender, OpenGLEventArgs args) + { + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + SCProgram.BindAll(GL); + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddData(OpenGL gl) + { + var axis = new Axis(2); + var axisLineWidth = 4; + + LinesBufferGroup groupAxisX = new LinesBufferGroup(gl); + LinesBufferGroup groupAxisY = new LinesBufferGroup(gl); + LinesBufferGroup groupAxisZ = new LinesBufferGroup(gl); + + groupAxisX.LineWidth = axisLineWidth; + groupAxisY.LineWidth = axisLineWidth; + groupAxisZ.LineWidth = axisLineWidth; + + var vertsX = axis.LineX.Item1.to_array().Concat(axis.LineX.Item2.to_array()).ToArray(); + var vertsY = axis.LineY.Item1.to_array().Concat(axis.LineY.Item2.to_array()).ToArray(); + var vertsZ = axis.LineZ.Item1.to_array().Concat(axis.LineZ.Item2.to_array()).ToArray(); + + groupAxisX.BufferData(gl, null, vertsX, new ColorF(255, 255, 0, 0)); + groupAxisY.BufferData(gl, null, vertsY, new ColorF(255, 0, 255, 0)); + groupAxisZ.BufferData(gl, null, vertsZ, new ColorF(255, 0, 0, 255)); + + groupAxisX.PrepareVAO(gl, SCProgram); + groupAxisY.PrepareVAO(gl, SCProgram); + groupAxisZ.PrepareVAO(gl, SCProgram); + + SCProgram.AddBufferGroup(groupAxisX); + SCProgram.AddBufferGroup(groupAxisY); + SCProgram.AddBufferGroup(groupAxisZ); + + + LinesBufferGroup groupGrid = new LinesBufferGroup(gl); + var grid = new SquareGrid(5, 1); + + groupGrid.LineWidth = 1; + + //var vertsGrid = grid.Lines.SelectMany(x => x.Item1.to_array().Concat(x.Item2.to_array())).ToArray(); + var vertsGrid = grid.Lines.SelectMany(x => x.to_array()).ToArray(); + + groupGrid.BufferData(gl, null, vertsGrid, new ColorF(255, 0, 0, 0)); + groupGrid.PrepareVAO(gl, SCProgram); + + SCProgram.AddBufferGroup(groupGrid); + + + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GlmNetExtensions.cs new file mode 100644 index 00000000..cef316ca --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLLinesSample +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml new file mode 100644 index 00000000..6cf879c8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml.cs new file mode 100644 index 00000000..cd65232b --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/MainWindow.xaml.cs @@ -0,0 +1,112 @@ +using GlmNet; +using SharpGL.SceneGraph; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SharpGLLinesSample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + + #region fields + private GLController _controller = new GLController(); + private Point _previousPosition; + + + #endregion fields + + #region properties + + public GLController Controller + { + get { return _controller; } + set { _controller = value; } + } + + public Action Draw { get { return Controller.Draw; } } + public Action Init { get { return Controller.Init; } } + public Action Resized { get { return Controller.Resized; } } + #endregion properties + + #region events + + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public MainWindow() + { + InitializeComponent(); + DataContext = this; + MouseMove += MainWindow_MouseMove; + MouseWheel += MainWindow_MouseWheel; + MouseDown += MainWindow_MouseDown; + + + } + #endregion constructors + + private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) + { + // Click + _previousPosition = e.GetPosition(sender as Window); + } + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + // Zoom + Controller.MvpBuilder.TranslationZ += e.Delta / 1000f; + Controller.RefreshModelview(); + } + + private void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + var pos = e.GetPosition(sender as Window); + + float xDiff = (float)(_previousPosition.X - pos.X); + float yDiff = (float)(_previousPosition.Y - pos.Y); + + if (e.LeftButton == MouseButtonState.Pressed) // Translate. + { + Controller.MvpBuilder.TranslationX += xDiff/10; + Controller.MvpBuilder.TranslationY += yDiff / 10; + Controller.RefreshModelview(); + } + else if (e.RightButton == MouseButtonState.Pressed) // Rotate. + { + var scaleFac = 1f; + var horiDeg = scaleFac * (float)(xDiff / Width * Math.PI); + var vertiDeg = scaleFac * (float)(yDiff / Height * Math.PI); + + Controller.MvpBuilder.AngleY += horiDeg; + Controller.MvpBuilder.AngleX += vertiDeg; + Controller.RefreshModelview(); + } + + _previousPosition = pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ModelviewProjectionBuilder.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ModelviewProjectionBuilder.cs new file mode 100644 index 00000000..4d3d306a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ModelviewProjectionBuilder.cs @@ -0,0 +1,151 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLLinesSample +{ + /// + /// Modelview x Projection matrix builder. + /// + public class ModelviewProjectionBuilder + { + #region fields + mat4 _modelviewMatrix = mat4.identity(), + _projectionMatrix = mat4.identity(); + + float _height, _width, _near, _far, _fovRadians; + + #endregion fields + + #region properties + public float Height + { + get { return _height; } + set { _height = value; } + } + + public float Width + { + get { return _width; } + set { _width = value; } + } + + public float Near + { + get { return _near; } + set { _near = value; } + } + + public float Far + { + get { return _far; } + set { _far = value; } + } + + public float FovRadians + { + get { return _fovRadians; } + set { _fovRadians = value; } + } + + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set { _modelviewMatrix = value; } + } + + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + + public float AngleX { get; set; } + public float AngleY { get; set; } + public float AngleZ { get; set; } + public float TranslationX { get; set; } + public float TranslationY { get; set; } + public float TranslationZ { get; set; } + + #endregion properties + + #region events + #endregion events + + #region constructors + public ModelviewProjectionBuilder() + { + + } + #endregion constructors + /// + /// Slightly edited formula! + /// + public void BuildPerspectiveProjection() + { + var a = Height / Width; + var n = Near; + var f = Far; + var e = 1 / (float)Math.Tan(FovRadians / 2); + + + var mat = new mat4( + new vec4[] + { + new vec4(e, 0, 0, 0), + new vec4(0, e/a, 0, 0), + new vec4(0, 0, -(2*f*n)/(f-n), -1), + new vec4(0, 0, -(f+n)/(f-n), 0), + }); + + ProjectionMatrix = mat; + } + + /// + /// Multiplies the Projection and modelview matrix into one. + /// + /// + public mat4 CombineToMvP() + { + return ProjectionMatrix * ModelviewMatrix; + } + public void BuildTurntableModelview(vec3 originPoint = new vec3()) + { + var cosX = (float)Math.Cos(AngleX); + var cosY = (float)Math.Cos(AngleY); + var cosZ = (float)Math.Cos(AngleZ); + var sinX = (float)Math.Sin(AngleX); + var sinY = (float)Math.Sin(AngleY); + var sinZ = (float)Math.Sin(AngleZ); + + mat4 rotX = new mat4( + new vec4[] + { + new vec4(1,0,0,0), + new vec4(0, cosX, -sinX, 0), + new vec4(0, sinX, cosX, 0), + new vec4(0,0,0,1) + }); + mat4 rotY = new mat4( + new vec4[] + { + new vec4(cosY, 0, sinY, 0), + new vec4(0, 1, 0,0), + new vec4(-sinY, 0, cosY, 0), + new vec4(0,0,0,1) + }); + + + var rotation = rotX * rotY; + var translation = rotation * glm.translate(mat4.identity(), new vec3(TranslationX + originPoint.x, TranslationY + originPoint.y, TranslationZ + originPoint.z)); + var translation2 = glm.translate(translation, new vec3(-originPoint.x, -originPoint.y, -originPoint.z)); + + + ModelviewMatrix = translation2; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/Axis.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/Axis.cs new file mode 100644 index 00000000..32366f7a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/Axis.cs @@ -0,0 +1,37 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.Core; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLLinesSample +{ + public class Axis + { + + #region fields + #endregion fields + + #region properties + public Tuple LineX { get; set; } + public Tuple LineY { get; set; } + public Tuple LineZ { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public Axis(float axisLength) + { + LineX = new Tuple(new vec3(0, 0, 0), new vec3(axisLength, 0, 0)); + LineY = new Tuple(new vec3(0, 0, 0), new vec3(0, axisLength, 0)); + LineZ = new Tuple(new vec3(0, 0, 0), new vec3(0, 0, axisLength)); + } + #endregion constructors + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/FlatShadedCube.cs new file mode 100644 index 00000000..93de9e85 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/FlatShadedCube.cs @@ -0,0 +1,67 @@ +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; + +namespace SharpGLLinesSample +{ + /// + /// A simple cube object + /// + public class FlatShadedCube + { + #region cube data + + static readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + + static readonly vec3[] _normals = new vec3[]{ + new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + }; + + static readonly uint[] _indices = new uint[]{ + 1,2,0, 2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + + + + #endregion cube data + + public static vec3[] Normals + { + get { return FlatShadedCube._normals; } + } + + public static vec3[] Vertices + { + get { return FlatShadedCube._vertices; } + } + + public static uint[] Indices + { + get { return FlatShadedCube._indices; } + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/MyTrefoilKnot.cs new file mode 100644 index 00000000..ccd56642 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ + +using GlmNet; +using SharpGL; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLLinesSample +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot + { + #region fields + /// The number of slices and stacks. + private static uint _slices = 128; + private static uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static uint[] _indices; + #endregion fields + + #region properties + public static vec3[] Normals + { + get { return MyTrefoilKnot._normals; } + } + + public static vec3[] Vertices + { + get { return MyTrefoilKnot._vertices; } + } + + public static uint[] Indices + { + get { return MyTrefoilKnot._indices; } + } + #endregion properties + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + #endregion constructor + + public static void ChangeDetail(uint slices, uint stacks) + { + _slices = slices; + _stacks = stacks; + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + uint vertexCount = _slices * _stacks; + uint indexCount = vertexCount * 6; + _indices = new uint[indexCount]; + int count = 0; + + uint n = 0; + for (uint i = 0; i < _slices; i++) + { + for (uint j = 0; j < _stacks; j++) + { + _indices[count++] = (uint)(n + j); + _indices[count++] = (uint)(n + (j + 1) % _stacks); + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (uint)_stacks; + } + } + #endregion calculate trefoil knot + + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/SquareGrid.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/SquareGrid.cs new file mode 100644 index 00000000..a1c57e0a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Primitives/SquareGrid.cs @@ -0,0 +1,117 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.Core; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLLinesSample +{ + public class SquareGrid + { + #region fields + private int _directionLineCount; + private float _stepSize, _lineThickness = 1f; + private List _lines = new List(); + #endregion fields + + #region properties + /// + /// Gets or sets the amount of lines in each direction. + /// + public int DirectionLineCount + { + get { return _directionLineCount; } + set { _directionLineCount = value; } + } + + /// + /// Distance between 2 lines. + /// + public float StepSize + { + get { return _stepSize; } + set { _stepSize = value; } + } + + public List Lines + { + get { return _lines; } + set { _lines = value; } + } + #endregion properties + + public SquareGrid() + :this(10, 1f) + { } + + public SquareGrid(int directionLineCount, float stepSize) + { + _directionLineCount = directionLineCount; + _stepSize = stepSize; + + RecalculateShape(); + } + + + /// + /// Calculates the lines using the current grid properties. + /// + public void RecalculateShape() + { + _lines = new List(); + var verts = new List(); + + float min = -StepSize * DirectionLineCount; + float max = StepSize * DirectionLineCount; + for (float x = min; x <= max; x += StepSize) + { + for (float z = min; z <= max; z += StepSize) + { + vec3 v1 = new vec3(x, 0.0f, min); + vec3 v2 = new vec3(x, 0.0f, max); + vec3 v3 = new vec3(min, 0.0f, z); + vec3 v4 = new vec3(max, 0.0f, z); + + verts.AddRange(new vec3[] { v1, v2, v3, v4 }); + + } + } + + Lines = verts; + } + public void RecalculateShape2() + { + List verts = new List(); + + float min = -StepSize * DirectionLineCount; + float max = StepSize * DirectionLineCount; + + // Vertical + bool swap = false; + for (float x = min; x <= max; x += StepSize) + { + if (swap) + { + verts.Add(new vec3(x, 0, min)); + verts.Add(new vec3(x, 0, max)); + } + else + { + verts.Add(new vec3(x, 0, max)); + verts.Add(new vec3(x, 0, min)); + } + + swap = !swap; + } + + // Horizontal + + Lines = verts; + + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0ca0f6e8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLLinesSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLLinesSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.Designer.cs new file mode 100644 index 00000000..fd195297 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLLinesSample.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLLinesSample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.Designer.cs new file mode 100644 index 00000000..6c4f3a17 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLLinesSample.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.frag new file mode 100644 index 00000000..7d1db9a4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.frag @@ -0,0 +1,10 @@ +#version 330 + +in vec3 Color; + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(Color, 1); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.vert new file mode 100644 index 00000000..ee35be3a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/ShaderResources/SingleColor.vert @@ -0,0 +1,15 @@ +#version 330 core + +in vec4 Position; +in vec3 ColorValue; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 Color; +void main() +{ + gl_Position = ModelviewProjection * Position; + + Color = ColorValue; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesBufferGroup.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesBufferGroup.cs new file mode 100644 index 00000000..aea7eda1 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesBufferGroup.cs @@ -0,0 +1,134 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLLinesSample +{ + public class LinesBufferGroup + { + #region fields + private uint _usage = OpenGL.GL_STATIC_COPY; + private uint _vboTarget = OpenGL.GL_ARRAY_BUFFER; + private uint _iboTarget = OpenGL.GL_ELEMENT_ARRAY_BUFFER; + + #endregion fields + + #region properties + public uint Vao { get; set; } + public uint Ibo { get; set; } + public uint Position { get; set; } + public uint ColorValue { get; set; } + + + public int IndicesCount { get; set; } + public int VerticesCount { get; set; } + + public float LineWidth = 1; + #endregion properties + + #region events + #endregion events + + #region constructors + public LinesBufferGroup(OpenGL gl) + { + CreateBufferIds(gl); + } + + #endregion constructors + + private void CreateBufferIds(OpenGL gl) + { + var amount = 3; + uint[] ids = new uint[amount]; + gl.GenBuffers(amount, ids); + Position = ids[0]; + ColorValue = ids[1]; + Ibo = ids[2]; + } + + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, ColorF colorValue) + { + if (indices != null) + IndicesCount = indices.Length; + else + IndicesCount = 0; + VerticesCount = vertices.Length; + + float[] colorsArr = new float[3]; + + // Convert materials to float arrays. + var newPos = 0; + var argb = colorValue; + for (int j = 0; j < 3; j++) + { + colorsArr[newPos] = argb[j+1]; + newPos++; + } + + // Set buffer data. + BufferData(gl, indices, vertices, colorsArr); + + } + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] colors) + { + if (indices != null) + { + gl.BindBuffer(_iboTarget, Ibo); + gl.BufferData(_iboTarget, indices, _usage); + } + + gl.BindBuffer(_vboTarget, Position); + gl.BufferData(_vboTarget, vertices, _usage); + + gl.BindBuffer(_vboTarget, ColorValue); + gl.BufferData(_vboTarget, colors, _usage); + + } + + public void PrepareVAO(OpenGL gl, LinesProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + Vao = vertArrIds[0]; + gl.BindVertexArray(Vao); + + BindVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + + public void BindVAO(OpenGL gl) + { + gl.BindVertexArray(Vao); + } + + public void BindVBOs(OpenGL gl, LinesProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["ColorValue"]; + gl.BindBuffer(_vboTarget, ColorValue); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + if (IndicesCount > 0) + gl.BindBuffer(_iboTarget, Ibo); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesProgram.cs new file mode 100644 index 00000000..d2c255b4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/LinesProgram.cs @@ -0,0 +1,149 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLLinesSample +{ + public class LinesProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "ColorValue" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.SingleColor.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.SingleColor.frag", assembly)); + + return stc; + } + } + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public LinesProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(LinesBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + //return; + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindVAO(gl); + + gl.LineWidth(group.LineWidth); + + // Use draw elements if an index buffer is defined. Else use draw arrays. + if (group.IndicesCount > 0) + gl.DrawElements(OpenGL.GL_LINES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero); + else + gl.DrawArrays(OpenGL.GL_LINES, 0, group.VerticesCount); + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs new file mode 100644 index 00000000..d8107294 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs @@ -0,0 +1,278 @@ +using GlmNet; +using SharpGL; +using SharpGLHelper; +using SharpGLHelper.Buffers; +using SharpGLHelper.Common; +using SharpGLHelper.OGLOverloads; +using SharpGLHelper.SceneElements; +using SharpGLTest.Shapes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGLTest.Shaders +{ + public class ShaderManagerNormalMaterialParticleTest + { + + #region fields + vec3 _lightPosition = new vec3(); + #endregion fields + + #region properties + + protected Dictionary AttributeLocations + { + get + { + var dic = new Dictionary(); + + dic.Add(0, "Position"); + dic.Add(1, "Normal"); + dic.Add(2, "TCol1"); + dic.Add(3, "TCol2"); + dic.Add(4, "TCol3"); + dic.Add(5, "TCol4"); + dic.Add(6, "AmbientMaterial"); + dic.Add(7, "DiffuseMaterial"); + dic.Add(8, "SpecularMaterial"); + dic.Add(9, "ShininessValue"); + + return dic; + } + } + #endregion properties + + #region events + #endregion events + + #region constructors + public ShaderManagerNormalMaterialParticleTest(OpenGL gl) + { + init(gl); + } + #endregion constructors + + MyTrefoilKnot knot; + // List of indices in the generated buffers + // and ultimately the buffer IDs. + uint ibo = 10; + uint vert = 0; + uint norm = 1; + uint tCol1 = 2; + uint tCol2 = 3; + uint tCol3 = 4; + uint tCol4 = 5; + uint amb = 6; + uint diff = 7; + uint spec = 8; + uint shini = 9; + + + uint iboPos = 10; + uint vertPos = 0; + uint normPos = 1; + uint tCol1Pos = 2; + uint tCol2Pos = 3; + uint tCol3Pos = 4; + uint tCol4Pos = 5; + uint ambPos = 6; + uint diffPos = 7; + uint specPos = 8; + uint shiniPos = 9; + + // Uniform positions + int lightPos = 0; + int modelView = 1; + int normMatrix = 2; + int projection = 3; + + // Shader program; + uint programId; + + public void init(OpenGL gl) + { + // Create vert and frag NormalMaterialParticle shader. + //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); + var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; + var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; + var executingAssembly = Assembly.GetExecutingAssembly(); + var autoAttachAssemblyName = true; + var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); + var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); + + var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); + gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); + gl.CompileShader(vertShaderId); + //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); + var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); + gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); + gl.CompileShader(fragShaderId); + + // Create Program from shaders. + programId = gl.CreateProgram(); + gl.AttachShader(programId, vertShaderId); + gl.AttachShader(programId, fragShaderId); + + gl.BindAttribLocation(programId, vertPos, "Position"); + gl.BindAttribLocation(programId, normPos, "Normal"); + gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); + gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); + gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); + gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); + gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); + gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); + gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); + gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); + + //gl.BindAttribLocation(programId, lightPos, "LightPosition"); + //gl.BindAttribLocation(programId, modelView, "Modelview"); + //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); + //gl.BindAttribLocation(programId, projection, "Projection"); + gl.LinkProgram(programId); + + + knot = MyTrefoilKnot.Instance; + + // Create the IBO and VBO's. + uint[] buffers = new uint[11]; + gl.GenBuffers(11, buffers); + ibo = buffers[iboPos]; + vert = buffers[vertPos]; + norm = buffers[normPos]; + tCol1 = buffers[tCol1Pos]; + tCol2 = buffers[tCol2Pos]; + tCol3 = buffers[tCol3Pos]; + tCol4 = buffers[tCol4Pos]; + amb = buffers[ambPos]; + diff = buffers[diffPos]; + spec = buffers[specPos]; + shini = buffers[shiniPos]; + + var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); + + + var dataSize = knot.Indices.Length * sizeof(uint); + IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); + var intData = new int[knot.Indices.Length]; + Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); + + // Set trefoil knot data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); + + // Set transformation data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); + + // Set material data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); + + // Apply uniforms. + gl.UseProgram(programId); + mat4 modelViewMat = mat4.identity(); + mat4 projectionMat = mat4.identity(); + mat3 NormalMat = mat3.identity(); + var zoomValue = new vec3(0, 0, -10); + //glm.translate(projectionMat, zoomValue); + + //projection = gl.GetUniformLocation(programId, "Projection"); + //modelView = gl.GetUniformLocation(programId, "Modelview"); + //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); + //lightPos = gl.GetUniformLocation(programId, "LightPosition"); + + + gl.Uniform3((int)lightPos, 5, 10, 15); + gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); + gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); + gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); + gl.UseProgram(0); + + + gl.FrontFace(OpenGL.GL_CW); + } + + public void render(OpenGL gl) + { + //Bind buffers. + gl.UseProgram(programId); + + float[] parameters = new float[16]; + gl.GetUniform(programId, projection, parameters); + + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(vertPos, 0); + gl.EnableVertexAttribArray(vertPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(normPos, 0); + gl.EnableVertexAttribArray(normPos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol1Pos, 1); + gl.EnableVertexAttribArray(tCol1Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol2Pos, 1); + gl.EnableVertexAttribArray(tCol2Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol3Pos, 1); + gl.EnableVertexAttribArray(tCol3Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol4Pos, 1); + gl.EnableVertexAttribArray(tCol4Pos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(ambPos, 1); + gl.EnableVertexAttribArray(ambPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(diffPos, 1); + gl.EnableVertexAttribArray(diffPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(specPos, 1); + gl.EnableVertexAttribArray(specPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); + gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(shiniPos, 1); + gl.EnableVertexAttribArray(shiniPos); + + gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); + //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); + + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); + gl.UseProgram(0); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/SharpGLLinesSample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/SharpGLLinesSample.csproj new file mode 100644 index 00000000..625560b3 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/SharpGLLinesSample.csproj @@ -0,0 +1,133 @@ + + + + + Debug + AnyCPU + {6F3EFCE8-BF8B-42BE-AD6A-3FA02284C60B} + WinExe + Properties + SharpGLLinesSample + SharpGLLinesSample + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\..\..\..\..\AH\SharpGLViewerSample\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + {47bcaa39-edad-4404-b6bd-4742b0abb523} + SharpGL.SceneGraph + + + {53e67055-13d2-4467-bb57-79589afac2cd} + SharpGL.WPF + + + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} + SharpGL + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/packages.config b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/packages.config new file mode 100644 index 00000000..e316866a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml new file mode 100644 index 00000000..746e82bc --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml.cs new file mode 100644 index 00000000..9faa206e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLMaterialSample +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GLController.cs new file mode 100644 index 00000000..6e756d74 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GLController.cs @@ -0,0 +1,208 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLMaterialSample +{ + public class GLController + { + #region fields + NormalMaterialProgram _nmProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public NormalMaterialProgram NmProgram + { + get { return _nmProgram; } + set { _nmProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + NmProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + NmProgram.Modelview = value; + } + } + + /// + /// A normal matrix, influences lighting reflection etc. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + _normalMatrix = value; + NmProgram.NormalMatrix = value; + } + } + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + // Create a shader program. + NmProgram = new NormalMaterialProgram(GL); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + NormalMatrix = mat3.identity(); + NmProgram.LightPosition = new vec3(5, 10, 15); + + + AddData(GL); + + GL.Enable(OpenGL.GL_DEPTH_TEST); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + } + public void Draw(object sender, OpenGLEventArgs args) + { + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + NmProgram.BindAll(GL); + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddData(OpenGL gl) + { + NMBufferGroup group = new NMBufferGroup(gl); + + var verts = MyTrefoilKnot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = MyTrefoilKnot.Normals.SelectMany(x => x.to_array()).ToArray(); + + group.BufferData(gl, MyTrefoilKnot.Indices, verts, normals, + new Material[] { new Material(new ColorF(255, 150, 50, 50), new ColorF(255,10,100,10), new ColorF(255, 225, 225, 225), null, 100f)}); + group.PrepareVAO(gl, NmProgram); + + NmProgram.AddBufferGroup(group); + NMBufferGroup groupCube = new NMBufferGroup(gl); + + var vertsCube = FlatShadedCube.Vertices.SelectMany(x => x.to_array()).ToArray(); + var normalsCube = FlatShadedCube.Normals.SelectMany(x => x.to_array()).ToArray(); + + + groupCube.BufferData(gl, FlatShadedCube.Indices, vertsCube, normalsCube, + new Material[] + { + new Material(new ColorF(1f, 0.3f, 1, 0), new ColorF(1f, 1f, 0.5f, 0), new ColorF(1f, 1, 0, 1), null, 100f), + }); + + groupCube.PrepareVAO(gl, NmProgram); + + NmProgram.AddBufferGroup(groupCube); + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GlmNetExtensions.cs new file mode 100644 index 00000000..adc57003 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLMaterialSample +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml new file mode 100644 index 00000000..0c2a86ba --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml.cs new file mode 100644 index 00000000..d7292c07 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/MainWindow.xaml.cs @@ -0,0 +1,112 @@ +using GlmNet; +using SharpGL.SceneGraph; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SharpGLMaterialSample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + + #region fields + private GLController _controller = new GLController(); + private Point _previousPosition; + + + #endregion fields + + #region properties + + public GLController Controller + { + get { return _controller; } + set { _controller = value; } + } + + public Action Draw { get { return Controller.Draw; } } + public Action Init { get { return Controller.Init; } } + public Action Resized { get { return Controller.Resized; } } + #endregion properties + + #region events + + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public MainWindow() + { + InitializeComponent(); + DataContext = this; + MouseMove += MainWindow_MouseMove; + MouseWheel += MainWindow_MouseWheel; + MouseDown += MainWindow_MouseDown; + + + } + #endregion constructors + + private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) + { + // Click + _previousPosition = e.GetPosition(sender as Window); + } + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + // Zoom + Controller.MvpBuilder.TranslationZ += e.Delta / 1000f; + Controller.RefreshModelview(); + } + + private void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + var pos = e.GetPosition(sender as Window); + + float xDiff = (float)(_previousPosition.X - pos.X); + float yDiff = (float)(_previousPosition.Y - pos.Y); + + if (e.LeftButton == MouseButtonState.Pressed) // Translate. + { + Controller.MvpBuilder.TranslationX += xDiff/10; + Controller.MvpBuilder.TranslationY += yDiff / 10; + Controller.RefreshModelview(); + } + else if (e.RightButton == MouseButtonState.Pressed) // Rotate. + { + var scaleFac = 1f; + var horiDeg = scaleFac * (float)(xDiff / Width * Math.PI); + var vertiDeg = scaleFac * (float)(yDiff / Height * Math.PI); + + Controller.MvpBuilder.AngleY += horiDeg; + Controller.MvpBuilder.AngleX += vertiDeg; + Controller.RefreshModelview(); + } + + _previousPosition = pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ModelviewProjectionBuilder.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ModelviewProjectionBuilder.cs new file mode 100644 index 00000000..a396154b --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ModelviewProjectionBuilder.cs @@ -0,0 +1,151 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLMaterialSample +{ + /// + /// Modelview x Projection matrix builder. + /// + public class ModelviewProjectionBuilder + { + #region fields + mat4 _modelviewMatrix = mat4.identity(), + _projectionMatrix = mat4.identity(); + + float _height, _width, _near, _far, _fovRadians; + + #endregion fields + + #region properties + public float Height + { + get { return _height; } + set { _height = value; } + } + + public float Width + { + get { return _width; } + set { _width = value; } + } + + public float Near + { + get { return _near; } + set { _near = value; } + } + + public float Far + { + get { return _far; } + set { _far = value; } + } + + public float FovRadians + { + get { return _fovRadians; } + set { _fovRadians = value; } + } + + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set { _modelviewMatrix = value; } + } + + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + + public float AngleX { get; set; } + public float AngleY { get; set; } + public float AngleZ { get; set; } + public float TranslationX { get; set; } + public float TranslationY { get; set; } + public float TranslationZ { get; set; } + + #endregion properties + + #region events + #endregion events + + #region constructors + public ModelviewProjectionBuilder() + { + + } + #endregion constructors + /// + /// Slightly edited formula! + /// + public void BuildPerspectiveProjection() + { + var a = Height / Width; + var n = Near; + var f = Far; + var e = 1 / (float)Math.Tan(FovRadians / 2); + + + var mat = new mat4( + new vec4[] + { + new vec4(e, 0, 0, 0), + new vec4(0, e/a, 0, 0), + new vec4(0, 0, -(2*f*n)/(f-n), -1), + new vec4(0, 0, -(f+n)/(f-n), 0), + }); + + ProjectionMatrix = mat; + } + + /// + /// Multiplies the Projection and modelview matrix into one. + /// + /// + public mat4 CombineToMvP() + { + return ProjectionMatrix * ModelviewMatrix; + } + public void BuildTurntableModelview(vec3 originPoint = new vec3()) + { + var cosX = (float)Math.Cos(AngleX); + var cosY = (float)Math.Cos(AngleY); + var cosZ = (float)Math.Cos(AngleZ); + var sinX = (float)Math.Sin(AngleX); + var sinY = (float)Math.Sin(AngleY); + var sinZ = (float)Math.Sin(AngleZ); + + mat4 rotX = new mat4( + new vec4[] + { + new vec4(1,0,0,0), + new vec4(0, cosX, -sinX, 0), + new vec4(0, sinX, cosX, 0), + new vec4(0,0,0,1) + }); + mat4 rotY = new mat4( + new vec4[] + { + new vec4(cosY, 0, sinY, 0), + new vec4(0, 1, 0,0), + new vec4(-sinY, 0, cosY, 0), + new vec4(0,0,0,1) + }); + + + var rotation = rotX * rotY; + var translation = rotation * glm.translate(mat4.identity(), new vec3(TranslationX + originPoint.x, TranslationY + originPoint.y, TranslationZ + originPoint.z)); + var translation2 = glm.translate(translation, new vec3(-originPoint.x, -originPoint.y, -originPoint.z)); + + + ModelviewMatrix = translation2; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/FlatShadedCube.cs new file mode 100644 index 00000000..f91ec2b3 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/FlatShadedCube.cs @@ -0,0 +1,67 @@ +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; + +namespace SharpGLMaterialSample +{ + /// + /// A simple cube object + /// + public class FlatShadedCube + { + #region cube data + + static readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + + static readonly vec3[] _normals = new vec3[]{ + new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + }; + + static readonly uint[] _indices = new uint[]{ + 1,2,0, 2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + + + + #endregion cube data + + public static vec3[] Normals + { + get { return FlatShadedCube._normals; } + } + + public static vec3[] Vertices + { + get { return FlatShadedCube._vertices; } + } + + public static uint[] Indices + { + get { return FlatShadedCube._indices; } + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/MyTrefoilKnot.cs new file mode 100644 index 00000000..47bb82cc --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Primitives/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ + +using GlmNet; +using SharpGL; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLMaterialSample +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot + { + #region fields + /// The number of slices and stacks. + private static uint _slices = 128; + private static uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static uint[] _indices; + #endregion fields + + #region properties + public static vec3[] Normals + { + get { return MyTrefoilKnot._normals; } + } + + public static vec3[] Vertices + { + get { return MyTrefoilKnot._vertices; } + } + + public static uint[] Indices + { + get { return MyTrefoilKnot._indices; } + } + #endregion properties + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + #endregion constructor + + public static void ChangeDetail(uint slices, uint stacks) + { + _slices = slices; + _stacks = stacks; + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + uint vertexCount = _slices * _stacks; + uint indexCount = vertexCount * 6; + _indices = new uint[indexCount]; + int count = 0; + + uint n = 0; + for (uint i = 0; i < _slices; i++) + { + for (uint j = 0; j < _stacks; j++) + { + _indices[count++] = (uint)(n + j); + _indices[count++] = (uint)(n + (j + 1) % _stacks); + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (uint)_stacks; + } + } + #endregion calculate trefoil knot + + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..1a123512 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLMaterialSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLMaterialSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.Designer.cs new file mode 100644 index 00000000..a55d811a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLMaterialSample.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLMaterialSample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.Designer.cs new file mode 100644 index 00000000..14602bb9 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLMaterialSample.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.frag new file mode 100644 index 00000000..5c909f73 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.frag @@ -0,0 +1,25 @@ +#version 330 +in vec3 EyespaceNormal; +in vec3 Diffuse; +in vec3 Ambient; +in vec3 Specular; +in float Shininess; + +uniform vec3 LightPosition; + +out vec4 FragColor; + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 E = vec3(0, 0, 1); + vec3 H = normalize(L + E); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + vec3 color = Ambient + df * Diffuse + sf * Specular; + FragColor = vec4(color, 1); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.vert new file mode 100644 index 00000000..e2853f81 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/ShaderResources/NormalMaterial.vert @@ -0,0 +1,27 @@ +#version 330 core + +in vec4 Position; +in vec3 Normal; +in vec3 DiffuseMaterial; +in vec3 AmbientMaterial; +in vec3 SpecularMaterial; +in float ShininessValue; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 EyespaceNormal; +out vec3 Diffuse; +out vec3 Ambient; +out vec3 Specular; +out float Shininess; +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = ModelviewProjection * Position; + + Diffuse = DiffuseMaterial; + Ambient = AmbientMaterial; + Specular = SpecularMaterial; + Shininess = ShininessValue; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NMBufferGroup.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NMBufferGroup.cs new file mode 100644 index 00000000..ebf06ca8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NMBufferGroup.cs @@ -0,0 +1,178 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLMaterialSample +{ + public class NMBufferGroup + { + #region fields + private uint _usage = OpenGL.GL_STATIC_COPY; + private uint _vboTarget = OpenGL.GL_ARRAY_BUFFER; + private uint _iboTarget = OpenGL.GL_ELEMENT_ARRAY_BUFFER; + + #endregion fields + + #region properties + public uint Vao { get; set; } + public uint Ibo { get; set; } + public uint Position { get; set; } + public uint Normal { get; set; } + public uint AmbientMaterial { get; set; } + public uint DiffuseMaterial { get; set; } + public uint SpecularMaterial { get; set; } + public uint ShininessValue { get; set; } + + + public int IndicesCount { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public NMBufferGroup(OpenGL gl) + { + CreateBufferIds(gl); + } + + #endregion constructors + + private void CreateBufferIds(OpenGL gl) + { + var amount = 7; + uint[] ids = new uint[amount]; + gl.GenBuffers(amount, ids); + Position = ids[0]; + Normal = ids[1]; + AmbientMaterial = ids[2]; + DiffuseMaterial = ids[3]; + SpecularMaterial = ids[4]; + ShininessValue = ids[5]; + Ibo = ids[6]; + } + + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, Material[] materials) + { + IndicesCount = indices.Length; + + var color3Size = 3 * materials.Length; + float[] ambs = new float[color3Size], + diffs = new float[color3Size], + specs = new float[color3Size], + shinis = new float[materials.Length]; + + // Convert materials to float arrays. + var newPos = 0; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + for (int j = 0; j < 3; j++) + { + ambs[newPos] = mat.Ambient[j+1]; + diffs[newPos] = mat.Diffuse[j+1]; + specs[newPos] = mat.Specular[j+1]; + newPos++; + } + shinis[i] = mat.Shininess; + } + + // Set buffer data. + BufferData(gl, indices, vertices, normals, + ambs, diffs, specs, shinis); + + } + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, + float[] ambs, float[] diffs, float[] specs, float[] shinis) + { + gl.BindBuffer(_iboTarget, Ibo); + gl.BufferData(_iboTarget, indices, _usage); + + gl.BindBuffer(_vboTarget, Position); + gl.BufferData(_vboTarget, vertices, _usage); + + gl.BindBuffer(_vboTarget, Normal); + gl.BufferData(_vboTarget, normals, _usage); + + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.BufferData(_vboTarget, ambs, _usage); + + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.BufferData(_vboTarget, diffs, _usage); + + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.BufferData(_vboTarget, specs, _usage); + + gl.BindBuffer(_vboTarget, ShininessValue); + gl.BufferData(_vboTarget, shinis, _usage); + + } + + public void PrepareVAO(OpenGL gl, NormalMaterialProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + Vao = vertArrIds[0]; + gl.BindVertexArray(Vao); + + BindVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + + public void BindVAO(OpenGL gl) + { + gl.BindVertexArray(Vao); + } + + public void BindVBOs(OpenGL gl, NormalMaterialProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["Normal"]; + gl.BindBuffer(_vboTarget, Normal); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["AmbientMaterial"]; + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["DiffuseMaterial"]; + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["SpecularMaterial"]; + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["ShininessValue"]; + gl.BindBuffer(_vboTarget, ShininessValue); + gl.VertexAttribPointer(attribPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + gl.BindBuffer(_iboTarget, Ibo); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs new file mode 100644 index 00000000..91f85039 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs @@ -0,0 +1,180 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLMaterialSample +{ + public class NormalMaterialProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + mat3 _normalMatrix; + vec3 _lightPosition; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "Normal", + "AmbientMaterial", + "DiffuseMaterial", + "SpecularMaterial", + "ShininessValue" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + "LightPosition" + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterial.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterial.frag", assembly)); + + return stc; + } + } + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + if (NormalMatrix.Equals(value)) + return; + + ChangedUniforms.Add(ApplyNormalMatrix); + _normalMatrix = value; + } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + public vec3 LightPosition + { + get { return _lightPosition; } + set + { + if (LightPosition.Equals(value)) + return; + + ChangedUniforms.Add(ApplyLightPosition); + _lightPosition = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public NormalMaterialProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(NMBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindVAO(gl); + gl.DrawElements(OpenGL.GL_TRIANGLES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero); + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + private void ApplyNormalMatrix(OpenGL gl) + { + gl.UniformMatrix3(Uniforms["NormalMatrix"], 1, false, NormalMatrix.to_array()); + } + private void ApplyLightPosition(OpenGL gl) + { + gl.Uniform3(Uniforms["LightPosition"], LightPosition.x, LightPosition.y, LightPosition.z); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs new file mode 100644 index 00000000..d8107294 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs @@ -0,0 +1,278 @@ +using GlmNet; +using SharpGL; +using SharpGLHelper; +using SharpGLHelper.Buffers; +using SharpGLHelper.Common; +using SharpGLHelper.OGLOverloads; +using SharpGLHelper.SceneElements; +using SharpGLTest.Shapes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGLTest.Shaders +{ + public class ShaderManagerNormalMaterialParticleTest + { + + #region fields + vec3 _lightPosition = new vec3(); + #endregion fields + + #region properties + + protected Dictionary AttributeLocations + { + get + { + var dic = new Dictionary(); + + dic.Add(0, "Position"); + dic.Add(1, "Normal"); + dic.Add(2, "TCol1"); + dic.Add(3, "TCol2"); + dic.Add(4, "TCol3"); + dic.Add(5, "TCol4"); + dic.Add(6, "AmbientMaterial"); + dic.Add(7, "DiffuseMaterial"); + dic.Add(8, "SpecularMaterial"); + dic.Add(9, "ShininessValue"); + + return dic; + } + } + #endregion properties + + #region events + #endregion events + + #region constructors + public ShaderManagerNormalMaterialParticleTest(OpenGL gl) + { + init(gl); + } + #endregion constructors + + MyTrefoilKnot knot; + // List of indices in the generated buffers + // and ultimately the buffer IDs. + uint ibo = 10; + uint vert = 0; + uint norm = 1; + uint tCol1 = 2; + uint tCol2 = 3; + uint tCol3 = 4; + uint tCol4 = 5; + uint amb = 6; + uint diff = 7; + uint spec = 8; + uint shini = 9; + + + uint iboPos = 10; + uint vertPos = 0; + uint normPos = 1; + uint tCol1Pos = 2; + uint tCol2Pos = 3; + uint tCol3Pos = 4; + uint tCol4Pos = 5; + uint ambPos = 6; + uint diffPos = 7; + uint specPos = 8; + uint shiniPos = 9; + + // Uniform positions + int lightPos = 0; + int modelView = 1; + int normMatrix = 2; + int projection = 3; + + // Shader program; + uint programId; + + public void init(OpenGL gl) + { + // Create vert and frag NormalMaterialParticle shader. + //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); + var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; + var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; + var executingAssembly = Assembly.GetExecutingAssembly(); + var autoAttachAssemblyName = true; + var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); + var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); + + var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); + gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); + gl.CompileShader(vertShaderId); + //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); + var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); + gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); + gl.CompileShader(fragShaderId); + + // Create Program from shaders. + programId = gl.CreateProgram(); + gl.AttachShader(programId, vertShaderId); + gl.AttachShader(programId, fragShaderId); + + gl.BindAttribLocation(programId, vertPos, "Position"); + gl.BindAttribLocation(programId, normPos, "Normal"); + gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); + gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); + gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); + gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); + gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); + gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); + gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); + gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); + + //gl.BindAttribLocation(programId, lightPos, "LightPosition"); + //gl.BindAttribLocation(programId, modelView, "Modelview"); + //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); + //gl.BindAttribLocation(programId, projection, "Projection"); + gl.LinkProgram(programId); + + + knot = MyTrefoilKnot.Instance; + + // Create the IBO and VBO's. + uint[] buffers = new uint[11]; + gl.GenBuffers(11, buffers); + ibo = buffers[iboPos]; + vert = buffers[vertPos]; + norm = buffers[normPos]; + tCol1 = buffers[tCol1Pos]; + tCol2 = buffers[tCol2Pos]; + tCol3 = buffers[tCol3Pos]; + tCol4 = buffers[tCol4Pos]; + amb = buffers[ambPos]; + diff = buffers[diffPos]; + spec = buffers[specPos]; + shini = buffers[shiniPos]; + + var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); + + + var dataSize = knot.Indices.Length * sizeof(uint); + IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); + var intData = new int[knot.Indices.Length]; + Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); + + // Set trefoil knot data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); + + // Set transformation data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); + + // Set material data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); + + // Apply uniforms. + gl.UseProgram(programId); + mat4 modelViewMat = mat4.identity(); + mat4 projectionMat = mat4.identity(); + mat3 NormalMat = mat3.identity(); + var zoomValue = new vec3(0, 0, -10); + //glm.translate(projectionMat, zoomValue); + + //projection = gl.GetUniformLocation(programId, "Projection"); + //modelView = gl.GetUniformLocation(programId, "Modelview"); + //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); + //lightPos = gl.GetUniformLocation(programId, "LightPosition"); + + + gl.Uniform3((int)lightPos, 5, 10, 15); + gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); + gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); + gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); + gl.UseProgram(0); + + + gl.FrontFace(OpenGL.GL_CW); + } + + public void render(OpenGL gl) + { + //Bind buffers. + gl.UseProgram(programId); + + float[] parameters = new float[16]; + gl.GetUniform(programId, projection, parameters); + + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(vertPos, 0); + gl.EnableVertexAttribArray(vertPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(normPos, 0); + gl.EnableVertexAttribArray(normPos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol1Pos, 1); + gl.EnableVertexAttribArray(tCol1Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol2Pos, 1); + gl.EnableVertexAttribArray(tCol2Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol3Pos, 1); + gl.EnableVertexAttribArray(tCol3Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol4Pos, 1); + gl.EnableVertexAttribArray(tCol4Pos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(ambPos, 1); + gl.EnableVertexAttribArray(ambPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(diffPos, 1); + gl.EnableVertexAttribArray(diffPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(specPos, 1); + gl.EnableVertexAttribArray(specPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); + gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(shiniPos, 1); + gl.EnableVertexAttribArray(shiniPos); + + gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); + //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); + + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); + gl.UseProgram(0); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj new file mode 100644 index 00000000..aecbfb72 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj @@ -0,0 +1,131 @@ + + + + + Debug + AnyCPU + {E28F65B6-C31C-4211-BFE0-32222F757BF8} + WinExe + Properties + SharpGLMaterialSample + SharpGLMaterialSample + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\..\..\..\..\AH\SharpGLViewerSample\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + {47bcaa39-edad-4404-b6bd-4742b0abb523} + SharpGL.SceneGraph + + + {53e67055-13d2-4467-bb57-79589afac2cd} + SharpGL.WPF + + + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} + SharpGL + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/packages.config b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/packages.config new file mode 100644 index 00000000..e316866a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.config new file mode 100644 index 00000000..74ade9db --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml new file mode 100644 index 00000000..3627cebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml.cs new file mode 100644 index 00000000..ba128f18 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLParticlesSample +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GLController.cs new file mode 100644 index 00000000..9be0a1c2 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GLController.cs @@ -0,0 +1,213 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLParticlesSample +{ + public class GLController + { + #region fields + NormalMaterialParticleProgram _nmpProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public NormalMaterialParticleProgram NmpProgram + { + get { return _nmpProgram; } + set { _nmpProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + NmpProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + NmpProgram.Modelview = value; + } + } + + /// + /// A normal matrix, influences lighting reflection etc. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + _normalMatrix = value; + NmpProgram.NormalMatrix = value; + } + } + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + // Create a shader program. + NmpProgram = new NormalMaterialParticleProgram(GL); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + NormalMatrix = mat3.identity(); + NmpProgram.LightPosition = new vec3(5, 10, 15); + + + AddData(GL); + + GL.Enable(OpenGL.GL_DEPTH_TEST); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + } + public void Draw(object sender, OpenGLEventArgs args) + { + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + NmpProgram.BindAll(GL); + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddData(OpenGL gl) + { + NMPBufferGroup group = new NMPBufferGroup(gl); + + var verts = MyTrefoilKnot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = MyTrefoilKnot.Normals.SelectMany(x => x.to_array()).ToArray(); + + group.BufferData(gl, MyTrefoilKnot.Indices, verts, normals, new mat4[] { mat4.identity() }, + new Material[] { new Material(new ColorF(255, 150, 50, 50), new ColorF(255,10,100,10), new ColorF(255, 225, 225, 225), null, 100f)}); + group.PrepareVAO(gl, NmpProgram); + + NmpProgram.AddBufferGroup(group); + NMPBufferGroup groupCube = new NMPBufferGroup(gl); + + var vertsCube = FlatShadedCube.Vertices.SelectMany(x => x.to_array()).ToArray(); + var normalsCube = FlatShadedCube.Normals.SelectMany(x => x.to_array()).ToArray(); + + + groupCube.BufferData(gl, FlatShadedCube.Indices, vertsCube, normalsCube, + new mat4[] + { + mat4.identity(), + glm.translate(mat4.identity(), new vec3(1,2,3)) + }, + new Material[] + { + new Material(new ColorF(1f, 0.3f, 1, 0), new ColorF(1f, 1f, 0.5f, 0), new ColorF(1f, 1, 0, 1), null, 100f), + new Material(new ColorF(1f, 0, 1, 0.3f), new ColorF(1f, 1f, 0.5f, 1), new ColorF(1f, 1, 0.3f, 0.3f), null, 100f) + }); + groupCube.PrepareVAO(gl, NmpProgram); + + NmpProgram.AddBufferGroup(groupCube); + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GlmNetExtensions.cs new file mode 100644 index 00000000..96cf78e4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLParticlesSample +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml new file mode 100644 index 00000000..e7b962dc --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml.cs new file mode 100644 index 00000000..18697840 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/MainWindow.xaml.cs @@ -0,0 +1,112 @@ +using GlmNet; +using SharpGL.SceneGraph; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SharpGLParticlesSample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + + #region fields + private GLController _controller = new GLController(); + private Point _previousPosition; + + + #endregion fields + + #region properties + + public GLController Controller + { + get { return _controller; } + set { _controller = value; } + } + + public Action Draw { get { return Controller.Draw; } } + public Action Init { get { return Controller.Init; } } + public Action Resized { get { return Controller.Resized; } } + #endregion properties + + #region events + + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public MainWindow() + { + InitializeComponent(); + DataContext = this; + MouseMove += MainWindow_MouseMove; + MouseWheel += MainWindow_MouseWheel; + MouseDown += MainWindow_MouseDown; + + + } + #endregion constructors + + private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) + { + // Click + _previousPosition = e.GetPosition(sender as Window); + } + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + // Zoom + Controller.MvpBuilder.TranslationZ += e.Delta / 1000f; + Controller.RefreshModelview(); + } + + private void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + var pos = e.GetPosition(sender as Window); + + float xDiff = (float)(_previousPosition.X - pos.X); + float yDiff = (float)(_previousPosition.Y - pos.Y); + + if (e.LeftButton == MouseButtonState.Pressed) // Translate. + { + Controller.MvpBuilder.TranslationX += xDiff/10; + Controller.MvpBuilder.TranslationY += yDiff / 10; + Controller.RefreshModelview(); + } + else if (e.RightButton == MouseButtonState.Pressed) // Rotate. + { + var scaleFac = 1f; + var horiDeg = scaleFac * (float)(xDiff / Width * Math.PI); + var vertiDeg = scaleFac * (float)(yDiff / Height * Math.PI); + + Controller.MvpBuilder.AngleY += horiDeg; + Controller.MvpBuilder.AngleX += vertiDeg; + Controller.RefreshModelview(); + } + + _previousPosition = pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ModelviewProjectionBuilder.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ModelviewProjectionBuilder.cs new file mode 100644 index 00000000..e98c29e7 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ModelviewProjectionBuilder.cs @@ -0,0 +1,151 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLParticlesSample +{ + /// + /// Modelview x Projection matrix builder. + /// + public class ModelviewProjectionBuilder + { + #region fields + mat4 _modelviewMatrix = mat4.identity(), + _projectionMatrix = mat4.identity(); + + float _height, _width, _near, _far, _fovRadians; + + #endregion fields + + #region properties + public float Height + { + get { return _height; } + set { _height = value; } + } + + public float Width + { + get { return _width; } + set { _width = value; } + } + + public float Near + { + get { return _near; } + set { _near = value; } + } + + public float Far + { + get { return _far; } + set { _far = value; } + } + + public float FovRadians + { + get { return _fovRadians; } + set { _fovRadians = value; } + } + + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set { _modelviewMatrix = value; } + } + + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + + public float AngleX { get; set; } + public float AngleY { get; set; } + public float AngleZ { get; set; } + public float TranslationX { get; set; } + public float TranslationY { get; set; } + public float TranslationZ { get; set; } + + #endregion properties + + #region events + #endregion events + + #region constructors + public ModelviewProjectionBuilder() + { + + } + #endregion constructors + /// + /// Slightly edited formula! + /// + public void BuildPerspectiveProjection() + { + var a = Height / Width; + var n = Near; + var f = Far; + var e = 1 / (float)Math.Tan(FovRadians / 2); + + + var mat = new mat4( + new vec4[] + { + new vec4(e, 0, 0, 0), + new vec4(0, e/a, 0, 0), + new vec4(0, 0, -(2*f*n)/(f-n), -1), + new vec4(0, 0, -(f+n)/(f-n), 0), + }); + + ProjectionMatrix = mat; + } + + /// + /// Multiplies the Projection and modelview matrix into one. + /// + /// + public mat4 CombineToMvP() + { + return ProjectionMatrix * ModelviewMatrix; + } + public void BuildTurntableModelview(vec3 originPoint = new vec3()) + { + var cosX = (float)Math.Cos(AngleX); + var cosY = (float)Math.Cos(AngleY); + var cosZ = (float)Math.Cos(AngleZ); + var sinX = (float)Math.Sin(AngleX); + var sinY = (float)Math.Sin(AngleY); + var sinZ = (float)Math.Sin(AngleZ); + + mat4 rotX = new mat4( + new vec4[] + { + new vec4(1,0,0,0), + new vec4(0, cosX, -sinX, 0), + new vec4(0, sinX, cosX, 0), + new vec4(0,0,0,1) + }); + mat4 rotY = new mat4( + new vec4[] + { + new vec4(cosY, 0, sinY, 0), + new vec4(0, 1, 0,0), + new vec4(-sinY, 0, cosY, 0), + new vec4(0,0,0,1) + }); + + + var rotation = rotX * rotY; + var translation = rotation * glm.translate(mat4.identity(), new vec3(TranslationX + originPoint.x, TranslationY + originPoint.y, TranslationZ + originPoint.z)); + var translation2 = glm.translate(translation, new vec3(-originPoint.x, -originPoint.y, -originPoint.z)); + + + ModelviewMatrix = translation2; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/FlatShadedCube.cs new file mode 100644 index 00000000..4390c8ca --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/FlatShadedCube.cs @@ -0,0 +1,67 @@ +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; + +namespace SharpGLParticlesSample +{ + /// + /// A simple cube object + /// + public class FlatShadedCube + { + #region cube data + + static readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + + static readonly vec3[] _normals = new vec3[]{ + new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + }; + + static readonly uint[] _indices = new uint[]{ + 1,2,0, 2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + + + + #endregion cube data + + public static vec3[] Normals + { + get { return FlatShadedCube._normals; } + } + + public static vec3[] Vertices + { + get { return FlatShadedCube._vertices; } + } + + public static uint[] Indices + { + get { return FlatShadedCube._indices; } + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/MyTrefoilKnot.cs new file mode 100644 index 00000000..502211ac --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Primitives/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ + +using GlmNet; +using SharpGL; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLParticlesSample +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot + { + #region fields + /// The number of slices and stacks. + private static uint _slices = 128; + private static uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static uint[] _indices; + #endregion fields + + #region properties + public static vec3[] Normals + { + get { return MyTrefoilKnot._normals; } + } + + public static vec3[] Vertices + { + get { return MyTrefoilKnot._vertices; } + } + + public static uint[] Indices + { + get { return MyTrefoilKnot._indices; } + } + #endregion properties + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + #endregion constructor + + public static void ChangeDetail(uint slices, uint stacks) + { + _slices = slices; + _stacks = stacks; + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + uint vertexCount = _slices * _stacks; + uint indexCount = vertexCount * 6; + _indices = new uint[indexCount]; + int count = 0; + + uint n = 0; + for (uint i = 0; i < _slices; i++) + { + for (uint j = 0; j < _stacks; j++) + { + _indices[count++] = (uint)(n + j); + _indices[count++] = (uint)(n + (j + 1) % _stacks); + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (uint)_stacks; + } + } + #endregion calculate trefoil knot + + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f6791d0a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLParticlesSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLParticlesSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.Designer.cs new file mode 100644 index 00000000..b19e7507 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLParticlesSample.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLParticlesSample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.Designer.cs new file mode 100644 index 00000000..889d0a05 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLParticlesSample.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.frag new file mode 100644 index 00000000..d0d6790d --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.frag @@ -0,0 +1,25 @@ +#version 330 +in vec3 EyespaceNormal; +in vec3 Ambient; +in vec3 Diffuse; +in vec3 Specular; +in float Shininess; + +uniform vec3 LightPosition; + +out vec4 FragColor; + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 E = vec3(0, 0, 1); + vec3 H = normalize(L + E); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + vec3 color = Ambient + df * Diffuse + sf * Specular; + FragColor = vec4(color, 0); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.vert new file mode 100644 index 00000000..3a1d2426 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/ShaderResources/NormalMaterialParticle.vert @@ -0,0 +1,46 @@ +#version 330 core +in vec4 Position; +in vec3 Normal; +in vec4 TCol1; +in vec4 TCol2; +in vec4 TCol3; +in vec4 TCol4; +in vec3 AmbientMaterial; +in vec3 DiffuseMaterial; +in vec3 SpecularMaterial; +in float ShininessValue; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 EyespaceNormal; +out vec3 Ambient; +out vec3 Diffuse; +out vec3 Specular; +out float Shininess; + +void main() +{ + // Put the transformation matrix back together. + mat4 transformation = mat4(0); + transformation[0] = TCol1; + transformation[1] = TCol2; + transformation[2] = TCol3; + transformation[3] = TCol4; + + // Get the transformed position and normal. + // NOTE! This is not the correct way to transform a mat3, but it's done like this for simplicity. + vec4 pos = Position * transformation; + vec4 norm4 = vec4(Normal.x, Normal.y, Normal.z, 0) * transformation; + + + vec3 norm3 = norm4.xyz; + EyespaceNormal = NormalMatrix * norm3; + + gl_Position = ModelviewProjection * pos; + + Ambient = AmbientMaterial; + Diffuse = DiffuseMaterial; + Specular = SpecularMaterial; + Shininess = ShininessValue; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NMPBufferGroup.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NMPBufferGroup.cs new file mode 100644 index 00000000..72e6cd40 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NMPBufferGroup.cs @@ -0,0 +1,246 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLParticlesSample +{ + public class NMPBufferGroup + { + #region fields + private uint _usage = OpenGL.GL_STATIC_COPY; + private uint _vboTarget = OpenGL.GL_ARRAY_BUFFER; + private uint _iboTarget = OpenGL.GL_ELEMENT_ARRAY_BUFFER; + + #endregion fields + + #region properties + public uint Vao { get; set; } + public uint Ibo { get; set; } + public uint Position { get; set; } + public uint Normal { get; set; } + public uint TCol1 { get; set; } + public uint TCol2 { get; set; } + public uint TCol3 { get; set; } + public uint TCol4 { get; set; } + public uint AmbientMaterial { get; set; } + public uint DiffuseMaterial { get; set; } + public uint SpecularMaterial { get; set; } + public uint ShininessValue { get; set; } + + + public int ParticleCount { get; set; } + public int IndicesCount { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public NMPBufferGroup(OpenGL gl) + { + CreateBufferIds(gl); + } + #endregion constructors + + private void CreateBufferIds(OpenGL gl) + { + var amount = 11; + uint[] ids = new uint[amount]; + gl.GenBuffers(amount, ids); + Position = ids[0]; + Normal = ids[1]; + TCol1 = ids[2]; + TCol2 = ids[3]; + TCol3 = ids[4]; + TCol4 = ids[5]; + AmbientMaterial = ids[6]; + DiffuseMaterial = ids[7]; + SpecularMaterial = ids[8]; + ShininessValue = ids[9]; + Ibo = ids[10]; + } + + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, + mat4[] transformations, Material[] materials) + { + // Use the amount of transformations to decide how many particles of this object should be drawn. + ParticleCount = transformations.Length; + IndicesCount = indices.Length; + + var tColSize = 4 * transformations.Length; + var color3Size = 3 * materials.Length; + float[] tCol1 = new float[tColSize], + tCol2 = new float[tColSize], + tCol3 = new float[tColSize], + tCol4 = new float[tColSize], + ambs = new float[color3Size], + diffs = new float[color3Size], + specs = new float[color3Size], + shinis = new float[materials.Length]; + + // Convert transformations to float arrays. + var newPos = 0; + foreach (var trans in transformations) + { + for (int i = 0; i < 4; i++) + { + tCol1[newPos] = trans[i][0]; + tCol2[newPos] = trans[i][1]; + tCol3[newPos] = trans[i][2]; + tCol4[newPos] = trans[i][3]; + newPos++; + } + } + + // Convert materials to float arrays. + newPos = 0; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + for (int j = 0; j < 3; j++) + { + ambs[newPos] = mat.Ambient[j+1]; + diffs[newPos] = mat.Diffuse[j+1]; + specs[newPos] = mat.Specular[j+1]; + newPos++; + } + shinis[i] = mat.Shininess; + } + + // Set buffer data. + BufferData(gl, indices, vertices, normals, + tCol1, tCol2, tCol3, tCol4, + ambs, diffs, specs, shinis); + } + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, + float[] tCol1, float[] tCol2, float[] tCol3, float[] tCol4, + float[] ambs, float[] diffs, float[] specs, float[] shinis) + { + gl.BindBuffer(_iboTarget, Ibo); + gl.BufferData(_iboTarget, indices, _usage); + + gl.BindBuffer(_vboTarget, Position); + gl.BufferData(_vboTarget, vertices, _usage); + + gl.BindBuffer(_vboTarget, Normal); + gl.BufferData(_vboTarget, normals, _usage); + + gl.BindBuffer(_vboTarget, TCol1); + gl.BufferData(_vboTarget, tCol1, _usage); + + gl.BindBuffer(_vboTarget, TCol2); + gl.BufferData(_vboTarget, tCol2, _usage); + + gl.BindBuffer(_vboTarget, TCol3); + gl.BufferData(_vboTarget, tCol3, _usage); + + gl.BindBuffer(_vboTarget, TCol4); + gl.BufferData(_vboTarget, tCol4, _usage); + + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.BufferData(_vboTarget, ambs, _usage); + + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.BufferData(_vboTarget, diffs, _usage); + + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.BufferData(_vboTarget, specs, _usage); + + gl.BindBuffer(_vboTarget, ShininessValue); + gl.BufferData(_vboTarget, shinis, _usage); + + } + + + public void PrepareVAO(OpenGL gl, NormalMaterialParticleProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + Vao = vertArrIds[0]; + gl.BindVertexArray(Vao); + + BindVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + + public void BindVAO(OpenGL gl) + { + gl.BindVertexArray(Vao); + } + + public void BindVBOs(OpenGL gl, NormalMaterialParticleProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["Normal"]; + gl.BindBuffer(_vboTarget, Normal); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["TCol1"]; + gl.BindBuffer(_vboTarget, TCol1); + gl.VertexAttribPointer(attribPos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["TCol2"]; + gl.BindBuffer(_vboTarget, TCol2); + gl.VertexAttribPointer(attribPos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["TCol3"]; + gl.BindBuffer(_vboTarget, TCol3); + gl.VertexAttribPointer(attribPos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["TCol4"]; + gl.BindBuffer(_vboTarget, TCol4); + gl.VertexAttribPointer(attribPos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["AmbientMaterial"]; + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["DiffuseMaterial"]; + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["SpecularMaterial"]; + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["ShininessValue"]; + gl.BindBuffer(_vboTarget, ShininessValue); + gl.VertexAttribPointer(attribPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + gl.BindBuffer(_iboTarget, Ibo); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NormalMaterialParticleProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NormalMaterialParticleProgram.cs new file mode 100644 index 00000000..2bbf5548 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/NormalMaterialParticleProgram.cs @@ -0,0 +1,187 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLParticlesSample +{ + public class NormalMaterialParticleProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + mat3 _normalMatrix; + vec3 _lightPosition; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "Normal", + "TCol1", + "TCol2", + "TCol3", + "TCol4", + "AmbientMaterial", + "DiffuseMaterial", + "SpecularMaterial", + "ShininessValue" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + "LightPosition" + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterialParticle.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterialParticle.frag", assembly)); + + return stc; + } + } + + + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + if (NormalMatrix.Equals(value)) + return; + + ChangedUniforms.Add(ApplyNormalMatrix); + _normalMatrix = value; + } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + public vec3 LightPosition + { + get { return _lightPosition; } + set + { + if (LightPosition.Equals(value)) + return; + + ChangedUniforms.Add(ApplyLightPosition); + _lightPosition = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public NormalMaterialParticleProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(NMPBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindVAO(gl); + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, group.ParticleCount); + + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + private void ApplyNormalMatrix(OpenGL gl) + { + gl.UniformMatrix3(Uniforms["NormalMatrix"], 1, false, NormalMatrix.to_array()); + } + private void ApplyLightPosition(OpenGL gl) + { + gl.Uniform3(Uniforms["LightPosition"], LightPosition.x, LightPosition.y, LightPosition.z); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs new file mode 100644 index 00000000..d8107294 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs @@ -0,0 +1,278 @@ +using GlmNet; +using SharpGL; +using SharpGLHelper; +using SharpGLHelper.Buffers; +using SharpGLHelper.Common; +using SharpGLHelper.OGLOverloads; +using SharpGLHelper.SceneElements; +using SharpGLTest.Shapes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGLTest.Shaders +{ + public class ShaderManagerNormalMaterialParticleTest + { + + #region fields + vec3 _lightPosition = new vec3(); + #endregion fields + + #region properties + + protected Dictionary AttributeLocations + { + get + { + var dic = new Dictionary(); + + dic.Add(0, "Position"); + dic.Add(1, "Normal"); + dic.Add(2, "TCol1"); + dic.Add(3, "TCol2"); + dic.Add(4, "TCol3"); + dic.Add(5, "TCol4"); + dic.Add(6, "AmbientMaterial"); + dic.Add(7, "DiffuseMaterial"); + dic.Add(8, "SpecularMaterial"); + dic.Add(9, "ShininessValue"); + + return dic; + } + } + #endregion properties + + #region events + #endregion events + + #region constructors + public ShaderManagerNormalMaterialParticleTest(OpenGL gl) + { + init(gl); + } + #endregion constructors + + MyTrefoilKnot knot; + // List of indices in the generated buffers + // and ultimately the buffer IDs. + uint ibo = 10; + uint vert = 0; + uint norm = 1; + uint tCol1 = 2; + uint tCol2 = 3; + uint tCol3 = 4; + uint tCol4 = 5; + uint amb = 6; + uint diff = 7; + uint spec = 8; + uint shini = 9; + + + uint iboPos = 10; + uint vertPos = 0; + uint normPos = 1; + uint tCol1Pos = 2; + uint tCol2Pos = 3; + uint tCol3Pos = 4; + uint tCol4Pos = 5; + uint ambPos = 6; + uint diffPos = 7; + uint specPos = 8; + uint shiniPos = 9; + + // Uniform positions + int lightPos = 0; + int modelView = 1; + int normMatrix = 2; + int projection = 3; + + // Shader program; + uint programId; + + public void init(OpenGL gl) + { + // Create vert and frag NormalMaterialParticle shader. + //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); + var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; + var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; + var executingAssembly = Assembly.GetExecutingAssembly(); + var autoAttachAssemblyName = true; + var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); + var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); + + var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); + gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); + gl.CompileShader(vertShaderId); + //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); + var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); + gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); + gl.CompileShader(fragShaderId); + + // Create Program from shaders. + programId = gl.CreateProgram(); + gl.AttachShader(programId, vertShaderId); + gl.AttachShader(programId, fragShaderId); + + gl.BindAttribLocation(programId, vertPos, "Position"); + gl.BindAttribLocation(programId, normPos, "Normal"); + gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); + gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); + gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); + gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); + gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); + gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); + gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); + gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); + + //gl.BindAttribLocation(programId, lightPos, "LightPosition"); + //gl.BindAttribLocation(programId, modelView, "Modelview"); + //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); + //gl.BindAttribLocation(programId, projection, "Projection"); + gl.LinkProgram(programId); + + + knot = MyTrefoilKnot.Instance; + + // Create the IBO and VBO's. + uint[] buffers = new uint[11]; + gl.GenBuffers(11, buffers); + ibo = buffers[iboPos]; + vert = buffers[vertPos]; + norm = buffers[normPos]; + tCol1 = buffers[tCol1Pos]; + tCol2 = buffers[tCol2Pos]; + tCol3 = buffers[tCol3Pos]; + tCol4 = buffers[tCol4Pos]; + amb = buffers[ambPos]; + diff = buffers[diffPos]; + spec = buffers[specPos]; + shini = buffers[shiniPos]; + + var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); + + + var dataSize = knot.Indices.Length * sizeof(uint); + IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); + var intData = new int[knot.Indices.Length]; + Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); + + // Set trefoil knot data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); + + // Set transformation data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); + + // Set material data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); + + // Apply uniforms. + gl.UseProgram(programId); + mat4 modelViewMat = mat4.identity(); + mat4 projectionMat = mat4.identity(); + mat3 NormalMat = mat3.identity(); + var zoomValue = new vec3(0, 0, -10); + //glm.translate(projectionMat, zoomValue); + + //projection = gl.GetUniformLocation(programId, "Projection"); + //modelView = gl.GetUniformLocation(programId, "Modelview"); + //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); + //lightPos = gl.GetUniformLocation(programId, "LightPosition"); + + + gl.Uniform3((int)lightPos, 5, 10, 15); + gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); + gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); + gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); + gl.UseProgram(0); + + + gl.FrontFace(OpenGL.GL_CW); + } + + public void render(OpenGL gl) + { + //Bind buffers. + gl.UseProgram(programId); + + float[] parameters = new float[16]; + gl.GetUniform(programId, projection, parameters); + + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(vertPos, 0); + gl.EnableVertexAttribArray(vertPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(normPos, 0); + gl.EnableVertexAttribArray(normPos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol1Pos, 1); + gl.EnableVertexAttribArray(tCol1Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol2Pos, 1); + gl.EnableVertexAttribArray(tCol2Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol3Pos, 1); + gl.EnableVertexAttribArray(tCol3Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol4Pos, 1); + gl.EnableVertexAttribArray(tCol4Pos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(ambPos, 1); + gl.EnableVertexAttribArray(ambPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(diffPos, 1); + gl.EnableVertexAttribArray(diffPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(specPos, 1); + gl.EnableVertexAttribArray(specPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); + gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(shiniPos, 1); + gl.EnableVertexAttribArray(shiniPos); + + gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); + //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); + + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); + gl.UseProgram(0); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/SharpGLParticlesSample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/SharpGLParticlesSample.csproj new file mode 100644 index 00000000..7153c9fe --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/SharpGLParticlesSample.csproj @@ -0,0 +1,134 @@ + + + + + Debug + AnyCPU + {A2965D87-5FB3-44B9-8D3E-8243A6F5FE14} + WinExe + Properties + SharpGLParticlesSample + SharpGLParticlesSample + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\..\..\..\..\AH\SharpGLViewerSample\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + {47bcaa39-edad-4404-b6bd-4742b0abb523} + SharpGL.SceneGraph + + + {53e67055-13d2-4467-bb57-79589afac2cd} + SharpGL.WPF + + + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} + SharpGL + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/packages.config b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/packages.config new file mode 100644 index 00000000..7bd4d3f8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml new file mode 100644 index 00000000..25de1406 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml.cs new file mode 100644 index 00000000..e6c19c08 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLTranslucencySample +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GLController.cs new file mode 100644 index 00000000..2b389d1b --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GLController.cs @@ -0,0 +1,211 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLTranslucencySample +{ + public class GLController + { + #region fields + NormalTranslucentMaterialProgram _ntmProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public NormalTranslucentMaterialProgram NtmProgram + { + get { return _ntmProgram; } + set { _ntmProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + NtmProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + NtmProgram.Modelview = value; + } + } + + /// + /// A normal matrix, influences lighting reflection etc. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + _normalMatrix = value; + NtmProgram.NormalMatrix = value; + } + } + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + // Create a shader program. + NtmProgram = new NormalTranslucentMaterialProgram(GL); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + NormalMatrix = mat3.identity(); + NtmProgram.LightPosition = new vec3(5, 10, 15); + + + AddData(GL); + + GL.DepthMask(OpenGL.GL_FALSE); + GL.Enable(OpenGL.GL_BLEND); + GL.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + } + public void Draw(object sender, OpenGLEventArgs args) + { + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + NtmProgram.BindAll(GL); + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddData(OpenGL gl) + { + NTMBufferGroup group = new NTMBufferGroup(gl); + + var verts = MyTrefoilKnot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = MyTrefoilKnot.Normals.SelectMany(x => x.to_array()).ToArray(); + + group.BufferData(gl, MyTrefoilKnot.Indices, verts, normals, + new Material[] { new Material(new ColorF(150, 150, 50, 50), new ColorF(255, 10, 100, 10), new ColorF(255, 225, 225, 225), null, 100f) }); + group.PrepareVAO(gl, NtmProgram); + + NtmProgram.AddBufferGroup(group); + NTMBufferGroup groupCube = new NTMBufferGroup(gl); + + var vertsCube = FlatShadedCube.Vertices.SelectMany(x => x.to_array()).ToArray(); + var normalsCube = FlatShadedCube.Normals.SelectMany(x => x.to_array()).ToArray(); + + + groupCube.BufferData(gl, FlatShadedCube.Indices, vertsCube, normalsCube, + new Material[] + { + new Material(new ColorF(0.5f, 0.3f, 1, 0), new ColorF(1f, 1f, 0.5f, 0), new ColorF(1f, 1, 0, 1), null, 100f) + }); + + groupCube.PrepareVAO(gl, NtmProgram); + + NtmProgram.AddBufferGroup(groupCube); + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GlmNetExtensions.cs new file mode 100644 index 00000000..a35ae8be --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLTranslucencySample +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml new file mode 100644 index 00000000..46558244 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml.cs new file mode 100644 index 00000000..7a689979 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/MainWindow.xaml.cs @@ -0,0 +1,112 @@ +using GlmNet; +using SharpGL.SceneGraph; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SharpGLTranslucencySample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + + #region fields + private GLController _controller = new GLController(); + private Point _previousPosition; + + + #endregion fields + + #region properties + + public GLController Controller + { + get { return _controller; } + set { _controller = value; } + } + + public Action Draw { get { return Controller.Draw; } } + public Action Init { get { return Controller.Init; } } + public Action Resized { get { return Controller.Resized; } } + #endregion properties + + #region events + + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public MainWindow() + { + InitializeComponent(); + DataContext = this; + MouseMove += MainWindow_MouseMove; + MouseWheel += MainWindow_MouseWheel; + MouseDown += MainWindow_MouseDown; + + + } + #endregion constructors + + private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e) + { + // Click + _previousPosition = e.GetPosition(sender as Window); + } + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + // Zoom + Controller.MvpBuilder.TranslationZ += e.Delta / 1000f; + Controller.RefreshModelview(); + } + + private void MainWindow_MouseMove(object sender, MouseEventArgs e) + { + var pos = e.GetPosition(sender as Window); + + float xDiff = (float)(_previousPosition.X - pos.X); + float yDiff = (float)(_previousPosition.Y - pos.Y); + + if (e.LeftButton == MouseButtonState.Pressed) // Translate. + { + Controller.MvpBuilder.TranslationX += xDiff/10; + Controller.MvpBuilder.TranslationY += yDiff / 10; + Controller.RefreshModelview(); + } + else if (e.RightButton == MouseButtonState.Pressed) // Rotate. + { + var scaleFac = 1f; + var horiDeg = scaleFac * (float)(xDiff / Width * Math.PI); + var vertiDeg = scaleFac * (float)(yDiff / Height * Math.PI); + + Controller.MvpBuilder.AngleY += horiDeg; + Controller.MvpBuilder.AngleX += vertiDeg; + Controller.RefreshModelview(); + } + + _previousPosition = pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ModelviewProjectionBuilder.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ModelviewProjectionBuilder.cs new file mode 100644 index 00000000..27029c9b --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ModelviewProjectionBuilder.cs @@ -0,0 +1,151 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLTranslucencySample +{ + /// + /// Modelview x Projection matrix builder. + /// + public class ModelviewProjectionBuilder + { + #region fields + mat4 _modelviewMatrix = mat4.identity(), + _projectionMatrix = mat4.identity(); + + float _height, _width, _near, _far, _fovRadians; + + #endregion fields + + #region properties + public float Height + { + get { return _height; } + set { _height = value; } + } + + public float Width + { + get { return _width; } + set { _width = value; } + } + + public float Near + { + get { return _near; } + set { _near = value; } + } + + public float Far + { + get { return _far; } + set { _far = value; } + } + + public float FovRadians + { + get { return _fovRadians; } + set { _fovRadians = value; } + } + + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set { _modelviewMatrix = value; } + } + + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + + public float AngleX { get; set; } + public float AngleY { get; set; } + public float AngleZ { get; set; } + public float TranslationX { get; set; } + public float TranslationY { get; set; } + public float TranslationZ { get; set; } + + #endregion properties + + #region events + #endregion events + + #region constructors + public ModelviewProjectionBuilder() + { + + } + #endregion constructors + /// + /// Slightly edited formula! + /// + public void BuildPerspectiveProjection() + { + var a = Height / Width; + var n = Near; + var f = Far; + var e = 1 / (float)Math.Tan(FovRadians / 2); + + + var mat = new mat4( + new vec4[] + { + new vec4(e, 0, 0, 0), + new vec4(0, e/a, 0, 0), + new vec4(0, 0, -(2*f*n)/(f-n), -1), + new vec4(0, 0, -(f+n)/(f-n), 0), + }); + + ProjectionMatrix = mat; + } + + /// + /// Multiplies the Projection and modelview matrix into one. + /// + /// + public mat4 CombineToMvP() + { + return ProjectionMatrix * ModelviewMatrix; + } + public void BuildTurntableModelview(vec3 originPoint = new vec3()) + { + var cosX = (float)Math.Cos(AngleX); + var cosY = (float)Math.Cos(AngleY); + var cosZ = (float)Math.Cos(AngleZ); + var sinX = (float)Math.Sin(AngleX); + var sinY = (float)Math.Sin(AngleY); + var sinZ = (float)Math.Sin(AngleZ); + + mat4 rotX = new mat4( + new vec4[] + { + new vec4(1,0,0,0), + new vec4(0, cosX, -sinX, 0), + new vec4(0, sinX, cosX, 0), + new vec4(0,0,0,1) + }); + mat4 rotY = new mat4( + new vec4[] + { + new vec4(cosY, 0, sinY, 0), + new vec4(0, 1, 0,0), + new vec4(-sinY, 0, cosY, 0), + new vec4(0,0,0,1) + }); + + + var rotation = rotX * rotY; + var translation = rotation * glm.translate(mat4.identity(), new vec3(TranslationX + originPoint.x, TranslationY + originPoint.y, TranslationZ + originPoint.z)); + var translation2 = glm.translate(translation, new vec3(-originPoint.x, -originPoint.y, -originPoint.z)); + + + ModelviewMatrix = translation2; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/FlatShadedCube.cs new file mode 100644 index 00000000..5da13bae --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/FlatShadedCube.cs @@ -0,0 +1,67 @@ +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; + +namespace SharpGLTranslucencySample +{ + /// + /// A simple cube object + /// + public class FlatShadedCube + { + #region cube data + + static readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + + static readonly vec3[] _normals = new vec3[]{ + new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + }; + + static readonly uint[] _indices = new uint[]{ + 1,2,0, 2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + + + + #endregion cube data + + public static vec3[] Normals + { + get { return FlatShadedCube._normals; } + } + + public static vec3[] Vertices + { + get { return FlatShadedCube._vertices; } + } + + public static uint[] Indices + { + get { return FlatShadedCube._indices; } + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/MyTrefoilKnot.cs new file mode 100644 index 00000000..59afe3bc --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Primitives/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ + +using GlmNet; +using SharpGL; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLTranslucencySample +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot + { + #region fields + /// The number of slices and stacks. + private static uint _slices = 128; + private static uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static uint[] _indices; + #endregion fields + + #region properties + public static vec3[] Normals + { + get { return MyTrefoilKnot._normals; } + } + + public static vec3[] Vertices + { + get { return MyTrefoilKnot._vertices; } + } + + public static uint[] Indices + { + get { return MyTrefoilKnot._indices; } + } + #endregion properties + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + #endregion constructor + + public static void ChangeDetail(uint slices, uint stacks) + { + _slices = slices; + _stacks = stacks; + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + uint vertexCount = _slices * _stacks; + uint indexCount = vertexCount * 6; + _indices = new uint[indexCount]; + int count = 0; + + uint n = 0; + for (uint i = 0; i < _slices; i++) + { + for (uint j = 0; j < _stacks; j++) + { + _indices[count++] = (uint)(n + j); + _indices[count++] = (uint)(n + (j + 1) % _stacks); + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (uint)_stacks; + } + } + #endregion calculate trefoil knot + + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c75f3f19 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLTranslucencySample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLTranslucencySample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.Designer.cs new file mode 100644 index 00000000..e534ecf3 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLTranslucencySample.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLTranslucencySample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.Designer.cs new file mode 100644 index 00000000..254e9628 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLTranslucencySample.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.frag new file mode 100644 index 00000000..e9468d26 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.frag @@ -0,0 +1,25 @@ +#version 330 +in vec3 EyespaceNormal; +in vec3 Diffuse; +in vec4 Ambient; +in vec3 Specular; +in float Shininess; + +uniform vec3 LightPosition; + +out vec4 FragColor; + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 E = vec3(0, 0, 1); + vec3 H = normalize(L + E); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + vec3 color = Ambient.xyz + df * Diffuse + sf * Specular; + FragColor = vec4(color, Ambient.w); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.vert new file mode 100644 index 00000000..9d7f27ef --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/ShaderResources/NormalTranslucentMaterial.vert @@ -0,0 +1,27 @@ +#version 330 core + +in vec4 Position; +in vec3 Normal; +in vec3 DiffuseMaterial; +in vec4 AmbientMaterial; +in vec3 SpecularMaterial; +in float ShininessValue; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 EyespaceNormal; +out vec3 Diffuse; +out vec4 Ambient; +out vec3 Specular; +out float Shininess; +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = ModelviewProjection * Position; + + Diffuse = DiffuseMaterial; + Ambient = AmbientMaterial; + Specular = SpecularMaterial; + Shininess = ShininessValue; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NTMBufferGroup.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NTMBufferGroup.cs new file mode 100644 index 00000000..e1c3985d --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NTMBufferGroup.cs @@ -0,0 +1,178 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLTranslucencySample +{ + public class NTMBufferGroup + { + #region fields + private uint _usage = OpenGL.GL_STATIC_COPY; + private uint _vboTarget = OpenGL.GL_ARRAY_BUFFER; + private uint _iboTarget = OpenGL.GL_ELEMENT_ARRAY_BUFFER; + + #endregion fields + + #region properties + public uint Vao { get; set; } + public uint Ibo { get; set; } + public uint Position { get; set; } + public uint Normal { get; set; } + public uint AmbientMaterial { get; set; } + public uint DiffuseMaterial { get; set; } + public uint SpecularMaterial { get; set; } + public uint ShininessValue { get; set; } + + + public int IndicesCount { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public NTMBufferGroup(OpenGL gl) + { + CreateBufferIds(gl); + } + + #endregion constructors + + private void CreateBufferIds(OpenGL gl) + { + var amount = 7; + uint[] ids = new uint[amount]; + gl.GenBuffers(amount, ids); + Position = ids[0]; + Normal = ids[1]; + AmbientMaterial = ids[2]; + DiffuseMaterial = ids[3]; + SpecularMaterial = ids[4]; + ShininessValue = ids[5]; + Ibo = ids[6]; + } + + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, Material[] materials) + { + IndicesCount = indices.Length; + + var color3Size = 3 * materials.Length; + float[] ambs = new float[4 * materials.Length], + diffs = new float[color3Size], + specs = new float[color3Size], + shinis = new float[materials.Length]; + + // Convert materials to float arrays. + var newPos = 0; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + for (int j = 0; j < 3; j++) + { + ambs[i * 4 + j] = mat.Ambient[j + 1]; + diffs[newPos] = mat.Diffuse[j + 1]; + specs[newPos] = mat.Specular[j + 1]; + newPos++; + } + ambs[i * 4 + 3] = mat.Ambient[0]; // Add alpha channel to ambient. + shinis[i] = mat.Shininess; + } + + // Set buffer data. + BufferData(gl, indices, vertices, normals, + ambs, diffs, specs, shinis); + } + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, + float[] ambs, float[] diffs, float[] specs, float[] shinis) + { + gl.BindBuffer(_iboTarget, Ibo); + gl.BufferData(_iboTarget, indices, _usage); + + gl.BindBuffer(_vboTarget, Position); + gl.BufferData(_vboTarget, vertices, _usage); + + gl.BindBuffer(_vboTarget, Normal); + gl.BufferData(_vboTarget, normals, _usage); + + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.BufferData(_vboTarget, ambs, _usage); + + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.BufferData(_vboTarget, diffs, _usage); + + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.BufferData(_vboTarget, specs, _usage); + + gl.BindBuffer(_vboTarget, ShininessValue); + gl.BufferData(_vboTarget, shinis, _usage); + } + + + + public void PrepareVAO(OpenGL gl, NormalTranslucentMaterialProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + Vao = vertArrIds[0]; + gl.BindVertexArray(Vao); + + BindVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + + public void BindVAO(OpenGL gl) + { + gl.BindVertexArray(Vao); + } + + public void BindVBOs(OpenGL gl, NormalTranslucentMaterialProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["Normal"]; + gl.BindBuffer(_vboTarget, Normal); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["AmbientMaterial"]; + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.VertexAttribPointer(attribPos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["DiffuseMaterial"]; + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["SpecularMaterial"]; + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["ShininessValue"]; + gl.BindBuffer(_vboTarget, ShininessValue); + gl.VertexAttribPointer(attribPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + gl.BindBuffer(_iboTarget, Ibo); + + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NormalTranslucentMaterialProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NormalTranslucentMaterialProgram.cs new file mode 100644 index 00000000..465e874c --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/NormalTranslucentMaterialProgram.cs @@ -0,0 +1,180 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLTranslucencySample +{ + public class NormalTranslucentMaterialProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + mat3 _normalMatrix; + vec3 _lightPosition; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "Normal", + "AmbientMaterial", + "DiffuseMaterial", + "SpecularMaterial", + "ShininessValue" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + "LightPosition" + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalTranslucentMaterial.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalTranslucentMaterial.frag", assembly)); + + return stc; + } + } + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + if (NormalMatrix.Equals(value)) + return; + + ChangedUniforms.Add(ApplyNormalMatrix); + _normalMatrix = value; + } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + public vec3 LightPosition + { + get { return _lightPosition; } + set + { + if (LightPosition.Equals(value)) + return; + + ChangedUniforms.Add(ApplyLightPosition); + _lightPosition = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public NormalTranslucentMaterialProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(NTMBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindVAO(gl); + gl.DrawElements(OpenGL.GL_TRIANGLES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero); + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + private void ApplyNormalMatrix(OpenGL gl) + { + gl.UniformMatrix3(Uniforms["NormalMatrix"], 1, false, NormalMatrix.to_array()); + } + private void ApplyLightPosition(OpenGL gl) + { + gl.Uniform3(Uniforms["LightPosition"], LightPosition.x, LightPosition.y, LightPosition.z); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs new file mode 100644 index 00000000..d8107294 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs @@ -0,0 +1,278 @@ +using GlmNet; +using SharpGL; +using SharpGLHelper; +using SharpGLHelper.Buffers; +using SharpGLHelper.Common; +using SharpGLHelper.OGLOverloads; +using SharpGLHelper.SceneElements; +using SharpGLTest.Shapes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGLTest.Shaders +{ + public class ShaderManagerNormalMaterialParticleTest + { + + #region fields + vec3 _lightPosition = new vec3(); + #endregion fields + + #region properties + + protected Dictionary AttributeLocations + { + get + { + var dic = new Dictionary(); + + dic.Add(0, "Position"); + dic.Add(1, "Normal"); + dic.Add(2, "TCol1"); + dic.Add(3, "TCol2"); + dic.Add(4, "TCol3"); + dic.Add(5, "TCol4"); + dic.Add(6, "AmbientMaterial"); + dic.Add(7, "DiffuseMaterial"); + dic.Add(8, "SpecularMaterial"); + dic.Add(9, "ShininessValue"); + + return dic; + } + } + #endregion properties + + #region events + #endregion events + + #region constructors + public ShaderManagerNormalMaterialParticleTest(OpenGL gl) + { + init(gl); + } + #endregion constructors + + MyTrefoilKnot knot; + // List of indices in the generated buffers + // and ultimately the buffer IDs. + uint ibo = 10; + uint vert = 0; + uint norm = 1; + uint tCol1 = 2; + uint tCol2 = 3; + uint tCol3 = 4; + uint tCol4 = 5; + uint amb = 6; + uint diff = 7; + uint spec = 8; + uint shini = 9; + + + uint iboPos = 10; + uint vertPos = 0; + uint normPos = 1; + uint tCol1Pos = 2; + uint tCol2Pos = 3; + uint tCol3Pos = 4; + uint tCol4Pos = 5; + uint ambPos = 6; + uint diffPos = 7; + uint specPos = 8; + uint shiniPos = 9; + + // Uniform positions + int lightPos = 0; + int modelView = 1; + int normMatrix = 2; + int projection = 3; + + // Shader program; + uint programId; + + public void init(OpenGL gl) + { + // Create vert and frag NormalMaterialParticle shader. + //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); + var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; + var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; + var executingAssembly = Assembly.GetExecutingAssembly(); + var autoAttachAssemblyName = true; + var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); + var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); + + var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); + gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); + gl.CompileShader(vertShaderId); + //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); + var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); + gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); + gl.CompileShader(fragShaderId); + + // Create Program from shaders. + programId = gl.CreateProgram(); + gl.AttachShader(programId, vertShaderId); + gl.AttachShader(programId, fragShaderId); + + gl.BindAttribLocation(programId, vertPos, "Position"); + gl.BindAttribLocation(programId, normPos, "Normal"); + gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); + gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); + gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); + gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); + gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); + gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); + gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); + gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); + + //gl.BindAttribLocation(programId, lightPos, "LightPosition"); + //gl.BindAttribLocation(programId, modelView, "Modelview"); + //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); + //gl.BindAttribLocation(programId, projection, "Projection"); + gl.LinkProgram(programId); + + + knot = MyTrefoilKnot.Instance; + + // Create the IBO and VBO's. + uint[] buffers = new uint[11]; + gl.GenBuffers(11, buffers); + ibo = buffers[iboPos]; + vert = buffers[vertPos]; + norm = buffers[normPos]; + tCol1 = buffers[tCol1Pos]; + tCol2 = buffers[tCol2Pos]; + tCol3 = buffers[tCol3Pos]; + tCol4 = buffers[tCol4Pos]; + amb = buffers[ambPos]; + diff = buffers[diffPos]; + spec = buffers[specPos]; + shini = buffers[shiniPos]; + + var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); + + + var dataSize = knot.Indices.Length * sizeof(uint); + IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); + var intData = new int[knot.Indices.Length]; + Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); + + // Set trefoil knot data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); + + // Set transformation data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); + + // Set material data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); + + // Apply uniforms. + gl.UseProgram(programId); + mat4 modelViewMat = mat4.identity(); + mat4 projectionMat = mat4.identity(); + mat3 NormalMat = mat3.identity(); + var zoomValue = new vec3(0, 0, -10); + //glm.translate(projectionMat, zoomValue); + + //projection = gl.GetUniformLocation(programId, "Projection"); + //modelView = gl.GetUniformLocation(programId, "Modelview"); + //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); + //lightPos = gl.GetUniformLocation(programId, "LightPosition"); + + + gl.Uniform3((int)lightPos, 5, 10, 15); + gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); + gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); + gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); + gl.UseProgram(0); + + + gl.FrontFace(OpenGL.GL_CW); + } + + public void render(OpenGL gl) + { + //Bind buffers. + gl.UseProgram(programId); + + float[] parameters = new float[16]; + gl.GetUniform(programId, projection, parameters); + + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(vertPos, 0); + gl.EnableVertexAttribArray(vertPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(normPos, 0); + gl.EnableVertexAttribArray(normPos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol1Pos, 1); + gl.EnableVertexAttribArray(tCol1Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol2Pos, 1); + gl.EnableVertexAttribArray(tCol2Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol3Pos, 1); + gl.EnableVertexAttribArray(tCol3Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol4Pos, 1); + gl.EnableVertexAttribArray(tCol4Pos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(ambPos, 1); + gl.EnableVertexAttribArray(ambPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(diffPos, 1); + gl.EnableVertexAttribArray(diffPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(specPos, 1); + gl.EnableVertexAttribArray(specPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); + gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(shiniPos, 1); + gl.EnableVertexAttribArray(shiniPos); + + gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); + //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); + + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); + gl.UseProgram(0); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/SharpGLTranslucencySample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/SharpGLTranslucencySample.csproj new file mode 100644 index 00000000..ecb053ae --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/SharpGLTranslucencySample.csproj @@ -0,0 +1,131 @@ + + + + + Debug + AnyCPU + {FBC91399-CE83-4FEE-88C4-39F0BF0239CE} + WinExe + Properties + SharpGLTranslucencySample + SharpGLTranslucencySample + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\..\..\..\..\AH\SharpGLViewerSample\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + {47bcaa39-edad-4404-b6bd-4742b0abb523} + SharpGL.SceneGraph + + + {53e67055-13d2-4467-bb57-79589afac2cd} + SharpGL.WPF + + + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} + SharpGL + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/packages.config b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/packages.config new file mode 100644 index 00000000..e316866a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 03fffebd7af6ba8ca17d12bc471fe9b8cfe294b6 Mon Sep 17 00:00:00 2001 From: Jochem Date: Tue, 20 May 2014 01:50:04 +0100 Subject: [PATCH 6/8] Included a hit test sample and extended the ColorF.cs a little. --- .../Core/SharpGL.SceneGraph/JOG/ColorF.cs | 17 + .../Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs | 37 +- .../WPF/JOG/SharpGLHitTestSample/App.config | 6 + .../WPF/JOG/SharpGLHitTestSample/App.xaml | 8 + .../WPF/JOG/SharpGLHitTestSample/App.xaml.cs | 17 + .../JOG/SharpGLHitTestSample/GLController.cs | 276 +++++++++++ .../SharpGLHitTestSample/GlmNetExtensions.cs | 431 ++++++++++++++++++ .../JOG/SharpGLHitTestSample/MainWindow.xaml | 12 + .../SharpGLHitTestSample/MainWindow.xaml.cs | 129 ++++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 71 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../ShaderResources/HitTest.frag | 9 + .../ShaderResources/HitTest.vert | 15 + .../ShaderResources/NormalMaterial.frag | 25 + .../ShaderResources/NormalMaterial.vert | 27 ++ .../Shaders/HitTestShader/HitTestProgram.cs | 145 ++++++ .../NormalMaterialShader/NMHTBufferGroup.cs | 227 +++++++++ .../NormalMaterialProgram.cs | 180 ++++++++ ...ShaderManagerNormalMaterialParticleTest.cs | 278 +++++++++++ .../SharpGLHitTestSample.csproj | 135 ++++++ .../JOG/SharpGLHitTestSample/packages.config | 4 + 27 files changed, 2624 insertions(+), 12 deletions(-) create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/HitTestShader/HitTestProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NMHTBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/SharpGLHitTestSample.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/packages.config diff --git a/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs index 19b977cb..4eedb60a 100644 --- a/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs +++ b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs @@ -129,5 +129,22 @@ public uint ToUint() // Get color id from pixel data. return (uint)(R * 255 + G * 65025 + B * 16581375); // r * 255 + g * 255² + b * 255³. } + + public float[] ToRGB() + { + return new float[] { R, G, B }; + } + public float[] ToRGBA() + { + return new float[] { R, G, B, A }; + } + public float[] ToBGR() + { + return new float[] { B, G, R }; + } + public float[] ToBGRA() + { + return new float[] { B, G, R, A }; + } } } diff --git a/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs index 1b124cee..79a2265b 100644 --- a/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs +++ b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs @@ -77,8 +77,14 @@ public TimeSpan Interval /// public ImageSource ImgSource { - get { return _imgSource; } - set { _imgSource = value; } + get { return _imgSource; } + set + { + if (RefreshImgSource) _imgSource = value; + + // Notify that the frame was updated. + OnPropertyChanged("ImgSource"); + } } /// @@ -109,9 +115,14 @@ public bool TimerIsEnabled //} /// /// Whether or not the image has to be refreshed by retrieving an update from the GPU. + /// Prevents setting ImgSource. /// - public bool RefreshImage { get; set; } + public bool RefreshImgSource { get; set; } + /// + /// Prevents executing GetFrame(...). + /// + public bool BlitImage { get; set; } @@ -205,7 +216,8 @@ public OpenGLControlJOG() { InitializeComponent(); DataContext = this; - RefreshImage = true; + RefreshImgSource = true; + BlitImage = true; } #endregion constructors @@ -220,18 +232,20 @@ private void StartTimer() /// /// Calls Viewport.GetFrame() and updates the ImgSource. /// - public void Refresh(bool notifyChanged = true) + public void Refresh() { // Update the frame. - ImgSource = GetFrame(); - - // Notify that the frame was updated. - if (notifyChanged) - OnPropertyChanged("ImgSource"); + if (BlitImage) + { + ImgSource = GetFrame(); + } } public ImageSource GetFrame() { + if (!BlitImage) + return ImgSource; + lock (Gl) { Gl.Blit(IntPtr.Zero); @@ -373,8 +387,7 @@ void OGLViewportImage_SizeChanged(object sender, SizeChangedEventArgs e) public virtual void Timer_Tick(object sender, EventArgs e) { stopwatch.Restart(); - if (RefreshImage) - Refresh(); + Refresh(); OnOpenGLDraw(); stopwatch.Stop(); diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml new file mode 100644 index 00000000..c9bcabe8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml.cs new file mode 100644 index 00000000..c195586c --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLHitTestSample +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GLController.cs new file mode 100644 index 00000000..3d713bf8 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GLController.cs @@ -0,0 +1,276 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLHitTestSample +{ + public class GLController + { + #region fields + NormalMaterialProgram _nmProgram; + HitTestProgram _htProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public NormalMaterialProgram NmProgram + { + get { return _nmProgram; } + set { _nmProgram = value; } + } + + public HitTestProgram HtProgram + { + get { return _htProgram; } + set { _htProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + NmProgram.Projection = value; + HtProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + NmProgram.Modelview = value; + HtProgram.Modelview = value; + } + } + + /// + /// A normal matrix, influences lighting reflection etc. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + _normalMatrix = value; + NmProgram.NormalMatrix = value; + } + } + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + + // Create a visible shader program. + NmProgram = new NormalMaterialProgram(GL); + NmProgram.LightPosition = new vec3(5, 10, 15); + NormalMatrix = mat3.identity(); + + // Create the hit test shader program. + HtProgram = new HitTestProgram(GL); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + + + AddData(GL); + + GL.Enable(OpenGL.GL_DEPTH_TEST); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + } + public void Draw(object sender, OpenGLEventArgs args) + { + var scene = sender as OpenGLControlJOG; + + if (NmProgram.ChangedUniforms.Count == 0) // Prepare HitTest scene + { + // Prevent the image from updating, so that the hittest id's won't be visible to the user. + if (HtProgram.ChangedUniforms.Count != 0) + { + scene.RefreshImgSource = false; + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + HtProgram.BindAll(GL); + } + else + { + // Prevent blitting the image when nothing changed. + scene.BlitImage = false; + } + } + else // Update the visual scene. + { + if (!scene.RefreshImgSource) + scene.RefreshImgSource = true; + if (!scene.BlitImage) + scene.BlitImage = true; + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + NmProgram.BindAll(GL); + } + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddData(OpenGL gl) + { + NMHTBufferGroup group = new NMHTBufferGroup(gl); + + var verts = MyTrefoilKnot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = MyTrefoilKnot.Normals.SelectMany(x => x.to_array()).ToArray(); + + group.BufferData(gl, MyTrefoilKnot.Indices, verts, normals, + new Material[] { new Material(new ColorF(255, 150, 50, 50), new ColorF(255, 10, 100, 10), new ColorF(255, 225, 225, 225), null, 100f) }); + group.PrepareNMVAO(gl, NmProgram); + group.PrepareHTVAO(gl, HtProgram); + + NmProgram.AddBufferGroup(group); + HtProgram.AddBufferGroup(group); + + + NMHTBufferGroup groupCube = new NMHTBufferGroup(gl); + + var vertsCube = FlatShadedCube.Vertices.SelectMany(x => x.to_array()).ToArray(); + var normalsCube = FlatShadedCube.Normals.SelectMany(x => x.to_array()).ToArray(); + + + groupCube.BufferData(gl, FlatShadedCube.Indices, vertsCube, normalsCube, + new Material[] + { + new Material(new ColorF(1f, 0.3f, 1, 0), new ColorF(1f, 1f, 0.5f, 0), new ColorF(1f, 1, 0, 1), null, 100f), + }); + + groupCube.PrepareNMVAO(gl, NmProgram); + groupCube.PrepareHTVAO(gl, HtProgram); + + NmProgram.AddBufferGroup(groupCube); + HtProgram.AddBufferGroup(groupCube); + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Returns the color id of the hitted face. + /// If the id == 0, then nothing was hit. + /// + /// + /// The X position in the scene. + /// The Y position in the scene. + /// The color id of the hitted face. + public uint DoHitTest(OpenGL gl, int posX, int posY ) + { + // Ensure the hit test scene is up to date. + if (HtProgram.ChangedUniforms.Count == 0) + { + byte[] pixels = new byte[4]; + gl.ReadPixels(posX, posY, 1, 1, OpenGL.GL_RGBA, OpenGL.GL_UNSIGNED_BYTE, pixels); + + return new ColorF(pixels[3], pixels[0], pixels[1], pixels[2]).ToUint(); + } + + return 0; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GlmNetExtensions.cs new file mode 100644 index 00000000..80b27141 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLHitTestSample +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml new file mode 100644 index 00000000..07dd1b76 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs new file mode 100644 index 00000000..422b0893 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs @@ -0,0 +1,129 @@ +using GlmNet; +using SharpGL.SceneGraph; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SharpGLHitTestSample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, INotifyPropertyChanged + { + + #region fields + private GLController _controller = new GLController(); + private Point _previousPosition; + + + #endregion fields + + #region properties + + public GLController Controller + { + get { return _controller; } + set { _controller = value; } + } + + public Action Draw { get { return Controller.Draw; } } + public Action Init { get { return Controller.Init; } } + public Action Resized { get { return Controller.Resized; } } + #endregion properties + + #region events + + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string prop) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(prop)); + } + #endregion events + + #region constructors + public MainWindow() + { + InitializeComponent(); + DataContext = this; + MouseWheel += MainWindow_MouseWheel; + + + } + #endregion constructors + + private void OpenGLControlJOG_MouseDown(object sender, MouseButtonEventArgs e) + { + var control = sender as OpenGLControlJOG; + + // Click + _previousPosition = e.GetPosition(control); + + // Check if hittest scene is up to date. + if (Controller.HtProgram.ChangedUniforms.Count == 0) + { + var id = Controller.DoHitTest(control.Gl, (int)(_previousPosition.X), (int)(control.ActualHeight - _previousPosition.Y)); + + //SetCursorPos((int)_previousPosition.X, (int)_previousPosition.Y); + if (id > 0) + MessageBox.Show("Clicked object has ID " + id); + } + } + + [DllImport("User32.dll")] + private static extern bool SetCursorPos(int X, int Y); + + private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) + { + // Zoom + Controller.MvpBuilder.TranslationZ += e.Delta / 1000f; + Controller.RefreshModelview(); + } + + private void OpenGLControlJOG_MouseMove(object sender, MouseEventArgs e) + { + var pos = e.GetPosition(sender as OpenGLControlJOG); + + + float xDiff = (float)(_previousPosition.X - pos.X); + float yDiff = (float)(_previousPosition.Y - pos.Y); + + if (e.LeftButton == MouseButtonState.Pressed) // Translate. + { + Controller.MvpBuilder.TranslationX += xDiff/10; + Controller.MvpBuilder.TranslationY += yDiff / 10; + Controller.RefreshModelview(); + } + else if (e.RightButton == MouseButtonState.Pressed) // Rotate. + { + var scaleFac = 1f; + var horiDeg = scaleFac * (float)(xDiff / Width * Math.PI); + var vertiDeg = scaleFac * (float)(yDiff / Height * Math.PI); + + Controller.MvpBuilder.AngleY += horiDeg; + Controller.MvpBuilder.AngleX += vertiDeg; + Controller.RefreshModelview(); + } + + _previousPosition = pos; + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ModelviewProjectionBuilder.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ModelviewProjectionBuilder.cs new file mode 100644 index 00000000..363a4eea --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ModelviewProjectionBuilder.cs @@ -0,0 +1,151 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLHitTestSample +{ + /// + /// Modelview x Projection matrix builder. + /// + public class ModelviewProjectionBuilder + { + #region fields + mat4 _modelviewMatrix = mat4.identity(), + _projectionMatrix = mat4.identity(); + + float _height, _width, _near, _far, _fovRadians; + + #endregion fields + + #region properties + public float Height + { + get { return _height; } + set { _height = value; } + } + + public float Width + { + get { return _width; } + set { _width = value; } + } + + public float Near + { + get { return _near; } + set { _near = value; } + } + + public float Far + { + get { return _far; } + set { _far = value; } + } + + public float FovRadians + { + get { return _fovRadians; } + set { _fovRadians = value; } + } + + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set { _modelviewMatrix = value; } + } + + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set { _projectionMatrix = value; } + } + + + public float AngleX { get; set; } + public float AngleY { get; set; } + public float AngleZ { get; set; } + public float TranslationX { get; set; } + public float TranslationY { get; set; } + public float TranslationZ { get; set; } + + #endregion properties + + #region events + #endregion events + + #region constructors + public ModelviewProjectionBuilder() + { + + } + #endregion constructors + /// + /// Slightly edited formula! + /// + public void BuildPerspectiveProjection() + { + var a = Height / Width; + var n = Near; + var f = Far; + var e = 1 / (float)Math.Tan(FovRadians / 2); + + + var mat = new mat4( + new vec4[] + { + new vec4(e, 0, 0, 0), + new vec4(0, e/a, 0, 0), + new vec4(0, 0, -(2*f*n)/(f-n), -1), + new vec4(0, 0, -(f+n)/(f-n), 0), + }); + + ProjectionMatrix = mat; + } + + /// + /// Multiplies the Projection and modelview matrix into one. + /// + /// + public mat4 CombineToMvP() + { + return ProjectionMatrix * ModelviewMatrix; + } + public void BuildTurntableModelview(vec3 originPoint = new vec3()) + { + var cosX = (float)Math.Cos(AngleX); + var cosY = (float)Math.Cos(AngleY); + var cosZ = (float)Math.Cos(AngleZ); + var sinX = (float)Math.Sin(AngleX); + var sinY = (float)Math.Sin(AngleY); + var sinZ = (float)Math.Sin(AngleZ); + + mat4 rotX = new mat4( + new vec4[] + { + new vec4(1,0,0,0), + new vec4(0, cosX, -sinX, 0), + new vec4(0, sinX, cosX, 0), + new vec4(0,0,0,1) + }); + mat4 rotY = new mat4( + new vec4[] + { + new vec4(cosY, 0, sinY, 0), + new vec4(0, 1, 0,0), + new vec4(-sinY, 0, cosY, 0), + new vec4(0,0,0,1) + }); + + + var rotation = rotX * rotY; + var translation = rotation * glm.translate(mat4.identity(), new vec3(TranslationX + originPoint.x, TranslationY + originPoint.y, TranslationZ + originPoint.z)); + var translation2 = glm.translate(translation, new vec3(-originPoint.x, -originPoint.y, -originPoint.z)); + + + ModelviewMatrix = translation2; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/FlatShadedCube.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/FlatShadedCube.cs new file mode 100644 index 00000000..3ba5d512 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/FlatShadedCube.cs @@ -0,0 +1,67 @@ +using SharpGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using GlmNet; + +namespace SharpGLHitTestSample +{ + /// + /// A simple cube object + /// + public class FlatShadedCube + { + #region cube data + + static readonly vec3[] _vertices = new vec3[]{ + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,1.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(0.0f,0.0f,1.0f), new vec3(0.0f,1.0f,1.0f), new vec3(0.0f,1.0f,0.0f), + new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(1.0f,1.0f,1.0f), new vec3(1.0f,1.0f,0.0f), + new vec3(0.0f,0.0f,0.0f), new vec3(1.0f,0.0f,0.0f), new vec3(1.0f,0.0f,1.0f), new vec3(0.0f,0.0f,1.0f), + new vec3(0.0f,1.0f,0.0f), new vec3(1.0f,1.0f,0.0f), new vec3(1.0f,1.0f,1.0f), new vec3(0.0f,1.0f,1.0f) + }; + + static readonly vec3[] _normals = new vec3[]{ + new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1),new vec3(0,0,-1), + new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1),new vec3(0,0,1), + new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0),new vec3(-1,0,0), + new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0),new vec3(1,0,0), + new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0),new vec3(0,-1,0), + new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0),new vec3(0,1,0), + }; + + static readonly uint[] _indices = new uint[]{ + 1,2,0, 2,3,0, + 4,6,5, 4,7,6, + 8,10,9, 8,11,10, + 13,14,12, 14,15,12, + 16,18,17, 16,19,18, + 21,22,20, 22,23,20, + }; + + + + #endregion cube data + + public static vec3[] Normals + { + get { return FlatShadedCube._normals; } + } + + public static vec3[] Vertices + { + get { return FlatShadedCube._vertices; } + } + + public static uint[] Indices + { + get { return FlatShadedCube._indices; } + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/MyTrefoilKnot.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/MyTrefoilKnot.cs new file mode 100644 index 00000000..fea3c21a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Primitives/MyTrefoilKnot.cs @@ -0,0 +1,160 @@ + +using GlmNet; +using SharpGL; +using SharpGL.VertexBuffers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SharpGLHitTestSample +{ + /// + /// The TrefoilKnot class creates geometry + /// for a trefoil knot. + /// + public class MyTrefoilKnot + { + #region fields + /// The number of slices and stacks. + private static uint _slices = 128; + private static uint _stacks = 32; + + private static vec3[] _vertices; + private static vec3[] _normals; + private static uint[] _indices; + #endregion fields + + #region properties + public static vec3[] Normals + { + get { return MyTrefoilKnot._normals; } + } + + public static vec3[] Vertices + { + get { return MyTrefoilKnot._vertices; } + } + + public static uint[] Indices + { + get { return MyTrefoilKnot._indices; } + } + #endregion properties + + #region constructor + static MyTrefoilKnot() + { + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + #endregion constructor + + public static void ChangeDetail(uint slices, uint stacks) + { + _slices = slices; + _stacks = stacks; + CreateIndexBuffer(); + CreateVertexNormalBuffer(); + } + + #region calculate trefoil knot + /// + /// Evaluates the trefoil, providing the vertex at a given coordinate. + /// + /// The s. + /// The t. + /// The vertex at (s,t). + private static vec3 EvaluateTrefoil(float s, float t) + { + const float TwoPi = (float)Math.PI * 2; + + float a = 0.5f; + float b = 0.3f; + float c = 0.5f; + float d = 0.1f; + float u = (1 - s) * 2 * TwoPi; + float v = t * TwoPi; + float r = (float)(a + b * Math.Cos(1.5f * u)); + float x = (float)(r * Math.Cos(u)); + float y = (float)(r * Math.Sin(u)); + float z = (float)(c * Math.Sin(1.5f * u)); + + vec3 dv = new vec3(); + dv.x = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Cos(u) - (a + b * Math.Cos(1.5f * u)) * Math.Sin(u)); + dv.y = (float)(-1.5f * b * Math.Sin(1.5f * u) * Math.Sin(u) + (a + b * Math.Cos(1.5f * u)) * Math.Cos(u)); + dv.z = (float)(1.5f * c * Math.Cos(1.5f * u)); + + vec3 q = glm.normalize(dv); + vec3 qvn = glm.normalize(new vec3(q.y, -q.x, 0.0f)); + vec3 ww = glm.cross(q, qvn); + + vec3 range = new vec3(); + range.x = (float)(x + d * (qvn.x * Math.Cos(v) + ww.x * Math.Sin(v))); + range.y = (float)(y + d * (qvn.y * Math.Cos(v) + ww.y * Math.Sin(v))); + range.z = (float)(z + d * ww.z * Math.Sin(v)); + + return range; + } + + private static void CreateVertexNormalBuffer() + { + var vertexCount = _slices * _stacks; + + _vertices = new vec3[vertexCount]; + _normals = new vec3[vertexCount]; + + int count = 0; + + float ds = 1.0f / _slices; + float dt = 1.0f / _stacks; + + // The upper bounds in these loops are tweaked to reduce the + // chance of precision error causing an incorrect # of iterations. + + for (float s = 0; s < 1 - ds / 2; s += ds) + { + for (float t = 0; t < 1 - dt / 2; t += dt) + { + const float E = 0.01f; + vec3 p = EvaluateTrefoil(s, t); + vec3 u = EvaluateTrefoil(s + E, t) - p; + vec3 v = EvaluateTrefoil(s, t + E) - p; + vec3 n = glm.normalize(glm.cross(u, v)); + _vertices[count] = p; + _normals[count] = n; + count++; + } + } + } + + private static void CreateIndexBuffer() + { + uint vertexCount = _slices * _stacks; + uint indexCount = vertexCount * 6; + _indices = new uint[indexCount]; + int count = 0; + + uint n = 0; + for (uint i = 0; i < _slices; i++) + { + for (uint j = 0; j < _stacks; j++) + { + _indices[count++] = (uint)(n + j); + _indices[count++] = (uint)(n + (j + 1) % _stacks); + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + + _indices[count++] = (uint)((n + j + _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks) % vertexCount); + _indices[count++] = (uint)((n + (j + 1) % _stacks + _stacks) % vertexCount); + } + + n += (uint)_stacks; + } + } + #endregion calculate trefoil knot + + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..134cf517 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpGLHitTestSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpGLHitTestSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.Designer.cs new file mode 100644 index 00000000..6550232a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLHitTestSample.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpGLHitTestSample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.Designer.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.Designer.cs new file mode 100644 index 00000000..7499bcde --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SharpGLHitTestSample.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.frag new file mode 100644 index 00000000..454b059d --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.frag @@ -0,0 +1,9 @@ +#version 330 +in vec3 Color; + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(Color, 1); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.vert new file mode 100644 index 00000000..7f8340b4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/HitTest.vert @@ -0,0 +1,15 @@ +#version 330 core + +in vec4 Position; +in vec3 HTColorId; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 Color; +void main() +{ + gl_Position = ModelviewProjection * Position; + + Color = HTColorId; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.frag b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.frag new file mode 100644 index 00000000..5c909f73 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.frag @@ -0,0 +1,25 @@ +#version 330 +in vec3 EyespaceNormal; +in vec3 Diffuse; +in vec3 Ambient; +in vec3 Specular; +in float Shininess; + +uniform vec3 LightPosition; + +out vec4 FragColor; + +void main() +{ + vec3 N = normalize(EyespaceNormal); + vec3 L = normalize(LightPosition); + vec3 E = vec3(0, 0, 1); + vec3 H = normalize(L + E); + + float df = max(0.0, dot(N, L)); + float sf = max(0.0, dot(N, H)); + sf = pow(sf, Shininess); + + vec3 color = Ambient + df * Diffuse + sf * Specular; + FragColor = vec4(color, 1); +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.vert b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.vert new file mode 100644 index 00000000..e2853f81 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/ShaderResources/NormalMaterial.vert @@ -0,0 +1,27 @@ +#version 330 core + +in vec4 Position; +in vec3 Normal; +in vec3 DiffuseMaterial; +in vec3 AmbientMaterial; +in vec3 SpecularMaterial; +in float ShininessValue; + +uniform mat4 ModelviewProjection; +uniform mat3 NormalMatrix; + +out vec3 EyespaceNormal; +out vec3 Diffuse; +out vec3 Ambient; +out vec3 Specular; +out float Shininess; +void main() +{ + EyespaceNormal = NormalMatrix * Normal; + gl_Position = ModelviewProjection * Position; + + Diffuse = DiffuseMaterial; + Ambient = AmbientMaterial; + Specular = SpecularMaterial; + Shininess = ShininessValue; +} \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/HitTestShader/HitTestProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/HitTestShader/HitTestProgram.cs new file mode 100644 index 00000000..be608746 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/HitTestShader/HitTestProgram.cs @@ -0,0 +1,145 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLHitTestSample +{ + public class HitTestProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "HTColorId" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.HitTest.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.HitTest.frag", assembly)); + + return stc; + } + } + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public HitTestProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(NMHTBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + //return; + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindHTVAO(gl); + + // Use draw elements if an index buffer is defined. Else use draw arrays. + if (group.IndicesCount > 0) + gl.DrawElements(OpenGL.GL_TRIANGLES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero); + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NMHTBufferGroup.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NMHTBufferGroup.cs new file mode 100644 index 00000000..ae4e1d39 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NMHTBufferGroup.cs @@ -0,0 +1,227 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLHitTestSample +{ + public class NMHTBufferGroup + { + #region fields + private uint _usage = OpenGL.GL_STATIC_COPY; + private uint _vboTarget = OpenGL.GL_ARRAY_BUFFER; + private uint _iboTarget = OpenGL.GL_ELEMENT_ARRAY_BUFFER; + + #endregion fields + + #region properties + /// + /// Binding for displaying the data. + /// + public uint VaoNM { get; set; } + /// + /// Binding for the HitTest + /// + public uint VaoHT { get; set; } + public uint Ibo { get; set; } + public uint HTColorId { get; set; } + public uint Position { get; set; } + public uint Normal { get; set; } + public uint AmbientMaterial { get; set; } + public uint DiffuseMaterial { get; set; } + public uint SpecularMaterial { get; set; } + public uint ShininessValue { get; set; } + + + public int IndicesCount { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public NMHTBufferGroup(OpenGL gl) + { + CreateBufferIds(gl); + } + + #endregion constructors + + private void CreateBufferIds(OpenGL gl) + { + var amount = 8; + uint[] ids = new uint[amount]; + gl.GenBuffers(amount, ids); + Position = ids[0]; + Normal = ids[1]; + AmbientMaterial = ids[2]; + DiffuseMaterial = ids[3]; + SpecularMaterial = ids[4]; + ShininessValue = ids[5]; + HTColorId = ids[6]; + Ibo = ids[7]; + } + + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, Material[] materials) + { + IndicesCount = indices.Length; + + var color3Size = 3 * materials.Length; + float[] ambs = new float[color3Size], + diffs = new float[color3Size], + specs = new float[color3Size], + shinis = new float[materials.Length]; + + // Convert materials to float arrays. + var newPos = 0; + for (int i = 0; i < materials.Length; i++) + { + var mat = materials[i]; + for (int j = 0; j < 3; j++) + { + ambs[newPos] = mat.Ambient[j+1]; + diffs[newPos] = mat.Diffuse[j+1]; + specs[newPos] = mat.Specular[j+1]; + newPos++; + } + shinis[i] = mat.Shininess; + } + + // Because an Index Buffer Object ID is unique, we'll use this to generate a hit test color. + var htColor = new ColorF(Ibo); + var htColorID = htColor.ToRGB(); + + // Set buffer data. + BufferData(gl, indices, vertices, normals, + ambs, diffs, specs, shinis, htColorID); + + } + public void BufferData(OpenGL gl, + uint[] indices, float[] vertices, float[] normals, + float[] ambs, float[] diffs, float[] specs, float[] shinis, + float[] htColor) + { + gl.BindBuffer(_iboTarget, Ibo); + gl.BufferData(_iboTarget, indices, _usage); + + gl.BindBuffer(_vboTarget, Position); + gl.BufferData(_vboTarget, vertices, _usage); + + gl.BindBuffer(_vboTarget, Normal); + gl.BufferData(_vboTarget, normals, _usage); + + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.BufferData(_vboTarget, ambs, _usage); + + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.BufferData(_vboTarget, diffs, _usage); + + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.BufferData(_vboTarget, specs, _usage); + + gl.BindBuffer(_vboTarget, ShininessValue); + gl.BufferData(_vboTarget, shinis, _usage); + + gl.BindBuffer(_vboTarget, HTColorId); + gl.BufferData(_vboTarget, htColor, _usage); + + } + + public void PrepareNMVAO(OpenGL gl, NormalMaterialProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + VaoNM = vertArrIds[0]; + gl.BindVertexArray(VaoNM); + + BindNMVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + public void PrepareHTVAO(OpenGL gl, HitTestProgram program) + { + var vertArrIds = new uint[1]; + gl.GenVertexArrays(1, vertArrIds); + + VaoHT = vertArrIds[0]; + gl.BindVertexArray(VaoHT); + + BindHTVBOs(gl, program); + + gl.EnableVertexAttribArray(0); + gl.BindVertexArray(0); + } + + public void BindNMVAO(OpenGL gl) + { + gl.BindVertexArray(VaoNM); + } + public void BindHTVAO(OpenGL gl) + { + gl.BindVertexArray(VaoHT); + } + + public void BindNMVBOs(OpenGL gl, NormalMaterialProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["Normal"]; + gl.BindBuffer(_vboTarget, Normal); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["AmbientMaterial"]; + gl.BindBuffer(_vboTarget, AmbientMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["DiffuseMaterial"]; + gl.BindBuffer(_vboTarget, DiffuseMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["SpecularMaterial"]; + gl.BindBuffer(_vboTarget, SpecularMaterial); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["ShininessValue"]; + gl.BindBuffer(_vboTarget, ShininessValue); + gl.VertexAttribPointer(attribPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + gl.BindBuffer(_iboTarget, Ibo); + + } + + public void BindHTVBOs(OpenGL gl, HitTestProgram program) + { + var attribPos = program.Attribs["Position"]; + gl.BindBuffer(_vboTarget, Position); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.EnableVertexAttribArray(attribPos); + + attribPos = program.Attribs["HTColorId"]; + gl.BindBuffer(_vboTarget, HTColorId); + gl.VertexAttribPointer(attribPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(attribPos, 1); + gl.EnableVertexAttribArray(attribPos); + + gl.BindBuffer(_iboTarget, Ibo); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs new file mode 100644 index 00000000..4d65fc8d --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/NormalMaterialProgram.cs @@ -0,0 +1,180 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace SharpGLHitTestSample +{ + public class NormalMaterialProgram : ShaderProgramJOG + { + #region fields + List _bufferGroups = new List(); + List> _changedUniforms = new List>(); + + mat4 _projection, _modelview; + mat3 _normalMatrix; + vec3 _lightPosition; + + + #endregion fields + + #region properties + public List BufferGroups + { + get { return _bufferGroups; } + set { _bufferGroups = value; } + } + + private static string[] AttributeNames + { + get + { + return new string[] + { + "Position", + "Normal", + "AmbientMaterial", + "DiffuseMaterial", + "SpecularMaterial", + "ShininessValue" + }; + } + } + + private static string[] UniformNames + { + get + { + return new string[] + { + "ModelviewProjection", + "NormalMatrix", + "LightPosition" + }; + } + } + + private static Dictionary ShaderTypeAndCode + { + get + { + var stc = new Dictionary(); + + var assembly = Assembly.GetExecutingAssembly(); + stc.Add(ShaderTypes.GL_VERTEX_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterial.vert", assembly)); + stc.Add(ShaderTypes.GL_FRAGMENT_SHADER, SharpGL.SceneGraph.JOG.ManifestResourceLoader.LoadTextFile("ShaderResources.NormalMaterial.frag", assembly)); + + return stc; + } + } + + public List> ChangedUniforms + { + get { return _changedUniforms; } + set { _changedUniforms = value; } + } + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + if (NormalMatrix.Equals(value)) + return; + + ChangedUniforms.Add(ApplyNormalMatrix); + _normalMatrix = value; + } + } + + public mat4 Projection + { + get { return _projection; } + set + { + //if (Projection.Equals(value)) + // return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _projection = value; + } + } + + public mat4 Modelview + { + get { return _modelview; } + set + { + if (Modelview.Equals(value)) + return; + + ChangedUniforms.Add(ApplyModelViewProjection); + _modelview = value; + } + } + public vec3 LightPosition + { + get { return _lightPosition; } + set + { + if (LightPosition.Equals(value)) + return; + + ChangedUniforms.Add(ApplyLightPosition); + _lightPosition = value; + } + } + + #endregion properties + + #region events + #endregion events + + #region constructors + public NormalMaterialProgram(OpenGL gl) + :base(gl, ShaderTypeAndCode, AttributeNames, UniformNames) + { + } + #endregion constructors + + public void AddBufferGroup(NMHTBufferGroup group) + { + BufferGroups.Add(group); + } + + public void BindAll(OpenGL gl) + { + UseProgram(gl, () => + { + // Update uniforms. + foreach (var action in ChangedUniforms) + { + action.Invoke(gl); + } + ChangedUniforms.Clear(); + + foreach (var group in BufferGroups) + { + group.BindNMVAO(gl); + gl.DrawElements(OpenGL.GL_TRIANGLES, group.IndicesCount, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero); + } + }); + } + private void ApplyModelViewProjection(OpenGL gl) + { + gl.UniformMatrix4(Uniforms["ModelviewProjection"], 1, false, (Modelview.Transpose() * Projection.Transpose()).to_array()); + } + private void ApplyNormalMatrix(OpenGL gl) + { + gl.UniformMatrix3(Uniforms["NormalMatrix"], 1, false, NormalMatrix.to_array()); + } + private void ApplyLightPosition(OpenGL gl) + { + gl.Uniform3(Uniforms["LightPosition"], LightPosition.x, LightPosition.y, LightPosition.z); + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs new file mode 100644 index 00000000..d8107294 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs @@ -0,0 +1,278 @@ +using GlmNet; +using SharpGL; +using SharpGLHelper; +using SharpGLHelper.Buffers; +using SharpGLHelper.Common; +using SharpGLHelper.OGLOverloads; +using SharpGLHelper.SceneElements; +using SharpGLTest.Shapes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace SharpGLTest.Shaders +{ + public class ShaderManagerNormalMaterialParticleTest + { + + #region fields + vec3 _lightPosition = new vec3(); + #endregion fields + + #region properties + + protected Dictionary AttributeLocations + { + get + { + var dic = new Dictionary(); + + dic.Add(0, "Position"); + dic.Add(1, "Normal"); + dic.Add(2, "TCol1"); + dic.Add(3, "TCol2"); + dic.Add(4, "TCol3"); + dic.Add(5, "TCol4"); + dic.Add(6, "AmbientMaterial"); + dic.Add(7, "DiffuseMaterial"); + dic.Add(8, "SpecularMaterial"); + dic.Add(9, "ShininessValue"); + + return dic; + } + } + #endregion properties + + #region events + #endregion events + + #region constructors + public ShaderManagerNormalMaterialParticleTest(OpenGL gl) + { + init(gl); + } + #endregion constructors + + MyTrefoilKnot knot; + // List of indices in the generated buffers + // and ultimately the buffer IDs. + uint ibo = 10; + uint vert = 0; + uint norm = 1; + uint tCol1 = 2; + uint tCol2 = 3; + uint tCol3 = 4; + uint tCol4 = 5; + uint amb = 6; + uint diff = 7; + uint spec = 8; + uint shini = 9; + + + uint iboPos = 10; + uint vertPos = 0; + uint normPos = 1; + uint tCol1Pos = 2; + uint tCol2Pos = 3; + uint tCol3Pos = 4; + uint tCol4Pos = 5; + uint ambPos = 6; + uint diffPos = 7; + uint specPos = 8; + uint shiniPos = 9; + + // Uniform positions + int lightPos = 0; + int modelView = 1; + int normMatrix = 2; + int projection = 3; + + // Shader program; + uint programId; + + public void init(OpenGL gl) + { + // Create vert and frag NormalMaterialParticle shader. + //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); + var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; + var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; + var executingAssembly = Assembly.GetExecutingAssembly(); + var autoAttachAssemblyName = true; + var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); + var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); + + var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); + gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); + gl.CompileShader(vertShaderId); + //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); + var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); + gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); + gl.CompileShader(fragShaderId); + + // Create Program from shaders. + programId = gl.CreateProgram(); + gl.AttachShader(programId, vertShaderId); + gl.AttachShader(programId, fragShaderId); + + gl.BindAttribLocation(programId, vertPos, "Position"); + gl.BindAttribLocation(programId, normPos, "Normal"); + gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); + gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); + gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); + gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); + gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); + gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); + gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); + gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); + + //gl.BindAttribLocation(programId, lightPos, "LightPosition"); + //gl.BindAttribLocation(programId, modelView, "Modelview"); + //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); + //gl.BindAttribLocation(programId, projection, "Projection"); + gl.LinkProgram(programId); + + + knot = MyTrefoilKnot.Instance; + + // Create the IBO and VBO's. + uint[] buffers = new uint[11]; + gl.GenBuffers(11, buffers); + ibo = buffers[iboPos]; + vert = buffers[vertPos]; + norm = buffers[normPos]; + tCol1 = buffers[tCol1Pos]; + tCol2 = buffers[tCol2Pos]; + tCol3 = buffers[tCol3Pos]; + tCol4 = buffers[tCol4Pos]; + amb = buffers[ambPos]; + diff = buffers[diffPos]; + spec = buffers[specPos]; + shini = buffers[shiniPos]; + + var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); + + + var dataSize = knot.Indices.Length * sizeof(uint); + IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); + var intData = new int[knot.Indices.Length]; + Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); + Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); + + // Set trefoil knot data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); + + // Set transformation data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); + + // Set material data. + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); + gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); + + // Apply uniforms. + gl.UseProgram(programId); + mat4 modelViewMat = mat4.identity(); + mat4 projectionMat = mat4.identity(); + mat3 NormalMat = mat3.identity(); + var zoomValue = new vec3(0, 0, -10); + //glm.translate(projectionMat, zoomValue); + + //projection = gl.GetUniformLocation(programId, "Projection"); + //modelView = gl.GetUniformLocation(programId, "Modelview"); + //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); + //lightPos = gl.GetUniformLocation(programId, "LightPosition"); + + + gl.Uniform3((int)lightPos, 5, 10, 15); + gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); + gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); + gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); + gl.UseProgram(0); + + + gl.FrontFace(OpenGL.GL_CW); + } + + public void render(OpenGL gl) + { + //Bind buffers. + gl.UseProgram(programId); + + float[] parameters = new float[16]; + gl.GetUniform(programId, projection, parameters); + + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); + gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(vertPos, 0); + gl.EnableVertexAttribArray(vertPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); + gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(normPos, 0); + gl.EnableVertexAttribArray(normPos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); + gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol1Pos, 1); + gl.EnableVertexAttribArray(tCol1Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); + gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol2Pos, 1); + gl.EnableVertexAttribArray(tCol2Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); + gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol3Pos, 1); + gl.EnableVertexAttribArray(tCol3Pos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); + gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(tCol4Pos, 1); + gl.EnableVertexAttribArray(tCol4Pos); + + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); + gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(ambPos, 1); + gl.EnableVertexAttribArray(ambPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); + gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(diffPos, 1); + gl.EnableVertexAttribArray(diffPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); + gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(specPos, 1); + gl.EnableVertexAttribArray(specPos); + gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); + gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); + gl.VertexAttribDivisor(shiniPos, 1); + gl.EnableVertexAttribArray(shiniPos); + + gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); + //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); + + gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); + gl.UseProgram(0); + + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/SharpGLHitTestSample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/SharpGLHitTestSample.csproj new file mode 100644 index 00000000..c58152e4 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/SharpGLHitTestSample.csproj @@ -0,0 +1,135 @@ + + + + + Debug + AnyCPU + {28551651-CCBD-4DCA-A486-84AA47757806} + WinExe + Properties + SharpGLHitTestSample + SharpGLHitTestSample + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\..\..\..\..\..\..\AH\SharpGLViewerSample\packages\GlmNet.0.0.2.0\lib\net40\GlmNet.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + + + {47bcaa39-edad-4404-b6bd-4742b0abb523} + SharpGL.SceneGraph + + + {53e67055-13d2-4467-bb57-79589afac2cd} + SharpGL.WPF + + + {5ef45533-e2c7-46f2-b4a3-b8f36cd406e0} + SharpGL + + + + + \ No newline at end of file diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/packages.config b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/packages.config new file mode 100644 index 00000000..e316866a --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 77a34c7e495ae10e0ed2ff3037ab0a7bd2e5d39b Mon Sep 17 00:00:00 2001 From: Jochem Date: Tue, 20 May 2014 01:56:39 +0100 Subject: [PATCH 7/8] Removed some excluded files. --- ...ShaderManagerNormalMaterialParticleTest.cs | 278 ------------------ ...ShaderManagerNormalMaterialParticleTest.cs | 278 ------------------ ...ShaderManagerNormalMaterialParticleTest.cs | 278 ------------------ ...ShaderManagerNormalMaterialParticleTest.cs | 278 ------------------ ...ShaderManagerNormalMaterialParticleTest.cs | 278 ------------------ 5 files changed, 1390 deletions(-) delete mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs delete mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs delete mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs delete mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs delete mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs deleted file mode 100644 index d8107294..00000000 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGLHelper; -using SharpGLHelper.Buffers; -using SharpGLHelper.Common; -using SharpGLHelper.OGLOverloads; -using SharpGLHelper.SceneElements; -using SharpGLTest.Shapes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -namespace SharpGLTest.Shaders -{ - public class ShaderManagerNormalMaterialParticleTest - { - - #region fields - vec3 _lightPosition = new vec3(); - #endregion fields - - #region properties - - protected Dictionary AttributeLocations - { - get - { - var dic = new Dictionary(); - - dic.Add(0, "Position"); - dic.Add(1, "Normal"); - dic.Add(2, "TCol1"); - dic.Add(3, "TCol2"); - dic.Add(4, "TCol3"); - dic.Add(5, "TCol4"); - dic.Add(6, "AmbientMaterial"); - dic.Add(7, "DiffuseMaterial"); - dic.Add(8, "SpecularMaterial"); - dic.Add(9, "ShininessValue"); - - return dic; - } - } - #endregion properties - - #region events - #endregion events - - #region constructors - public ShaderManagerNormalMaterialParticleTest(OpenGL gl) - { - init(gl); - } - #endregion constructors - - MyTrefoilKnot knot; - // List of indices in the generated buffers - // and ultimately the buffer IDs. - uint ibo = 10; - uint vert = 0; - uint norm = 1; - uint tCol1 = 2; - uint tCol2 = 3; - uint tCol3 = 4; - uint tCol4 = 5; - uint amb = 6; - uint diff = 7; - uint spec = 8; - uint shini = 9; - - - uint iboPos = 10; - uint vertPos = 0; - uint normPos = 1; - uint tCol1Pos = 2; - uint tCol2Pos = 3; - uint tCol3Pos = 4; - uint tCol4Pos = 5; - uint ambPos = 6; - uint diffPos = 7; - uint specPos = 8; - uint shiniPos = 9; - - // Uniform positions - int lightPos = 0; - int modelView = 1; - int normMatrix = 2; - int projection = 3; - - // Shader program; - uint programId; - - public void init(OpenGL gl) - { - // Create vert and frag NormalMaterialParticle shader. - //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); - var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; - var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; - var executingAssembly = Assembly.GetExecutingAssembly(); - var autoAttachAssemblyName = true; - var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); - var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); - - var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); - gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); - gl.CompileShader(vertShaderId); - //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); - var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); - gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); - gl.CompileShader(fragShaderId); - - // Create Program from shaders. - programId = gl.CreateProgram(); - gl.AttachShader(programId, vertShaderId); - gl.AttachShader(programId, fragShaderId); - - gl.BindAttribLocation(programId, vertPos, "Position"); - gl.BindAttribLocation(programId, normPos, "Normal"); - gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); - gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); - gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); - gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); - gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); - gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); - gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); - gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); - - //gl.BindAttribLocation(programId, lightPos, "LightPosition"); - //gl.BindAttribLocation(programId, modelView, "Modelview"); - //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); - //gl.BindAttribLocation(programId, projection, "Projection"); - gl.LinkProgram(programId); - - - knot = MyTrefoilKnot.Instance; - - // Create the IBO and VBO's. - uint[] buffers = new uint[11]; - gl.GenBuffers(11, buffers); - ibo = buffers[iboPos]; - vert = buffers[vertPos]; - norm = buffers[normPos]; - tCol1 = buffers[tCol1Pos]; - tCol2 = buffers[tCol2Pos]; - tCol3 = buffers[tCol3Pos]; - tCol4 = buffers[tCol4Pos]; - amb = buffers[ambPos]; - diff = buffers[diffPos]; - spec = buffers[specPos]; - shini = buffers[shiniPos]; - - var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); - var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); - - - var dataSize = knot.Indices.Length * sizeof(uint); - IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); - var intData = new int[knot.Indices.Length]; - Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); - Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); - - // Set trefoil knot data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); - - // Set transformation data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); - - // Set material data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); - - // Apply uniforms. - gl.UseProgram(programId); - mat4 modelViewMat = mat4.identity(); - mat4 projectionMat = mat4.identity(); - mat3 NormalMat = mat3.identity(); - var zoomValue = new vec3(0, 0, -10); - //glm.translate(projectionMat, zoomValue); - - //projection = gl.GetUniformLocation(programId, "Projection"); - //modelView = gl.GetUniformLocation(programId, "Modelview"); - //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); - //lightPos = gl.GetUniformLocation(programId, "LightPosition"); - - - gl.Uniform3((int)lightPos, 5, 10, 15); - gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); - gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); - gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); - gl.UseProgram(0); - - - gl.FrontFace(OpenGL.GL_CW); - } - - public void render(OpenGL gl) - { - //Bind buffers. - gl.UseProgram(programId); - - float[] parameters = new float[16]; - gl.GetUniform(programId, projection, parameters); - - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(vertPos, 0); - gl.EnableVertexAttribArray(vertPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(normPos, 0); - gl.EnableVertexAttribArray(normPos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol1Pos, 1); - gl.EnableVertexAttribArray(tCol1Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol2Pos, 1); - gl.EnableVertexAttribArray(tCol2Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol3Pos, 1); - gl.EnableVertexAttribArray(tCol3Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol4Pos, 1); - gl.EnableVertexAttribArray(tCol4Pos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(ambPos, 1); - gl.EnableVertexAttribArray(ambPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(diffPos, 1); - gl.EnableVertexAttribArray(diffPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(specPos, 1); - gl.EnableVertexAttribArray(specPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); - gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(shiniPos, 1); - gl.EnableVertexAttribArray(shiniPos); - - gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); - //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); - - gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); - gl.UseProgram(0); - - } - - } -} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs deleted file mode 100644 index d8107294..00000000 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Shaders/LinesShader/ShaderManagerNormalMaterialParticleTest.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGLHelper; -using SharpGLHelper.Buffers; -using SharpGLHelper.Common; -using SharpGLHelper.OGLOverloads; -using SharpGLHelper.SceneElements; -using SharpGLTest.Shapes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -namespace SharpGLTest.Shaders -{ - public class ShaderManagerNormalMaterialParticleTest - { - - #region fields - vec3 _lightPosition = new vec3(); - #endregion fields - - #region properties - - protected Dictionary AttributeLocations - { - get - { - var dic = new Dictionary(); - - dic.Add(0, "Position"); - dic.Add(1, "Normal"); - dic.Add(2, "TCol1"); - dic.Add(3, "TCol2"); - dic.Add(4, "TCol3"); - dic.Add(5, "TCol4"); - dic.Add(6, "AmbientMaterial"); - dic.Add(7, "DiffuseMaterial"); - dic.Add(8, "SpecularMaterial"); - dic.Add(9, "ShininessValue"); - - return dic; - } - } - #endregion properties - - #region events - #endregion events - - #region constructors - public ShaderManagerNormalMaterialParticleTest(OpenGL gl) - { - init(gl); - } - #endregion constructors - - MyTrefoilKnot knot; - // List of indices in the generated buffers - // and ultimately the buffer IDs. - uint ibo = 10; - uint vert = 0; - uint norm = 1; - uint tCol1 = 2; - uint tCol2 = 3; - uint tCol3 = 4; - uint tCol4 = 5; - uint amb = 6; - uint diff = 7; - uint spec = 8; - uint shini = 9; - - - uint iboPos = 10; - uint vertPos = 0; - uint normPos = 1; - uint tCol1Pos = 2; - uint tCol2Pos = 3; - uint tCol3Pos = 4; - uint tCol4Pos = 5; - uint ambPos = 6; - uint diffPos = 7; - uint specPos = 8; - uint shiniPos = 9; - - // Uniform positions - int lightPos = 0; - int modelView = 1; - int normMatrix = 2; - int projection = 3; - - // Shader program; - uint programId; - - public void init(OpenGL gl) - { - // Create vert and frag NormalMaterialParticle shader. - //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); - var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; - var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; - var executingAssembly = Assembly.GetExecutingAssembly(); - var autoAttachAssemblyName = true; - var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); - var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); - - var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); - gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); - gl.CompileShader(vertShaderId); - //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); - var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); - gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); - gl.CompileShader(fragShaderId); - - // Create Program from shaders. - programId = gl.CreateProgram(); - gl.AttachShader(programId, vertShaderId); - gl.AttachShader(programId, fragShaderId); - - gl.BindAttribLocation(programId, vertPos, "Position"); - gl.BindAttribLocation(programId, normPos, "Normal"); - gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); - gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); - gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); - gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); - gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); - gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); - gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); - gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); - - //gl.BindAttribLocation(programId, lightPos, "LightPosition"); - //gl.BindAttribLocation(programId, modelView, "Modelview"); - //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); - //gl.BindAttribLocation(programId, projection, "Projection"); - gl.LinkProgram(programId); - - - knot = MyTrefoilKnot.Instance; - - // Create the IBO and VBO's. - uint[] buffers = new uint[11]; - gl.GenBuffers(11, buffers); - ibo = buffers[iboPos]; - vert = buffers[vertPos]; - norm = buffers[normPos]; - tCol1 = buffers[tCol1Pos]; - tCol2 = buffers[tCol2Pos]; - tCol3 = buffers[tCol3Pos]; - tCol4 = buffers[tCol4Pos]; - amb = buffers[ambPos]; - diff = buffers[diffPos]; - spec = buffers[specPos]; - shini = buffers[shiniPos]; - - var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); - var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); - - - var dataSize = knot.Indices.Length * sizeof(uint); - IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); - var intData = new int[knot.Indices.Length]; - Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); - Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); - - // Set trefoil knot data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); - - // Set transformation data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); - - // Set material data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); - - // Apply uniforms. - gl.UseProgram(programId); - mat4 modelViewMat = mat4.identity(); - mat4 projectionMat = mat4.identity(); - mat3 NormalMat = mat3.identity(); - var zoomValue = new vec3(0, 0, -10); - //glm.translate(projectionMat, zoomValue); - - //projection = gl.GetUniformLocation(programId, "Projection"); - //modelView = gl.GetUniformLocation(programId, "Modelview"); - //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); - //lightPos = gl.GetUniformLocation(programId, "LightPosition"); - - - gl.Uniform3((int)lightPos, 5, 10, 15); - gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); - gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); - gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); - gl.UseProgram(0); - - - gl.FrontFace(OpenGL.GL_CW); - } - - public void render(OpenGL gl) - { - //Bind buffers. - gl.UseProgram(programId); - - float[] parameters = new float[16]; - gl.GetUniform(programId, projection, parameters); - - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(vertPos, 0); - gl.EnableVertexAttribArray(vertPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(normPos, 0); - gl.EnableVertexAttribArray(normPos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol1Pos, 1); - gl.EnableVertexAttribArray(tCol1Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol2Pos, 1); - gl.EnableVertexAttribArray(tCol2Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol3Pos, 1); - gl.EnableVertexAttribArray(tCol3Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol4Pos, 1); - gl.EnableVertexAttribArray(tCol4Pos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(ambPos, 1); - gl.EnableVertexAttribArray(ambPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(diffPos, 1); - gl.EnableVertexAttribArray(diffPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(specPos, 1); - gl.EnableVertexAttribArray(specPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); - gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(shiniPos, 1); - gl.EnableVertexAttribArray(shiniPos); - - gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); - //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); - - gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); - gl.UseProgram(0); - - } - - } -} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs deleted file mode 100644 index d8107294..00000000 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/Shaders/NormalMaterialShader/ShaderManagerNormalMaterialParticleTest.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGLHelper; -using SharpGLHelper.Buffers; -using SharpGLHelper.Common; -using SharpGLHelper.OGLOverloads; -using SharpGLHelper.SceneElements; -using SharpGLTest.Shapes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -namespace SharpGLTest.Shaders -{ - public class ShaderManagerNormalMaterialParticleTest - { - - #region fields - vec3 _lightPosition = new vec3(); - #endregion fields - - #region properties - - protected Dictionary AttributeLocations - { - get - { - var dic = new Dictionary(); - - dic.Add(0, "Position"); - dic.Add(1, "Normal"); - dic.Add(2, "TCol1"); - dic.Add(3, "TCol2"); - dic.Add(4, "TCol3"); - dic.Add(5, "TCol4"); - dic.Add(6, "AmbientMaterial"); - dic.Add(7, "DiffuseMaterial"); - dic.Add(8, "SpecularMaterial"); - dic.Add(9, "ShininessValue"); - - return dic; - } - } - #endregion properties - - #region events - #endregion events - - #region constructors - public ShaderManagerNormalMaterialParticleTest(OpenGL gl) - { - init(gl); - } - #endregion constructors - - MyTrefoilKnot knot; - // List of indices in the generated buffers - // and ultimately the buffer IDs. - uint ibo = 10; - uint vert = 0; - uint norm = 1; - uint tCol1 = 2; - uint tCol2 = 3; - uint tCol3 = 4; - uint tCol4 = 5; - uint amb = 6; - uint diff = 7; - uint spec = 8; - uint shini = 9; - - - uint iboPos = 10; - uint vertPos = 0; - uint normPos = 1; - uint tCol1Pos = 2; - uint tCol2Pos = 3; - uint tCol3Pos = 4; - uint tCol4Pos = 5; - uint ambPos = 6; - uint diffPos = 7; - uint specPos = 8; - uint shiniPos = 9; - - // Uniform positions - int lightPos = 0; - int modelView = 1; - int normMatrix = 2; - int projection = 3; - - // Shader program; - uint programId; - - public void init(OpenGL gl) - { - // Create vert and frag NormalMaterialParticle shader. - //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); - var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; - var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; - var executingAssembly = Assembly.GetExecutingAssembly(); - var autoAttachAssemblyName = true; - var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); - var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); - - var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); - gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); - gl.CompileShader(vertShaderId); - //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); - var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); - gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); - gl.CompileShader(fragShaderId); - - // Create Program from shaders. - programId = gl.CreateProgram(); - gl.AttachShader(programId, vertShaderId); - gl.AttachShader(programId, fragShaderId); - - gl.BindAttribLocation(programId, vertPos, "Position"); - gl.BindAttribLocation(programId, normPos, "Normal"); - gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); - gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); - gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); - gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); - gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); - gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); - gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); - gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); - - //gl.BindAttribLocation(programId, lightPos, "LightPosition"); - //gl.BindAttribLocation(programId, modelView, "Modelview"); - //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); - //gl.BindAttribLocation(programId, projection, "Projection"); - gl.LinkProgram(programId); - - - knot = MyTrefoilKnot.Instance; - - // Create the IBO and VBO's. - uint[] buffers = new uint[11]; - gl.GenBuffers(11, buffers); - ibo = buffers[iboPos]; - vert = buffers[vertPos]; - norm = buffers[normPos]; - tCol1 = buffers[tCol1Pos]; - tCol2 = buffers[tCol2Pos]; - tCol3 = buffers[tCol3Pos]; - tCol4 = buffers[tCol4Pos]; - amb = buffers[ambPos]; - diff = buffers[diffPos]; - spec = buffers[specPos]; - shini = buffers[shiniPos]; - - var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); - var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); - - - var dataSize = knot.Indices.Length * sizeof(uint); - IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); - var intData = new int[knot.Indices.Length]; - Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); - Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); - - // Set trefoil knot data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); - - // Set transformation data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); - - // Set material data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); - - // Apply uniforms. - gl.UseProgram(programId); - mat4 modelViewMat = mat4.identity(); - mat4 projectionMat = mat4.identity(); - mat3 NormalMat = mat3.identity(); - var zoomValue = new vec3(0, 0, -10); - //glm.translate(projectionMat, zoomValue); - - //projection = gl.GetUniformLocation(programId, "Projection"); - //modelView = gl.GetUniformLocation(programId, "Modelview"); - //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); - //lightPos = gl.GetUniformLocation(programId, "LightPosition"); - - - gl.Uniform3((int)lightPos, 5, 10, 15); - gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); - gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); - gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); - gl.UseProgram(0); - - - gl.FrontFace(OpenGL.GL_CW); - } - - public void render(OpenGL gl) - { - //Bind buffers. - gl.UseProgram(programId); - - float[] parameters = new float[16]; - gl.GetUniform(programId, projection, parameters); - - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(vertPos, 0); - gl.EnableVertexAttribArray(vertPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(normPos, 0); - gl.EnableVertexAttribArray(normPos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol1Pos, 1); - gl.EnableVertexAttribArray(tCol1Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol2Pos, 1); - gl.EnableVertexAttribArray(tCol2Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol3Pos, 1); - gl.EnableVertexAttribArray(tCol3Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol4Pos, 1); - gl.EnableVertexAttribArray(tCol4Pos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(ambPos, 1); - gl.EnableVertexAttribArray(ambPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(diffPos, 1); - gl.EnableVertexAttribArray(diffPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(specPos, 1); - gl.EnableVertexAttribArray(specPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); - gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(shiniPos, 1); - gl.EnableVertexAttribArray(shiniPos); - - gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); - //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); - - gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); - gl.UseProgram(0); - - } - - } -} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs deleted file mode 100644 index d8107294..00000000 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLParticlesSample/Shaders/NormalMaterialParticleShader/ShaderManagerNormalMaterialParticleTest.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGLHelper; -using SharpGLHelper.Buffers; -using SharpGLHelper.Common; -using SharpGLHelper.OGLOverloads; -using SharpGLHelper.SceneElements; -using SharpGLTest.Shapes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -namespace SharpGLTest.Shaders -{ - public class ShaderManagerNormalMaterialParticleTest - { - - #region fields - vec3 _lightPosition = new vec3(); - #endregion fields - - #region properties - - protected Dictionary AttributeLocations - { - get - { - var dic = new Dictionary(); - - dic.Add(0, "Position"); - dic.Add(1, "Normal"); - dic.Add(2, "TCol1"); - dic.Add(3, "TCol2"); - dic.Add(4, "TCol3"); - dic.Add(5, "TCol4"); - dic.Add(6, "AmbientMaterial"); - dic.Add(7, "DiffuseMaterial"); - dic.Add(8, "SpecularMaterial"); - dic.Add(9, "ShininessValue"); - - return dic; - } - } - #endregion properties - - #region events - #endregion events - - #region constructors - public ShaderManagerNormalMaterialParticleTest(OpenGL gl) - { - init(gl); - } - #endregion constructors - - MyTrefoilKnot knot; - // List of indices in the generated buffers - // and ultimately the buffer IDs. - uint ibo = 10; - uint vert = 0; - uint norm = 1; - uint tCol1 = 2; - uint tCol2 = 3; - uint tCol3 = 4; - uint tCol4 = 5; - uint amb = 6; - uint diff = 7; - uint spec = 8; - uint shini = 9; - - - uint iboPos = 10; - uint vertPos = 0; - uint normPos = 1; - uint tCol1Pos = 2; - uint tCol2Pos = 3; - uint tCol3Pos = 4; - uint tCol4Pos = 5; - uint ambPos = 6; - uint diffPos = 7; - uint specPos = 8; - uint shiniPos = 9; - - // Uniform positions - int lightPos = 0; - int modelView = 1; - int normMatrix = 2; - int projection = 3; - - // Shader program; - uint programId; - - public void init(OpenGL gl) - { - // Create vert and frag NormalMaterialParticle shader. - //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); - var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; - var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; - var executingAssembly = Assembly.GetExecutingAssembly(); - var autoAttachAssemblyName = true; - var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); - var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); - - var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); - gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); - gl.CompileShader(vertShaderId); - //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); - var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); - gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); - gl.CompileShader(fragShaderId); - - // Create Program from shaders. - programId = gl.CreateProgram(); - gl.AttachShader(programId, vertShaderId); - gl.AttachShader(programId, fragShaderId); - - gl.BindAttribLocation(programId, vertPos, "Position"); - gl.BindAttribLocation(programId, normPos, "Normal"); - gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); - gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); - gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); - gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); - gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); - gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); - gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); - gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); - - //gl.BindAttribLocation(programId, lightPos, "LightPosition"); - //gl.BindAttribLocation(programId, modelView, "Modelview"); - //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); - //gl.BindAttribLocation(programId, projection, "Projection"); - gl.LinkProgram(programId); - - - knot = MyTrefoilKnot.Instance; - - // Create the IBO and VBO's. - uint[] buffers = new uint[11]; - gl.GenBuffers(11, buffers); - ibo = buffers[iboPos]; - vert = buffers[vertPos]; - norm = buffers[normPos]; - tCol1 = buffers[tCol1Pos]; - tCol2 = buffers[tCol2Pos]; - tCol3 = buffers[tCol3Pos]; - tCol4 = buffers[tCol4Pos]; - amb = buffers[ambPos]; - diff = buffers[diffPos]; - spec = buffers[specPos]; - shini = buffers[shiniPos]; - - var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); - var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); - - - var dataSize = knot.Indices.Length * sizeof(uint); - IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); - var intData = new int[knot.Indices.Length]; - Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); - Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); - - // Set trefoil knot data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); - - // Set transformation data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); - - // Set material data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); - - // Apply uniforms. - gl.UseProgram(programId); - mat4 modelViewMat = mat4.identity(); - mat4 projectionMat = mat4.identity(); - mat3 NormalMat = mat3.identity(); - var zoomValue = new vec3(0, 0, -10); - //glm.translate(projectionMat, zoomValue); - - //projection = gl.GetUniformLocation(programId, "Projection"); - //modelView = gl.GetUniformLocation(programId, "Modelview"); - //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); - //lightPos = gl.GetUniformLocation(programId, "LightPosition"); - - - gl.Uniform3((int)lightPos, 5, 10, 15); - gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); - gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); - gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); - gl.UseProgram(0); - - - gl.FrontFace(OpenGL.GL_CW); - } - - public void render(OpenGL gl) - { - //Bind buffers. - gl.UseProgram(programId); - - float[] parameters = new float[16]; - gl.GetUniform(programId, projection, parameters); - - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(vertPos, 0); - gl.EnableVertexAttribArray(vertPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(normPos, 0); - gl.EnableVertexAttribArray(normPos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol1Pos, 1); - gl.EnableVertexAttribArray(tCol1Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol2Pos, 1); - gl.EnableVertexAttribArray(tCol2Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol3Pos, 1); - gl.EnableVertexAttribArray(tCol3Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol4Pos, 1); - gl.EnableVertexAttribArray(tCol4Pos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(ambPos, 1); - gl.EnableVertexAttribArray(ambPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(diffPos, 1); - gl.EnableVertexAttribArray(diffPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(specPos, 1); - gl.EnableVertexAttribArray(specPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); - gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(shiniPos, 1); - gl.EnableVertexAttribArray(shiniPos); - - gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); - //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); - - gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); - gl.UseProgram(0); - - } - - } -} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs deleted file mode 100644 index d8107294..00000000 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLTranslucencySample/Shaders/NormalTranslucentMaterialShader/ShaderManagerNormalMaterialParticleTest.cs +++ /dev/null @@ -1,278 +0,0 @@ -using GlmNet; -using SharpGL; -using SharpGLHelper; -using SharpGLHelper.Buffers; -using SharpGLHelper.Common; -using SharpGLHelper.OGLOverloads; -using SharpGLHelper.SceneElements; -using SharpGLTest.Shapes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -namespace SharpGLTest.Shaders -{ - public class ShaderManagerNormalMaterialParticleTest - { - - #region fields - vec3 _lightPosition = new vec3(); - #endregion fields - - #region properties - - protected Dictionary AttributeLocations - { - get - { - var dic = new Dictionary(); - - dic.Add(0, "Position"); - dic.Add(1, "Normal"); - dic.Add(2, "TCol1"); - dic.Add(3, "TCol2"); - dic.Add(4, "TCol3"); - dic.Add(5, "TCol4"); - dic.Add(6, "AmbientMaterial"); - dic.Add(7, "DiffuseMaterial"); - dic.Add(8, "SpecularMaterial"); - dic.Add(9, "ShininessValue"); - - return dic; - } - } - #endregion properties - - #region events - #endregion events - - #region constructors - public ShaderManagerNormalMaterialParticleTest(OpenGL gl) - { - init(gl); - } - #endregion constructors - - MyTrefoilKnot knot; - // List of indices in the generated buffers - // and ultimately the buffer IDs. - uint ibo = 10; - uint vert = 0; - uint norm = 1; - uint tCol1 = 2; - uint tCol2 = 3; - uint tCol3 = 4; - uint tCol4 = 5; - uint amb = 6; - uint diff = 7; - uint spec = 8; - uint shini = 9; - - - uint iboPos = 10; - uint vertPos = 0; - uint normPos = 1; - uint tCol1Pos = 2; - uint tCol2Pos = 3; - uint tCol3Pos = 4; - uint tCol4Pos = 5; - uint ambPos = 6; - uint diffPos = 7; - uint specPos = 8; - uint shiniPos = 9; - - // Uniform positions - int lightPos = 0; - int modelView = 1; - int normMatrix = 2; - int projection = 3; - - // Shader program; - uint programId; - - public void init(OpenGL gl) - { - // Create vert and frag NormalMaterialParticle shader. - //scene::vertShader = shader(OpenGL.GL_VERTEX_SHADER, &NORMAL_MATERIAL_PARTICLE_VERT); - var vertexShaderSource = "ShaderResources.NormalMaterialParticle.vert"; - var fragmentShaderSource = "ShaderResources.NormalMaterialParticle.frag"; - var executingAssembly = Assembly.GetExecutingAssembly(); - var autoAttachAssemblyName = true; - var NORMAL_MATERIAL_PARTICLE_VERT = ManifestResourceLoader.LoadTextFile(vertexShaderSource, executingAssembly, autoAttachAssemblyName); - var NORMAL_MATERIAL_PARTICLE_FRAG = ManifestResourceLoader.LoadTextFile(fragmentShaderSource, executingAssembly, autoAttachAssemblyName); - - var vertShaderId = gl.CreateShader(OpenGL.GL_VERTEX_SHADER); - gl.ShaderSource(vertShaderId, NORMAL_MATERIAL_PARTICLE_VERT); - gl.CompileShader(vertShaderId); - //scene::fragShader = shader(OpenGL.GL_FRAGMENT_SHADER, &NORMAL_MATERIAL_PARTICLE_FRAG); - var fragShaderId = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER); - gl.ShaderSource(fragShaderId, NORMAL_MATERIAL_PARTICLE_FRAG); - gl.CompileShader(fragShaderId); - - // Create Program from shaders. - programId = gl.CreateProgram(); - gl.AttachShader(programId, vertShaderId); - gl.AttachShader(programId, fragShaderId); - - gl.BindAttribLocation(programId, vertPos, "Position"); - gl.BindAttribLocation(programId, normPos, "Normal"); - gl.BindAttribLocation(programId, tCol1Pos, "TCol1"); - gl.BindAttribLocation(programId, tCol2Pos, "TCol2"); - gl.BindAttribLocation(programId, tCol3Pos, "TCol3"); - gl.BindAttribLocation(programId, tCol4Pos, "TCol4"); - gl.BindAttribLocation(programId, ambPos, "AmbientMaterial"); - gl.BindAttribLocation(programId, diffPos, "DiffuseMaterial"); - gl.BindAttribLocation(programId, specPos, "SpecularMaterial"); - gl.BindAttribLocation(programId, shiniPos, "ShininessValue"); - - //gl.BindAttribLocation(programId, lightPos, "LightPosition"); - //gl.BindAttribLocation(programId, modelView, "Modelview"); - //gl.BindAttribLocation(programId, normMatrix, "NormalMatrix"); - //gl.BindAttribLocation(programId, projection, "Projection"); - gl.LinkProgram(programId); - - - knot = MyTrefoilKnot.Instance; - - // Create the IBO and VBO's. - uint[] buffers = new uint[11]; - gl.GenBuffers(11, buffers); - ibo = buffers[iboPos]; - vert = buffers[vertPos]; - norm = buffers[normPos]; - tCol1 = buffers[tCol1Pos]; - tCol2 = buffers[tCol2Pos]; - tCol3 = buffers[tCol3Pos]; - tCol4 = buffers[tCol4Pos]; - amb = buffers[ambPos]; - diff = buffers[diffPos]; - spec = buffers[specPos]; - shini = buffers[shiniPos]; - - var vertices = knot.Vertices.SelectMany(x=>x.to_array()).ToArray(); - var normals = knot.Normals.SelectMany(x=>x.to_array()).ToArray(); - - - var dataSize = knot.Indices.Length * sizeof(uint); - IntPtr newDataPtr = Marshal.AllocHGlobal(dataSize); - var intData = new int[knot.Indices.Length]; - Buffer.BlockCopy(knot.Indices, 0, intData, 0, dataSize); - Marshal.Copy(intData, 0, newDataPtr, knot.Indices.Length); - - // Set trefoil knot data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, ibo); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, dataSize, newDataPtr, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, normals, OpenGL.GL_STATIC_DRAW); - - // Set transformation data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 1, 0, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 1, 0, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 1, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[4] { 0, 0, 0, 1 }, OpenGL.GL_STATIC_COPY); - - // Set material data. - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 0, 200, 200 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[3] { 200, 200, 0 }, OpenGL.GL_STATIC_COPY); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, shini); - gl.BufferData(OpenGL.GL_ARRAY_BUFFER, new float[1] { 5 }, OpenGL.GL_STATIC_COPY); - - // Apply uniforms. - gl.UseProgram(programId); - mat4 modelViewMat = mat4.identity(); - mat4 projectionMat = mat4.identity(); - mat3 NormalMat = mat3.identity(); - var zoomValue = new vec3(0, 0, -10); - //glm.translate(projectionMat, zoomValue); - - //projection = gl.GetUniformLocation(programId, "Projection"); - //modelView = gl.GetUniformLocation(programId, "Modelview"); - //normMatrix = gl.GetUniformLocation(programId, "NormalMatrix"); - //lightPos = gl.GetUniformLocation(programId, "LightPosition"); - - - gl.Uniform3((int)lightPos, 5, 10, 15); - gl.UniformMatrix4(modelView, 1, false, modelViewMat.to_array()); - gl.UniformMatrix4(projection, 1, false, projectionMat.to_array()); - gl.UniformMatrix3(normMatrix, 1, false, NormalMat.to_array()); - gl.UseProgram(0); - - - gl.FrontFace(OpenGL.GL_CW); - } - - public void render(OpenGL gl) - { - //Bind buffers. - gl.UseProgram(programId); - - float[] parameters = new float[16]; - gl.GetUniform(programId, projection, parameters); - - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vert); - gl.VertexAttribPointer(vertPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(vertPos, 0); - gl.EnableVertexAttribArray(vertPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, norm); - gl.VertexAttribPointer(normPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(normPos, 0); - gl.EnableVertexAttribArray(normPos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol1); - gl.VertexAttribPointer(tCol1Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol1Pos, 1); - gl.EnableVertexAttribArray(tCol1Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol2); - gl.VertexAttribPointer(tCol2Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol2Pos, 1); - gl.EnableVertexAttribArray(tCol2Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol3); - gl.VertexAttribPointer(tCol3Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol3Pos, 1); - gl.EnableVertexAttribArray(tCol3Pos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, tCol4); - gl.VertexAttribPointer(tCol4Pos, 4, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(tCol4Pos, 1); - gl.EnableVertexAttribArray(tCol4Pos); - - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, amb); - gl.VertexAttribPointer(ambPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(ambPos, 1); - gl.EnableVertexAttribArray(ambPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, diff); - gl.VertexAttribPointer(diffPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(diffPos, 1); - gl.EnableVertexAttribArray(diffPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, spec); - gl.VertexAttribPointer(specPos, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(specPos, 1); - gl.EnableVertexAttribArray(specPos); - gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,shini); - gl.VertexAttribPointer(shiniPos, 1, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); - gl.VertexAttribDivisor(shiniPos, 1); - gl.EnableVertexAttribArray(shiniPos); - - gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, ibo); - //gl.VertexAttribPointer(ibo, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, false, 0, IntPtr.Zero); - - gl.DrawElementsInstanced(OpenGL.GL_TRIANGLES, knot.Indices.Length, OpenGL.GL_UNSIGNED_INT, IntPtr.Zero, 1); - gl.UseProgram(0); - - } - - } -} From 6b3ef31f62978f8948faa4151acb5647a7557cef Mon Sep 17 00:00:00 2001 From: Jochem Date: Wed, 21 May 2014 12:00:55 +0100 Subject: [PATCH 8/8] Added a OBJ- file import sample. NOTE: triangulation only works for quads and the reading algorithm has only been tested for vertex positions(v), normals (vn) and faces (f). And will probably give issues if the faces include more than just vertex positions and normal positions. OpenFileDialog results into not displaying any buffer data anymore for some yet unknown reason. Just entering the URL and press "Open from URL" works without a problem. --- .../SharpGLHitTestSample/MainWindow.xaml.cs | 4 - .../WPF/JOG/SharpGLObjFileImport/App.config | 6 + .../WPF/JOG/SharpGLObjFileImport/App.xaml | 8 + .../WPF/JOG/SharpGLObjFileImport/App.xaml.cs | 17 + .../JOG/SharpGLObjFileImport/GLController.cs | 246 ++++++++++ .../SharpGLObjFileImport/GlmNetExtensions.cs | 431 ++++++++++++++++++ .../SharpGLObjFileImport/IO/ObjFileModel.cs | 340 ++++++++++++++ .../SharpGLObjFileImport/IO/PositionNormal.cs | 20 + .../JOG/SharpGLObjFileImport/MainWindow.xaml | 18 + .../SharpGLObjFileImport/MainWindow.xaml.cs | 147 ++++++ .../ModelviewProjectionBuilder.cs | 151 ++++++ .../Primitives/FlatShadedCube.cs | 67 +++ .../Primitives/MyTrefoilKnot.cs | 160 +++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 63 +++ .../Properties/Resources.resx | 117 +++++ .../Properties/Settings.Designer.cs | 26 ++ .../Properties/Settings.settings | 7 + .../ShaderResources/NormalMaterial.frag | 25 + .../ShaderResources/NormalMaterial.vert | 27 ++ .../NormalMaterialShader/NMBufferGroup.cs | 193 ++++++++ .../NormalMaterialProgram.cs | 181 ++++++++ .../SharpGLObjFileImport.csproj | 178 ++++++++ .../JOG/SharpGLObjFileImport/packages.config | 4 + 24 files changed, 2487 insertions(+), 4 deletions(-) create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.config create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GLController.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GlmNetExtensions.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/ObjFileModel.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/PositionNormal.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/MainWindow.xaml create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/MainWindow.xaml.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/ModelviewProjectionBuilder.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Primitives/FlatShadedCube.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Primitives/MyTrefoilKnot.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Properties/AssemblyInfo.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Properties/Resources.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Properties/Resources.resx create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Properties/Settings.Designer.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Properties/Settings.settings create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/ShaderResources/NormalMaterial.frag create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/ShaderResources/NormalMaterial.vert create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Shaders/NormalMaterialShader/NMBufferGroup.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/Shaders/NormalMaterialShader/NormalMaterialProgram.cs create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/SharpGLObjFileImport.csproj create mode 100644 source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/packages.config diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs index 422b0893..b3cb7258 100644 --- a/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs @@ -81,15 +81,11 @@ private void OpenGLControlJOG_MouseDown(object sender, MouseButtonEventArgs e) { var id = Controller.DoHitTest(control.Gl, (int)(_previousPosition.X), (int)(control.ActualHeight - _previousPosition.Y)); - //SetCursorPos((int)_previousPosition.X, (int)_previousPosition.Y); if (id > 0) MessageBox.Show("Clicked object has ID " + id); } } - [DllImport("User32.dll")] - private static extern bool SetCursorPos(int X, int Y); - private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e) { // Zoom diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.config b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.config new file mode 100644 index 00000000..74ade9db --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml new file mode 100644 index 00000000..9e602794 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml.cs new file mode 100644 index 00000000..acdac9e5 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SharpGLObjFileImport +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GLController.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GLController.cs new file mode 100644 index 00000000..7037d05d --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GLController.cs @@ -0,0 +1,246 @@ +using GlmNet; +using SharpGL; +using SharpGL.SceneGraph; +using SharpGL.SceneGraph.JOG; +using SharpGL.Shaders; +using SharpGL.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLObjFileImport +{ + public class GLController + { + #region fields + NormalMaterialProgram _nmProgram; + mat4 _projectionMatrix = mat4.identity(), + _modelviewMatrix = mat4.identity(); + mat3 _normalMatrix = mat3.identity(); + + List _runOnNextDraw = new List(); + + + + ModelviewProjectionBuilder _mvpBuilder = new ModelviewProjectionBuilder(); + #endregion fields + + #region properties + public NormalMaterialProgram NmProgram + { + get { return _nmProgram; } + set { _nmProgram = value; } + } + /// + /// The matrix responsable for deforming the projection. + /// + public mat4 ProjectionMatrix + { + get { return _projectionMatrix; } + set + { + _projectionMatrix = value; + NmProgram.Projection = value; + } + } + /// + /// The projection matrix, responsable for transforming objects in the world. + /// + public mat4 ModelviewMatrix + { + get { return _modelviewMatrix; } + set + { + _modelviewMatrix = value; + NmProgram.Modelview = value; + } + } + + /// + /// A normal matrix, influences lighting reflection etc. + /// + public mat3 NormalMatrix + { + get { return _normalMatrix; } + set + { + _normalMatrix = value; + NmProgram.NormalMatrix = value; + } + } + + public OpenGL GL { get { return SceneControl.Gl; } } + public OpenGLControlJOG SceneControl { get; set; } + + public ModelviewProjectionBuilder MvpBuilder + { + get { return _mvpBuilder; } + set { _mvpBuilder = value; } + } + public List RunOnNextDraw + { + get { return _runOnNextDraw; } + set { _runOnNextDraw = value; } + } + #endregion properties + + #region events + #endregion events + + #region constructors + #endregion constructors + public void Init(object sender, OpenGLEventArgs args) + { + SceneControl = sender as OpenGLControlJOG; + + // Set up the view. + MvpBuilder.FovRadians = (float)Math.PI / 2f; // Set FOV to 90° + MvpBuilder.Far = 100f; + MvpBuilder.Near = 0.01f; + MvpBuilder.Width = (int)SceneControl.ActualWidth; + MvpBuilder.Height = (int)SceneControl.ActualHeight; + + MvpBuilder.TranslationZ = -10; + + MvpBuilder.BuildPerspectiveProjection(); + MvpBuilder.BuildTurntableModelview(); + + + // Create a shader program. + NmProgram = new NormalMaterialProgram(GL); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + NormalMatrix = mat3.identity(); + NmProgram.LightPosition = new vec3(5, 10, 15); + + //AddMonkey(); + //AddTestData(GL); + + GL.Enable(OpenGL.GL_DEPTH_TEST); + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + } + + public void Draw(object sender, OpenGLEventArgs args) + { + foreach (var act in _runOnNextDraw) + { + act.Invoke(); + } + + _runOnNextDraw.Clear(); + + + GL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); + + // Add gradient background. + SetVerticalGradientBackground(GL, new ColorF(255, 146, 134, 188), new ColorF(1f, 0, 1, 0)); + + NmProgram.BindAll(GL); + + } + public void Resized(object sender, OpenGLEventArgs args) + { + var control = sender as OpenGLControlJOG; + + MvpBuilder.Width = (int)control.ActualWidth; + MvpBuilder.Height = (int)control.ActualHeight; + + MvpBuilder.BuildPerspectiveProjection(); + + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + private void AddTestData(OpenGL gl) + { + NMBufferGroup group = new NMBufferGroup(gl); + + var verts = MyTrefoilKnot.Vertices.SelectMany(x=>x.to_array()).ToArray(); + var normals = MyTrefoilKnot.Normals.SelectMany(x => x.to_array()).ToArray(); + + group.BufferData(gl, MyTrefoilKnot.Indices, verts, normals, + new Material[] { new Material(new ColorF(255, 150, 50, 50), new ColorF(255,10,100,10), new ColorF(255, 225, 225, 225), null, 100f)}); + group.PrepareVAO(gl, NmProgram); + + NmProgram.AddBufferGroup(group); + NMBufferGroup groupCube = new NMBufferGroup(gl); + + var vertsCube = FlatShadedCube.Vertices.SelectMany(x => x.to_array()).ToArray(); + var normalsCube = FlatShadedCube.Normals.SelectMany(x => x.to_array()).ToArray(); + + + groupCube.BufferData(gl, FlatShadedCube.Indices, vertsCube, normalsCube, + new Material[] + { + new Material(new ColorF(1f, 0.3f, 1, 0), new ColorF(1f, 1f, 0.5f, 0), new ColorF(1f, 1, 0, 1), null, 100f), + }); + + groupCube.PrepareVAO(gl, NmProgram); + + NmProgram.AddBufferGroup(groupCube); + } + + public void AddMonkey() + { + var objFM = new ObjFileModel("C:\\Users\\Jochem\\Desktop\\monkey.obj"); + + AddData(objFM.Indices, objFM.Vertices.Select(x => x.ToVec3()).ToArray(), objFM.Normals); + } + + public void AddData(uint[] indices, vec3[] verticesVec, vec3[] normalsVec) + { + NMBufferGroup group = new NMBufferGroup(GL); + + var verts = verticesVec.SelectMany(x => x.to_array()).ToArray(); + var normals = normalsVec.SelectMany(x => x.to_array()).ToArray(); + var indicesFixed = indices.Select(x => x).ToArray(); + group.BufferData(GL, indicesFixed, verts, normals, + new Material[] { new Material(new ColorF(255, 150, 50, 50), new ColorF(255, 10, 100, 10), new ColorF(255, 225, 225, 225), null, 100f) }); + group.PrepareVAO(GL, NmProgram); + + NmProgram.AddBufferGroup(group); + } + + public void RefreshModelview() + { + MvpBuilder.BuildTurntableModelview(); + ModelviewMatrix = MvpBuilder.ModelviewMatrix; + } + public void RefreshProjection() + { + MvpBuilder.BuildPerspectiveProjection(); + ProjectionMatrix = MvpBuilder.ProjectionMatrix; + } + + /// + /// Sets the background color, using a gradient existing from 2 colors + /// + /// + private static void SetVerticalGradientBackground(OpenGL gl, ColorF colorTop, ColorF colorBot) + { + float topRed = colorTop.R;// / 255.0f; + float topGreen = colorTop.G;// / 255.0f; + float topBlue = colorTop.B;// / 255.0f; + float botRed = colorBot.R;// / 255.0f; + float botGreen = colorBot.G;// / 255.0f; + float botBlue = colorBot.B;// / 255.0f; + + gl.Begin(OpenGL.GL_QUADS); + + //bottom color + gl.Color(botRed, botGreen, botBlue); + gl.Vertex(-1.0, -1.0); + gl.Vertex(1.0, -1.0); + + //top color + gl.Color(topRed, topGreen, topBlue); + gl.Vertex(1.0, 1.0); + gl.Vertex(-1.0, 1.0); + + gl.End(); + } + + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GlmNetExtensions.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GlmNetExtensions.cs new file mode 100644 index 00000000..161dd7bd --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/GlmNetExtensions.cs @@ -0,0 +1,431 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SharpGLObjFileImport +{ + /// + /// Provides matrix and vector extentions primarely for the GlmNET library. + /// + public static class GlmNetExtensions + { + /// + /// Deep copy of the mat4 object + /// + /// The matrix + /// Deep copy of the input matrix. + public static mat4 DeepCopy(this mat4 mat) + { + return new mat4( + new vec4[]{ + mat[0].DeepCopy(), + mat[1].DeepCopy(), + mat[2].DeepCopy(), + mat[3].DeepCopy(), + }); + } + + /// + /// Deep copy of a vec4 object + /// + /// The vector + /// Deep copy of the input vector. + public static vec4 DeepCopy(this vec4 v) + { + return new vec4(v.x, v.y, v.z, v.w); + } + + /// + /// Copies everything except the z-value from the vector v into a new vec3. + /// + /// input vector + /// + public static vec3 ToVec3(this vec4 v) + { + return new vec3(v.x, v.y, v.z); + } + + /// + /// Puts the values from the matrix in a readable 4 line string, where each line defines 1 vector. + /// BEWARE: if m contains null vectors, it will throw an exception. This exception is being caught here, but this might create performance issues. + /// If exception is caught, this method will return an empty string( = ""). + /// + /// The matrix. + /// Used for calling Math.Round(m[i][j], round) + /// A readable 4 line string, where each line defines 1 vector + public static string ToValueString(this mat4 m, int round = 3) + { + var txt = ""; + try + { + for (int i = 0; i < 4; i++) + { + var arr = m.to_array(); + var mi = m[i]; + txt += mi.ToValueString(round); + txt += "\n"; + } + } + catch (Exception) + { + txt = ""; + } + return txt; + + } + + /// + /// Create a string from the values in the vec4. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec4. + public static string ToValueString(this vec4 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 4; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Create a string from the values in the vec3. + /// + /// The vector. + /// Used for calling Math.Round(v[j], round). + /// A string from the values in the vec3. + public static string ToValueString(this vec3 v, int round = 3) + { + string txt = ""; + for (int j = 0; j < 3; j++) + { + txt += Math.Round(v[j], round) + "\t"; + } + + return txt; + } + + /// + /// Transposes the mat4. + /// + /// The 4x4 matrix. + /// The Transpose of the matrix. + public static mat4 Transpose(this mat4 m) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[j][i]; + } + } + + return new mat4(vecs); + } + + /// + /// Concatenates every value in this matrix with it's corresponding value in the other one. + /// + /// This matrix + /// Other matrix + /// The concatenated result. + public static mat4 Concat(this mat4 m, mat4 m2) + { + vec4[] vecs = new vec4[4]; + + for (int i = 0; i < vecs.Length; i++) + { + vecs[i] = new vec4(); + for (int j = 0; j < vecs.Length; j++) + { + vecs[i][j] = m[i][j] + m2[i][j]; + } + } + + return new mat4(vecs); + } + + /// + /// Not sure if this one works 100%, but might be more performant (if it's ever needed). + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse2(this mat4 mat) + { + int n = 4; + float[,] a = new float[n,n]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + a[i,j] = mat[j][i]; + } + } + + var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; + var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; + var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; + var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; + var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; + var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; + + var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; + var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; + var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; + var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; + var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; + var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; + + // Should check for 0 determinant + var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); + + var b = mat4.identity(); + + b[0, 0] = (float)((a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet); + b[0, 1] = (float)((-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet); + b[0, 2] = (float)((a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet); + b[0, 3] = (float)((-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet); + + b[1, 0] = (float)((-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet); + b[1, 1] = (float)((a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet); + b[1, 2] = (float)((-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet); + b[1, 3] = (float)((a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet); + + b[2, 0] = (float)((a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet); + b[2, 1] = (float)((-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet); + b[2, 2] = (float)((a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet); + b[2, 3] = (float)((-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet); + + b[3, 0] = (float)((-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet); + b[3, 1] = (float)((a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet); + b[3, 2] = (float)((-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet); + b[3, 3] = (float)((a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet); + + return b; + } + + /// + /// Creates the Inverse of the matrix. + /// + /// A 4x4 matrix. + /// The inversed matrix. + public static mat4 Inverse(this mat4 a) + { + int n = 4; + float[][] arrA = new float[n][]; + float[][] arrInverse; + mat4 inverse = mat4.identity(); + + for (int i = 0; i < n; i++) + { + arrA[i] = new float[n]; + for (int j = 0; j < n; j++) + { + arrA[i][j] = a[j][i]; + } + } + + var d = Determinant(arrA, n); + if (d != 0) + { + arrInverse = Cofactor(arrA, n); + + //float[][] to mat4 + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + inverse[i, j] = arrInverse[i][j]; + } + } + + //test if result == I + var res = a * inverse; + + + return inverse; + } + else + { + throw new Exception("Matrix can't be inverted, determinant == 0."); + } + } + + /// + /// For calculating Determinant of the Matrix. + /// + /// The matrix. + /// The order of the matrix (k = 3 => assuming a matrix of size 3x3) + /// The determinant. + public static float Determinant(float[][] a, int k) + { + float s=1,det=0; + float[][] b = new float[k][]; + + + for (int idx = 0; idx < b.Length; idx++) + { + b[idx] = new float[k]; + } + + int m,n,c; + if (k==1) + { + return (a[0][0]); + } + else + { + det=0; + for (c=0;c + /// Calculates the Cofactor of a matrix of the order f. + /// + /// The matrix. + /// The order of the matrix (f = 3 => assuming a matrix of size 3x3) + /// The cofactor. + public static float[][] Cofactor(float[][] a, int f) + { + var b = new float[f][]; + var fac = new float[f][]; + + for (int i = 0; i < f; i++) + { + b[i] = new float[f]; + fac[i] = new float[f]; + } + + + int m,n; + for (int q = 0; q < f; q++) + { + for (int p = 0; p < f; p++) + { + m=0; + n=0; + for (int i = 0; i < f; i++) + { + for (int j = 0; j < f; j++) + { + if (i != q && j != p) + { + b[m][n]=a[i][j]; + if (n<(f-2)) + n++; + else + { + n=0; + m++; + } + } + } + } + fac[q][p] = (float)Math.Pow(-1, q + p) * Determinant(b, f - 1); + } + } + return Transpose(a, fac, f); + } + + /// + /// Finding the transpose of a matrix. + /// + /// The matrix + /// The cofactor. + /// The order of the matrix (r = 3 => assuming a matrix of size 3x3) + /// The transpose. + public static float[][] Transpose(float[][] a, float[][] fac, int r) + { + float[][] b = new float[r][], + inverse = new float[r][]; + float d; + + for (int i = 0; i < r; i++) + { + b[i] = new float[r]; + inverse[i] = new float[r]; + } + + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + b[i][j]=fac[j][i]; + } + } + d = Determinant(a, r); + for (int i = 0; i < r; i++) + { + for (int j = 0; j < r; j++) + { + inverse[i][j] = b[i][j] / d; + } + } + //The inverse of matrix is : + return inverse; + } + + public static vec3 Substract(this vec3 v1, vec3 v2) + { + return new vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + /// + /// Multiplies a 4x1 vector with a 4x4 transformation matrix. + /// + /// The 4x1 vector. + /// The 4x4 matrix. + /// + public static vec4 Multiply (this vec4 vec, mat4 mat) + { + var pos = new vec4(); + for (int i = 0; i < 4; i++) + { + float newPosVal = 0.0f; + for (int j = 0; j < 4; j++) + { + newPosVal += vec[j] * mat[j][i]; + } + pos[i] = newPosVal; + } + + return pos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/ObjFileModel.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/ObjFileModel.cs new file mode 100644 index 00000000..903c14a0 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/ObjFileModel.cs @@ -0,0 +1,340 @@ +using GlmNet; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace SharpGLObjFileImport +{ + public class ObjFileModel + { + #region fields + #endregion fields + + #region properties + public uint[] Indices { get; set; } + public vec4[] Vertices { get; set; } + public vec3[] Normals { get; set; } + #endregion properties + + #region events + #endregion events + + #region constructors + public ObjFileModel(string path) + { + Load(path); + } + #endregion constructors + + private void Load(string path) + { + var v = new List(); // Vertices coordinates + var vt = new List(); // Texture coordinates + var vn = new List(); // Normals + var vp = new List(); // Parameter space vertices + var f = new List>(); // Face definitions (position id and normal id) + + var culture = System.Globalization.CultureInfo.InvariantCulture; + + #region read data + using (var sr = new StreamReader(path)) + { + while (!sr.EndOfStream) + { + string line = sr.ReadLine(); + + if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) + { + // # : comments + continue; + } + else if (line.StartsWith("vt")) + { + // vt : texture coordinate + #region load texture coordinate + var pattern = @"\d+.?\d*"; + var matches = new Regex(pattern).Matches(line); + var matchCount = matches.Count; + if (matchCount < 2) continue; // Invalid texture coordinate. + var vec = new vec3(); + vec.x = float.Parse(matches[0].Value, culture); + vec.y = float.Parse(matches[1].Value, culture); + vec.z = matchCount > 2 ? float.Parse(matches[2].Value, culture) : 0; + + vt.Add(vec); + #endregion load texture coordinate + } + else if (line.StartsWith("vn")) + { + // vn : vertex normal + #region load vertex normal + var pattern = @"-?\d+.?\d*"; + var matches = new Regex(pattern).Matches(line); + var matchCount = matches.Count; + if (matchCount < 2) continue; // Invalid. + var vec = new vec3(); + vec.x = float.Parse(matches[0].Value, culture); + vec.y = float.Parse(matches[1].Value, culture); + vec.z = float.Parse(matches[2].Value, culture); + + vn.Add(vec); + #endregion load vertex normal + } + else if (line.StartsWith("v ")) + { + // v : vertex coordinates + #region load vertex coordinates + var pattern = @"-?\d+.?\d*"; + var matches = new Regex(pattern).Matches(line); + var matchCount = matches.Count; + if (matchCount < 3) continue; // Invalid vertex. + var vec = new vec4(); + vec.x = (float)double.Parse(matches[0].Value, culture); + vec.y = float.Parse(matches[1].Value, culture); + vec.z = float.Parse(matches[2].Value, culture); + vec.w = matchCount > 3 ? float.Parse(matches[3].Value, culture) : 1; + + v.Add(vec); + #endregion load vertex coordinates + } + else if (line.StartsWith("vp")) + { + // vp : parameter space vertices + #region load parameter space vertices + var pattern = @"\d+.?\d*"; + var matches = new Regex(pattern).Matches(line); + var matchCount = matches.Count; + if (matchCount < 1) continue; // Invalid vertex. + var vec = new vec3(); + vec.x = float.Parse(matches[0].Value, culture); + vec.y = matchCount > 1 ? float.Parse(matches[1].Value, culture) : float.MaxValue; + vec.z = matchCount > 2 ? float.Parse(matches[2].Value, culture) : float.MaxValue; + + vp.Add(vec); + #endregion load parameter space vertices + } + else if (line.StartsWith("f")) + { + // vt : face definitions + #region load face definitions + var pattern = @"(\d+)(//(\d+))?"; + var matches = Regex.Matches(line, pattern); + var matchCount = matches.Count; + if (matchCount < 3) continue; // Invalid face. + + List points = new List(); + foreach (Match match in matches) + { + var groups = match.Groups; + var posId = int.Parse(groups[1].ToString()); + var normId = int.Parse("0" + groups[3].ToString()); + points.Add(new PositionNormal(posId-1,normId-1)); + } + + f.Add(points); + #endregion load face definitions + } + } + } + #endregion read data + + ConvertInputDataToUsableData(v, vt, vn, vp, f); + } + + private void ConvertInputDataToUsableData(List positions, + List textureCoords, List normals, List paramSpacePositions, + List> faces) + { + var indices = new List(); + uint nextIdxValue = 0; + + var posNormMap = new Dictionary>(); // posNormMap[position][normal] = index + + var posNormMap2 = new Dictionary>(); // posNormMap[positionId][normalId] = index + + #region create the indices from the normals and positions. + //for (int i = 0; i < faces.Count; i++) + //{ + // var face = faces[i]; + + // var triangulatedFaces = TriangulateSimple(face, ref positions); + // foreach (var tFace in triangulatedFaces) + // { + // var i1 = tFace.Item1; + // var i2 = tFace.Item2; + // var i3 = tFace.Item3; + + + // foreach (var point in new PositionNormal[]{i1, i2, i3}) + // { + // var position = positions[point.Position]; + // var normal = normals[point.NormalPosition]; + + // uint idx; + + // if (posNormMap.ContainsKey(position)) + // { + // if (posNormMap[position].ContainsKey(normal)) + // { + // // Index that uses this position and normal combination already exists, so use it again. + // idx = posNormMap[position][normal]; + // } + // else + // { + // // Index for this combination doesn't exist, so create and add it. + // idx = nextIdxValue++; + // posNormMap[position].Add(normal, idx); + // } + // } + // else + // { + // var dic = new Dictionary(); + + // // Index for this combination doesn't exist, so create and add it. + // idx = nextIdxValue++; + // dic.Add(normal, idx); + + // posNormMap.Add(position, dic); + // } + // indices.Add(idx); + // } + // } + //} + #endregion create the indices from the normals and positions. + + #region v2 + for (int i = 0; i < faces.Count; i++) + { + var face = faces[i]; + + var triangulatedFaces = TriangulateSimple(face, ref positions); + foreach (var tFace in triangulatedFaces) + { + var i1 = tFace.Item1; + var i2 = tFace.Item2; + var i3 = tFace.Item3; + + + foreach (var point in new PositionNormal[] { i1, i2, i3 }) + { + var position = point.Position; + var normal = point.NormalPosition; + + uint idx; + + if (posNormMap2.ContainsKey(position)) + { + if (posNormMap2[position].ContainsKey(normal)) + { + // Index that uses this position and normal combination already exists, so use it again. + idx = posNormMap2[position][normal]; + } + else + { + // Index for this combination doesn't exist, so create and add it. + idx = nextIdxValue++; + posNormMap2[position].Add(normal, idx); + } + } + else + { + var dic = new Dictionary(); + + // Index for this combination doesn't exist, so create and add it. + idx = nextIdxValue++; + dic.Add(normal, idx); + + posNormMap2.Add(position, dic); + } + indices.Add(idx); + } + } + } + #endregion v2 + + var positionsRes = new vec4[nextIdxValue]; + var normalsRes = new vec3[nextIdxValue]; + + + //for (int posId = 0; posId < posNormMap.Keys.Count; posId++) + //{ + // var elemPos = posNormMap.ElementAt(posId); + // var position = elemPos.Key; + // var dicNorms = elemPos.Value; + // for (int normId = 0; normId < dicNorms.Count; normId++) + // { + // var elemNorm = dicNorms.ElementAt(normId); + // var normal = elemNorm.Key; + + // var idx = elemNorm.Value; + // positionsRes[idx] = position; + // normalsRes[idx] = normal; + // } + //} + + for (int posId = 0; posId < posNormMap2.Keys.Count; posId++) + { + var elemPos = posNormMap2.ElementAt(posId); + var position = elemPos.Key; + var dicNorms = elemPos.Value; + for (int normId = 0; normId < dicNorms.Count; normId++) + { + var elemNorm = dicNorms.ElementAt(normId); + var normal = elemNorm.Key; + + var idx = elemNorm.Value; + positionsRes[idx] = positions[position]; + normalsRes[idx] = normals[normal]; + } + } + + + Indices = indices.ToArray(); + Vertices = positionsRes; + Normals = normalsRes; + + + var str = AsString(Indices, Vertices); + } + + private string AsString(uint[] indices, vec4[] verts) + { + var sb = new StringBuilder(); + + foreach (var idx in indices) + { + var v = verts[idx]; + var signs = v.x < 0 ? "-" : "+"; + signs += v.y < 0 ? "-" : "+"; + signs += v.z < 0 ? "-" : "+"; + sb.Append(idx + " : " + signs + "\n"); + } + + return sb.ToString(); + } + + private List> TriangulateSimple(List points, ref List positions) + { + var res = new List>(); + if (points.Count == 3) + { + res.Add(new Tuple(points[0], points[1], points[2])); + } + else if (points.Count == 4) + { + res.Add(new Tuple(points[0], points[1], points[2])); + res.Add(new Tuple(points[0], points[2], points[3])); + } + else + { + throw new Exception("This algorithm doesn't know how to triangulate a face with " + points.Count + " points."); + } + + return res; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/PositionNormal.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/PositionNormal.cs new file mode 100644 index 00000000..fa8cde56 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/IO/PositionNormal.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpGLObjFileImport +{ + public class PositionNormal + { + public int Position { get; set; } + public int NormalPosition { get; set; } + + public PositionNormal(int pos, int normPos) + { + Position = pos; + NormalPosition = normPos; + } + } +} diff --git a/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/MainWindow.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/MainWindow.xaml new file mode 100644 index 00000000..2f940155 --- /dev/null +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLObjFileImport/MainWindow.xaml @@ -0,0 +1,18 @@ + + + + + +

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 - - - SharpGL - - - -