diff --git a/GLWidget.sln b/GLWidget.sln
index cf6713c..35aefcf 100644
--- a/GLWidget.sln
+++ b/GLWidget.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29709.97
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GLWidget", "GLWidget\GLWidget.csproj", "{2F1DF6C0-67E9-4ADF-B2DA-F3E1504CF57B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GLWidgetTestGTK3", "GLWidgetTestGTK3\GLWidgetTestGTK3.csproj", "{227DE1F9-A40A-440A-9A06-4AA5532DBA17}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,18 @@ Global
{2F1DF6C0-67E9-4ADF-B2DA-F3E1504CF57B}.Release|x64.Build.0 = Release|Any CPU
{2F1DF6C0-67E9-4ADF-B2DA-F3E1504CF57B}.Release|x86.ActiveCfg = Release|Any CPU
{2F1DF6C0-67E9-4ADF-B2DA-F3E1504CF57B}.Release|x86.Build.0 = Release|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|x64.Build.0 = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Debug|x86.Build.0 = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|Any CPU.Build.0 = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|x64.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|x64.Build.0 = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|x86.ActiveCfg = Debug|Any CPU
+ {227DE1F9-A40A-440A-9A06-4AA5532DBA17}.Release|x86.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/GLWidget/GLWidget.cs b/GLWidget/GLWidget.cs
index 17936e6..22d5bb3 100644
--- a/GLWidget/GLWidget.cs
+++ b/GLWidget/GLWidget.cs
@@ -35,9 +35,11 @@ using System.ComponentModel;
using OpenTK.Graphics;
-using OpenTK.Platform;
+using OpenTK.Graphics.OpenGL;
+
using Gtk;
+using Cairo;
namespace OpenTK
{
@@ -50,85 +52,48 @@ namespace OpenTK
private static int _graphicsContextCount;
private static bool _sharedContextInitialized;
- public bool IsRenderHandler { get; set; } = false;
+ public bool IsRenderHandler { get; set; } = false;
#endregion
#region Attributes
- private IGraphicsContext _graphicsContext;
- private IWindowInfo _windowInfo;
private bool _initialized;
#endregion
#region Properties
- /// Use a single buffer versus a double buffer.
- [Browsable(true)]
- public bool SingleBuffer { get; set; }
-
- /// Color Buffer Bits-Per-Pixel
- public int ColorBPP { get; set; }
-
- /// Accumulation Buffer Bits-Per-Pixel
- public int AccumulatorBPP { get; set; }
-
- /// Depth Buffer Bits-Per-Pixel
- public int DepthBPP { get; set; }
-
- /// Stencil Buffer Bits-Per-Pixel
- public int StencilBPP { get; set; }
-
- /// Number of samples
- public int Samples { get; set; }
-
- /// Indicates if steropic renderering is enabled
- public bool Stereo { get; set; }
-
/// The major version of OpenGL to use.
public int GLVersionMajor { get; set; }
/// The minor version of OpenGL to use.
public int GLVersionMinor { get; set; }
- public GraphicsContextFlags GraphicsContextFlags
+ private int _framebuffer;
+ private int _renderbuffer;
+ private int _stencilbuffer;
+
+ public Gdk.GLContext GraphicsContext { get; set; }
+ public bool ForwardCompatible { get; }
+
+ #endregion
+
+ #region Construction/Destruction
+
+ /// Constructs a new GLWidget
+ public GLWidget() : this(new Version(4, 0), true)
+ {
+
+ }
+
+ /// Constructs a new GLWidget
+ public GLWidget(Version apiVersion, bool forwardCompatible)
{
- get;
- set;
- }
-
- #endregion
-
- #region Construction/Destruction
-
- /// Constructs a new GLWidget.
- public GLWidget()
- : this(GraphicsMode.Default)
- {
- }
-
- /// Constructs a new GLWidget using a given GraphicsMode
- public GLWidget(GraphicsMode graphicsMode)
- : this(graphicsMode, 1, 0, GraphicsContextFlags.Default)
- {
- }
-
- /// Constructs a new GLWidget
- public GLWidget(GraphicsMode graphicsMode, int glVersionMajor, int glVersionMinor, GraphicsContextFlags graphicsContextFlags)
- {
- SingleBuffer = graphicsMode.Buffers == 1;
- ColorBPP = graphicsMode.ColorFormat.BitsPerPixel;
- AccumulatorBPP = graphicsMode.AccumulatorFormat.BitsPerPixel;
- DepthBPP = graphicsMode.Depth;
- StencilBPP = graphicsMode.Stencil;
- Samples = graphicsMode.Samples;
- Stereo = graphicsMode.Stereo;
-
- GLVersionMajor = glVersionMajor;
- GLVersionMinor = glVersionMinor;
- GraphicsContextFlags = graphicsContextFlags;
- }
+ GLVersionMajor = apiVersion.Major;
+ GLVersionMinor = apiVersion.Minor;
+ ForwardCompatible = forwardCompatible;
+ }
~GLWidget()
{
@@ -139,22 +104,8 @@ namespace OpenTK
{
if (disposing)
{
- try
- {
- GraphicsContext.MakeCurrent(WindowInfo);
- }catch(Exception ex)
- {
-
- }
-
OnShuttingDown();
- if (OpenTK.Graphics.GraphicsContext.ShareContexts && (Interlocked.Decrement(ref _graphicsContextCount) == 0))
- {
- OnGraphicsContextShuttingDown();
- _sharedContextInitialized = false;
- }
-
GraphicsContext.Dispose();
}
}
@@ -201,11 +152,8 @@ namespace OpenTK
protected virtual void OnRenderFrame()
{
- if (RenderFrame != null)
- {
- RenderFrame(this, EventArgs.Empty);
- }
- }
+ RenderFrame?.Invoke(this, EventArgs.Empty);
+ }
// Called when this GLWidget is being Disposed
public event EventHandler ShuttingDown;
@@ -220,334 +168,113 @@ namespace OpenTK
#endregion
- // Called when a widget is realized. (window handles and such are valid)
- // protected override void OnRealized() { base.OnRealized(); }
-
// Called when the widget needs to be (fully or partially) redrawn.
protected override bool OnDrawn(Cairo.Context cr)
{
if (!_initialized)
Initialize();
- else if(!IsRenderHandler)
- GraphicsContext.MakeCurrent(WindowInfo);
+ else if (!IsRenderHandler)
+ {
+ MakeCurrent();
+ }
- return true;
+ cr.SetSourceColor(new Color(0, 0, 0, 1));
+ cr.Paint();
+
+ var scale = this.ScaleFactor;
+
+ Gdk.CairoHelper.DrawFromGl(cr, this.Window, _renderbuffer, (int)ObjectLabelIdentifier.Renderbuffer, scale, 0, 0, AllocatedWidth, AllocatedHeight);
+
+ return true;
}
- // Called on Resize
- protected override bool OnConfigureEvent(Gdk.EventConfigure evnt)
+ public void Swapbuffers()
+ {
+ GL.Flush();
+
+ QueueDraw();
+ }
+
+ public void MakeCurrent()
+ {
+ GraphicsContext?.MakeCurrent();
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebuffer);
+ }
+
+ public void ClearCurrent()
+ {
+ Gdk.GLContext.ClearCurrent();
+ }
+
+ // Called on Resize
+ protected override bool OnConfigureEvent(Gdk.EventConfigure evnt)
{
if (GraphicsContext != null)
{
- GraphicsContext.Update(WindowInfo);
- }
+ MakeCurrent();
+
+ GraphicsContext.Window.Resize(evnt.X, evnt.Y);
+
+ DeleteBuffers();
+
+ CreateFramebuffer();
+ }
return true;
}
- private void Initialize()
+ private void DeleteBuffers()
+ {
+ if (_framebuffer != 0)
+ {
+ GL.DeleteFramebuffer(_framebuffer);
+ GL.DeleteRenderbuffer(_renderbuffer);
+ }
+ }
+
+ private void CreateFramebuffer()
+ {
+ _framebuffer = GL.GenFramebuffer();
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebuffer);
+
+ _renderbuffer = GL.GenRenderbuffer();
+ GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _renderbuffer);
+ GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgba8, AllocatedWidth, AllocatedHeight);
+
+ GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, _renderbuffer);
+
+ _stencilbuffer = GL.GenRenderbuffer();
+ GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _stencilbuffer);
+ GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, AllocatedWidth, AllocatedHeight);
+
+ GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _stencilbuffer);
+
+ GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
+ var state = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
+ }
+
+ private void Initialize()
{
_initialized = true;
- // If this looks uninitialized... initialize.
- if (ColorBPP == 0)
- {
- ColorBPP = 32;
-
- if (DepthBPP == 0)
- {
- DepthBPP = 16;
- }
- }
-
- ColorFormat colorBufferColorFormat = new ColorFormat(ColorBPP);
-
- ColorFormat accumulationColorFormat = new ColorFormat(AccumulatorBPP);
-
- int buffers = 2;
- if (SingleBuffer)
- {
- buffers--;
- }
-
- GraphicsMode graphicsMode = new GraphicsMode(colorBufferColorFormat, DepthBPP, StencilBPP, Samples, accumulationColorFormat, buffers, Stereo);
-
this.Window.EnsureNative();
- // IWindowInfo
- if (OpenTK.Configuration.RunningOnWindows)
- {
- WindowInfo = InitializeWindows();
- }
- else if (OpenTK.Configuration.RunningOnMacOS)
- {
- WindowInfo = InitializeOSX();
- }
- else
- {
- WindowInfo = InitializeX(graphicsMode);
- }
+ GraphicsContext = Window.CreateGlContext();
- // GraphicsContext
- GraphicsContext = new GraphicsContext(graphicsMode, WindowInfo, GLVersionMajor, GLVersionMinor, GraphicsContextFlags);
- GraphicsContext.MakeCurrent(WindowInfo);
+ GraphicsContext.SetRequiredVersion(GLVersionMajor, GLVersionMinor);
- if (OpenTK.Graphics.GraphicsContext.ShareContexts)
- {
- Interlocked.Increment(ref _graphicsContextCount);
+ GraphicsContext.SetUseEs(0);
- if (!_sharedContextInitialized)
- {
- _sharedContextInitialized = true;
- ((IGraphicsContextInternal)GraphicsContext).LoadAll();
- OnGraphicsContextInitialized();
- }
- }
- else
- {
- ((IGraphicsContextInternal)GraphicsContext).LoadAll();
- OnGraphicsContextInitialized();
- }
+ GraphicsContext.ForwardCompatible = ForwardCompatible;
- OnInitialized();
+ GraphicsContext.Realize();
+
+ GraphicsContext.MakeCurrent();
+
+ CreateFramebuffer();
+
+ OnInitialized();
}
-
- #region Windows Specific initalization
-
- IWindowInfo InitializeWindows()
- {
- IntPtr windowHandle = gdk_win32_window_get_handle(this.Window.Handle);
- return Utilities.CreateWindowsWindowInfo(windowHandle);
- }
-
- [SuppressUnmanagedCodeSecurity, DllImport("libgdk-3-0.dll")]
- public static extern IntPtr gdk_win32_window_get_handle(IntPtr d);
-
- #endregion
-
- #region OSX Specific Initialization
-
- IWindowInfo InitializeOSX()
- {
- IntPtr windowHandle = gdk_quartz_window_get_nswindow(this.Window.Handle);
- //IntPtr viewHandle = gdk_quartz_window_get_nsview(this.GdkWindow.Handle);
- return Utilities.CreateMacOSWindowInfo(windowHandle);
- }
-
- [SuppressUnmanagedCodeSecurity, DllImport("libgdk-3.0.dylib")]
- static extern IntPtr gdk_quartz_window_get_nswindow(IntPtr handle);
-
- [SuppressUnmanagedCodeSecurity, DllImport("libgdk-3.0.dylib")]
- static extern IntPtr gdk_quartz_window_get_nsview(IntPtr handle);
-
- #endregion
-
- #region X Specific Initialization
-
- const string UnixLibGdkName = "libgdk-3.so.0";
-
- const string UnixLibX11Name = "libX11.so.6";
- const string UnixLibGLName = "libGL.so.1";
-
- const int GLX_NONE = 0;
- const int GLX_USE_GL = 1;
- const int GLX_BUFFER_SIZE = 2;
- const int GLX_LEVEL = 3;
- const int GLX_RGBA = 4;
- const int GLX_DOUBLEBUFFER = 5;
- const int GLX_STEREO = 6;
- const int GLX_AUX_BUFFERS = 7;
- const int GLX_RED_SIZE = 8;
- const int GLX_GREEN_SIZE = 9;
- const int GLX_BLUE_SIZE = 10;
- const int GLX_ALPHA_SIZE = 11;
- const int GLX_DEPTH_SIZE = 12;
- const int GLX_STENCIL_SIZE = 13;
- const int GLX_ACCUM_RED_SIZE = 14;
- const int GLX_ACCUM_GREEN_SIZE = 15;
- const int GLX_ACCUM_BLUE_SIZE = 16;
- const int GLX_ACCUM_ALPHA_SIZE = 17;
-
- public enum XVisualClass
- {
- StaticGray = 0,
- GrayScale = 1,
- StaticColor = 2,
- PseudoColor = 3,
- TrueColor = 4,
- DirectColor = 5,
- }
-
- [StructLayout(LayoutKind.Sequential)]
- struct XVisualInfo
- {
- public IntPtr Visual;
- public IntPtr VisualID;
- public int Screen;
- public int Depth;
- public XVisualClass Class;
- public long RedMask;
- public long GreenMask;
- public long blueMask;
- public int ColormapSize;
- public int BitsPerRgb;
-
- public override string ToString()
- {
- return $"id ({VisualID}), screen ({Screen}), depth ({Depth}), class ({Class})";
- }
- }
-
- [Flags]
- internal enum XVisualInfoMask
- {
- No = 0x0,
- ID = 0x1,
- Screen = 0x2,
- Depth = 0x4,
- Class = 0x8,
- Red = 0x10,
- Green = 0x20,
- Blue = 0x40,
- ColormapSize = 0x80,
- BitsPerRGB = 0x100,
- All = 0x1FF,
- }
-
- private IWindowInfo InitializeX(GraphicsMode mode)
- {
- IntPtr display = gdk_x11_display_get_xdisplay(Display.Handle);
- int screen = Screen.Number;
-
- IntPtr windowHandle = gdk_x11_window_get_xid(Window.Handle);
- IntPtr rootWindow = gdk_x11_window_get_xid(RootWindow.Handle);
-
- IntPtr visualInfo;
-
- if (mode.Index.HasValue)
- {
- XVisualInfo info = new XVisualInfo();
- info.VisualID = mode.Index.Value;
- int dummy;
- visualInfo = XGetVisualInfo(display, XVisualInfoMask.ID, ref info, out dummy);
- }
- else
- {
- visualInfo = GetVisualInfo(display);
- }
-
- IWindowInfo retval = Utilities.CreateX11WindowInfo(display, screen, windowHandle, rootWindow, visualInfo);
- XFree(visualInfo);
-
- return retval;
- }
-
- private static IntPtr XGetVisualInfo(IntPtr display, XVisualInfoMask vinfo_mask, ref XVisualInfo template, out int nitems)
- {
- return XGetVisualInfoInternal(display, (IntPtr)(int)vinfo_mask, ref template, out nitems);
- }
-
- private IntPtr GetVisualInfo(IntPtr display)
- {
- try
- {
- int[] attributes = AttributeList.ToArray();
- return glXChooseVisual(display, Screen.Number, attributes);
- }
- catch (DllNotFoundException e)
- {
- throw new DllNotFoundException("OpenGL dll not found!", e);
- }
- catch (EntryPointNotFoundException enf)
- {
- throw new EntryPointNotFoundException("Glx entry point not found!", enf);
- }
- }
-
- private List AttributeList
- {
- get
- {
- List attributeList = new List(24);
-
- attributeList.Add(GLX_RGBA);
-
- if (!SingleBuffer)
- attributeList.Add(GLX_DOUBLEBUFFER);
-
- if (Stereo)
- attributeList.Add(GLX_STEREO);
-
- attributeList.Add(GLX_RED_SIZE);
- attributeList.Add(ColorBPP / 4); // TODO support 16-bit
-
- attributeList.Add(GLX_GREEN_SIZE);
- attributeList.Add(ColorBPP / 4); // TODO support 16-bit
-
- attributeList.Add(GLX_BLUE_SIZE);
- attributeList.Add(ColorBPP / 4); // TODO support 16-bit
-
- attributeList.Add(GLX_ALPHA_SIZE);
- attributeList.Add(ColorBPP / 4); // TODO support 16-bit
-
- attributeList.Add(GLX_DEPTH_SIZE);
- attributeList.Add(DepthBPP);
-
- attributeList.Add(GLX_STENCIL_SIZE);
- attributeList.Add(StencilBPP);
-
- attributeList.Add(GLX_ACCUM_RED_SIZE);
- attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
-
- attributeList.Add(GLX_ACCUM_GREEN_SIZE);
- attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
-
- attributeList.Add(GLX_ACCUM_BLUE_SIZE);
- attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
-
- attributeList.Add(GLX_ACCUM_ALPHA_SIZE);
- attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
-
- attributeList.Add(GLX_NONE);
-
- return attributeList;
- }
- }
-
- public IGraphicsContext GraphicsContext { get => _graphicsContext; set => _graphicsContext = value; }
- public IWindowInfo WindowInfo { get => _windowInfo; set => _windowInfo = value; }
-
- [DllImport(UnixLibX11Name, EntryPoint = "XGetVisualInfo")]
- private static extern IntPtr XGetVisualInfoInternal(IntPtr display, IntPtr vinfo_mask, ref XVisualInfo template, out int nitems);
-
- [SuppressUnmanagedCodeSecurity, DllImport(UnixLibX11Name)]
- private static extern void XFree(IntPtr handle);
-
- /// Returns the X resource (window or pixmap) belonging to a GdkDrawable.
- /// XID gdk_x11_drawable_get_xid(GdkDrawable *drawable);
- /// The GdkDrawable.
- /// The ID of drawable's X resource.
- [SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
- private static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkDisplay);
-
- /// Returns the X resource (window or pixmap) belonging to a GdkDrawable.
- /// XID gdk_x11_drawable_get_xid(GdkDrawable *drawable);
- /// The GdkDrawable.
- /// The ID of drawable's X resource.
- [SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
- private static extern IntPtr gdk_x11_window_get_xid(IntPtr gdkDisplay);
-
- /// Returns the X display of a GdkDisplay.
- /// Display* gdk_x11_display_get_xdisplay(GdkDisplay *display);
- /// The GdkDrawable.
- /// The X Display of the GdkDisplay.
- [SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
- private static extern IntPtr gdk_x11_display_get_xdisplay(IntPtr gdkDisplay);
-
- [SuppressUnmanagedCodeSecurity, DllImport(UnixLibGLName)]
- private static extern IntPtr glXChooseVisual(IntPtr display, int screen, int[] attr);
-
- #endregion
}
}
\ No newline at end of file
diff --git a/GLWidget/GLWidget.csproj b/GLWidget/GLWidget.csproj
index 8b59567..c31add6 100644
--- a/GLWidget/GLWidget.csproj
+++ b/GLWidget/GLWidget.csproj
@@ -1,5 +1,4 @@
-
netstandard2.1
true
@@ -7,10 +6,9 @@
1.0.1
https://github.com/Ryujinx/GLWidget
-
-
+
+
-
-
+
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Data/RGB.cs b/GLWidgetTestGTK3/Data/RGB.cs
new file mode 100644
index 0000000..c66d90a
--- /dev/null
+++ b/GLWidgetTestGTK3/Data/RGB.cs
@@ -0,0 +1,49 @@
+//
+// Vertex.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+namespace GLWidgetTestGTK3.Data
+{
+ public class RGB
+ {
+ public float R
+ {
+ get; set;
+ }
+
+ public float G
+ {
+ get; set;
+ }
+
+ public float B
+ {
+ get; set;
+ }
+
+ public RGB(float R, float G, float B)
+ {
+ this.R = R;
+ this.G = G;
+ this.B = B;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Data/Transform.cs b/GLWidgetTestGTK3/Data/Transform.cs
new file mode 100644
index 0000000..77e9f6e
--- /dev/null
+++ b/GLWidgetTestGTK3/Data/Transform.cs
@@ -0,0 +1,61 @@
+//
+// Transform.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//using System.Net;
+
+
+using System;
+using OpenTK.Mathematics;
+
+namespace GLWidgetTestGTK3.Data
+{
+ public class Transform
+ {
+ public Vector3 Translation
+ {
+ get;
+ set;
+ }
+
+ public Quaternion Rotation
+ {
+ get;
+ set;
+ }
+
+ public Vector3 Scale
+ {
+ get;
+ set;
+ }
+
+ public Transform(Vector3 Translation)
+ : this(Translation, Quaternion.FromAxisAngle(Vector3.UnitX, 0.0f), Vector3.One)
+ {
+ }
+
+ public Transform(Vector3 Translation, Quaternion Rotation, Vector3 Scale)
+ {
+ this.Translation = Translation;
+ this.Rotation = Rotation;
+ this.Scale = Scale;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Data/UVCoordinate.cs b/GLWidgetTestGTK3/Data/UVCoordinate.cs
new file mode 100644
index 0000000..6690028
--- /dev/null
+++ b/GLWidgetTestGTK3/Data/UVCoordinate.cs
@@ -0,0 +1,47 @@
+//
+// UVCoordinate.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+
+namespace GLWidgetTestGTK3.Data
+{
+ public sealed class UVCoordinate
+ {
+ public float U
+ {
+ get;
+ set;
+ }
+
+ public float V
+ {
+ get;
+ set;
+ }
+
+ public UVCoordinate(float U, float V)
+ {
+ this.U = U;
+ this.V = V;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Data/Vertex.cs b/GLWidgetTestGTK3/Data/Vertex.cs
new file mode 100644
index 0000000..efcdb60
--- /dev/null
+++ b/GLWidgetTestGTK3/Data/Vertex.cs
@@ -0,0 +1,92 @@
+//
+// Vertex.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using OpenTK.Mathematics;
+
+namespace GLWidgetTestGTK3.Data
+{
+ public sealed class Vertex
+ {
+ public Vector3 Position
+ {
+ get;
+ private set;
+ }
+
+ public Vector3 Normal
+ {
+ get;
+ private set;
+ }
+
+ public UVCoordinate UVCoordinate
+ {
+ get;
+ private set;
+ }
+
+ public RGB VertexColour
+ {
+ get;
+ private set;
+ }
+
+ public Vertex(Vector3 Position)
+ :this(Position, Vector3.Zero, new UVCoordinate(0.0f, 0.0f), new RGB(1.0f, 1.0f, 1.0f))
+ {
+ }
+
+ public Vertex(Vector3 Position, Vector3 Normal)
+ :this(Position, Normal, new UVCoordinate(0.0f, 0.0f), new RGB(1.0f, 1.0f, 1.0f))
+ {
+ }
+
+
+ public Vertex(Vector3 Position, RGB VertexColour)
+ :this(Position, Vector3.Zero, new UVCoordinate(0.0f, 0.0f), VertexColour)
+ {
+ }
+
+ public Vertex(Vector3 Position, Vector3 Normal, RGB VertexColour)
+ :this(Position, Normal, new UVCoordinate(0.0f, 0.0f), VertexColour)
+ {
+ }
+
+ public Vertex(Vector3 Position, UVCoordinate UVCoordinate)
+ :this(Position, Vector3.Zero, UVCoordinate, new RGB(1.0f, 1.0f, 1.0f))
+ {
+ }
+
+ public Vertex(Vector3 Position, Vector3 Normal, UVCoordinate UVCoordinate)
+ :this(Position, Normal, UVCoordinate, new RGB(1.0f, 1.0f, 1.0f))
+ {
+ }
+
+ public Vertex(Vector3 Position, Vector3 Normal, UVCoordinate UVCoordinate, RGB VertexColour)
+ {
+ this.Position = Position;
+ this.Normal = Normal;
+ this.UVCoordinate = UVCoordinate;
+ this.VertexColour = VertexColour;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Extensions/ExtensionMethods.cs b/GLWidgetTestGTK3/Extensions/ExtensionMethods.cs
new file mode 100644
index 0000000..2d49382
--- /dev/null
+++ b/GLWidgetTestGTK3/Extensions/ExtensionMethods.cs
@@ -0,0 +1,41 @@
+//
+// ExtensionMethods.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using OpenTK.Mathematics;
+
+namespace GLWidgetTestGTK3.Extensions
+{
+ public static class ExtensionMethods
+ {
+ public static Quaternion QuaternionFromEuler(float Yaw, float Pitch, float Roll)
+ {
+ Quaternion XRotation = Quaternion.FromAxisAngle(Vector3.UnitX, Yaw);
+ Quaternion YRotation = Quaternion.FromAxisAngle(Vector3.UnitY, Pitch);
+ Quaternion ZRotation = Quaternion.FromAxisAngle(Vector3.UnitZ, Roll);
+
+ Quaternion final = Quaternion.Multiply(ZRotation, YRotation);
+ final = Quaternion.Multiply(XRotation, final);
+
+ return final;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/GLWidgetTestGTK3.csproj b/GLWidgetTestGTK3/GLWidgetTestGTK3.csproj
new file mode 100644
index 0000000..60dcc92
--- /dev/null
+++ b/GLWidgetTestGTK3/GLWidgetTestGTK3.csproj
@@ -0,0 +1,39 @@
+
+
+ netcoreapp3.1
+ 8.0
+ win-x64;osx-x64;linux-x64
+ Exe
+ true
+ Debug;Release
+ GLWidgetTestGTK3
+ GLWidgetTestGTK3.MainClass
+ GLWidgetTestGTK3
+ 1.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/GTKBindingContext.cs b/GLWidgetTestGTK3/GTKBindingContext.cs
new file mode 100644
index 0000000..5775da8
--- /dev/null
+++ b/GLWidgetTestGTK3/GTKBindingContext.cs
@@ -0,0 +1,140 @@
+using System;
+using OpenTK;
+using OpenGL;
+using System.Runtime.InteropServices;
+using Khronos;
+using System.Collections.Generic;
+
+namespace GLWidgetTestGTK3
+{
+ public class GTKBindingContext : IBindingsContext
+ {
+ private static bool _loaded;
+
+ private const string GlxLibrary = "libGL.so.1";
+ private const string WglLibrary = "opengl32.dll";
+ private const string OSXLibrary = "libdl.dylib";
+
+
+ ///
+ /// Currently loaded libraries.
+ ///
+ private static readonly Dictionary _LibraryHandles = new Dictionary();
+
+ public IntPtr GetProcAddress(string procName)
+ {
+ switch (Platform.CurrentPlatformId)
+ {
+ case Platform.Id.WindowsNT:
+ return GetProcAddressWgl(procName);
+ case Platform.Id.Linux:
+ return GetProcAddressGlx(procName);
+ case Platform.Id.MacOS:
+ return !Glx.IsRequired ? GetProcAddressOSX(procName) : GetProcAddressGlx(procName);
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ private static IntPtr GetProcAddressWgl(string function)
+ {
+ return UnsafeNativeMethods.wglGetProcAddress(function);
+ }
+
+ private static void LoadLibraries()
+ {
+ if (_loaded)
+ {
+ return;
+ }
+
+ string function = "glXGetProcAddress";
+
+ IntPtr handle = GetLibraryHandle(GlxLibrary, true);
+
+ if (handle == IntPtr.Zero)
+ throw new ArgumentNullException(nameof(handle));
+
+ IntPtr functionPtr = UnsafeNativeMethods.dlsym(handle, function);
+
+ if (functionPtr != IntPtr.Zero)
+ Delegates.pglXGetProcAddress = (Delegates.glXGetProcAddress)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(Delegates.glXGetProcAddress));
+
+ _loaded = true;
+ }
+
+ internal static IntPtr GetLibraryHandle(string libraryPath, bool throws)
+ {
+ IntPtr libraryHandle;
+
+ if (_LibraryHandles.TryGetValue(libraryPath, out libraryHandle) == false)
+ {
+ if ((libraryHandle = UnsafeNativeMethods.dlopen(libraryPath, UnsafeNativeMethods.RTLD_LAZY)) == IntPtr.Zero)
+ {
+ if (throws)
+ throw new InvalidOperationException($"unable to load library at {libraryPath}", new InvalidOperationException(UnsafeNativeMethods.dlerror()));
+ }
+
+ _LibraryHandles.Add(libraryPath, libraryHandle);
+ }
+
+ return libraryHandle;
+ }
+
+ private static IntPtr GetProcAddressGlx(string function)
+ {
+ LoadLibraries();
+
+ return Delegates.pglXGetProcAddress != null ? Delegates.pglXGetProcAddress(function) : IntPtr.Zero;
+ }
+
+ private static IntPtr GetProcAddressOSX(string function)
+ {
+ string fname = "_" + function;
+ if (!UnsafeNativeMethods.NSIsSymbolNameDefined(fname))
+ return IntPtr.Zero;
+
+ IntPtr symbol = UnsafeNativeMethods.NSLookupAndBindSymbol(fname);
+
+ if (symbol != IntPtr.Zero)
+ symbol = UnsafeNativeMethods.NSAddressOfSymbol(symbol);
+
+ return symbol;
+ }
+
+ private static class UnsafeNativeMethods
+ {
+ [DllImport(WglLibrary, EntryPoint = "wglGetProcAddress", ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr wglGetProcAddress(string lpszProc);
+
+ [DllImport(OSXLibrary, EntryPoint = "NSIsSymbolNameDefined")]
+ public static extern bool NSIsSymbolNameDefined(string s);
+
+ [DllImport(OSXLibrary, EntryPoint = "NSLookupAndBindSymbol")]
+ public static extern IntPtr NSLookupAndBindSymbol(string s);
+
+ [DllImport(OSXLibrary, EntryPoint = "NSAddressOfSymbol")]
+ public static extern IntPtr NSAddressOfSymbol(IntPtr symbol);
+
+ public const int RTLD_LAZY = 1;
+
+ public const int RTLD_NOW = 2;
+
+ [DllImport("dl")]
+ public static extern IntPtr dlopen(string filename, int flags);
+
+ [DllImport("dl")]
+ public static extern IntPtr dlsym(IntPtr handle, string symbol);
+
+ [DllImport("dl")]
+ public static extern string dlerror();
+ }
+
+ private static class Delegates
+ {
+ public delegate IntPtr glXGetProcAddress(string procName);
+
+ public static glXGetProcAddress pglXGetProcAddress;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Geometry/Shapes.cs b/GLWidgetTestGTK3/Geometry/Shapes.cs
new file mode 100644
index 0000000..d544806
--- /dev/null
+++ b/GLWidgetTestGTK3/Geometry/Shapes.cs
@@ -0,0 +1,76 @@
+//
+// Mesh.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+
+namespace GLWidgetTestGTK3.Debug
+{
+ public static class Shapes
+ {
+ public static readonly float[] UnindexedTriangle =
+ {
+ -1.0f, -1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f
+ };
+
+ public static readonly float[] UnindexedCube =
+ {
+ -1.0f,-1.0f,-1.0f,
+ -1.0f,-1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f,-1.0f,
+ -1.0f,-1.0f,-1.0f,
+ -1.0f, 1.0f,-1.0f,
+ 1.0f,-1.0f, 1.0f,
+ -1.0f,-1.0f,-1.0f,
+ 1.0f,-1.0f,-1.0f,
+ 1.0f, 1.0f,-1.0f,
+ 1.0f,-1.0f,-1.0f,
+ -1.0f,-1.0f,-1.0f,
+ -1.0f,-1.0f,-1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, 1.0f,-1.0f,
+ 1.0f,-1.0f, 1.0f,
+ -1.0f,-1.0f, 1.0f,
+ -1.0f,-1.0f,-1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f,-1.0f, 1.0f,
+ 1.0f,-1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f,-1.0f,-1.0f,
+ 1.0f, 1.0f,-1.0f,
+ 1.0f,-1.0f,-1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f,-1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f,-1.0f,
+ -1.0f, 1.0f,-1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, 1.0f,-1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f,-1.0f, 1.0f
+ };
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/MainWindow.cs b/GLWidgetTestGTK3/MainWindow.cs
new file mode 100644
index 0000000..176ccba
--- /dev/null
+++ b/GLWidgetTestGTK3/MainWindow.cs
@@ -0,0 +1,578 @@
+//
+// MainWindow.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using Gdk;
+using GLWidgetTestGTK3.Data;
+using GLWidgetTestGTK3.Debug;
+using GLWidgetTestGTK3.World;
+using Gtk;
+using UI = Gtk.Builder.ObjectAttribute;
+using OpenTK;
+using OpenTK.Mathematics;
+using OpenTK.Graphics.OpenGL;
+using KeyPressEventArgs = Gtk.KeyPressEventArgs;
+
+namespace GLWidgetTestGTK3
+{
+ public partial class MainWindow : Gtk.Window
+ {
+ [UI] readonly Box MainBox;
+ [UI] readonly MenuBar MainMenuBar;
+
+ [UI] readonly Alignment GLWidgetAlignment;
+ [UI] readonly GLWidget MainGLWidget;
+
+ private bool GLInit;
+
+ private Scene Scene;
+
+ private uint VertexArrayID;
+ private uint ColourBufferID;
+
+ private int ShaderProgramID;
+
+ /* Default camera positions */
+ private Vector3 cameraPosition;
+ private Vector3 cameraLookDirection;
+ private Vector3 cameraRightVector;
+
+ private Vector3 cameraUpVector;
+ private float horizontalViewAngle;
+ private float verticalViewAngle;
+ private const float defaultFOV = 45.0f;
+
+ private const float defaultMovementSpeed = 10.0f;
+ private const float defaultCameraSpeed = 0.5f;
+
+ // Other variables
+ private bool wantsToMove = false;
+ private float deltaTime;
+
+ private int mouseXLastFrame;
+ private int mouseYLastFrame;
+
+ private float rightAxis;
+ private float forwardAxis;
+
+ private static readonly float[] cubeColourBufferData =
+ {
+ 0.583f, 0.771f, 0.014f,
+ 0.609f, 0.115f, 0.436f,
+ 0.327f, 0.483f, 0.844f,
+ 0.822f, 0.569f, 0.201f,
+ 0.435f, 0.602f, 0.223f,
+ 0.310f, 0.747f, 0.185f,
+ 0.597f, 0.770f, 0.761f,
+ 0.559f, 0.436f, 0.730f,
+ 0.359f, 0.583f, 0.152f,
+ 0.483f, 0.596f, 0.789f,
+ 0.559f, 0.861f, 0.639f,
+ 0.195f, 0.548f, 0.859f,
+ 0.014f, 0.184f, 0.576f,
+ 0.771f, 0.328f, 0.970f,
+ 0.406f, 0.615f, 0.116f,
+ 0.676f, 0.977f, 0.133f,
+ 0.971f, 0.572f, 0.833f,
+ 0.140f, 0.616f, 0.489f,
+ 0.997f, 0.513f, 0.064f,
+ 0.945f, 0.719f, 0.592f,
+ 0.543f, 0.021f, 0.978f,
+ 0.279f, 0.317f, 0.505f,
+ 0.167f, 0.620f, 0.077f,
+ 0.347f, 0.857f, 0.137f,
+ 0.055f, 0.953f, 0.042f,
+ 0.714f, 0.505f, 0.345f,
+ 0.783f, 0.290f, 0.734f,
+ 0.722f, 0.645f, 0.174f,
+ 0.302f, 0.455f, 0.848f,
+ 0.225f, 0.587f, 0.040f,
+ 0.517f, 0.713f, 0.338f,
+ 0.053f, 0.959f, 0.120f,
+ 0.393f, 0.621f, 0.362f,
+ 0.673f, 0.211f, 0.457f,
+ 0.820f, 0.883f, 0.371f,
+ 0.982f, 0.099f, 0.879f
+ };
+
+ public static MainWindow Create()
+ {
+ Builder builder = new Builder(null, "GLWidgetTestGTK3.interfaces.MainWindow.glade", null);
+ return new MainWindow(builder, builder.GetObject("MainWindow").Handle);
+ }
+
+ protected MainWindow(Builder builder, IntPtr handle)
+ : base(handle)
+ {
+ builder.Autoconnect(this);
+ DeleteEvent += OnDeleteEvent;
+
+ this.GLInit = false;
+ ResetCamera();
+
+ this.MainGLWidget = new GLWidget()
+ {
+ GLVersionMajor = 3,
+ GLVersionMinor = 3,
+ };
+
+ this.MainGLWidget.Events |=
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask |
+ EventMask.KeyPressMask |
+ EventMask.KeyReleaseMask;
+
+ this.MainGLWidget.Initialized += OnViewportInitialized;
+ this.MainGLWidget.ButtonPressEvent += OnViewportButtonPressed;
+ this.MainGLWidget.ButtonReleaseEvent += OnViewportButtonReleased;
+ this.MainGLWidget.KeyPressEvent += OnViewportKeyPressed;
+ this.MainGLWidget.KeyReleaseEvent += OnViewportKeyReleased;
+
+ // Add the GL widget to the UI
+ this.GLWidgetAlignment.Add(this.MainGLWidget);
+ this.GLWidgetAlignment.ShowAll();
+
+ }
+
+ private List FloatArrayToVertexList(float[] vertexPositions)
+ {
+ if ((vertexPositions.Length % 3) != 0)
+ {
+ throw new ArgumentException("The input array must be of a 3-multiple length. Incomplete entries are not allowed.", nameof(vertexPositions));
+ }
+
+ List convertedVertices = new List();
+
+ for (int i = 0; i < vertexPositions.Length; i += 3)
+ {
+ Vector3 Position = new Vector3(vertexPositions[i], vertexPositions[i + 1], vertexPositions[i + 2]);
+ Vertex vertex = new Vertex(Position);
+
+ convertedVertices.Add(vertex);
+ }
+
+ return convertedVertices;
+ }
+
+ private void OnViewportKeyReleased(object o, KeyReleaseEventArgs args)
+ {
+ if (args.Event.Type == EventType.KeyRelease)
+ {
+ if( args.Event.Key == Gdk.Key.w || args.Event.Key == Gdk.Key.W)
+ {
+ forwardAxis = 0.0f;
+ }
+ else if( args.Event.Key == Gdk.Key.s || args.Event.Key == Gdk.Key.S)
+ {
+ forwardAxis = 0.0f;
+ }
+
+ if( args.Event.Key == Gdk.Key.d || args.Event.Key == Gdk.Key.D)
+ {
+ rightAxis = 0.0f;
+ }
+ else if( args.Event.Key == Gdk.Key.a || args.Event.Key == Gdk.Key.A)
+ {
+ rightAxis = 0.0f;
+ }
+ }
+ }
+
+ private void OnViewportKeyPressed(object o, KeyPressEventArgs args)
+ {
+ if (args.Event.Type == EventType.KeyPress)
+ {
+ if( args.Event.Key == Gdk.Key.w || args.Event.Key == Gdk.Key.W)
+ {
+ forwardAxis = 1.0f;
+ }
+ else if( args.Event.Key == Gdk.Key.s || args.Event.Key == Gdk.Key.S)
+ {
+ forwardAxis = -1.0f;
+ }
+
+ if( args.Event.Key == Gdk.Key.d || args.Event.Key == Gdk.Key.D)
+ {
+ rightAxis = 1.0f;
+ }
+ else if( args.Event.Key == Gdk.Key.a || args.Event.Key == Gdk.Key.A)
+ {
+ rightAxis = -1.0f;
+ }
+
+ if( args.Event.Key == Gdk.Key.r || args.Event.Key == Gdk.Key.R)
+ {
+ if (wantsToMove)
+ {
+ ResetCamera();
+ }
+ }
+
+ if (args.Event.Key == Gdk.Key.Escape)
+ {
+ Application.Quit();
+ }
+ }
+ }
+
+ private void ResetCamera()
+ {
+ this.cameraPosition = new Vector3(0.0f, 0.0f, 5.0f);
+ this.horizontalViewAngle = MathHelper.DegreesToRadians(180.0f);
+ this.verticalViewAngle = MathHelper.DegreesToRadians(0.0f);
+
+ this.cameraLookDirection = new Vector3(
+ (float)(Math.Cos(this.verticalViewAngle) * Math.Sin(this.horizontalViewAngle)),
+ (float)Math.Sin(this.verticalViewAngle),
+ (float)(Math.Cos(this.verticalViewAngle) * Math.Cos(this.horizontalViewAngle)));
+
+ this.cameraRightVector = new Vector3(
+ (float)Math.Sin(horizontalViewAngle - MathHelper.PiOver2),
+ 0,
+ (float)Math.Cos(horizontalViewAngle - MathHelper.PiOver2));
+
+ this.cameraUpVector = Vector3.Cross(cameraRightVector, cameraLookDirection);
+ }
+
+ [GLib.ConnectBefore]
+ private void OnViewportButtonReleased(object o, ButtonReleaseEventArgs args)
+ {
+ // Right click is released
+ if (args.Event.Type == EventType.ButtonRelease && args.Event.Button == 3)
+ {
+ // Return the mouse pointer
+ this.Window.Cursor = new Cursor(CursorType.Arrow);
+
+ this.GrabFocus();
+ this.wantsToMove = false;
+ }
+ }
+
+ [GLib.ConnectBefore]
+ private void OnViewportButtonPressed(object o, ButtonPressEventArgs args)
+ {
+ // Right click is pressed
+ if (args.Event.Type == EventType.ButtonPress && args.Event.Button == 3)
+ {
+ // Hide the mouse pointer
+ this.Window.Cursor = new Cursor(CursorType.BlankCursor);
+
+ this.MainGLWidget.GrabFocus();
+ this.wantsToMove = true;
+ this.MainGLWidget.GetPointer(out this.mouseXLastFrame, out this.mouseYLastFrame);
+ }
+ }
+
+ protected virtual void OnViewportInitialized(object sender, EventArgs e)
+ {
+ var version = GL.GetString(StringName.Version);
+
+ this.Scene = new Scene();
+
+ // Create the cube actor
+ Actor cubeActor = new Actor(new Mesh(FloatArrayToVertexList(Shapes.UnindexedCube)));
+ Actor cubeActor1 = new Actor(new Mesh(FloatArrayToVertexList(Shapes.UnindexedCube)));
+ Actor cubeActor2 = new Actor(new Mesh(FloatArrayToVertexList(Shapes.UnindexedCube)));
+ Actor cubeActor3 = new Actor(new Mesh(FloatArrayToVertexList(Shapes.UnindexedCube)));
+
+ // Translate the cube actor
+ cubeActor.Transform.Translation = new Vector3(4.0f, 0.0f, 0.0f);
+ cubeActor1.Transform.Translation = new Vector3(0.0f, 4.0f, 0.0f);
+ cubeActor2.Transform.Translation = new Vector3(0.0f, -4.0f, 0.0f);
+ cubeActor3.Transform.Translation = new Vector3(-4.0f, 0.0f, 0.0f);
+
+ Actor triangleActor = new Actor(new Mesh(FloatArrayToVertexList(Shapes.UnindexedTriangle)));
+
+ this.Scene.Actors.Add(cubeActor);
+ this.Scene.Actors.Add(cubeActor1);
+ this.Scene.Actors.Add(cubeActor2);
+ this.Scene.Actors.Add(cubeActor3);
+ this.Scene.Actors.Add(triangleActor);
+
+ // Generate the colour buffer
+ GL.GenBuffers(1, out ColourBufferID);
+
+ // Upload the colour data
+ GL.BindBuffer(BufferTarget.ArrayBuffer, ColourBufferID);
+ GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(cubeColourBufferData.Length * sizeof(float)), cubeColourBufferData, BufferUsageHint.StaticDraw);
+
+ // Make sure we use the depth buffer when drawing
+ GL.Enable(EnableCap.DepthTest);
+ //GL.DepthFunc(DepthFunction.Less);
+
+ // Enable backface culling for performance reasons
+ //GL.Enable(EnableCap.CullFace);
+
+ // Render wireframe
+ //GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
+
+ // Initialize the viewport
+ int widgetWidth = this.GLWidgetAlignment.AllocatedWidth;
+ int widgetHeight = this.GLWidgetAlignment.AllocatedHeight;
+
+ GL.Viewport(0, 0, widgetWidth, widgetHeight);
+ GL.ClearColor(0.522f, 0.573f, 0.678f, 1.0f);
+ GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+
+ // Load the shaders
+ ShaderProgramID = LoadShaders();
+
+ // Add idle event handler to process rendering whenever and as long as time is available.
+ GLInit = true;
+ GLib.Idle.Add(OnIdleProcessMain);
+ }
+
+ protected void RenderFrame()
+ {
+ MainGLWidget.MakeCurrent();
+
+ // Make sure the viewport is accurate for the current widget size on screen
+ int widgetWidth = this.GLWidgetAlignment.AllocatedWidth;
+ int widgetHeight = this.GLWidgetAlignment.AllocatedHeight;
+ var error = GL.GetError();
+ GL.Viewport(0, 0, widgetWidth, widgetHeight);
+ GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+
+ // Activate the shaders
+ GL.UseProgram(ShaderProgramID);
+
+ // See if there's any movement to compute
+ if (wantsToMove)
+ {
+ int mouseX;
+ int mouseY;
+ this.MainGLWidget.GetPointer(out mouseX, out mouseY);
+
+ this.horizontalViewAngle += defaultCameraSpeed * this.deltaTime * (float)(mouseXLastFrame - mouseX);
+ this.verticalViewAngle += defaultCameraSpeed * this.deltaTime * (float)(mouseYLastFrame - mouseY);
+
+ if (verticalViewAngle > MathHelper.DegreesToRadians(90.0f))
+ {
+ verticalViewAngle = MathHelper.DegreesToRadians(90.0f);
+ }
+ else if (verticalViewAngle < MathHelper.DegreesToRadians(-90.0f))
+ {
+ verticalViewAngle = MathHelper.DegreesToRadians(-90.0f);
+ }
+
+ mouseXLastFrame = mouseX;
+ mouseYLastFrame = mouseY;
+
+ // Compute the look direction
+ this.cameraLookDirection = new Vector3(
+ (float)(Math.Cos(this.verticalViewAngle) * Math.Sin(this.horizontalViewAngle)),
+ (float)Math.Sin(this.verticalViewAngle),
+ (float)(Math.Cos(this.verticalViewAngle) * Math.Cos(this.horizontalViewAngle)));
+
+ this.cameraRightVector = new Vector3(
+ (float)Math.Sin(this.horizontalViewAngle - MathHelper.PiOver2),
+ 0,
+ (float)Math.Cos(this.horizontalViewAngle - MathHelper.PiOver2));
+
+ this.cameraUpVector = Vector3.Cross(this.cameraRightVector, this.cameraLookDirection);
+
+ // Perform any movement
+ if (forwardAxis > 0)
+ {
+ this.cameraPosition += this.cameraLookDirection * deltaTime * defaultMovementSpeed;
+ }
+
+ if (forwardAxis < 0)
+ {
+ this.cameraPosition -= this.cameraLookDirection * deltaTime * defaultMovementSpeed;
+ }
+
+ if (rightAxis > 0)
+ {
+ this.cameraPosition += this.cameraRightVector * deltaTime * defaultMovementSpeed;
+ }
+
+ if (rightAxis < 0)
+ {
+ this.cameraPosition -= this.cameraRightVector * deltaTime * defaultMovementSpeed;
+ }
+ }
+
+ // Calculate the relative viewpoint
+ float aspectRatio = (float)widgetWidth / (float)widgetHeight;
+ Matrix4 Projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(defaultFOV), aspectRatio, 0.1f, 1000.0f);
+ Matrix4 View = Matrix4.LookAt(
+ cameraPosition,
+ cameraPosition + cameraLookDirection,
+ cameraUpVector
+ );
+
+ // Enable the colour array
+ GL.EnableVertexAttribArray(1);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, ColourBufferID);
+ GL.VertexAttribPointer(
+ 1,
+ 3,
+ VertexAttribPointerType.Float,
+ false,
+ 0,
+ 0);
+
+ // Tick the actors before any rendering is done
+ this.Scene.Tick(deltaTime);
+
+ foreach (Actor actor in this.Scene.Actors)
+ {
+ actor.Render(ShaderProgramID, View, Projection);
+ }
+
+ // Release the arrays
+ GL.DisableVertexAttribArray(1);
+
+ //swap
+ MainGLWidget.Swapbuffers();
+ }
+
+ protected bool OnIdleProcessMain()
+ {
+ if (!GLInit)
+ return false;
+ else
+ {
+ // Start deltaTime calculation
+ Stopwatch deltaTimeWatcher = new Stopwatch();
+ deltaTimeWatcher.Start();
+
+ System.Threading.Tasks.Task.Run(RenderFrame).Wait();
+
+ //RenderFrame();
+
+ MainGLWidget.ClearCurrent();
+
+ // End delta time calculation
+ deltaTimeWatcher.Stop();
+ this.deltaTime = (float)(deltaTimeWatcher.ElapsedMilliseconds * 0.001f);
+ return true;
+ }
+ }
+
+ private int LoadShaders()
+ {
+ int VertexShaderID = GL.CreateShader(ShaderType.VertexShader);
+ int FragmentShaderID = GL.CreateShader(ShaderType.FragmentShader);
+
+ string vertexShaderSourceCode;
+ using (Stream shaderStream =
+ Assembly.GetExecutingAssembly().GetManifestResourceStream("GLWidgetTestGTK3.Shaders.VertexShader.glsl"))
+ {
+ using (StreamReader sr = new StreamReader(shaderStream))
+ {
+ vertexShaderSourceCode = sr.ReadToEnd();
+ }
+ }
+
+ string fragmentShaderSourceCode;
+ using (Stream shaderStream =
+ Assembly.GetExecutingAssembly().GetManifestResourceStream("GLWidgetTestGTK3.Shaders.FragmentShader.glsl"))
+ {
+ using (StreamReader sr = new StreamReader(shaderStream))
+ {
+ fragmentShaderSourceCode = sr.ReadToEnd();
+ }
+ }
+
+
+ int result = 0;
+ int compilationLogLength;
+
+ Console.WriteLine("Compiling vertex shader...");
+ GL.ShaderSource(VertexShaderID, vertexShaderSourceCode);
+ GL.CompileShader(VertexShaderID);
+
+ GL.GetShader(VertexShaderID, ShaderParameter.CompileStatus, out result);
+ GL.GetShader(VertexShaderID, ShaderParameter.InfoLogLength, out compilationLogLength);
+
+ if (compilationLogLength > 0)
+ {
+ string compilationLog;
+ GL.GetShaderInfoLog(VertexShaderID, out compilationLog);
+
+ Console.WriteLine(compilationLog);
+ }
+
+ Console.WriteLine("Compiling fragment shader...");
+ GL.ShaderSource(FragmentShaderID, fragmentShaderSourceCode);
+ GL.CompileShader(FragmentShaderID);
+
+ GL.GetShader(FragmentShaderID, ShaderParameter.CompileStatus, out result);
+ GL.GetShader(FragmentShaderID, ShaderParameter.InfoLogLength, out compilationLogLength);
+
+ if (compilationLogLength > 0)
+ {
+ string compilationLog;
+ GL.GetShaderInfoLog(FragmentShaderID, out compilationLog);
+
+ Console.WriteLine(compilationLog);
+ }
+
+
+ Console.WriteLine("Linking shader program...");
+ int shaderProgramID = GL.CreateProgram();
+
+ GL.AttachShader(shaderProgramID, VertexShaderID);
+ GL.AttachShader(shaderProgramID, FragmentShaderID);
+ GL.LinkProgram(shaderProgramID);
+
+ GL.GetProgram(shaderProgramID, ProgramParameter.LinkStatus, out result);
+ GL.GetProgram(shaderProgramID, ProgramParameter.InfoLogLength, out compilationLogLength);
+
+ if (compilationLogLength > 0)
+ {
+ string compilationLog;
+ GL.GetProgramInfoLog(shaderProgramID, out compilationLog);
+
+ Console.WriteLine(compilationLog);
+ }
+
+ // Clean up the shader source code and unlinked object files from graphics memory
+ GL.DetachShader(shaderProgramID, VertexShaderID);
+ GL.DetachShader(shaderProgramID, FragmentShaderID);
+
+ GL.DeleteShader(VertexShaderID);
+ GL.DeleteShader(FragmentShaderID);
+
+ return shaderProgramID;
+ }
+
+ ///
+ /// Handles application shutdown procedures - terminating render threads, cleaning
+ /// up the UI, etc.
+ ///
+ /// Sender.
+ /// The deletion arguments.
+ protected void OnDeleteEvent(object sender, DeleteEventArgs a)
+ {
+ Application.Quit();
+ a.RetVal = true;
+ }
+ }
+}
+
diff --git a/GLWidgetTestGTK3/Program.cs b/GLWidgetTestGTK3/Program.cs
new file mode 100644
index 0000000..dc9e588
--- /dev/null
+++ b/GLWidgetTestGTK3/Program.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Reflection;
+using Gtk;
+using OpenTK;
+
+namespace GLWidgetTestGTK3
+{
+ class MainClass
+ {
+ public static void Main(string[] args)
+ {
+ InitializeGlBindings();
+
+ // GTK
+ Application.Init();
+ MainWindow win = MainWindow.Create();
+ win.Show();
+ Application.Run();
+ }
+
+ private static void InitializeGlBindings()
+ {
+ // We don't put a hard dependency on OpenTK.Graphics here.
+ // So we need to use reflection to initialize the GL bindings, so users don't have to.
+
+ // Try to load OpenTK.Graphics assembly.
+ Assembly assembly;
+ try
+ {
+ assembly = Assembly.Load("OpenTK.Graphics");
+ }
+ catch
+ {
+ // Failed to load graphics, oh well.
+ // Up to the user I guess?
+ // TODO: Should we expose this load failure to the user better?
+ return;
+ }
+
+ var provider = new GTKBindingContext();
+
+ void LoadBindings(string typeNamespace)
+ {
+ var type = assembly.GetType($"OpenTK.Graphics.{typeNamespace}.GL");
+ if (type == null)
+ {
+ return;
+ }
+
+ var load = type.GetMethod("LoadBindings");
+ load.Invoke(null, new object[] { provider });
+ }
+
+ LoadBindings("ES11");
+ LoadBindings("ES20");
+ LoadBindings("ES30");
+ LoadBindings("OpenGL");
+ LoadBindings("OpenGL4");
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Shaders/FragmentShader.glsl b/GLWidgetTestGTK3/Shaders/FragmentShader.glsl
new file mode 100644
index 0000000..8569e51
--- /dev/null
+++ b/GLWidgetTestGTK3/Shaders/FragmentShader.glsl
@@ -0,0 +1,12 @@
+#version 330 core
+
+in vec3 fragmentColour;
+
+out vec3 color;
+
+void main()
+{
+ //color = vec3(0.18, 0.204, 0.212);
+ color = fragmentColour;
+ //color = vec3(gl_FragCoord.z);
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/Shaders/VertexShader.glsl b/GLWidgetTestGTK3/Shaders/VertexShader.glsl
new file mode 100644
index 0000000..8ed2a72
--- /dev/null
+++ b/GLWidgetTestGTK3/Shaders/VertexShader.glsl
@@ -0,0 +1,14 @@
+#version 330 core
+layout(location = 0) in vec3 vertexPosition_modelSpace;
+layout(location = 1) in vec3 vertexColour;
+
+uniform mat4 ModelViewProjection;
+
+out vec3 fragmentColour;
+
+void main()
+{
+ gl_Position = ModelViewProjection * vec4(vertexPosition_modelSpace, 1.0);
+
+ fragmentColour = vertexColour;
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/World/Actor.cs b/GLWidgetTestGTK3/World/Actor.cs
new file mode 100644
index 0000000..7657bf6
--- /dev/null
+++ b/GLWidgetTestGTK3/World/Actor.cs
@@ -0,0 +1,104 @@
+//
+// Actor.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using GLib;
+using GLWidgetTestGTK3.Data;
+using OpenTK.Mathematics;
+using OpenTK.Graphics.OpenGL;
+
+namespace GLWidgetTestGTK3.World
+{
+ public class Actor
+ {
+ public Transform Transform;
+ private readonly Mesh Mesh;
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// The mesh bound to the actor.
+ public Actor(Mesh Mesh)
+ {
+ this.Mesh = Mesh;
+ this.Transform = new Transform(new Vector3(0.0f, 0.0f, 0.0f));
+ }
+
+ ///
+ /// Performs any arbitrary actions needed every frame, such as animations, texture manipulations or state
+ /// updates.
+ ///
+ /// The time (in thousands of a second) taken to render the previous frame.
+ public void Tick(float deltaTime)
+ {
+
+ }
+
+ ///
+ /// Renders this actor within the current OpenGL context.
+ ///
+ /// The ID of the currently active shader.
+ /// The camera view matrix, calulcated from the camera position.
+ /// The perspective projection currently in use.
+ public void Render(int ShaderProgramID, Matrix4 ViewMatrix, Matrix4 ProjectionMatrix)
+ {
+ // Enable the mesh vertex array
+ GL.BindBuffer(BufferTarget.ArrayBuffer, Mesh.VertexBufferID);
+
+ GL.EnableVertexAttribArray(0);
+ GL.VertexAttribPointer(
+ 0,
+ 3,
+ VertexAttribPointerType.Float,
+ false,
+ 0,
+ 0);
+
+ // Enable the normal attributes
+ GL.EnableVertexAttribArray(3);
+ GL.VertexAttribPointer(
+ 2,
+ 3,
+ VertexAttribPointerType.Float,
+ false,
+ 0,
+ 0);
+
+ Matrix4 modelTranslation = Matrix4.CreateTranslation(Transform.Translation);
+ Matrix4 modelScale = Matrix4.CreateScale(Transform.Scale);
+ Matrix4 modelRotation = Matrix4.CreateFromQuaternion(Transform.Rotation);
+
+ Matrix4 modelViewProjection = modelScale * modelRotation * modelTranslation * ViewMatrix * ProjectionMatrix;
+
+ // Send the model matrix to the shader
+ int projectionShaderVariableHandle = GL.GetUniformLocation(ShaderProgramID, "ModelViewProjection");
+ GL.UniformMatrix4(projectionShaderVariableHandle, false, ref modelViewProjection);
+
+ // Draw the model
+ GL.DrawArrays(BeginMode.Triangles, 0, Mesh.GetVertexCount());
+
+ // Release the attribute arrays
+ GL.DisableVertexAttribArray(0);
+ GL.DisableVertexAttribArray(3);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/World/Mesh.cs b/GLWidgetTestGTK3/World/Mesh.cs
new file mode 100644
index 0000000..9a61c7c
--- /dev/null
+++ b/GLWidgetTestGTK3/World/Mesh.cs
@@ -0,0 +1,135 @@
+//
+// Mesh.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using System.Collections.Generic;
+using GLWidgetTestGTK3.Data;
+using OpenTK.Graphics.OpenGL;
+
+namespace GLWidgetTestGTK3.World
+{
+ public class Mesh
+ {
+ private List Vertices;
+
+ private int vertexBufferID = -1;
+ public int VertexBufferID
+ {
+ get { return vertexBufferID; }
+ }
+
+ private int normalBufferID = -1;
+ public int NormalBufferID
+ {
+ get { return normalBufferID; }
+ }
+
+ private bool cullFaces;
+
+ public bool CullFaces
+ {
+ get;
+ set;
+ }
+
+ public Mesh(List Vertices)
+ {
+ this.Vertices = Vertices;
+
+ this.vertexBufferID = UploadVertexPositions();
+ this.normalBufferID = UploadVertexNormals();
+ }
+
+ public int GetVertexCount()
+ {
+ return Vertices.Count;
+ }
+
+ private int UploadVertexPositions()
+ {
+ if (vertexBufferID > 0)
+ {
+ return vertexBufferID;
+ }
+
+ // Generate a buffer
+ GL.GenBuffers(1, out vertexBufferID);
+
+ // Get the vertex positions
+ float[] vertexPositions = GetVertexPositions();
+
+ // Upload the vertices to the GPU
+ GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferID);
+ GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertexPositions.Length * sizeof(float)), vertexPositions, BufferUsageHint.StaticDraw);
+
+ return vertexBufferID;
+ }
+
+ private int UploadVertexNormals()
+ {
+ if (normalBufferID > 0)
+ {
+ return normalBufferID;
+ }
+
+ // Generate a buffer
+ GL.GenBuffers(1, out normalBufferID);
+
+ // Get the vertex positions
+ float[] vertexNormals = GetVertexNormals();
+
+ // Upload the vertices to the GPU
+ GL.BindBuffer(BufferTarget.ArrayBuffer, normalBufferID);
+ GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertexNormals.Length * sizeof(float)), vertexNormals, BufferUsageHint.StaticDraw);
+
+ return vertexBufferID;
+ }
+
+ private float[] GetVertexPositions()
+ {
+ List vertexPositions = new List();
+
+ foreach (Vertex StoredVertex in Vertices)
+ {
+ vertexPositions.Add(StoredVertex.Position.X);
+ vertexPositions.Add(StoredVertex.Position.Y);
+ vertexPositions.Add(StoredVertex.Position.Z);
+ }
+
+ return vertexPositions.ToArray();
+ }
+
+ private float[] GetVertexNormals()
+ {
+ List vertexNormals = new List();
+
+ foreach (Vertex StoredVertex in Vertices)
+ {
+ vertexNormals.Add(StoredVertex.Normal.X);
+ vertexNormals.Add(StoredVertex.Normal.Y);
+ vertexNormals.Add(StoredVertex.Normal.Z);
+ }
+
+ return vertexNormals.ToArray();
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/World/Scene.cs b/GLWidgetTestGTK3/World/Scene.cs
new file mode 100644
index 0000000..e5afbac
--- /dev/null
+++ b/GLWidgetTestGTK3/World/Scene.cs
@@ -0,0 +1,60 @@
+//
+// Scene.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2016 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using System.Collections.Generic;
+using OpenTK.Graphics.OpenGL;
+
+namespace GLWidgetTestGTK3.World
+{
+ public class Scene
+ {
+ public readonly List Actors = new List();
+
+ private readonly int vertexArrayID = -1;
+ public int VertexArrayID
+ {
+ get { return vertexArrayID; }
+ }
+
+ public Scene()
+ {
+ // Generate the vertex array
+ GL.GenVertexArrays(1, out vertexArrayID);
+ GL.BindVertexArray(VertexArrayID);
+ }
+
+ ///
+ /// Runs the function on all instances
+ /// in the scene. Actors can define arbitrary behaviour in their ticks, but in most
+ /// cases it's used for animation.
+ ///
+ /// The time (in thousands of a second) taken to render the previous frame.
+ public void Tick(float deltaTime)
+ {
+ for (int i = 0; i < Actors.Count; ++i)
+ {
+ Actors[i].Tick(deltaTime);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GLWidgetTestGTK3/interfaces/MainWindow.glade b/GLWidgetTestGTK3/interfaces/MainWindow.glade
new file mode 100644
index 0000000..f2cab33
--- /dev/null
+++ b/GLWidgetTestGTK3/interfaces/MainWindow.glade
@@ -0,0 +1,194 @@
+
+
+
+
+
+