attempt opentk4
This commit is contained in:
parent
0b409d641a
commit
f7b22649c6
19 changed files with 1831 additions and 389 deletions
14
GLWidget.sln
14
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
|
||||
|
|
|
@ -35,9 +35,11 @@ using System.ComponentModel;
|
|||
|
||||
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Platform;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
|
||||
using Gtk;
|
||||
using Cairo;
|
||||
|
||||
namespace OpenTK
|
||||
{
|
||||
|
@ -56,78 +58,41 @@ namespace OpenTK
|
|||
|
||||
#region Attributes
|
||||
|
||||
private IGraphicsContext _graphicsContext;
|
||||
private IWindowInfo _windowInfo;
|
||||
private bool _initialized;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>Use a single buffer versus a double buffer.</summary>
|
||||
[Browsable(true)]
|
||||
public bool SingleBuffer { get; set; }
|
||||
|
||||
/// <summary>Color Buffer Bits-Per-Pixel</summary>
|
||||
public int ColorBPP { get; set; }
|
||||
|
||||
/// <summary>Accumulation Buffer Bits-Per-Pixel</summary>
|
||||
public int AccumulatorBPP { get; set; }
|
||||
|
||||
/// <summary>Depth Buffer Bits-Per-Pixel</summary>
|
||||
public int DepthBPP { get; set; }
|
||||
|
||||
/// <summary>Stencil Buffer Bits-Per-Pixel</summary>
|
||||
public int StencilBPP { get; set; }
|
||||
|
||||
/// <summary>Number of samples</summary>
|
||||
public int Samples { get; set; }
|
||||
|
||||
/// <summary>Indicates if steropic renderering is enabled</summary>
|
||||
public bool Stereo { get; set; }
|
||||
|
||||
/// <summary>The major version of OpenGL to use.</summary>
|
||||
public int GLVersionMajor { get; set; }
|
||||
|
||||
/// <summary>The minor version of OpenGL to use.</summary>
|
||||
public int GLVersionMinor { get; set; }
|
||||
|
||||
public GraphicsContextFlags GraphicsContextFlags
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
private int _framebuffer;
|
||||
private int _renderbuffer;
|
||||
private int _stencilbuffer;
|
||||
|
||||
public Gdk.GLContext GraphicsContext { get; set; }
|
||||
public bool ForwardCompatible { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction/Destruction
|
||||
|
||||
/// <summary>Constructs a new GLWidget.</summary>
|
||||
public GLWidget()
|
||||
: this(GraphicsMode.Default)
|
||||
/// <summary>Constructs a new GLWidget</summary>
|
||||
public GLWidget() : this(new Version(4, 0), true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Constructs a new GLWidget using a given GraphicsMode</summary>
|
||||
public GLWidget(GraphicsMode graphicsMode)
|
||||
: this(graphicsMode, 1, 0, GraphicsContextFlags.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Constructs a new GLWidget</summary>
|
||||
public GLWidget(GraphicsMode graphicsMode, int glVersionMajor, int glVersionMinor, GraphicsContextFlags graphicsContextFlags)
|
||||
public GLWidget(Version apiVersion, bool forwardCompatible)
|
||||
{
|
||||
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,10 +152,7 @@ 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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
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<int> AttributeList
|
||||
{
|
||||
get
|
||||
{
|
||||
List<int> attributeList = new List<int>(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);
|
||||
|
||||
/// <summary> Returns the X resource (window or pixmap) belonging to a GdkDrawable. </summary>
|
||||
/// <remarks> XID gdk_x11_drawable_get_xid(GdkDrawable *drawable); </remarks>
|
||||
/// <param name="gdkDisplay"> The GdkDrawable. </param>
|
||||
/// <returns> The ID of drawable's X resource. </returns>
|
||||
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
|
||||
private static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkDisplay);
|
||||
|
||||
/// <summary> Returns the X resource (window or pixmap) belonging to a GdkDrawable. </summary>
|
||||
/// <remarks> XID gdk_x11_drawable_get_xid(GdkDrawable *drawable); </remarks>
|
||||
/// <param name="gdkDisplay"> The GdkDrawable. </param>
|
||||
/// <returns> The ID of drawable's X resource. </returns>
|
||||
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
|
||||
private static extern IntPtr gdk_x11_window_get_xid(IntPtr gdkDisplay);
|
||||
|
||||
/// <summary> Returns the X display of a GdkDisplay. </summary>
|
||||
/// <remarks> Display* gdk_x11_display_get_xdisplay(GdkDisplay *display); </remarks>
|
||||
/// <param name="gdkDisplay"> The GdkDrawable. </param>
|
||||
/// <returns> The X Display of the GdkDisplay. </returns>
|
||||
[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
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
|
@ -7,10 +6,9 @@
|
|||
<Version>1.0.1</Version>
|
||||
<RepositoryUrl>https://github.com/Ryujinx/GLWidget</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GtkSharp" Version="3.22.25.56" />
|
||||
<PackageReference Include="OpenTK.NetStandard" Version="1.0.5.12" />
|
||||
<PackageReference Include="OpenTK.Graphics" Version="4.0.0-pre9.4" />
|
||||
<PackageReference Include="OpenTK.Windowing.Common" Version="4.0.0-pre9.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
49
GLWidgetTestGTK3/Data/RGB.cs
Normal file
49
GLWidgetTestGTK3/Data/RGB.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Vertex.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
61
GLWidgetTestGTK3/Data/Transform.cs
Normal file
61
GLWidgetTestGTK3/Data/Transform.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Transform.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
47
GLWidgetTestGTK3/Data/UVCoordinate.cs
Normal file
47
GLWidgetTestGTK3/Data/UVCoordinate.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// UVCoordinate.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
92
GLWidgetTestGTK3/Data/Vertex.cs
Normal file
92
GLWidgetTestGTK3/Data/Vertex.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// Vertex.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
41
GLWidgetTestGTK3/Extensions/ExtensionMethods.cs
Normal file
41
GLWidgetTestGTK3/Extensions/ExtensionMethods.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// ExtensionMethods.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
39
GLWidgetTestGTK3/GLWidgetTestGTK3.csproj
Normal file
39
GLWidgetTestGTK3/GLWidgetTestGTK3.csproj
Normal file
|
@ -0,0 +1,39 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<RootNamespace>GLWidgetTestGTK3</RootNamespace>
|
||||
<StartupObject>GLWidgetTestGTK3.MainClass</StartupObject>
|
||||
<AssemblyName>GLWidgetTestGTK3</AssemblyName>
|
||||
<ReleaseVersion>1.1</ReleaseVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GtkSharp" Version="3.22.25.56"/>
|
||||
<PackageReference Include="OpenTK" Version="4.0.0-pre9.4"/>
|
||||
<PackageReference Include="OpenGL.Net" Version="1.0.304"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="interfaces\MainWindow.glade"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Shaders\FragmentShader.glsl"/>
|
||||
<EmbeddedResource Include="Shaders\VertexShader.glsl"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GLWidget\GLWidget.csproj"/>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties>
|
||||
<GtkDesignInfo generateGettext="False"/>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
140
GLWidgetTestGTK3/GTKBindingContext.cs
Normal file
140
GLWidgetTestGTK3/GTKBindingContext.cs
Normal file
|
@ -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";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Currently loaded libraries.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, IntPtr> _LibraryHandles = new Dictionary<string, IntPtr>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
76
GLWidgetTestGTK3/Geometry/Shapes.cs
Normal file
76
GLWidgetTestGTK3/Geometry/Shapes.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Mesh.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
578
GLWidgetTestGTK3/MainWindow.cs
Normal file
578
GLWidgetTestGTK3/MainWindow.cs
Normal file
|
@ -0,0 +1,578 @@
|
|||
//
|
||||
// MainWindow.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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<Vertex> 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<Vertex> convertedVertices = new List<Vertex>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles application shutdown procedures - terminating render threads, cleaning
|
||||
/// up the UI, etc.
|
||||
/// </summary>
|
||||
/// <param name="sender">Sender.</param>
|
||||
/// <param name="a">The deletion arguments.</param>
|
||||
protected void OnDeleteEvent(object sender, DeleteEventArgs a)
|
||||
{
|
||||
Application.Quit();
|
||||
a.RetVal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
GLWidgetTestGTK3/Program.cs
Normal file
61
GLWidgetTestGTK3/Program.cs
Normal file
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
12
GLWidgetTestGTK3/Shaders/FragmentShader.glsl
Normal file
12
GLWidgetTestGTK3/Shaders/FragmentShader.glsl
Normal file
|
@ -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);
|
||||
}
|
14
GLWidgetTestGTK3/Shaders/VertexShader.glsl
Normal file
14
GLWidgetTestGTK3/Shaders/VertexShader.glsl
Normal file
|
@ -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;
|
||||
}
|
104
GLWidgetTestGTK3/World/Actor.cs
Normal file
104
GLWidgetTestGTK3/World/Actor.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// Actor.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="Actor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="Mesh">The mesh bound to the actor.</param>
|
||||
public Actor(Mesh Mesh)
|
||||
{
|
||||
this.Mesh = Mesh;
|
||||
this.Transform = new Transform(new Vector3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs any arbitrary actions needed every frame, such as animations, texture manipulations or state
|
||||
/// updates.
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">The time (in thousands of a second) taken to render the previous frame.</param>
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders this actor within the current OpenGL context.
|
||||
/// </summary>
|
||||
/// <param name="ShaderProgramID">The ID of the currently active shader.</param>
|
||||
/// <param name="ViewMatrix">The camera view matrix, calulcated from the camera position.</param>
|
||||
/// <param name="ProjectionMatrix">The perspective projection currently in use.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
135
GLWidgetTestGTK3/World/Mesh.cs
Normal file
135
GLWidgetTestGTK3/World/Mesh.cs
Normal file
|
@ -0,0 +1,135 @@
|
|||
//
|
||||
// Mesh.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GLWidgetTestGTK3.Data;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace GLWidgetTestGTK3.World
|
||||
{
|
||||
public class Mesh
|
||||
{
|
||||
private List<Vertex> 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<Vertex> 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<float> vertexPositions = new List<float>();
|
||||
|
||||
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<float> vertexNormals = new List<float>();
|
||||
|
||||
foreach (Vertex StoredVertex in Vertices)
|
||||
{
|
||||
vertexNormals.Add(StoredVertex.Normal.X);
|
||||
vertexNormals.Add(StoredVertex.Normal.Y);
|
||||
vertexNormals.Add(StoredVertex.Normal.Z);
|
||||
}
|
||||
|
||||
return vertexNormals.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
60
GLWidgetTestGTK3/World/Scene.cs
Normal file
60
GLWidgetTestGTK3/World/Scene.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Scene.cs
|
||||
//
|
||||
// Author:
|
||||
// Jarl Gullberg <jarl.gullberg@gmail.com>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace GLWidgetTestGTK3.World
|
||||
{
|
||||
public class Scene
|
||||
{
|
||||
public readonly List<Actor> Actors = new List<Actor>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the <see cref="Actor.Tick"/> function on all <see cref="Actor"/> instances
|
||||
/// in the scene. Actors can define arbitrary behaviour in their ticks, but in most
|
||||
/// cases it's used for animation.
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">The time (in thousands of a second) taken to render the previous frame.</param>
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < Actors.Count; ++i)
|
||||
{
|
||||
Actors[i].Tick(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
194
GLWidgetTestGTK3/interfaces/MainWindow.glade
Normal file
194
GLWidgetTestGTK3/interfaces/MainWindow.glade
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.10"/>
|
||||
<object class="GtkWindow" id="MainWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="MainBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuBar" id="MainMenuBar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menuitem1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_File</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="menu1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem1">
|
||||
<property name="label">gtk-new</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem2">
|
||||
<property name="label">gtk-open</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem3">
|
||||
<property name="label">gtk-save</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem4">
|
||||
<property name="label">gtk-save-as</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem5">
|
||||
<property name="label">gtk-quit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menuitem2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Edit</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="menu2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem6">
|
||||
<property name="label">gtk-cut</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem7">
|
||||
<property name="label">gtk-copy</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem8">
|
||||
<property name="label">gtk-paste</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem9">
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menuitem3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_View</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menuitem4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Help</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="menu3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem10">
|
||||
<property name="label">gtk-about</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="GLWidgetAlignment">
|
||||
<property name="width_request">500</property>
|
||||
<property name="height_request">400</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
Loading…
Reference in a new issue