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 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)); + + if (id > 0) + MessageBox.Show("Clicked object has ID " + id); + } + } + + 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/SimpleShaderSample/Properties/Resources.resx b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx similarity index 97% rename from source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx rename to source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx index ffecec85..af7dbebb 100644 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Resources.resx +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Resources.resx @@ -1,117 +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 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/SimpleShaderSample/Properties/Settings.settings b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings similarity index 97% rename from source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings rename to source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings index 8f2fd95d..033d7a5e 100644 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/Settings.settings +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLHitTestSample/Properties/Settings.settings @@ -1,7 +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/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 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/SimpleShaderSample/App.xaml.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs similarity index 82% rename from source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs rename to source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs index 0ab665f0..311083e9 100644 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/App.xaml.cs +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/App.xaml.cs @@ -1,16 +1,17 @@ -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 - { - } -} +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/SimpleShaderSample/Properties/AssemblyInfo.cs b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs similarity index 71% rename from source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs rename to source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs index d4b1707c..0ca0f6e8 100644 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/Properties/AssemblyInfo.cs +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLLinesSample/Properties/AssemblyInfo.cs @@ -1,38 +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("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 +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/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/SimpleShaderSample/SimpleShaderSample.csproj b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj similarity index 66% rename from source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj rename to source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj index efbca480..aecbfb72 100644 --- a/source/SharpGL/Samples/WPF/SimpleShaderSample/SimpleShaderSample.csproj +++ b/source/SharpGL/Samples/WPF/JOG/SharpGLMaterialSample/SharpGLMaterialSample.csproj @@ -1,130 +1,131 @@ - - - - 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 - - - - + + + + + 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/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 @@ + + + + + +