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..4eedb60a
--- /dev/null
+++ b/source/SharpGL/Core/SharpGL.SceneGraph/JOG/ColorF.cs
@@ -0,0 +1,150 @@
+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³.
+ }
+
+ 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.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..79a2265b
--- /dev/null
+++ b/source/SharpGL/Core/SharpGL.WPF/OpenGLControlJOG.xaml.cs
@@ -0,0 +1,401 @@
+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
+ {
+ if (RefreshImgSource) _imgSource = value;
+
+ // Notify that the frame was updated.
+ OnPropertyChanged("ImgSource");
+ }
+ }
+
+ ///
+ /// 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.
+ /// Prevents setting ImgSource.
+ ///
+ public bool RefreshImgSource { get; set; }
+
+ ///
+ /// Prevents executing GetFrame(...).
+ ///
+ public bool BlitImage { 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;
+ RefreshImgSource = true;
+ BlitImage = true;
+ }
+ #endregion constructors
+
+ ///
+ /// Start the timer.
+ ///
+ private void StartTimer()
+ {
+ _timer.Start();
+ }
+
+ ///
+ /// Calls Viewport.GetFrame() and updates the ImgSource.
+ ///
+ public void Refresh()
+ {
+ // Update the frame.
+ if (BlitImage)
+ {
+ ImgSource = GetFrame();
+ }
+ }
+
+ public ImageSource GetFrame()
+ {
+ if (!BlitImage)
+ return ImgSource;
+
+ 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();
+ 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
new file mode 100644
index 00000000..b8c38eec
--- /dev/null
+++ b/source/SharpGL/Core/SharpGL/OpenGLExtensionsJOG.cs
@@ -0,0 +1,77 @@
+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, p, 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, p, usage);
+ Marshal.FreeHGlobal(p);
+ }
+ }
+
+}
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/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/SimpleShaderSample/App.xaml b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml
similarity index 82%
rename from source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml
rename to source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml
index b409b1ef..c9bcabe8 100644
--- a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml
+++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/App.xaml
@@ -1,8 +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..b3cb7258
--- /dev/null
+++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/MainWindow.xaml.cs
@@ -0,0 +1,125 @@
+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