diff --git a/GLWidget/GLWidget.cs b/GLWidget/GLWidget.cs index 175b6e1..440f425 100644 --- a/GLWidget/GLWidget.cs +++ b/GLWidget/GLWidget.cs @@ -35,437 +35,535 @@ using System.ComponentModel; using OpenTK.Graphics; -using OpenTK.Graphics.OpenGL; - +using OpenTK.Platform; using Gtk; -using Cairo; -using GLib; -using Gdk; -using OpenGL; -using System.Diagnostics; -using OpenTK.Mathematics; namespace OpenTK { - [ToolboxItem(true)] - public class GLWidget : DrawingArea - { - private static bool xThreadInit; + [ToolboxItem(true)] + public class GLWidget : DrawingArea + { - /// - /// Get or set the OpenGL minimum color buffer bits. - /// - [Property("color-bits")] - public uint ColorBits - { - get { return (_ColorBits); } - set { _ColorBits = value; } - } + #region Static attrs. - /// - /// The OpenGL color buffer bits. - /// - private uint _ColorBits = 24; + private static int _graphicsContextCount; + private static bool _sharedContextInitialized; - /// - /// Get or set the OpenGL minimum depth buffer bits. - /// - [Property("depth-bits")] - public uint DepthBits - { - get { return (_DepthBits); } - set { _DepthBits = value; } - } - - /// - /// The OpenGL color buffer bits. - /// - private uint _DepthBits; - - /// - /// Get or set the OpenGL minimum stencil buffer bits. - /// - [Property("stencil-bits")] - public uint StencilBits - { - get { return (_StencilBits); } - set { _StencilBits = value; } - } - - /// - /// The OpenGL color buffer bits. - /// - private uint _StencilBits; - - /// - /// Get or set the OpenGL minimum multisample buffer "bits". - /// - [Property("multisample-bits")] - public uint MultisampleBits - { - get { return (_MultisampleBits); } - set { _MultisampleBits = value; } - } - - /// - /// The OpenGL multisample buffer bits. - /// - private uint _MultisampleBits; - - /// - /// Get or set the OpenGL swap buffers interval. - /// - [Property("swap-interval")] - public int SwapInterval - { - get { return (_SwapInterval); } - set { _SwapInterval = value; } - } - - /// - /// The OpenGL swap buffers interval. - /// - private int _SwapInterval = 1; - - /// - /// The describing the minimum pixel format required by this control. - /// - private DevicePixelFormat ControlPixelFormat - { - get - { - DevicePixelFormat controlReqFormat = new DevicePixelFormat(); - - controlReqFormat.RgbaUnsigned = true; - controlReqFormat.RenderWindow = true; - - controlReqFormat.ColorBits = (int)ColorBits; - controlReqFormat.DepthBits = (int)DepthBits; - controlReqFormat.StencilBits = (int)StencilBits; - controlReqFormat.MultisampleBits = (int)MultisampleBits; - controlReqFormat.DoubleBuffer = true; - - return (controlReqFormat); - } - } - - - - #region Static attrs. - public bool HandleRendering { get; set; } = false; + public bool IsRenderHandler { get; set; } = false; #endregion #region Attributes + private IGraphicsContext _graphicsContext; + private IWindowInfo _windowInfo; private bool _initialized; - #endregion + #endregion - #region Properties + #region Properties - /// The major version of OpenGL to use. - public int GLVersionMajor { get; set; } + /// Use a single buffer versus a double buffer. + [Browsable(true)] + public bool SingleBuffer { get; set; } - /// The minor version of OpenGL to use. - public int GLVersionMinor { get; set; } + /// Color Buffer Bits-Per-Pixel + public int ColorBPP { get; set; } - private DeviceContext _deviceContext; - private IntPtr _graphicsContext; - private int _error; + /// Accumulation Buffer Bits-Per-Pixel + public int AccumulatorBPP { get; set; } - private IGraphicsContext _context; - private GLContext _gdkGlContext; + /// Depth Buffer Bits-Per-Pixel + public int DepthBPP { get; set; } - public bool ForwardCompatible { get; } - public DeviceContext DeviceContext { get => _deviceContext; set => _deviceContext = value; } + /// 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 + { + get; + set; + } #endregion #region Construction/Destruction - /// Constructs a new GLWidget - public GLWidget() : this(new Version(4, 0), true) + /// 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) { - /*this.ColorBits = 32; - this.DepthBits = 24; - this.StencilBits = 8;*/ } /// Constructs a new GLWidget - public GLWidget(Version apiVersion, bool forwardCompatible) - { - GLVersionMajor = apiVersion.Major; - GLVersionMinor = apiVersion.Minor; - ForwardCompatible = forwardCompatible; - } + 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; - ~GLWidget() - { - Dispose(false); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - OnShuttingDown(); + GLVersionMajor = glVersionMajor; + GLVersionMinor = glVersionMinor; + GraphicsContextFlags = graphicsContextFlags; + } - DeviceContext?.DeleteContext(_graphicsContext); + ~GLWidget() + { + Dispose(false); + } - DeviceContext?.Dispose(); + public void MakeCurrent() + { + GraphicsContext.MakeCurrent(_windowInfo); + } - _gdkGlContext?.Dispose(); + public void ClearCurrent() + { + GraphicsContext.MakeCurrent(null); + } + + public void Swapbuffers() + { + GraphicsContext.SwapBuffers(); + } + + protected override void Dispose(bool disposing) + { + 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(); } - } + } - #endregion + #endregion - #region New Events + #region New Events - // Called when the first GraphicsContext is created in the case of GraphicsContext.ShareContexts == True; - public static event EventHandler GraphicsContextInitialized; + // Called when the first GraphicsContext is created in the case of GraphicsContext.ShareContexts == True; + public static event EventHandler GraphicsContextInitialized; + + private static void OnGraphicsContextInitialized() + { + if (GraphicsContextInitialized != null) + { + GraphicsContextInitialized(null, EventArgs.Empty); + } + } // Called when the first GraphicsContext is being destroyed in the case of GraphicsContext.ShareContexts == True; public static event EventHandler GraphicsContextShuttingDown; + private static void OnGraphicsContextShuttingDown() + { + if (GraphicsContextShuttingDown != null) + { + GraphicsContextShuttingDown(null, EventArgs.Empty); + } + } + // Called when this GLWidget has a valid GraphicsContext public event EventHandler Initialized; - protected virtual void OnInitialized() - { - if (Initialized != null) - { - Initialized(this, EventArgs.Empty); - } - } - - // Called when this GLWidget needs to render a frame - public event EventHandler RenderFrame; - - protected virtual void OnRenderFrame() - { - RenderFrame?.Invoke(this, EventArgs.Empty); + protected virtual void OnInitialized() + { + if (Initialized != null) + { + Initialized(this, EventArgs.Empty); + } } - // Called when this GLWidget is being Disposed - public event EventHandler ShuttingDown; + // Called when this GLWidget needs to render a frame + public event EventHandler RenderFrame; - protected virtual void OnShuttingDown() - { - if (ShuttingDown != null) - { - ShuttingDown(this, EventArgs.Empty); - } - } + protected virtual void OnRenderFrame() + { + if (RenderFrame != null) + { + RenderFrame(this, EventArgs.Empty); + } + } - #endregion + // Called when this GLWidget is being Disposed + public event EventHandler ShuttingDown; - // Called when the widget needs to be (fully or partially) redrawn. + protected virtual void OnShuttingDown() + { + if (ShuttingDown != null) + { + ShuttingDown(this, EventArgs.Empty); + } + } - protected override bool OnDrawn(Cairo.Context cr) - { - if (!_initialized) - Initialize(); + #endregion - ClearCurrent(); + // 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); return true; - } - - public void Swapbuffers() - { - _context?.SwapBuffers(); } - public void MakeCurrent() - { - ClearCurrent(); - - _context?.MakeCurrent(); - - _error = Marshal.GetLastWin32Error(); - } - - public void ClearCurrent() - { - if (GTKBindingHelper.CurrentPlatform == OSPlatform.Windows) - { - DeviceContext?.MakeCurrent(IntPtr.Zero); - } - else - { - Gdk.GLContext.ClearCurrent(); - } - } - - private void CreateContext() - { - if (_graphicsContext != IntPtr.Zero) - throw new InvalidOperationException("context already created"); - - IntPtr sharingContext = IntPtr.Zero; - - if (Gl.PlatformExtensions.CreateContext_ARB) - { - List attributes = new List(); - uint contextProfile = 0, contextFlags = 0; - bool debuggerAttached = Debugger.IsAttached; - - #region WGL_ARB_create_context|GLX_ARB_create_context - - #endregion - - #region WGL_ARB_create_context_profile|GLX_ARB_create_context_profile - - if (Gl.PlatformExtensions.CreateContextProfile_ARB) - { - - } - - #endregion - - #region WGL_ARB_create_context_robustness|GLX_ARB_create_context_robustness - - if (Gl.PlatformExtensions.CreateContextRobustness_ARB) - { - - } - - #endregion - - Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB); - if (contextFlags != 0) - attributes.AddRange(new int[] { Wgl.CONTEXT_FLAGS_ARB, unchecked((int)contextFlags) }); - - Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB); - Debug.Assert(contextProfile == 0 || Gl.PlatformExtensions.CreateContextProfile_ARB); - if (contextProfile != 0) - attributes.AddRange(new int[] { Wgl.CONTEXT_PROFILE_MASK_ARB, unchecked((int)contextProfile) }); - - attributes.Add(0); - - if ((_graphicsContext = _deviceContext.CreateContextAttrib(sharingContext, attributes.ToArray())) == IntPtr.Zero) - throw new InvalidOperationException(String.Format("unable to create render context ({0})", Gl.GetError())); - } - else - { - // Create OpenGL context using compatibility profile - if ((_graphicsContext = _deviceContext.CreateContext(sharingContext)) == IntPtr.Zero) - throw new InvalidOperationException("unable to create render context"); - } - } - - private void CreateDeviceContext(DevicePixelFormat controlReqFormat) - { - #region Create device context - - DeviceContext = DeviceContext.Create(GTKBindingHelper.GetDisplayHandle(Display.Handle), GTKBindingHelper.GetWindowHandle(Window.Handle)); - DeviceContext.IncRef(); - - #endregion - - #region Set pixel format - - DevicePixelFormatCollection pixelFormats = DeviceContext.PixelsFormats; - List matchingPixelFormats = pixelFormats.Choose(controlReqFormat); - - if ((matchingPixelFormats.Count == 0) && controlReqFormat.MultisampleBits > 0) - { - // Try to select the maximum multisample configuration - int multisampleBits = 0; - - pixelFormats.ForEach(delegate (DevicePixelFormat item) { multisampleBits = Math.Max(multisampleBits, item.MultisampleBits); }); - - controlReqFormat.MultisampleBits = multisampleBits; - - matchingPixelFormats = pixelFormats.Choose(controlReqFormat); - } - - if ((matchingPixelFormats.Count == 0) && controlReqFormat.DoubleBuffer) - { - // Try single buffered pixel formats - controlReqFormat.DoubleBuffer = false; - - matchingPixelFormats = pixelFormats.Choose(controlReqFormat); - if (matchingPixelFormats.Count == 0) - throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat))); - } - else if (matchingPixelFormats.Count == 0) - throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat))); - - DeviceContext.SetPixelFormat(matchingPixelFormats[0]); - - #endregion - - #region Set V-Sync - - if (Gl.PlatformExtensions.SwapControl) - { - int swapInterval = SwapInterval; - - // Mask value in case it is not supported - if (!Gl.PlatformExtensions.SwapControlTear && swapInterval == -1) - swapInterval = 1; - - DeviceContext.SwapInterval(swapInterval); - } - - #endregion - } - - private void CreateGdkGlContext() + // Called on Resize + protected override bool OnConfigureEvent(Gdk.EventConfigure evnt) { - _gdkGlContext = Window.CreateGlContext(); + if (GraphicsContext != null) + { + GraphicsContext.Update(WindowInfo); + } - _gdkGlContext.SetRequiredVersion(GLVersionMajor, GLVersionMinor); - - _gdkGlContext.ForwardCompatible = ForwardCompatible; - - _gdkGlContext.SetUseEs(0); - - _gdkGlContext.Realize(); - - _gdkGlContext.MakeCurrent(); + return true; } private void Initialize() - { - ClearCurrent(); + { + _initialized = true; - Khronos.KhronosApi.LogEnabled = true; - - Window.EnsureNative(); - - if (GTKBindingHelper.CurrentPlatform == OSPlatform.Windows) + // If this looks uninitialized... initialize. + if (ColorBPP == 0) { - CreateDeviceContext(ControlPixelFormat); + ColorBPP = 32; - CreateContext(); - - DeviceContext.MakeCurrent(_graphicsContext); - } - else { - GraphicsContext.Display = Display.Handle; - - CreateGdkGlContext(); + if (DepthBPP == 0) + { + DepthBPP = 16; + } } - _context = GraphicsContext.GetCurrentContext(Window.Handle); + ColorFormat colorBufferColorFormat = new ColorFormat(ColorBPP); - MakeCurrent(); + ColorFormat accumulationColorFormat = new ColorFormat(AccumulatorBPP); - GTKBindingHelper.InitializeGlBindings(); + 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 + GraphicsContext = new GraphicsContext(graphicsMode, WindowInfo, GLVersionMajor, GLVersionMinor, GraphicsContextFlags); + GraphicsContext.MakeCurrent(WindowInfo); + + if (OpenTK.Graphics.GraphicsContext.ShareContexts) + { + Interlocked.Increment(ref _graphicsContextCount); + + if (!_sharedContextInitialized) + { + _sharedContextInitialized = true; + ((IGraphicsContextInternal)GraphicsContext).LoadAll(); + OnGraphicsContextInitialized(); + } + } + else + { + ((IGraphicsContextInternal)GraphicsContext).LoadAll(); + OnGraphicsContextInitialized(); + } OnInitialized(); + } - OpenTK.GraphicsContext.GetCurrentContext(Window.Handle).SwapInterval(1); + #region Windows Specific initalization - ClearCurrent(); + IWindowInfo InitializeWindows() + { + IntPtr windowHandle = gdk_win32_window_get_handle(this.Window.Handle); + return Utilities.CreateWindowsWindowInfo(windowHandle); + } - _initialized = true; + [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 9225855..b86b1cb 100644 --- a/GLWidget/GLWidget.csproj +++ b/GLWidget/GLWidget.csproj @@ -5,11 +5,13 @@ GLWigdet for GTKSharp, using Opentk. 1.0.3.2 https://github.com/Ryujinx/GLWidget + True - - - - + + + + + \ No newline at end of file diff --git a/GLWidget/GTKBindingHelper.cs b/GLWidget/GTKBindingHelper.cs index 2329753..a07b450 100644 --- a/GLWidget/GTKBindingHelper.cs +++ b/GLWidget/GTKBindingHelper.cs @@ -47,32 +47,16 @@ namespace OpenTK { if (CurrentPlatform == OSPlatform.Windows) { - var addr = GetProcAddressWgl(procName); - if (addr == null || addr == IntPtr.Zero) - { - var library = UnsafeNativeMethods.LoadLibrary(WglLibrary); - - addr = UnsafeNativeMethods.GetProcAddress(library, procName); - } - - if (addr != IntPtr.Zero) - { - Loaded = true; - } - return addr; + IntPtr library = OpenTK.Platform.Windows.Functions.LoadLibrary(WglLibrary); + return OpenTK.Platform.Windows.Functions.GetProcAddress(library, procName); } else if (CurrentPlatform == OSPlatform.Linux) { - return GetProcAddressGlx(procName); + return OpenTK.Platform.X11.Glx.GetProcAddress(procName); } else if(CurrentPlatform == OSPlatform.OSX) { - var osxAddr = GetProcAddressOSX(procName); - if (osxAddr != IntPtr.Zero) - { - Loaded = true; - } - return osxAddr; + return OpenTK.Platform.MacOS.NS.GetAddress(procName); } else { diff --git a/GLWidget/GraphicsContext.cs b/GLWidget/GraphicsContext.cs index f9f9961..90cf619 100644 --- a/GLWidget/GraphicsContext.cs +++ b/GLWidget/GraphicsContext.cs @@ -6,7 +6,7 @@ using static OpenTK.GTKBindingHelper; namespace OpenTK { - public interface IGraphicsContext + public interface ILegacyGraphicsContext { void MakeCurrent(); void SwapBuffers(); @@ -14,7 +14,7 @@ namespace OpenTK void SwapInterval(int interval); } - public abstract class GraphicsContext : IGraphicsContext + public abstract class LegacyGraphicsContext : ILegacyGraphicsContext { public static IntPtr Display{ get; set; } @@ -40,7 +40,7 @@ namespace OpenTK } } - public static IGraphicsContext GetCurrentContext(IntPtr handle) + public static ILegacyGraphicsContext GetCurrentContext(IntPtr handle) { var currentPlatform = CurrentPlatform; @@ -66,7 +66,7 @@ namespace OpenTK public abstract void SwapInterval(int interval); } - public class WglGraphicsContext : GraphicsContext + public class WglGraphicsContext : LegacyGraphicsContext { private delegate int wglSwapIntervalExtDelegate(int interval); private static wglSwapIntervalExtDelegate wglSwapIntervalExt = null; @@ -120,7 +120,7 @@ namespace OpenTK } } - public class GlxGraphicsContext : GraphicsContext + public class GlxGraphicsContext : LegacyGraphicsContext { private IntPtr _windowHandle; @@ -162,7 +162,7 @@ namespace OpenTK } } - public class CglGraphicsContext : GraphicsContext + public class CglGraphicsContext : LegacyGraphicsContext { private IntPtr _windowHandle; diff --git a/GLWidget/OpenTK/BindingsBase.cs b/GLWidget/OpenTK/BindingsBase.cs new file mode 100644 index 0000000..aa40693 --- /dev/null +++ b/GLWidget/OpenTK/BindingsBase.cs @@ -0,0 +1,210 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + /// + /// Provides a common foundation for all flat API bindings and implements the extension loading interface. + /// + public abstract class LegacyBindingsBase + { + /// + /// Constructs a new BindingsBase instance. + /// + public LegacyBindingsBase() + { + } + + /// + /// Gets or sets a that indicates whether the list of supported extensions may have changed. + /// + protected bool RebuildExtensionList { get; set; } = true; + + /// + /// Retrieves an unmanaged function pointer to the specified function. + /// + /// + /// A that defines the name of the function. + /// + /// + /// A that contains the address of funcname or IntPtr.Zero, + /// if the function is not supported by the drivers. + /// + /// + /// Note: some drivers are known to return non-zero values for unsupported functions. + /// Typical values include 1 and 2 - inheritors are advised to check for and ignore these + /// values. + /// + public abstract IntPtr GetAddress(string funcname); + + /// + /// Gets an object that can be used to synchronize access to the bindings implementation. + /// + /// This object should be unique across bindings but consistent between bindings + /// of the same type. For example, ES10.GL, OpenGL.GL and CL10.CL should all return + /// unique objects, but all instances of ES10.GL should return the same object. + protected abstract object SyncRoot { get; } + + /// + /// Marshals a pointer to a null-terminated byte array to a new System.String. + /// This method supports OpenTK and is not intended to be called by user code. + /// + /// A pointer to a null-terminated byte array. + /// + /// A System.String with the data from . + /// + protected static string MarshalPtrToString(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + { + throw new ArgumentException("ptr"); + } + + unsafe + { + sbyte* str = (sbyte*)ptr; + int len = 0; + while (*str != 0) + { + ++len; + ++str; + } + + return new string((sbyte*)ptr, 0, len, Encoding.UTF8); + } + } + + /// + /// Marshal a System.String to unmanaged memory. + /// The resulting string is encoded in UTF8 and must be freed + /// with FreeStringPtr. + /// + /// The System.String to marshal. + /// + /// An unmanaged pointer containing the marshalled string. + /// This pointer must be freed with FreeStringPtr + /// + protected static IntPtr MarshalStringToPtr(string str) + { + if (String.IsNullOrEmpty(str)) + { + return IntPtr.Zero; + } + + // Allocate a buffer big enough to hold the marshalled string. + // GetMaxByteCount() appears to allocate space for the final NUL + // character, but allocate an extra one just in case (who knows + // what old Mono version would do here.) + int max_count = Encoding.UTF8.GetMaxByteCount(str.Length) + 1; + IntPtr ptr = Marshal.AllocHGlobal(max_count); + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + // Pin the managed string and convert it to UTF8 using + // the pointer overload of System.Encoding.UTF8.GetBytes(). + unsafe + { + fixed (char* pstr = str) + { + int actual_count = Encoding.UTF8.GetBytes(pstr, str.Length, (byte*)ptr, max_count); + Marshal.WriteByte(ptr, actual_count, 0); // Append '\0' at the end of the string + return ptr; + } + } + } + + /// + /// Frees a marshalled string that allocated by MarshalStringToPtr. + /// + /// An unmanaged pointer allocated with MarshalStringToPtr + protected static void FreeStringPtr(IntPtr ptr) + { + Marshal.FreeHGlobal(ptr); + } + + /// + /// Marshals a System.String array to unmanaged memory by calling + /// Marshal.AllocHGlobal for each element. + /// + /// An unmanaged pointer to an array of null-terminated strings + /// The string array to marshal. + protected static IntPtr MarshalStringArrayToPtr(string[] str_array) + { + IntPtr ptr = IntPtr.Zero; + if (str_array != null && str_array.Length != 0) + { + ptr = Marshal.AllocHGlobal(str_array.Length * IntPtr.Size); + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + int i = 0; + try + { + for (i = 0; i < str_array.Length; i++) + { + IntPtr str = MarshalStringToPtr(str_array[i]); + Marshal.WriteIntPtr(ptr, i * IntPtr.Size, str); + } + } + catch (OutOfMemoryException) + { + for (i = i - 1; i >= 0; --i) + { + Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size)); + } + + Marshal.FreeHGlobal(ptr); + + throw; + } + } + return ptr; + } + + /// + /// Frees a marshalled string that allocated by MarshalStringArrayToPtr. + /// + /// An unmanaged pointer allocated with MarshalStringArrayToPtr + /// The length of the string array. + protected static void FreeStringArrayPtr(IntPtr ptr, int length) + { + for (int i = 0; i < length; i++) + { + Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size)); + } + Marshal.FreeHGlobal(ptr); + } + + internal abstract void LoadEntryPoints(); + } +} diff --git a/GLWidget/OpenTK/Configuration.cs b/GLWidget/OpenTK/Configuration.cs new file mode 100644 index 0000000..b5d2f2f --- /dev/null +++ b/GLWidget/OpenTK/Configuration.cs @@ -0,0 +1,197 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + /// + /// Provides information about the underlying OS and runtime. + /// You must call Toolkit.Init before accessing members + /// of this class. + /// + public sealed class Configuration + { + private static bool runningOnUnix, runningOnMacOS, runningOnLinux; + private volatile static bool initialized; + private readonly static object InitLock = new object(); + + private Configuration() { } + + /// Gets a System.Boolean indicating whether OpenTK is running on a Windows platform. + public static bool RunningOnWindows { get; private set; } + + /// Gets a System.Boolean indicating whether OpenTK is running on an X11 platform. + public static bool RunningOnX11 { get; private set; } + + /// + /// Gets a indicating whether OpenTK is running on a Unix platform. + /// + public static bool RunningOnUnix + { + get { return runningOnUnix; } + } + + /// Gets a System.Boolean indicating whether OpenTK is running on the Linux kernel. + public static bool RunningOnLinux { get { return runningOnLinux; } } + + /// Gets a System.Boolean indicating whether OpenTK is running on a MacOS platform. + public static bool RunningOnMacOS { get { return runningOnMacOS; } } + + /// + /// Gets a System.Boolean indicating whether OpenTK is running on the Mono runtime. + /// + public static bool RunningOnMono { get; private set; } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + private struct utsname + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string sysname; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string nodename; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string release; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string version; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string machine; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] + public string extraJustInCase; + + } + + /// + /// Detects the unix kernel by p/invoking uname (libc). + /// + /// + private static string DetectUnixKernel() + { + Debug.Print("Size: {0}", Marshal.SizeOf(typeof(utsname)).ToString()); + Debug.Flush(); + utsname uts = new utsname(); + uname(out uts); + + Debug.WriteLine("System:"); + Debug.Indent(); + Debug.WriteLine(uts.sysname); + Debug.WriteLine(uts.nodename); + Debug.WriteLine(uts.release); + Debug.WriteLine(uts.version); + Debug.WriteLine(uts.machine); + Debug.Unindent(); + + return uts.sysname.ToString(); + } + + [DllImport("libc")] + private static extern void uname(out utsname uname_struct); + + private static bool DetectMono() + { + // Detect the Mono runtime (code taken from http://mono.wikia.com/wiki/Detecting_if_program_is_running_in_Mono). + Type t = Type.GetType("Mono.Runtime"); + return t != null; + } + + private static void DetectUnix(out bool unix, out bool linux, out bool macos) + { + unix = linux = macos = false; + + string kernel_name = DetectUnixKernel(); + switch (kernel_name) + { + case null: + case "": + throw new PlatformNotSupportedException( + "Unknown platform. Please file a bug report at https://github.com/opentk/opentk/issues"); + + case "Linux": + linux = unix = true; + break; + + case "Darwin": + macos = unix = true; + break; + + default: + unix = true; + break; + } + } + + private static bool DetectWindows() + { + return + System.Environment.OSVersion.Platform == PlatformID.Win32NT || + System.Environment.OSVersion.Platform == PlatformID.Win32S || + System.Environment.OSVersion.Platform == PlatformID.Win32Windows || + System.Environment.OSVersion.Platform == PlatformID.WinCE; + } + + private static bool DetectX11() + { + // Detect whether X is present. + try { return OpenTK.Platform.X11.API.DefaultDisplay != IntPtr.Zero; } + catch { return false; } + } + + // Detects the underlying OS and runtime. + internal static void Init(ToolkitOptions options) + { + lock (InitLock) + { + if (!initialized) + { + RunningOnMono = DetectMono(); + RunningOnWindows = DetectWindows(); + if (!RunningOnWindows) + { + DetectUnix(out runningOnUnix, out runningOnLinux, out runningOnMacOS); + } + + if ((runningOnLinux) || options.Backend == PlatformBackend.PreferX11) + { + RunningOnX11 = DetectX11(); + } + + initialized = true; + Debug.Print("Detected configuration: {0} / {1}", + RunningOnWindows ? "Windows" : RunningOnLinux ? "Linux" : RunningOnMacOS ? "MacOS" : + runningOnUnix ? "Unix" : RunningOnX11 ? "X11" : "Unknown Platform", + RunningOnMono ? "Mono" : ".Net"); + } + } + } + } +} diff --git a/GLWidget/OpenTK/ContextHandle.cs b/GLWidget/OpenTK/ContextHandle.cs new file mode 100644 index 0000000..fd10e32 --- /dev/null +++ b/GLWidget/OpenTK/ContextHandle.cs @@ -0,0 +1,127 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; + +namespace OpenTK +{ + /// + /// Represents a handle to an OpenGL or OpenAL context. + /// + public struct ContextHandle : IComparable, IEquatable + { + private IntPtr handle; + + /// + /// Gets a System.IntPtr that represents the handle of this ContextHandle. + /// + public IntPtr Handle { get { return handle; } } + + /// A read-only field that represents a handle that has been initialized to zero. + public static readonly ContextHandle Zero = new ContextHandle(IntPtr.Zero); + + /// + /// Constructs a new instance with the specified handle. + /// + /// A System.IntPtr containing the value for this instance. + public ContextHandle(IntPtr h) { handle = h; } + + /// + /// Converts this instance to its equivalent string representation. + /// + /// A System.String that contains the string representation of this instance. + public override string ToString() + { + return Handle.ToString(); + } + + /// + /// Compares this instance to the specified object. + /// + /// The System.Object to compare to. + /// True if obj is a ContextHandle that is equal to this instance; false otherwise. + public override bool Equals(object obj) + { + if (obj is ContextHandle) + { + return this.Equals((ContextHandle)obj); + } + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// A System.Int32 with the hash code of this instance. + public override int GetHashCode() + { + return Handle.GetHashCode(); + } + + /// + /// Converts the specified ContextHandle to the equivalent IntPtr. + /// + /// The ContextHandle to convert. + /// A System.IntPtr equivalent to the specified ContextHandle. + public static explicit operator IntPtr(ContextHandle c) + { + return c != ContextHandle.Zero ? c.handle : IntPtr.Zero; + } + + /// + /// Converts the specified IntPtr to the equivalent ContextHandle. + /// + /// The System.IntPtr to convert. + /// A ContextHandle equivalent to the specified IntPtr. + public static explicit operator ContextHandle(IntPtr p) + { + return new ContextHandle(p); + } + + /// + /// Compares two ContextHandles for equality. + /// + /// The ContextHandle to compare. + /// The ContextHandle to compare to. + /// True if left is equal to right; false otherwise. + public static bool operator ==(ContextHandle left, ContextHandle right) + { + return left.Equals(right); + } + + /// + /// Compares two ContextHandles for inequality. + /// + /// The ContextHandle to compare. + /// The ContextHandle to compare to. + /// True if left is not equal to right; false otherwise. + public static bool operator !=(ContextHandle left, ContextHandle right) + { + return !left.Equals(right); + } + + /// + /// Compares the numerical value of this instance to the specified ContextHandle and + /// returns a value indicating their relative order. + /// + /// The ContextHandle to compare to. + /// Less than 0, if this instance is less than other; 0 if both are equal; Greater than 0 if other is greater than this instance. + public int CompareTo(ContextHandle other) + { + unsafe { return (int)((int*)other.handle.ToPointer() - (int*)this.handle.ToPointer()); } + } + + /// + /// Compares this instance to the specified ContextHandle for equality. + /// + /// The ContextHandle to compare to. + /// True if this instance is equal to other; false otherwise. + public bool Equals(ContextHandle other) + { + return Handle == other.Handle; + } + } +} diff --git a/GLWidget/OpenTK/DisplayDevice.cs b/GLWidget/OpenTK/DisplayDevice.cs new file mode 100644 index 0000000..180c484 --- /dev/null +++ b/GLWidget/OpenTK/DisplayDevice.cs @@ -0,0 +1,445 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace OpenTK +{ + /// + /// Defines a display device on the underlying system, and provides + /// methods to query and change its display parameters. + /// + public class DisplayDevice + { + // TODO: Add properties that describe the 'usable' size of the Display, i.e. the maximized size without the taskbar etc. + // TODO: Does not detect changes to primary device. + + private bool primary; + private Rectangle bounds; + private DisplayResolution current_resolution = new DisplayResolution(); + private List available_resolutions = new List(); + private IList available_resolutions_readonly; + + internal object Id; // A platform-specific id for this monitor + + private static readonly object display_lock = new object(); + private static DisplayDevice primary_display; + + private static Platform.IDisplayDeviceDriver implementation; + + static DisplayDevice() + { + implementation = Platform.Factory.Default.CreateDisplayDeviceDriver(); + } + + internal DisplayDevice() + { + available_resolutions_readonly = available_resolutions.AsReadOnly(); + } + + internal DisplayDevice(DisplayResolution currentResolution, bool primary, + IEnumerable availableResolutions, Rectangle bounds, + object id) + : this() + { + // Todo: Consolidate current resolution with bounds? Can they fall out of sync right now? + this.current_resolution = currentResolution; + IsPrimary = primary; + this.available_resolutions.AddRange(availableResolutions); + #pragma warning disable 612,618 + this.bounds = bounds == Rectangle.Empty ? currentResolution.Bounds : bounds; + #pragma warning restore 612,618 + this.Id = id; + } + + /// + /// Gets the bounds of this instance in pixel coordinates.. + /// + public Rectangle Bounds + { + get { return bounds; } + internal set + { + bounds = value; + current_resolution.Height = bounds.Height; + current_resolution.Width = bounds.Width; + } + } + + /// Gets a System.Int32 that contains the width of this display in pixels. + public int Width { get { return current_resolution.Width; } } + + /// Gets a System.Int32 that contains the height of this display in pixels. + public int Height { get { return current_resolution.Height; } } + + /// Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32. + public int BitsPerPixel + { + get { return current_resolution.BitsPerPixel; } + internal set { current_resolution.BitsPerPixel = value; } + } + + /// + /// Gets a System.Single representing the vertical refresh rate of this display. + /// + public float RefreshRate + { + get { return current_resolution.RefreshRate; } + internal set { current_resolution.RefreshRate = value; } + } + + /// Gets a System.Boolean that indicates whether this Display is the primary Display in systems with multiple Displays. + public bool IsPrimary + { + get { return primary; } + internal set + { + if (value && primary_display != null && primary_display != this) + { + primary_display.IsPrimary = false; + } + + lock (display_lock) + { + primary = value; + if (value) + { + primary_display = this; + } + } + } + } + + /// + /// Selects an available resolution that matches the specified parameters. + /// + /// The width of the requested resolution in pixels. + /// The height of the requested resolution in pixels. + /// The bits per pixel of the requested resolution. + /// The refresh rate of the requested resolution in hertz. + /// The requested DisplayResolution or null if the parameters cannot be met. + /// + /// If a matching resolution is not found, this function will retry ignoring the specified refresh rate, + /// bits per pixel and resolution, in this order. If a matching resolution still doesn't exist, this function will + /// return the current resolution. + /// A parameter set to 0 or negative numbers will not be used in the search (e.g. if refreshRate is 0, + /// any refresh rate will be considered valid). + /// This function allocates memory. + /// + public DisplayResolution SelectResolution(int width, int height, int bitsPerPixel, float refreshRate) + { + DisplayResolution resolution = FindResolution(width, height, bitsPerPixel, refreshRate); + if (resolution == null) + { + resolution = FindResolution(width, height, bitsPerPixel, 0); + } + if (resolution == null) + { + resolution = FindResolution(width, height, 0, 0); + } + if (resolution == null) + { + return current_resolution; + } + return resolution; + } + + /// + /// Gets the list of objects available on this device. + /// + public IList AvailableResolutions + { + get { return available_resolutions_readonly; } + internal set + { + available_resolutions = (List)value; + available_resolutions_readonly = available_resolutions.AsReadOnly(); + } + } + + /// Changes the resolution of the DisplayDevice. + /// The resolution to set. + /// Thrown if the requested resolution could not be set. + /// If the specified resolution is null, this function will restore the original DisplayResolution. + public void ChangeResolution(DisplayResolution resolution) + { + if (resolution == null) + { + this.RestoreResolution(); + } + + if (resolution == current_resolution) + { + return; + } + + //effect.FadeOut(); + + if (implementation.TryChangeResolution(this, resolution)) + { + if (OriginalResolution == null) + { + OriginalResolution = current_resolution; + } + current_resolution = resolution; + } + else + { + throw new Graphics.GraphicsModeException(String.Format("Device {0}: Failed to change resolution to {1}.", + this, resolution)); + } + + //effect.FadeIn(); + } + + /// Changes the resolution of the DisplayDevice. + /// The new width of the DisplayDevice. + /// The new height of the DisplayDevice. + /// The new bits per pixel of the DisplayDevice. + /// The new refresh rate of the DisplayDevice. + /// Thrown if the requested resolution could not be set. + public void ChangeResolution(int width, int height, int bitsPerPixel, float refreshRate) + { + this.ChangeResolution(this.SelectResolution(width, height, bitsPerPixel, refreshRate)); + } + + /// Restores the original resolution of the DisplayDevice. + /// Thrown if the original resolution could not be restored. + public void RestoreResolution() + { + if (OriginalResolution != null) + { + //effect.FadeOut(); + + if (implementation.TryRestoreResolution(this)) + { + current_resolution = OriginalResolution; + OriginalResolution = null; + } + else + { + throw new Graphics.GraphicsModeException(String.Format("Device {0}: Failed to restore resolution.", this)); + } + + //effect.FadeIn(); + } + } + + /// Gets the default (primary) display of this system. + public static DisplayDevice Default + { + get { return implementation.GetDisplay(DisplayIndex.Primary); } + } + + /// + /// Gets the for the specified . + /// + /// The that defines the desired display. + /// A or null, if no device corresponds to the specified index. + public static DisplayDevice GetDisplay(DisplayIndex index) + { + return implementation.GetDisplay(index); + } + + /// + /// Gets the original resolution of this instance. + /// + internal DisplayResolution OriginalResolution { get; set; } + + internal static DisplayDevice FromPoint(int x, int y) + { + for (DisplayIndex i = DisplayIndex.First; i < DisplayIndex.Sixth; i++) + { + DisplayDevice display = DisplayDevice.GetDisplay(i); + if (display != null) + { + if (display.Bounds.Contains(x, y)) + { + return display; + } + } + } + return null; + } + + private DisplayResolution FindResolution(int width, int height, int bitsPerPixel, float refreshRate) + { + return available_resolutions.Find(delegate(DisplayResolution test) + { + return + ((width > 0 && width == test.Width) || width == 0) && + ((height > 0 && height == test.Height) || height == 0) && + ((bitsPerPixel > 0 && bitsPerPixel == test.BitsPerPixel) || bitsPerPixel == 0) && + ((refreshRate > 0 && System.Math.Abs(refreshRate - test.RefreshRate) < 1.0) || refreshRate == 0); + }); + } + + /// + /// Returns a System.String representing this DisplayDevice. + /// + /// A System.String representing this DisplayDevice. + public override string ToString() + { + return String.Format("{0}: {1} ({2} modes available)", IsPrimary ? "Primary" : "Secondary", + Bounds.ToString(), available_resolutions.Count); + } + + ///// Determines whether the specified DisplayDevices are equal. + ///// The System.Object to check against. + ///// True if the System.Object is an equal DisplayDevice; false otherwise. + //public override bool Equals(object obj) + //{ + // if (obj is DisplayDevice) + // { + // DisplayDevice dev = (DisplayDevice)obj; + // return + // IsPrimary == dev.IsPrimary && + // current_resolution == dev.current_resolution && + // available_resolutions.Count == dev.available_resolutions.Count; + // } + + // return false; + //} + + ///// Returns a unique hash representing this DisplayDevice. + ///// A System.Int32 that may serve as a hash code for this DisplayDevice. + ////public override int GetHashCode() + //{ + // return current_resolution.GetHashCode() ^ IsPrimary.GetHashCode() ^ available_resolutions.Count; + //} + } +#if false + class FadeEffect : IDisposable + { + List
forms = new List(); + double opacity_step = 0.04; + int sleep_step; + + internal FadeEffect() + { + foreach (Screen s in Screen.AllScreens) + { + Form form = new Form(); + form.ShowInTaskbar = false; + form.StartPosition = FormStartPosition.Manual; + form.WindowState = FormWindowState.Maximized; + form.FormBorderStyle = FormBorderStyle.None; + form.TopMost = true; + + form.BackColor = System.Drawing.Color.Black; + forms.Add(form); + } + + sleep_step = 10 / forms.Count; + MoveToStartPositions(); + } + + void MoveToStartPositions() + { + int count = 0; + foreach (Screen s in Screen.AllScreens) + { + // forms[count++].Location = new System.Drawing.Point(s.Bounds.X, s.Bounds.Y); + //forms[count].Size = new System.Drawing.Size(4096, 4096); + count++; + } + } + + bool FadedOut + { + get + { + bool ready = true; + foreach (Form form in forms) + ready = ready && form.Opacity >= 1.0; + + return ready; + } + } + + bool FadedIn + { + get + { + bool ready = true; + foreach (Form form in forms) + ready = ready && form.Opacity <= 0.0; + + return ready; + } + } + + internal void FadeOut() + { + MoveToStartPositions(); + + foreach (Form form in forms) + { + form.Opacity = 0.0; + form.Visible = true; + } + + while (!FadedOut) + { + foreach (Form form in forms) + { + form.Opacity += opacity_step; + form.Refresh(); + } + Thread.Sleep(sleep_step); + } + } + + internal void FadeIn() + { + MoveToStartPositions(); + + foreach (Form form in forms) + form.Opacity = 1.0; + + while (!FadedIn) + { + foreach (Form form in forms) + { + form.Opacity -= opacity_step; + form.Refresh(); + } + Thread.Sleep(sleep_step); + } + + foreach (Form form in forms) + form.Visible = false; + } + + public void Dispose() + { + foreach (Form form in forms) + form.Dispose(); + } + } +#endif +} diff --git a/GLWidget/OpenTK/DisplayIndex.cs b/GLWidget/OpenTK/DisplayIndex.cs new file mode 100644 index 0000000..27805dd --- /dev/null +++ b/GLWidget/OpenTK/DisplayIndex.cs @@ -0,0 +1,66 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace OpenTK +{ + /// + /// Defines indices. + /// + public enum DisplayIndex + { + /// + /// The first DisplayDevice. + /// + First = 0, + /// + /// The second DisplayDevice. + /// + Second, + /// + /// The third DisplayDevice. + /// + Third, + /// + /// The fourth DisplayDevice. + /// + Fourth, + /// + /// The fifth DisplayDevice. + /// + Fifth, + /// + /// The sixth DisplayDevice. + /// + Sixth, + /// + /// The default (primary) DisplayDevice. + /// + Primary = -1, + /// + /// The default (primary) DisplayDevice. + /// + Default = Primary, + } +} diff --git a/GLWidget/OpenTK/DisplayResolution.cs b/GLWidget/OpenTK/DisplayResolution.cs new file mode 100644 index 0000000..4247f97 --- /dev/null +++ b/GLWidget/OpenTK/DisplayResolution.cs @@ -0,0 +1,179 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK team. + * This notice may not be removed. + * See license.txt for licensing detailed licensing details. + */ + +using System; +using System.Drawing; + +namespace OpenTK +{ + /// Contains information regarding a monitor's display resolution. + public class DisplayResolution + { + private Rectangle bounds; + + internal DisplayResolution() { } + + // Creates a new DisplayResolution object for the primary DisplayDevice. + internal DisplayResolution(int x, int y, int width, int height, int bitsPerPixel, float refreshRate) + { + // Refresh rate may be zero, since this information may not be available on some platforms. + if (width <= 0) + { + throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); + } + if (height <= 0) + { + throw new ArgumentOutOfRangeException("height", "Must be greater than zero."); + } + if (bitsPerPixel <= 0) + { + throw new ArgumentOutOfRangeException("bitsPerPixel", "Must be greater than zero."); + } + if (refreshRate < 0) + { + throw new ArgumentOutOfRangeException("refreshRate", "Must be greater than, or equal to zero."); + } + + this.bounds = new Rectangle(x, y, width, height); + this.BitsPerPixel = bitsPerPixel; + this.RefreshRate = refreshRate; + } + +#if false + + /// + /// Creates a new DisplayResolution object for the specified DisplayDevice. + /// + /// The requested width in pixels. + /// The requested height in pixels. + /// The requested bits per pixel in bits. + /// The requested refresh rate in hertz. + /// OpenTK will select the closest match between all available resolutions on the specified DisplayDevice. + /// + public DisplayResolution(int width, int height, int bitsPerPixel, float refreshRate, DisplayDevice device) + { + // Refresh rate may be zero, since this information may not be available on some platforms. + if (width <= 0) throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); + if (height <= 0) throw new ArgumentOutOfRangeException("height", "Must be greater than zero."); + if (bitsPerPixel <= 0) throw new ArgumentOutOfRangeException("bitsPerPixel", "Must be greater than zero."); + if (refreshRate < 0) throw new ArgumentOutOfRangeException("refreshRate", "Must be greater than, or equal to zero."); + if (device == null) throw new ArgumentNullException("DisplayDevice", "Must be a valid DisplayDevice"); + + DisplayResolution res = device.SelectResolution(width, height, bitsPerPixel, refreshRate); + + this.width = res.width; + this.height = res.height; + this.bits_per_pixel = res.bits_per_pixel; + this.refresh_rate = res.refresh_rate; + } +#endif + + /// + /// Gets a System.Drawing.Rectangle that contains the bounds of this display device. + /// + [Obsolete("This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.")] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public Rectangle Bounds + { + get { return bounds; } + } + + /// Gets a System.Int32 that contains the width of this display in pixels. + public int Width + { + get { return bounds.Width; } + internal set { bounds.Width = value; } + } + + /// Gets a System.Int32 that contains the height of this display in pixels. + public int Height + { + get { return bounds.Height; } + internal set { bounds.Height = value; } + } + + /// Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32. + public int BitsPerPixel { get; internal set; } + + /// + /// Gets a System.Single representing the vertical refresh rate of this display. + /// + public float RefreshRate { get; internal set; } + + /// + /// Returns a System.String representing this DisplayResolution. + /// + /// A System.String representing this DisplayResolution. + public override string ToString() + { + #pragma warning disable 612,618 + return String.Format("{0}x{1}@{2}Hz", Bounds, BitsPerPixel, RefreshRate); + #pragma warning restore 612,618 + } + + /// Determines whether the specified resolutions are equal. + /// The System.Object to check against. + /// True if the System.Object is an equal DisplayResolution; false otherwise. + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + if (this.GetType() == obj.GetType()) + { + DisplayResolution res = (DisplayResolution)obj; + return + Width == res.Width && + Height == res.Height && + BitsPerPixel == res.BitsPerPixel && + RefreshRate == res.RefreshRate; + } + + return false; + } + + /// Returns a unique hash representing this resolution. + /// A System.Int32 that may serve as a hash code for this resolution. + public override int GetHashCode() + { + #pragma warning disable 612,618 + return Bounds.GetHashCode() ^ BitsPerPixel ^ RefreshRate.GetHashCode(); + #pragma warning restore 612,618 + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator== (DisplayResolution left, DisplayResolution right) + { + if (((object)left) == null && ((object)right) == null) + { + return true; + } + else if ((((object)left) == null && ((object)right) != null) || + (((object)left) != null && ((object)right) == null)) + { + return false; + } + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equal right; false otherwise. + public static bool operator !=(DisplayResolution left, DisplayResolution right) + { + return !(left == right); + } + } +} diff --git a/GLWidget/OpenTK/Exceptions.cs b/GLWidget/OpenTK/Exceptions.cs new file mode 100644 index 0000000..5eb6b92 --- /dev/null +++ b/GLWidget/OpenTK/Exceptions.cs @@ -0,0 +1,50 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK +{ + + /// + /// This exception is thrown when a GraphicsContext property cannot be changed after creation. + /// + public class ContextExistsException : ApplicationException + { + /// + /// Constructs a new ContextExistsException instance. + /// + /// A System.String explaining the cause of this exception. + public ContextExistsException(string message) + { + Message = message; + } + + /// + /// Gets a System.String explaining the cause of this exception. + /// + public override string Message { get; } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Graphics/ColorFormat.cs b/GLWidget/OpenTK/Graphics/ColorFormat.cs new file mode 100644 index 0000000..f983b27 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/ColorFormat.cs @@ -0,0 +1,281 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK.Graphics +{ + /// Defines the ColorFormat component of a GraphicsMode. + /// + /// A ColorFormat contains Red, Green, Blue and Alpha components that descibe + /// the allocated bits per pixel for the corresponding color. + /// + public struct ColorFormat : IComparable, IEquatable + { + private byte red, green, blue, alpha; + + /// + /// Constructs a new ColorFormat with the specified aggregate bits per pixel. + /// + /// The bits per pixel sum for the Red, Green, Blue and Alpha color channels. + public ColorFormat(int bpp) + { + if (bpp < 0) + { + throw new ArgumentOutOfRangeException("bpp", "Must be greater or equal to zero."); + } + red = green = blue = alpha = 0; + BitsPerPixel = bpp; + IsIndexed = false; + + switch (bpp) + { + case 32: + Red = Green = Blue = Alpha = 8; + break; + case 24: + Red = Green = Blue = 8; + break; + case 16: + Red = Blue = 5; + Green = 6; + break; + case 15: + Red = Green = Blue = 5; + break; + case 8: + Red = Green = 3; + Blue = 2; + IsIndexed = true; + break; + case 4: + Red = Green = 2; + Blue = 1; + IsIndexed = true; + break; + case 1: + IsIndexed = true; + break; + default: + Red = Blue = Alpha = (byte)(bpp / 4); + Green = (byte)((bpp / 4) + (bpp % 4)); + break; + } + } + + /// + /// Constructs a new ColorFormat with the specified bits per pixel for + /// the Red, Green, Blue and Alpha color channels. + /// + /// Bits per pixel for the Red color channel. + /// Bits per pixel for the Green color channel. + /// Bits per pixel for the Blue color channel. + /// Bits per pixel for the Alpha color channel. + public ColorFormat(int red, int green, int blue, int alpha) + { + if (red < 0 || green < 0 || blue < 0 || alpha < 0) + { + throw new ArgumentOutOfRangeException("Arguments must be greater or equal to zero."); + } + this.red = (byte)red; + this.green = (byte)green; + this.blue = (byte)blue; + this.alpha = (byte)alpha; + this.BitsPerPixel = red + green + blue + alpha; + this.IsIndexed = false; + if (this.BitsPerPixel < 15 && this.BitsPerPixel != 0) + { + this.IsIndexed = true; + } + } + + /// Gets the bits per pixel for the Red channel. + public int Red { get { return red; } private set { red = (byte)value; } } + /// Gets the bits per pixel for the Green channel. + public int Green { get { return green; } private set { green = (byte)value; } } + /// Gets the bits per pixel for the Blue channel. + public int Blue { get { return blue; } private set { blue = (byte)value; } } + /// Gets the bits per pixel for the Alpha channel. + public int Alpha { get { return alpha; } private set { alpha = (byte)value; } } + /// Gets a System.Boolean indicating whether this ColorFormat is indexed. + public bool IsIndexed { get; private set; } + + /// Gets the sum of Red, Green, Blue and Alpha bits per pixel. + public int BitsPerPixel { get; private set; } + + /// + /// Defines an empty ColorFormat, where all properties are set to zero. + /// + public static readonly ColorFormat Empty = new ColorFormat(0); + + /// + /// Converts the specified bpp into a new ColorFormat. + /// + /// The bits per pixel to convert. + /// A ColorFormat with the specified bits per pixel. + public static implicit operator ColorFormat(int bpp) + { + return new ColorFormat(bpp); + } + + //public static implicit operator int(ColorFormat mode) + //{ + // return mode.BitsPerPixel; + //} + + /// + /// Compares two instances. + /// + /// The other instance. + /// + /// Zero if this instance is equal to other; + /// a positive value if this instance is greater than other; + /// a negative value otherwise. + /// + public int CompareTo(ColorFormat other) + { + int result = BitsPerPixel.CompareTo(other.BitsPerPixel); + if (result != 0) + { + return result; + } + result = IsIndexed.CompareTo(other.IsIndexed); + if (result != 0) + { + return result; + } + result = Alpha.CompareTo(other.Alpha); + return result; + } + + /// + /// Compares whether this ColorFormat structure is equal to the specified ColorFormat. + /// + /// The ColorFormat structure to compare to. + /// True if both ColorFormat structures contain the same components; false otherwise. + public bool Equals(ColorFormat other) + { + return + Red == other.Red && + Green == other.Green && + Blue == other.Blue && + Alpha == other.Alpha; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// Another object to compare to. + /// True if this instance is equal to obj; false otherwise. + public override bool Equals(object obj) + { + return (obj is ColorFormat) ? this.Equals((ColorFormat)obj) : false; + } + + /// + /// Compares two instances for equality. + /// + /// The left operand. + /// The right operand. + /// True if both instances are equal; false otherwise. + public static bool operator ==(ColorFormat left, ColorFormat right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The left operand. + /// The right operand. + /// True if both instances are not equal; false otherwise. + public static bool operator !=(ColorFormat left, ColorFormat right) + { + return !(left == right); + } + + /// + /// Compares two instances for inequality. + /// + /// The left operand. + /// The right operand. + /// True if left is greater than right; false otherwise. + public static bool operator >(ColorFormat left, ColorFormat right) + { + return left.CompareTo(right) > 0; + } + + /// + /// Compares two instances for inequality. + /// + /// The left operand. + /// The right operand. + /// True if left is greater than or equal to right; false otherwise. + public static bool operator >=(ColorFormat left, ColorFormat right) + { + return left.CompareTo(right) >= 0; + } + + /// + /// Compares two instances for inequality. + /// + /// The left operand. + /// The right operand. + /// True if left is less than right; false otherwise. + public static bool operator <(ColorFormat left, ColorFormat right) + { + return left.CompareTo(right) < 0; + } + + /// + /// Compares two instances for inequality. + /// + /// The left operand. + /// The right operand. + /// True if left is less than or equal to right; false otherwise. + public static bool operator <=(ColorFormat left, ColorFormat right) + { + return left.CompareTo(right) <= 0; + } + + /// + /// Returns the hash code for this instance. + /// + /// A System.Int32 with the hash code of this instance. + public override int GetHashCode() + { + return Red ^ Green ^ Blue ^ Alpha; + } + + /// + /// Returns a that describes this instance. + /// + /// A that describes this instance. + public override string ToString() + { + return string.Format("{0} ({1})", BitsPerPixel, (IsIndexed ? " indexed" : Red.ToString() + Green.ToString() + Blue.ToString() + Alpha.ToString())); + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsBindingsBase.cs b/GLWidget/OpenTK/Graphics/GraphicsBindingsBase.cs new file mode 100644 index 0000000..704b359 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsBindingsBase.cs @@ -0,0 +1,94 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using OpenTK; + +namespace OpenTK.Graphics +{ + /// + /// Implements BindingsBase for the OpenTK.Graphics namespace (OpenGL and OpenGL|ES). + /// + public abstract class GraphicsBindingsBase : LegacyBindingsBase + { + internal IntPtr[] _EntryPointsInstance; + internal byte[] _EntryPointNamesInstance; + internal int[] _EntryPointNameOffsetsInstance; + + /// + /// Retrieves an unmanaged function pointer to the specified function. + /// + /// + /// A that defines the name of the function. + /// + /// + /// A that contains the address of funcname or IntPtr.Zero, + /// if the function is not supported by the drivers. + /// + /// + /// Note: some drivers are known to return non-zero values for unsupported functions. + /// Typical values include 1 and 2 - inheritors are advised to check for and ignore these + /// values. + /// + public override IntPtr GetAddress(string funcname) + { + var context = GraphicsContext.CurrentContext as IGraphicsContextInternal; + if (context == null) + { + throw new GraphicsContextMissingException(); + } + return context != null ? context.GetAddress(funcname) : IntPtr.Zero; + } + + // Loads all available entry points for the current API. + // Note: we prefer IGraphicsContextInternal.GetAddress over + // this.GetAddress to improve loading performance (less + // validation necessary.) + internal override void LoadEntryPoints() + { + Debug.Print("Loading entry points for {0}", GetType().FullName); + + IGraphicsContext context = GraphicsContext.CurrentContext; + if (context == null) + { + throw new GraphicsContextMissingException(); + } + + IGraphicsContextInternal context_internal = context as IGraphicsContextInternal; + unsafe + { + fixed (byte* name = _EntryPointNamesInstance) + { + for (int i = 0; i < _EntryPointsInstance.Length; i++) + { + _EntryPointsInstance[i] = context_internal.GetAddress( + new IntPtr(name + _EntryPointNameOffsetsInstance[i])); + } + } + } + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContext.cs b/GLWidget/OpenTK/Graphics/GraphicsContext.cs new file mode 100644 index 0000000..cccee2b --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContext.cs @@ -0,0 +1,620 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2013 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +using OpenTK.Platform; + +namespace OpenTK.Graphics +{ + /// + /// Represents and provides methods to manipulate an OpenGL render context. + /// + public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal + { + /// + /// Used to retrive function pointers by name. + /// + /// The function name. + /// A function pointer to , or IntPtr.Zero + public delegate IntPtr GetAddressDelegate(string function); + + /// + /// Used to return the handel of the current OpenGL context. + /// + /// The current OpenGL context, or IntPtr.Zero if no context is on the calling thread. + public delegate ContextHandle GetCurrentContextDelegate(); + + private IGraphicsContext implementation; // The actual render context implementation for the underlying platform. + private bool disposed; + + // Cache for the context handle. We need this for RemoveContext() + // in case the user does not call Dispose(). When this happens, + // RemoveContext() is called by the finalizer, in which case + // the IGraphicsContext implementation may already be null + // (hence we cannot call implementation.Context to retrieve + // the handle.) + private ContextHandle handle_cached; + + private readonly static object SyncRoot = new object(); + // Maps OS-specific context handles to GraphicsContext instances. + private readonly static Dictionary available_contexts = + new Dictionary(); + + /// + /// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window. + /// + /// The OpenTK.Graphics.GraphicsMode of the GraphicsContext. + /// The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to. + public GraphicsContext(GraphicsMode mode, IWindowInfo window) + : this(mode, window, 1, 0, GraphicsContextFlags.Default) + { } + + /// + /// Constructs a new GraphicsContext with the specified GraphicsMode, version and flags, and attaches it to the specified window. + /// + /// The OpenTK.Graphics.GraphicsMode of the GraphicsContext. + /// The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to. + /// The major version of the new GraphicsContext. + /// The minor version of the new GraphicsContext. + /// The GraphicsContextFlags for the GraphicsContext. + /// + /// Different hardware supports different flags, major and minor versions. Invalid parameters will be silently ignored. + /// + public GraphicsContext(GraphicsMode mode, IWindowInfo window, int major, int minor, GraphicsContextFlags flags) + : this(mode, window, FindSharedContext(), major, minor, flags) + { + } + + /// + /// Constructs a new GraphicsContext with the specified GraphicsMode, version and flags, and attaches it to the specified window. A dummy context will be created if both + /// the handle and the window are null. + /// + /// The OpenTK.Graphics.GraphicsMode of the GraphicsContext. + /// The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to. + /// The GraphicsContext to share resources with, or null for explicit non-sharing. + /// The major version of the new GraphicsContext. + /// The minor version of the new GraphicsContext. + /// The GraphicsContextFlags for the GraphicsContext. + /// + /// Different hardware supports different flags, major and minor versions. Invalid parameters will be silently ignored. + /// + public GraphicsContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags) + { + lock (SyncRoot) + { + bool designMode = false; + if (mode == null && window == null) + { + designMode = true; + } + else if (mode == null) + { + throw new ArgumentNullException("mode", "Must be a valid GraphicsMode."); + } + else if (window == null) + { + throw new ArgumentNullException("window", "Must point to a valid window."); + } + + // Silently ignore invalid major and minor versions. + if (major <= 0) + { + major = 1; + } + if (minor < 0) + { + minor = 0; + } + + // Angle needs an embedded context + const GraphicsContextFlags useAngleFlag = GraphicsContextFlags.Angle + | GraphicsContextFlags.AngleD3D9 + | GraphicsContextFlags.AngleD3D11 + | GraphicsContextFlags.AngleOpenGL; + var useAngle = false; + if ((flags & useAngleFlag) != 0) + { + flags |= GraphicsContextFlags.Embedded; + useAngle = true; + } + + Debug.Print("Creating GraphicsContext."); + try + { + Debug.Indent(); + Debug.Print("GraphicsMode: {0}", mode); + Debug.Print("IWindowInfo: {0}", window); + Debug.Print("GraphicsContextFlags: {0}", flags); + Debug.Print("Requested version: {0}.{1}", major, minor); + + // Todo: Add a DummyFactory implementing IPlatformFactory. + if (designMode) + { + implementation = new Platform.Dummy.DummyGLContext(); + } + else + { + IPlatformFactory factory = null; + switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded) + { + case false: + factory = Factory.Default; + break; + case true: + factory = useAngle ? Factory.Angle : Factory.Embedded; + break; + } + + // Note: this approach does not allow us to mix native and EGL contexts in the same process. + // This should not be a problem, as this use-case is not interesting for regular applications. + // Note 2: some platforms may not support a direct way of getting the current context + // (this happens e.g. with DummyGLContext). In that case, we use a slow fallback which + // iterates through all known contexts and checks if any is current (check GetCurrentContext + // declaration). + if (GetCurrentContext == null) + { + GetCurrentContext = factory.CreateGetCurrentGraphicsContext(); + } + + implementation = factory.CreateGLContext(mode, window, shareContext, DirectRendering, major, minor, flags); + handle_cached = ((IGraphicsContextInternal)implementation).Context; + factory.RegisterResource(this); + } + + AddContext(this); + } + finally + { + Debug.Unindent(); + } + } + } + + /// + /// Initializes a new instance of the class using + /// an external context handle that was created by a third-party library. + /// + /// + /// A valid, unique handle for an external OpenGL context, or ContextHandle.Zero to use the current context. + /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before. + /// + /// + /// A GetAddressDelegate instance that accepts the name of an OpenGL function and returns + /// a valid function pointer, or IntPtr.Zero if that function is not supported. This delegate should be + /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with + /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function + /// pointers.) + /// + /// + /// A GetCurrentContextDelegate instance that returns the handle of the current OpenGL context, + /// or IntPtr.Zero if no context is current on the calling thread. This delegate should be implemented + /// using the same toolkit that created the OpenGL context (i.e. if the context was created with + /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve + /// the current context.) + /// + public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent) + { + if (getAddress == null || getCurrent == null) + { + throw new ArgumentNullException(); + } + + lock (SyncRoot) + { + // Replace a zero-handle by the current context, if any + if (handle == ContextHandle.Zero) + { + handle = getCurrent(); + } + + // Make sure this handle corresponds to a valid, unique OpenGL context + if (handle == ContextHandle.Zero) + { + throw new GraphicsContextMissingException(); + } + else if (available_contexts.ContainsKey(handle)) + { + throw new InvalidOperationException("Context handle has already been added"); + } + + // We have a valid handle for an external OpenGL context, wrap it into a + // DummyGLContext instance. + implementation = new Platform.Dummy.DummyGLContext(handle, getAddress); + GetCurrentContext = getCurrent ?? GetCurrentContext; + AddContext(this); + } + implementation.LoadAll(); + } + + /// + /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. A dummy context will be created if both + /// the handle and the window are null. + /// + /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. + /// This parameter is reserved. + public GraphicsContext(ContextHandle handle, IWindowInfo window) + : this(handle, window, null, 1, 0, GraphicsContextFlags.Default) + { } + + /// + /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. + /// + /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved.. + public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags) + : this(handle, Platform.Utilities.CreateGetAddress(), Factory.Default.CreateGetCurrentGraphicsContext()) + { } + + /// + /// Returns a representing this instance. + /// + /// A that contains a string representation of this instance. + public override string ToString() + { + return (this as IGraphicsContextInternal).Context.ToString(); + } + + /// + /// Returns the hash code for this instance. + /// + /// A System.Int32 with the hash code of this instance. + public override int GetHashCode() + { + return (this as IGraphicsContextInternal).Context.GetHashCode(); + } + + /// + /// Compares two instances. + /// + /// The instance to compare to. + /// True, if obj is equal to this instance; false otherwise. + public override bool Equals(object obj) + { + return (obj is GraphicsContext) && + (this as IGraphicsContextInternal).Context == (obj as IGraphicsContextInternal).Context; + } + + private static void AddContext(IGraphicsContextInternal context) + { + ContextHandle ctx = context.Context; + if (!available_contexts.ContainsKey(ctx)) + { + available_contexts.Add(ctx, (IGraphicsContext)context); + } + else + { + Debug.Print("A GraphicsContext with handle {0} already exists.", ctx); + Debug.Print("Did you forget to call Dispose()?"); + available_contexts[ctx] = (IGraphicsContext)context; + } + } + + private static void RemoveContext(IGraphicsContextInternal context) + { + ContextHandle ctx = context.Context; + if (available_contexts.ContainsKey(ctx)) + { + available_contexts.Remove(ctx); + } + else + { + Debug.Print("Tried to remove non-existent GraphicsContext handle {0}. Call Dispose() to avoid this error.", ctx); + } + } + + private static IGraphicsContext FindSharedContext() + { + if (GraphicsContext.ShareContexts) + { + // A small hack to create a shared context with the first available context. + foreach (IGraphicsContext target in GraphicsContext.available_contexts.Values) + { + // Fix for bug 1874: if a GraphicsContext gets finalized + // (but not disposed), it won't be removed from available_contexts + // making this return null even if another valid context exists. + // The workaround is to simply ignore null targets. + if (target != null) + { + return target; + } + } + } + return null; + } + + /// + /// Checks if a GraphicsContext exists in the calling thread and throws a GraphicsContextMissingException if it doesn't. + /// + /// Generated when no GraphicsContext is current in the calling thread. + public static void Assert() + { + if (GraphicsContext.CurrentContext == null) + { + throw new GraphicsContextMissingException(); + } + } + + internal static GetCurrentContextDelegate GetCurrentContext; + + /// + /// Gets the handle of the current GraphicsContext in the calling thread. + /// + public static ContextHandle CurrentContextHandle + { + get { return GetCurrentContext(); } + } + + /// + /// Gets the GraphicsContext that is current in the calling thread. + /// + /// + /// Note: this property will not function correctly when both desktop and EGL contexts are + /// available in the same process. This scenario is very unlikely to appear in practice. + /// + public static IGraphicsContext CurrentContext + { + get + { + lock (SyncRoot) + { + if (available_contexts.Count > 0) + { + ContextHandle handle = CurrentContextHandle; + if (handle.Handle != IntPtr.Zero) + { + return (IGraphicsContext)available_contexts[handle]; + } + } + return null; + } + } + } + + /// Gets or sets a System.Boolean, indicating whether GraphicsContext resources are shared + /// + /// If ShareContexts is true, new GLContexts will share resources. If this value is + /// false, new GLContexts will not share resources. + /// Changing this value will not affect already created GLContexts. + /// + public static bool ShareContexts { get; set; } = true; + + /// Gets or sets a System.Boolean, indicating whether GraphicsContexts will perform direct rendering. + /// + /// + /// If DirectRendering is true, new contexts will be constructed with direct rendering capabilities, if possible. + /// If DirectRendering is false, new contexts will be constructed with indirect rendering capabilities. + /// + /// This property does not affect existing GraphicsContexts, unless they are recreated. + /// + /// This property is ignored on Operating Systems without support for indirect rendering, like Windows and OS X. + /// + /// + public static bool DirectRendering { get; set; } = true; + + /// + /// Gets or sets a System.Boolean, indicating whether automatic error checking should be performed. + /// Influences the debug version of OpenTK.dll, only. + /// + /// Automatic error checking will clear the OpenGL error state. Set CheckErrors to false if you use + /// the OpenGL error state in your code flow (e.g. for checking supported texture formats). + public bool ErrorChecking { get; set; } = true; + + /// + /// Swaps buffers on a context. This presents the rendered scene to the user. + /// + public void SwapBuffers() + { + implementation.SwapBuffers(); + } + + /// + /// Makes the GraphicsContext the current rendering target. + /// + /// A valid structure. + /// + /// You can use this method to bind the GraphicsContext to a different window than the one it was created from. + /// + public void MakeCurrent(IWindowInfo window) + { + implementation.MakeCurrent(window); + } + + /// + /// Gets a indicating whether this instance is current in the calling thread. + /// + public bool IsCurrent + { + get { return implementation.IsCurrent; } + } + + /// + /// Gets a indicating whether this instance has been disposed. + /// It is an error to access any instance methods if this property returns true. + /// + public bool IsDisposed + { + get { return disposed && implementation.IsDisposed; } + private set { disposed = value; } + } + + /// + /// Gets or sets a positive integer in the range [1, n), indicating the number of + /// refreshes between consecutive + /// calls. The maximum value for n is + /// implementation-dependent. The default value is 1. + /// Invalid values will be clamped to the valid range. + /// + public int SwapInterval + { + get { return implementation.SwapInterval; } + set { implementation.SwapInterval = value; } + } + + /// + /// Updates the graphics context. This must be called when the render target + /// is resized for proper behavior on Mac OS X. + /// + /// + public void Update(IWindowInfo window) + { + implementation.Update(window); + } + + /// + /// Loads all OpenGL entry points. + /// + /// + /// Occurs when this instance is not current on the calling thread. + /// + public void LoadAll() + { + if (GraphicsContext.CurrentContext != this) + { + throw new GraphicsContextException(); + } + + implementation.LoadAll(); + } + + /// + /// Gets the platform-specific implementation of this IGraphicsContext. + /// + IGraphicsContext IGraphicsContextInternal.Implementation + { + get { return implementation; } + } + + /// + /// Gets a handle to the OpenGL rendering context. + /// + ContextHandle IGraphicsContextInternal.Context + { + get + { + if (implementation != null) + { + handle_cached = ((IGraphicsContextInternal)implementation).Context; + } + return handle_cached; + } + } + + /// + /// Gets the GraphicsMode of the context. + /// + public GraphicsMode GraphicsMode + { + get { return (implementation as IGraphicsContext).GraphicsMode; } + } + + /// + /// Retrieves the implementation-defined address of an OpenGL function. + /// + /// The name of the OpenGL function (e.g. "glGetString") + /// + /// A pointer to the specified function or an invalid pointer if the function is not + /// available in the current OpenGL context. The return value and calling convention + /// depends on the underlying platform. + /// + IntPtr IGraphicsContextInternal.GetAddress(string function) + { + IntPtr name = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(function); + IntPtr address = (implementation as IGraphicsContextInternal).GetAddress(name); + System.Runtime.InteropServices.Marshal.FreeHGlobal(name); + return address; + } + + /// + /// Retrieves the implementation-defined address of an OpenGL function. + /// + /// + /// A pointer to a null-terminated buffer + /// containing the name of the OpenGL function. + /// + /// + /// A pointer to the specified function or an invalid pointer if the function is not + /// available in the current OpenGL context. The return value and calling convention + /// depends on the underlying platform. + /// + IntPtr IGraphicsContextInternal.GetAddress(IntPtr function) + { + return (implementation as IGraphicsContextInternal).GetAddress(function); + } + + /// + /// Disposes of the GraphicsContext. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!IsDisposed) + { + lock (SyncRoot) + { + RemoveContext(this); + } + + // Note: we cannot dispose the implementation + // from a different thread. See wglDeleteContext. + // This is also known to crash GLX implementations. + if (manual) + { + Debug.Print("Disposing context {0}.", (this as IGraphicsContextInternal).Context.ToString()); + if (implementation != null) + { + implementation.Dispose(); + } + } + else + { + Debug.WriteLine("GraphicsContext leaked, did you forget to call Dispose()?"); + } + IsDisposed = true; + } + } + + /// + /// Marks this context as deleted, but does not actually release unmanaged resources + /// due to the threading requirements of OpenGL. Use + /// instead. + /// + ~GraphicsContext() + { + Dispose(false); + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContextBase.cs b/GLWidget/OpenTK/Graphics/GraphicsContextBase.cs new file mode 100644 index 0000000..936221e --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContextBase.cs @@ -0,0 +1,132 @@ +// +// GraphicsContextBase.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using OpenTK.Platform; + +namespace OpenTK.Graphics +{ + // Provides the foundation for all IGraphicsContext implementations. + internal abstract class GraphicsContextBase : IGraphicsContext, IGraphicsContextInternal, IEquatable + { + protected ContextHandle Handle; + protected GraphicsMode Mode; + + public abstract void SwapBuffers(); + + public abstract void MakeCurrent(IWindowInfo window); + + public abstract bool IsCurrent { get; } + + public bool IsDisposed { get; protected set; } + + public bool VSync + { + get { return SwapInterval > 0; } + set + { + if (value && SwapInterval <= 0) + { + SwapInterval = 1; + } + else if (!value && SwapInterval > 0) + { + SwapInterval = 0; + } + } + } + + public abstract int SwapInterval { get; set; } + + public virtual void Update(IWindowInfo window) { } + + public GraphicsMode GraphicsMode { get { return Mode; } } + + public bool ErrorChecking + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public IGraphicsContext Implementation { get { return this; } } + + public abstract void LoadAll(); + + public ContextHandle Context { get { return Handle; } } + + // This function is no longer used. + // The GraphicsContext facade will + // always call the IntPtr overload. + public IntPtr GetAddress(string function) + { + throw new NotImplementedException(); + } + + public abstract IntPtr GetAddress(IntPtr function); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected abstract void Dispose(bool disposing); + + #if DEBUG + ~GraphicsContextBase() + { + Dispose(false); + Debug.Print("[Warning] {0}:{1} leaked. Did you forget to call Dispose()?", + GetType().FullName, Handle); + } + #endif + + public bool Equals(IGraphicsContextInternal other) + { + return Context.Equals(other.Context); + } + + public override string ToString() + { + return string.Format("[{0}: IsCurrent={1}, IsDisposed={2}, VSync={3}, SwapInterval={4}, GraphicsMode={5}, Context={6}]", + GetType().Name, IsCurrent, IsDisposed, VSync, SwapInterval, GraphicsMode, Context); + } + + public override int GetHashCode() + { + return Handle.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is IGraphicsContextInternal && + Equals((IGraphicsContextInternal)obj); + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContextException.cs b/GLWidget/OpenTK/Graphics/GraphicsContextException.cs new file mode 100644 index 0000000..2723720 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContextException.cs @@ -0,0 +1,19 @@ +using System; + +namespace OpenTK.Graphics +{ + /// + /// Represents errors related to a GraphicsContext. + /// + public class GraphicsContextException : Exception + { + /// + /// Constructs a new GraphicsContextException. + /// + public GraphicsContextException() : base() { } + /// + /// Constructs a new GraphicsContextException with the given error message. + /// + public GraphicsContextException(string message) : base(message) { } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContextFlags.cs b/GLWidget/OpenTK/Graphics/GraphicsContextFlags.cs new file mode 100644 index 0000000..80bf86d --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContextFlags.cs @@ -0,0 +1,81 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK.Graphics +{ + /// + /// Enumerates various flags that affect the creation of new GraphicsContexts. + /// + [Flags] + public enum GraphicsContextFlags + { + /// + /// The default value of the GraphicsContextFlags enumeration. + /// + Default = 0x0000, + /// + /// Indicates that this is a debug GraphicsContext. Debug contexts may provide + /// additional debugging information at the cost of performance. + /// + /// + Debug = 0x0001, + /// + /// Indicates that this is a forward compatible GraphicsContext. Forward-compatible contexts + /// do not support functionality marked as deprecated in the current GraphicsContextVersion. + /// + /// Forward-compatible contexts are defined only for OpenGL versions 3.0 and later. + ForwardCompatible = 0x0002, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES. + /// + Embedded = 0x0004, + /// + /// Indicates that this GraphicsContext is intended for offscreen rendering. + /// + Offscreen = 0x0008, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and that angle-specific extensions are available. + /// + Angle = 0x0010, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses Direct3D9 as rendering backend. + /// + AngleD3D9 = 0x0020, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses Direct3D11 as rendering backend. + /// + AngleD3D11 = 0x0040, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses OpenGL as rendering backend. + /// + AngleOpenGL = 0x0080, + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContextMissingException.cs b/GLWidget/OpenTK/Graphics/GraphicsContextMissingException.cs new file mode 100644 index 0000000..bcf43ee --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContextMissingException.cs @@ -0,0 +1,20 @@ +using System; + +namespace OpenTK.Graphics +{ + /// + /// Thrown when an operation that required GraphicsContext is performed, when no + /// GraphicsContext is current in the calling thread. + /// + public class GraphicsContextMissingException : GraphicsContextException + { + /// + /// Constructs a new GraphicsContextMissingException. + /// + public GraphicsContextMissingException() + : base(String.Format( + "No context is current in the calling thread (ThreadId: {0}).", + System.Threading.Thread.CurrentThread.ManagedThreadId)) + { } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsContextVersion.cs b/GLWidget/OpenTK/Graphics/GraphicsContextVersion.cs new file mode 100644 index 0000000..109850f --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsContextVersion.cs @@ -0,0 +1,63 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK.Graphics +{ + /// + /// Defines the version information of a GraphicsContext. + /// + public sealed class GraphicsContextVersion + { + internal GraphicsContextVersion(int minor, int major, string vendor, string renderer) + { + Minor = minor; + Major = major; + Vendor = vendor; + Renderer = renderer; + } + + /// + /// Gets a System.Int32 indicating the minor version of a GraphicsContext instance. + /// + public int Minor { get; private set; } + + /// + /// Gets a System.Int32 indicating the major version of a GraphicsContext instance. + /// + public int Major { get; private set; } + + /// + /// Gets a System.String indicating the vendor of a GraphicsContext instance. + /// + public string Vendor { get; private set; } = String.Empty; + + /// + /// Gets a System.String indicating the renderer of a GraphicsContext instance. + /// + public string Renderer { get; private set; } = String.Empty; + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsErrorException.cs b/GLWidget/OpenTK/Graphics/GraphicsErrorException.cs new file mode 100644 index 0000000..c2f774a --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsErrorException.cs @@ -0,0 +1,17 @@ +namespace OpenTK.Graphics +{ + /// + /// Identifies a specific OpenGL or OpenGL|ES error. Such exceptions are only thrown + /// when OpenGL or OpenGL|ES automatic error checking is enabled - + /// property. + /// Important: Do *not* catch this exception. Rather, fix the underlying issue that caused the error. + /// + public class GraphicsErrorException : GraphicsException + { + /// + /// Constructs a new GraphicsErrorException instance with the specified error message. + /// + /// + public GraphicsErrorException(string message) : base(message) { } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsExceptions.cs b/GLWidget/OpenTK/Graphics/GraphicsExceptions.cs new file mode 100644 index 0000000..aee32a7 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsExceptions.cs @@ -0,0 +1,20 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK team. + * This notice may not be removed. + * See license.txt for licensing detailed licensing details. + */ + +using System; + +namespace OpenTK +{ + /// Represents errors related to Graphics operations. + public class GraphicsException : Exception + { + /// Constructs a new GraphicsException. + public GraphicsException() : base() { } + /// Constructs a new GraphicsException with the specified excpetion message. + /// + public GraphicsException(string message) : base(message) { } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsMode.cs b/GLWidget/OpenTK/Graphics/GraphicsMode.cs new file mode 100644 index 0000000..e10228b --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsMode.cs @@ -0,0 +1,239 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; +using System.Diagnostics; +using OpenTK.Core; + +namespace OpenTK.Graphics +{ + /// Defines the format for graphics operations. + public class GraphicsMode : IEquatable + { + private int samples; + + private static GraphicsMode defaultMode; + private static readonly object SyncRoot = new object(); + + // Disable BeforeFieldInit + static GraphicsMode() { } + + internal GraphicsMode(GraphicsMode mode) + : this(mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo) { } + + internal GraphicsMode(IntPtr? index, ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, + int buffers, bool stereo) + { + if (depth < 0) + { + throw new ArgumentOutOfRangeException("depth", "Must be greater than, or equal to zero."); + } + if (stencil < 0) + { + throw new ArgumentOutOfRangeException("stencil", "Must be greater than, or equal to zero."); + } + if (buffers < 0) + { + throw new ArgumentOutOfRangeException("buffers", "Must be greater than, or equal to zero."); + } + if (samples < 0) + { + throw new ArgumentOutOfRangeException("samples", "Must be greater than, or equal to zero."); + } + + this.Index = index; + this.ColorFormat = color; + this.Depth = depth; + this.Stencil = stencil; + this.Samples = samples; + this.AccumulatorFormat = accum; + this.Buffers = buffers; + this.Stereo = stereo; + } + + /// Constructs a new GraphicsMode with sensible default parameters. + public GraphicsMode() + : this(Default) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + public GraphicsMode(ColorFormat color) + : this(color, Default.Depth, Default.Stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + public GraphicsMode(ColorFormat color, int depth) + : this(color, depth, Default.Stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + /// The number of bits in the stencil buffer. + public GraphicsMode(ColorFormat color, int depth, int stencil) + : this(color, depth, stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + /// The number of bits in the stencil buffer. + /// The number of samples for FSAA. + public GraphicsMode(ColorFormat color, int depth, int stencil, int samples) + : this(color, depth, stencil, samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + /// The number of bits in the stencil buffer. + /// The number of samples for FSAA. + /// The ColorFormat of the accumilliary buffer. + public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum) + : this(color, depth, stencil, samples, accum, Default.Buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + /// The number of bits in the stencil buffer. + /// The number of samples for FSAA. + /// The ColorFormat of the accumilliary buffer. + /// The number of render buffers. Typical values include one (single-), two (double-) or three (triple-buffering). + public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers) + : this(color, depth, stencil, samples, accum, buffers, Default.Stereo) + { } + + /// Constructs a new GraphicsMode with the specified parameters. + /// The ColorFormat of the color buffer. + /// The number of bits in the depth buffer. + /// The number of bits in the stencil buffer. + /// The number of samples for FSAA. + /// The ColorFormat of the accumilliary buffer. + /// Set to true for a GraphicsMode with stereographic capabilities. + /// The number of render buffers. Typical values include one (single-), two (double-) or three (triple-buffering). + public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, bool stereo) + : this(null, color, depth, stencil, samples, accum, buffers, stereo) { } + + /// + /// Gets a nullable value, indicating the platform-specific index for this GraphicsMode. + /// + public IntPtr? Index { get; set; } = null; + + /// + /// Gets an OpenTK.Graphics.ColorFormat that describes the color format for this GraphicsFormat. + /// + public ColorFormat ColorFormat { get; private set; } + + /// + /// Gets an OpenTK.Graphics.ColorFormat that describes the accumulator format for this GraphicsFormat. + /// + public ColorFormat AccumulatorFormat { get; private set; } + + /// + /// Gets a System.Int32 that contains the bits per pixel for the depth buffer + /// for this GraphicsFormat. + /// + public int Depth { get; private set; } + + /// + /// Gets a System.Int32 that contains the bits per pixel for the stencil buffer + /// of this GraphicsFormat. + /// + public int Stencil { get; private set; } + + /// + /// Gets a System.Int32 that contains the number of FSAA samples per pixel for this GraphicsFormat. + /// + public int Samples + { + get + { + return samples; + } + private set + { + // Clamp antialiasing samples to max 64x + // This protects against a potential DOS during + // mode selection, when the user requests an + // abnormally high AA level. + samples = Math.Clamp(value, 0, 64); + } + } + + /// + /// Gets a System.Boolean indicating whether this DisplayMode is stereoscopic. + /// + public bool Stereo { get; private set; } + + /// + /// Gets a System.Int32 containing the number of buffers associated with this + /// DisplayMode. + /// + public int Buffers { get; private set; } + + /// Returns an OpenTK.GraphicsFormat compatible with the underlying platform. + public static GraphicsMode Default + { + get + { + lock (SyncRoot) + { + if (defaultMode == null) + { + defaultMode = new GraphicsMode(null, 32, 16, 0, 0, 0, 2, false); + Debug.Print("GraphicsMode.Default = {0}", defaultMode.ToString()); + } + return defaultMode; + } + } + } + + /// Returns a System.String describing the current GraphicsFormat. + /// ! System.String describing the current GraphicsFormat. + public override string ToString() + { + return String.Format("Index: {0}, Color: {1}, Depth: {2}, Stencil: {3}, Samples: {4}, Accum: {5}, Buffers: {6}, Stereo: {7}", + Index, ColorFormat, Depth, Stencil, Samples, AccumulatorFormat, Buffers, Stereo); + } + + /// + /// Returns the hashcode for this instance. + /// + /// A hashcode for this instance. + public override int GetHashCode() + { + return Index.GetHashCode(); + } + + /// + /// Indicates whether obj is equal to this instance. + /// + /// An object instance to compare for equality. + /// True, if obj equals this instance; false otherwise. + public override bool Equals(object obj) + { + if (obj is GraphicsMode) + { + return Equals((GraphicsMode)obj); + } + return false; + } + + /// + /// Indicates whether other represents the same mode as this instance. + /// + /// The GraphicsMode to compare to. + /// True, if other is equal to this instance; false otherwise. + public bool Equals(GraphicsMode other) + { + return Index.HasValue && Index == other.Index; + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsModeComparer.cs b/GLWidget/OpenTK/Graphics/GraphicsModeComparer.cs new file mode 100644 index 0000000..2cd610f --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsModeComparer.cs @@ -0,0 +1,67 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; + +namespace OpenTK.Graphics +{ + internal sealed class GraphicsModeComparer : IComparer + { + public int Compare(GraphicsMode x, GraphicsMode y) + { + int result = x.ColorFormat.CompareTo(y.ColorFormat); + if (result != 0) + { + return result; + } + result = x.Depth.CompareTo(y.Depth); + if (result != 0) + { + return result; + } + result = x.Stencil.CompareTo(y.Stencil); + if (result != 0) + { + return result; + } + result = x.Samples.CompareTo(y.Samples); + if (result != 0) + { + return result; + } + result = x.Stereo.CompareTo(y.Stereo); + if (result != 0) + { + return result; + } + result = x.Buffers.CompareTo(y.Buffers); + if (result != 0) + { + return result; + } + return x.AccumulatorFormat.CompareTo(y.AccumulatorFormat); + } + } +} diff --git a/GLWidget/OpenTK/Graphics/GraphicsModeException.cs b/GLWidget/OpenTK/Graphics/GraphicsModeException.cs new file mode 100644 index 0000000..97f92d3 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/GraphicsModeException.cs @@ -0,0 +1,19 @@ +using System; + +namespace OpenTK.Graphics +{ + /// + /// Represents errors related to unavailable graphics parameters. + /// + public class GraphicsModeException : Exception + { + /// + /// Constructs a new GraphicsModeException. + /// + public GraphicsModeException() : base() { } + /// + /// Constructs a new GraphicsModeException with the given error message. + /// + public GraphicsModeException(string message) : base(message) { } + } +} diff --git a/GLWidget/OpenTK/Graphics/IGraphicsContext.cs b/GLWidget/OpenTK/Graphics/IGraphicsContext.cs new file mode 100644 index 0000000..eafd517 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/IGraphicsContext.cs @@ -0,0 +1,122 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; +using OpenTK.Platform; + +namespace OpenTK.Graphics +{ + /// + /// Provides methods for creating and interacting with an OpenGL context. + /// + public interface IGraphicsContext : IDisposable + { + /// Swaps buffers, presenting the rendered scene to the user. + void SwapBuffers(); + + /// Makes the GraphicsContext current in the calling thread. + /// An OpenTK.Platform.IWindowInfo structure that points to a valid window. + /// + /// OpenGL commands in one thread, affect the GraphicsContext which is current in that thread. + /// It is an error to issue an OpenGL command in a thread without a current GraphicsContext. + /// + void MakeCurrent(IWindowInfo window); + + /// + /// Gets a indicating whether this instance is current in the calling thread. + /// + bool IsCurrent { get; } + + /// + /// Gets a indicating whether this instance has been disposed. + /// It is an error to access any instance methods if this property returns true. + /// + bool IsDisposed { get; } + + /// + /// Gets or sets a positive integer in the range [1, n), indicating the number of + /// refreshes between consecutive + /// calls. The maximum value for n is + /// implementation-dependent. The default value is 1. + /// Invalid values will be clamped to the valid range. + /// + int SwapInterval { get; set; } + + /// + /// Updates the graphics context. This must be called when the region the graphics context + /// is drawn to is resized. + /// + /// + void Update(IWindowInfo window); + + /// Gets the GraphicsMode of this instance. + GraphicsMode GraphicsMode { get; } + + /// + /// Gets or sets a System.Boolean, indicating whether automatic error checking should be performed. + /// + /// + /// It is an error to enable error checking inside a Begin()-End() region. + /// This method only affects the debug version of OpenTK.dll. + /// + bool ErrorChecking { get; set; } + + /// + /// Loads all OpenGL entry points. Requires this instance to be current on the calling thread. + /// + void LoadAll(); + } + + // Functions for internal use by OpenTK. + // TODO: RegisterForDisposal/DisposeResources for 0.3.15 (GC & OpenGL) + // TODO: Remove or move GetDisplayModes to another class. + /// + /// Provides methods to create new GraphicsContexts. Should only be used for extending OpenTK. + /// + public interface IGraphicsContextInternal + { + /// + /// Gets the internal implementation of the current instance. + /// + IGraphicsContext Implementation { get; } + + /// + /// Loads all OpenGL entry points. Requires this instance to be current on the calling thread. + /// + void LoadAll(); + + /// + /// Gets a handle to the OpenGL rendering context. + /// + ContextHandle Context { get; } + + /// + /// Retrieves the implementation-defined address of an OpenGL function. + /// + /// The name of the OpenGL function (e.g. "glGetString") + /// + /// A pointer to the specified function or an invalid pointer if the function is not + /// available in the current OpenGL context. The return value and calling convention + /// depends on the underlying platform. + /// + IntPtr GetAddress(string function); + + /// + /// Retrieves the implementation-defined address of an OpenGL function. + /// + /// + /// A pointer to a null-terminated buffer + /// containing the name of the OpenGL function. + /// + /// + /// A pointer to the specified function or an invalid pointer if the function is not + /// available in the current OpenGL context. The return value and calling convention + /// depends on the underlying platform. + /// + /// + IntPtr GetAddress(IntPtr function); + } +} diff --git a/GLWidget/OpenTK/Graphics/IGraphicsMode.cs b/GLWidget/OpenTK/Graphics/IGraphicsMode.cs new file mode 100644 index 0000000..5f47681 --- /dev/null +++ b/GLWidget/OpenTK/Graphics/IGraphicsMode.cs @@ -0,0 +1,16 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +namespace OpenTK.Graphics +{ + internal interface IGraphicsMode + { + // Creates a temporary OpenGL context (if necessary) and finds the mode which closest matches + // the specified parameters. + GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, + bool stereo); + } +} diff --git a/GLWidget/OpenTK/Platform/DesktopGraphicsContext.cs b/GLWidget/OpenTK/Platform/DesktopGraphicsContext.cs new file mode 100644 index 0000000..07acb79 --- /dev/null +++ b/GLWidget/OpenTK/Platform/DesktopGraphicsContext.cs @@ -0,0 +1,80 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Diagnostics; +using System.Reflection; +using OpenTK.Graphics; + +namespace OpenTK.Platform +{ + // Provides the foundation for all desktop IGraphicsContext implementations. + internal abstract class DesktopGraphicsContext : GraphicsContextBase + { + public override void LoadAll() + { + // Modern unices can use EGL to create + // both GL and ES contexts, so we need + // to load all entry points. This is + // especially true on KMS, Wayland and Mir. + + Stopwatch time = Stopwatch.StartNew(); + + 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 GTKBindingHelper(); + + 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"); + + Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds); + } + } +} diff --git a/GLWidget/OpenTK/Platform/DeviceCollection.cs b/GLWidget/OpenTK/Platform/DeviceCollection.cs new file mode 100644 index 0000000..6a48994 --- /dev/null +++ b/GLWidget/OpenTK/Platform/DeviceCollection.cs @@ -0,0 +1,227 @@ +// +// DeviceCollection.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenTK.Platform +{ + // Holds a collection of hardware devices with an associated id. + // Note: 'id' refers to a unique hardware-specific device identifier. + // Note: 'index' refers to the offset of the device in the Devices array. + // Indices are allocated sequentially as devices are added to the system. + // If a device is removed, its index will be reused for the next device + // that is added. + internal class DeviceCollection : IEnumerable + { + internal struct Enumerator : IEnumerator + { + private int Index; + private DeviceCollection Collection; + + internal Enumerator(DeviceCollection collection) + { + Collection = collection; + Index = -1; + Current = default(T); + } + + public T Current { get; private set; } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + public void Dispose() + { + } + + public bool MoveNext() + { + do + { + ++Index; + if (Index < Collection.Devices.Count) + { + Current = Collection.Devices[Index]; + } + } while (Index < Collection.Devices.Count && Collection.Devices[Index] == null); + + return Index < Collection.Devices.Count; + } + + public void Reset() + { + Index = -1; + Current = default(T); + } + } + + private readonly Dictionary Map = new Dictionary(); + private readonly List Devices = new List(); + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(this); + } + + // This avoids boxing when using foreach loops + public Enumerator GetEnumerator() + { + return new Enumerator(this); + } + + public T this[int index] + { + get { return FromIndex(index); } + } + + /// \internal + /// + /// Adds or replaces a device based on its hardware id. + /// A zero-based device index will be generated automatically + /// for the first available device slot. + /// + /// The hardware id for the device. + /// The device instance. + public void Add(long id, T device) + { + if (!Map.ContainsKey(id)) + { + int index = GetIndex(); + Map.Add(id, index); + } + + Devices[Map[id]] = device; + } + + public void Remove(long id) + { + if (!TryRemove(id)) + { + Debug.Print("Invalid DeviceCollection<{0}> id: {1}", typeof(T).FullName, id); + } + } + + public bool TryRemove(long id) + { + if (!Map.ContainsKey(id)) + { + return false; + } + + Devices[Map[id]] = default(T); + Map.Remove(id); + return true; + } + + public T FromIndex(int index) + { + if (index >= 0 && index < Devices.Count) + { + return Devices[index]; + } + else + { + return default(T); + } + } + + public bool FromIndex(int index, out T device) + { + if (index >= 0 && index < Devices.Count) + { + device = Devices[index]; + return true; + } + else + { + device = default(T); + return false; + } + } + + public T FromHardwareId(long id) + { + if (Map.ContainsKey(id)) + { + return FromIndex(Map[id]); + } + else + { + return default(T); + } + } + + public bool FromHardwareId(long id, out T device) + { + if (Map.ContainsKey(id)) + { + device = FromIndex(Map[id]); + return true; + } + else + { + device = default(T); + return false; + } + } + + public int Count + { + get { return Map.Count; } + } + + // Return the index of the first empty slot in Devices. + // If no empty slot exists, append a new one and return + // that index. + private int GetIndex() + { + for (int i = 0; i < Devices.Count; i++) + { + if (Devices[i] == null) + { + return i; + } + } + + Devices.Add(default(T)); + return Devices.Count - 1; + } + } +} + diff --git a/GLWidget/OpenTK/Platform/DisplayDeviceBase.cs b/GLWidget/OpenTK/Platform/DisplayDeviceBase.cs new file mode 100644 index 0000000..9e95330 --- /dev/null +++ b/GLWidget/OpenTK/Platform/DisplayDeviceBase.cs @@ -0,0 +1,61 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +namespace OpenTK.Platform +{ + internal abstract class DisplayDeviceBase : IDisplayDeviceDriver + { + internal sealed class SystemEvents + { + public static event EventHandler DisplaySettingsChanged; + } + + protected readonly List AvailableDevices = new List(); + protected DisplayDevice Primary; + + public abstract bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution); + public abstract bool TryRestoreResolution(DisplayDevice device); + + // Gets the DisplayDevice that corresponds to the specified index. + public virtual DisplayDevice GetDisplay(DisplayIndex index) + { + if (index == DisplayIndex.Primary) + { + return Primary; + } + else if ((int)index >= 0 && (int)index < AvailableDevices.Count) + { + return AvailableDevices[(int)index]; + } + else + { + return null; + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/Dummy/DummyGLContext.cs b/GLWidget/OpenTK/Platform/Dummy/DummyGLContext.cs new file mode 100644 index 0000000..6190e68 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Dummy/DummyGLContext.cs @@ -0,0 +1,97 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; +using System.Threading; + +using OpenTK.Graphics; + +namespace OpenTK.Platform.Dummy +{ + /// \internal + /// + /// An empty IGraphicsContext implementation to be used inside the Visual Studio designer. + /// This class supports OpenTK, and is not intended for use by OpenTK programs. + /// + internal sealed class DummyGLContext : GraphicsContextBase + { + private readonly GraphicsContext.GetAddressDelegate Loader; + + private static int handle_count; + private Thread current_thread; + + public DummyGLContext() + { + Handle = new ContextHandle( + new IntPtr(Interlocked.Increment( + ref handle_count))); + } + + public DummyGLContext(ContextHandle handle, GraphicsContext.GetAddressDelegate loader) + : this() + { + if (handle != ContextHandle.Zero) + { + Handle = handle; + } + Loader = loader; + Mode = new GraphicsMode(new IntPtr(2), 32, 16, 0, 0, 0, 2, false); + } + + public override void SwapBuffers() { } + + public override void MakeCurrent(IWindowInfo info) + { + Thread new_thread = Thread.CurrentThread; + // A context may be current only on one thread at a time. + if (current_thread != null && new_thread != current_thread) + { + throw new GraphicsContextException( + "Cannot make context current on two threads at the same time"); + } + + if (info != null) + { + current_thread = Thread.CurrentThread; + } + else + { + current_thread = null; + } + } + + public override bool IsCurrent + { + get { return current_thread != null && current_thread == Thread.CurrentThread; } + } + + public override IntPtr GetAddress(IntPtr function) + { + string str = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(function); + return Loader(str); + } + + public override int SwapInterval { get; set; } + + public override void Update(IWindowInfo window) + { } + + public override void LoadAll() + { + #if OPENGL + new OpenTK.Graphics.OpenGL.GL().LoadEntryPoints(); + new OpenTK.Graphics.OpenGL4.GL().LoadEntryPoints(); + #endif + #if OPENGLES + new OpenTK.Graphics.ES11.GL().LoadEntryPoints(); + new OpenTK.Graphics.ES20.GL().LoadEntryPoints(); + new OpenTK.Graphics.ES30.GL().LoadEntryPoints(); + #endif + } + + protected override void Dispose(bool disposing) { IsDisposed = true; } + } +} diff --git a/GLWidget/OpenTK/Platform/Dummy/DummyWindowInfo.cs b/GLWidget/OpenTK/Platform/Dummy/DummyWindowInfo.cs new file mode 100644 index 0000000..95dafb3 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Dummy/DummyWindowInfo.cs @@ -0,0 +1,16 @@ +using System; + +namespace OpenTK.Platform.Dummy +{ + internal class DummyWindowInfo : IWindowInfo + { + public void Dispose() + { + } + + public IntPtr Handle + { + get { return IntPtr.Zero; } + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/AngleWindowInfo.cs b/GLWidget/OpenTK/Platform/Egl/AngleWindowInfo.cs new file mode 100644 index 0000000..b7ae396 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/AngleWindowInfo.cs @@ -0,0 +1,179 @@ +using System; +using OpenTK.Graphics; +using OpenTK.Platform.Windows; + +namespace OpenTK.Platform.Egl +{ + using EGLSurface = IntPtr; + /// + /// A window info for angle. + /// + public interface IAngleWindowInfo : IWindowInfo + { + /// + /// Query the underlying platform pointer / handle for this window's + /// default surface or IntPtr.Zero + /// + IntPtr QuerySurfacePointer(); + /// + /// Create an additional rendering surface that shares the display + /// of this window. + /// + /// width in pixels + /// height in pixels + /// A reference to the new surface + EGLSurface CreateSurface(int width, int height); + /// + /// Destroy a surface created with CreateSurface and clears the passed reference. + /// + /// Reference to the surface. + void DestroySurface(ref EGLSurface surface); + /// + /// MakeCurrent the custom surface created with CreateSurface. + /// + /// Reference to the surface. + void MakeCurrent(EGLSurface surface); + /// + /// Query the underlying platform pointer / handle for an EGLSurface + /// created with CreateSurface. + /// + /// + IntPtr QuerySurfacePointer(EGLSurface surface); + } + + internal interface IAngleWindowInfoInternal : IAngleWindowInfo + { + IWindowInfo PlatformWindow { get; } + IntPtr Display { get; } + IntPtr Surface { get; } + EglContext EglContext { get; set; } + EglWindowInfo EglWindowInfo { get; set; } + IntPtr DeviceContext { get; } + } + + internal class AngleWindowInfo : IAngleWindowInfoInternal + { + private bool _disposed; + + public AngleWindowInfo(IWindowInfo platform_window) + { + PlatformWindow = platform_window; + } + + public IWindowInfo PlatformWindow { get; } + + public IWindowInfo WindowInfo + { + get { return EglWindowInfo; } + } + + public IntPtr DeviceContext + { + get + { + var win_win = PlatformWindow as WinWindowInfo; + if (win_win != null) + { + return win_win.DeviceContext; + } + return IntPtr.Zero; + } + } + + public EglContext EglContext { get; set; } + public EglWindowInfo EglWindowInfo { get; set; } + + public IntPtr Display + { + get { return EglWindowInfo.Display; } + } + + public IntPtr Surface + { + get { return EglWindowInfo.Surface; } + } + + public void Dispose() + { + Dispose(false); + } + + public IntPtr Handle + { + get { return PlatformWindow.Handle; } + } + + ~AngleWindowInfo() + { + Dispose(true); + } + + private void Dispose(bool called_from_finalizer) + { + if (_disposed) + { + return; + } + if (!called_from_finalizer) + { + PlatformWindow.Dispose(); + } + // dispose unmanaged + + _disposed = true; + GC.SuppressFinalize(this); + } + + public IntPtr QuerySurfacePointer() + { + return QuerySurfacePointer(Surface); + } + + public EGLSurface CreateSurface(int width, int height) + { + IntPtr surface; + EglWindowInfo.CreatePbufferSurface( + EglContext.GraphicsMode.Index.Value, + width, height, + out surface); + return surface; + } + + public void DestroySurface(ref EGLSurface surface) + { + EglWindowInfo.DestroySurface(ref surface); + } + + public void MakeCurrent(EGLSurface surface) + { + Egl.MakeCurrent(Display, surface, surface, EglContext.HandleAsEGLContext); + } + + public IntPtr QuerySurfacePointer(IntPtr surface) + { + if (UsesDirect3DBackend()) + { + return QuerySurfacePointer(surface, + Egl.EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE); + } + return IntPtr.Zero; + } + + private IntPtr QuerySurfacePointer(IntPtr surface, int attrib) + { + IntPtr surface_pointer; + if (Egl.QuerySurfacePointerANGLE( + Display, surface, attrib, out surface_pointer)) + { + return surface_pointer; + } + return IntPtr.Zero; + } + + private bool UsesDirect3DBackend() + { + var d3d_flags = GraphicsContextFlags.AngleD3D9 | GraphicsContextFlags.AngleD3D11; + return ((EglContext.GraphicsContextFlags & d3d_flags) != 0); + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Egl/Egl.cs b/GLWidget/OpenTK/Platform/Egl/Egl.cs new file mode 100644 index 0000000..7e31380 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/Egl.cs @@ -0,0 +1,403 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2011 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; +using OpenTK.Graphics; + +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +#pragma warning disable 1591 // Missing XML comments + +namespace OpenTK.Platform.Egl +{ + using EGLNativeDisplayType = IntPtr; + using EGLNativeWindowType = IntPtr; + using EGLNativePixmapType = IntPtr; + using EGLConfig = IntPtr; + using EGLContext = IntPtr; + using EGLDisplay = IntPtr; + using EGLSurface = IntPtr; + using EGLClientBuffer = IntPtr; + + internal enum RenderApi + { + ES = Egl.OPENGL_ES_API, + GL = Egl.OPENGL_API, + VG = Egl.OPENVG_API + } + + [Flags] + internal enum RenderableFlags + { + ES = Egl.OPENGL_ES_BIT, + ES2 = Egl.OPENGL_ES2_BIT, + ES3 = Egl.OPENGL_ES3_BIT, + GL = Egl.OPENGL_BIT, + VG = Egl.OPENVG_BIT, + } + + public enum ErrorCode + { + SUCCESS = 12288, + NOT_INITIALIZED = 12289, + BAD_ACCESS = 12290, + BAD_ALLOC = 12291, + BAD_ATTRIBUTE = 12292, + BAD_CONFIG = 12293, + BAD_CONTEXT = 12294, + BAD_CURRENT_SURFACE = 12295, + BAD_DISPLAY = 12296, + BAD_MATCH = 12297, + BAD_NATIVE_PIXMAP = 12298, + BAD_NATIVE_WINDOW = 12299, + BAD_PARAMETER = 12300, + BAD_SURFACE = 12301, + CONTEXT_LOST = 12302, + } + + internal enum SurfaceType + { + PBUFFER_BIT = 0x0001, + PIXMAP_BIT = 0x0002, + WINDOW_BIT = 0x0004, + VG_COLORSPACE_LINEAR_BIT = 0x0020, + VG_ALPHA_FORMAT_PRE_BIT = 0x0040, + MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200, + SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400, + } + + internal static partial class Egl + { + public const int VERSION_1_0 = 1; + public const int VERSION_1_1 = 1; + public const int VERSION_1_2 = 1; + public const int VERSION_1_3 = 1; + public const int VERSION_1_4 = 1; + public const int FALSE = 0; + public const int TRUE = 1; + public const int DONT_CARE = -1; + public const int CONTEXT_LOST = 12302; + public const int BUFFER_SIZE = 12320; + public const int ALPHA_SIZE = 12321; + public const int BLUE_SIZE = 12322; + public const int GREEN_SIZE = 12323; + public const int RED_SIZE = 12324; + public const int DEPTH_SIZE = 12325; + public const int STENCIL_SIZE = 12326; + public const int CONFIG_CAVEAT = 12327; + public const int CONFIG_ID = 12328; + public const int LEVEL = 12329; + public const int MAX_PBUFFER_HEIGHT = 12330; + public const int MAX_PBUFFER_PIXELS = 12331; + public const int MAX_PBUFFER_WIDTH = 12332; + public const int NATIVE_RENDERABLE = 12333; + public const int NATIVE_VISUAL_ID = 12334; + public const int NATIVE_VISUAL_TYPE = 12335; + public const int PRESERVED_RESOURCES = 12336; + public const int SAMPLES = 12337; + public const int SAMPLE_BUFFERS = 12338; + public const int SURFACE_TYPE = 12339; + public const int TRANSPARENT_TYPE = 12340; + public const int TRANSPARENT_BLUE_VALUE = 12341; + public const int TRANSPARENT_GREEN_VALUE = 12342; + public const int TRANSPARENT_RED_VALUE = 12343; + public const int NONE = 12344; + public const int BIND_TO_TEXTURE_RGB = 12345; + public const int BIND_TO_TEXTURE_RGBA = 12346; + public const int MIN_SWAP_INTERVAL = 12347; + public const int MAX_SWAP_INTERVAL = 12348; + public const int LUMINANCE_SIZE = 12349; + public const int ALPHA_MASK_SIZE = 12350; + public const int COLOR_BUFFER_TYPE = 12351; + public const int RENDERABLE_TYPE = 12352; + public const int MATCH_NATIVE_PIXMAP = 12353; + public const int CONFORMANT = 12354; + public const int SLOW_CONFIG = 12368; + public const int NON_CONFORMANT_CONFIG = 12369; + public const int TRANSPARENT_RGB = 12370; + public const int RGB_BUFFER = 12430; + public const int LUMINANCE_BUFFER = 12431; + public const int NO_TEXTURE = 12380; + public const int TEXTURE_RGB = 12381; + public const int TEXTURE_RGBA = 12382; + public const int TEXTURE_2D = 12383; + public const int PBUFFER_BIT = 1; + public const int PIXMAP_BIT = 2; + public const int WINDOW_BIT = 4; + public const int VG_COLORSPACE_LINEAR_BIT = 32; + public const int VG_ALPHA_FORMAT_PRE_BIT = 64; + public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512; + public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024; + public const int OPENGL_ES_BIT = 1; + public const int OPENVG_BIT = 2; + public const int OPENGL_ES2_BIT = 4; + public const int OPENGL_BIT = 8; + public const int OPENGL_ES3_BIT = 64; + public const int VENDOR = 12371; + public const int VERSION = 12372; + public const int EXTENSIONS = 12373; + public const int CLIENT_APIS = 12429; + public const int HEIGHT = 12374; + public const int WIDTH = 12375; + public const int LARGEST_PBUFFER = 12376; + public const int TEXTURE_FORMAT = 12416; + public const int TEXTURE_TARGET = 12417; + public const int MIPMAP_TEXTURE = 12418; + public const int MIPMAP_LEVEL = 12419; + public const int RENDER_BUFFER = 12422; + public const int VG_COLORSPACE = 12423; + public const int VG_ALPHA_FORMAT = 12424; + public const int HORIZONTAL_RESOLUTION = 12432; + public const int VERTICAL_RESOLUTION = 12433; + public const int PIXEL_ASPECT_RATIO = 12434; + public const int SWAP_BEHAVIOR = 12435; + public const int MULTISAMPLE_RESOLVE = 12441; + public const int BACK_BUFFER = 12420; + public const int SINGLE_BUFFER = 12421; + public const int VG_COLORSPACE_sRGB = 12425; + public const int VG_COLORSPACE_LINEAR = 12426; + public const int VG_ALPHA_FORMAT_NONPRE = 12427; + public const int VG_ALPHA_FORMAT_PRE = 12428; + public const int DISPLAY_SCALING = 10000; + public const int UNKNOWN = -1; + public const int BUFFER_PRESERVED = 12436; + public const int BUFFER_DESTROYED = 12437; + public const int OPENVG_IMAGE = 12438; + public const int CONTEXT_CLIENT_TYPE = 12439; + public const int CONTEXT_CLIENT_VERSION = 12440; + public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442; + public const int MULTISAMPLE_RESOLVE_BOX = 12443; + public const int OPENGL_ES_API = 12448; + public const int OPENVG_API = 12449; + public const int OPENGL_API = 12450; + public const int DRAW = 12377; + public const int READ = 12378; + public const int CORE_NATIVE_ENGINE = 12379; + public const int COLORSPACE = VG_COLORSPACE; + public const int ALPHA_FORMAT = VG_ALPHA_FORMAT; + public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB; + public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR; + public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE; + public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE; + + // EGL_ANGLE_d3d_share_handle_client_buffer + public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; + // EGL_ANGLE_window_fixed_size + public const int FIXED_SIZE_ANGLE = 0x3201; + // EGL_ANGLE_query_surface_pointer + [DllImport("libEGL.dll", EntryPoint = "eglQuerySurfacePointerANGLE")] + public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value); + + [DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")] + public static extern EGLDisplay GetPlatformDisplay(int platform, EGLNativeDisplayType displayId, int[] attribList); + + // EGL_ANGLE_software_display + public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1); + // EGL_ANGLE_direct3d_display + public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2); + public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3); + // EGL_ANGLE_device_d3d + public const int D3D9_DEVICE_ANGLE = 0x33A0; + public const int D3D11_DEVICE_ANGLE = 0x33A1; + // EGL_ANGLE_platform_angle + public const int PLATFORM_ANGLE_ANGLE = 0x3202; + public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203; + public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204; + public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205; + public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206; + // EGL_ANGLE_platform_angle_d3d + public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207; + public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208; + public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209; + public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A; + public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B; + public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C; + public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F; + // EGL_ANGLE_platform_angle_opengl + public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D; + public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E; + // See EGL_ANGLE_surface_d3d_texture_2d_share_handle + public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")] + public static extern ErrorCode GetError(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")] + public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglInitialize")] + //[return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglTerminate")] + //[return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool Terminate(EGLDisplay dpy); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryString")] + public static extern IntPtr QueryString(EGLDisplay dpy, int name); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigs")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglChooseConfig")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigAttrib")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateWindowSurface")] + public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferSurface")] + public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePixmapSurface")] + public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroySurface")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglQuerySurface")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool BindAPI(RenderApi api); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")] + public static extern int QueryAPI(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitClient")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool WaitClient(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseThread")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool ReleaseThread(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferFromClientBuffer")] + public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglSurfaceAttrib")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglBindTexImage")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseTexImage")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapInterval")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool SwapInterval(EGLDisplay dpy, int interval); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateContext")] + private static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list); + + public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list) + { + IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list); + if (ptr == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format("Failed to create EGL context, error: {0}.", Egl.GetError())); + } + return ptr; + } + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroyContext")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglMakeCurrent")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentContext")] + public static extern EGLContext GetCurrentContext(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentSurface")] + public static extern EGLSurface GetCurrentSurface(int readdraw); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentDisplay")] + public static extern EGLDisplay GetCurrentDisplay(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryContext")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitGL")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool WaitGL(); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitNative")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool WaitNative(int engine); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapBuffers")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglCopyBuffers")] + [return: MarshalAsAttribute(UnmanagedType.I1)] + public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")] + public static extern IntPtr GetProcAddress(string funcname); + + [DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")] + public static extern IntPtr GetProcAddress(IntPtr funcname); + + // EGL_EXT_platform_base + [DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")] + public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list); + + [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")] + public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list); + + [DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")] + public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list); + + // Returns true if Egl drivers exist on the system. + public static bool IsSupported + { + get + { + try { GetCurrentContext(); } + catch (Exception) { return false; } + return true; + } + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs b/GLWidget/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs new file mode 100644 index 0000000..b890d5a --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs @@ -0,0 +1,138 @@ + +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2015 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + internal class EglAnglePlatformFactory : PlatformFactoryBase + { + private readonly IPlatformFactory _platform_factory; + public EglAnglePlatformFactory(IPlatformFactory platform_factory) + { + _platform_factory = platform_factory; + } + + public override IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + return _platform_factory.CreateDisplayDeviceDriver(); + } + + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, + IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + var angle_window = (IAngleWindowInfoInternal)window; + var egl_window = CreateWindowInfo(angle_window, major, flags); + var egl_context = new EglWinContext(mode, egl_window, shareContext, major, minor, flags); + angle_window.EglContext = egl_context; + return egl_context; + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, + IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + var angle_window = (IAngleWindowInfoInternal)window; + var egl_window = CreateWindowInfo(angle_window, major, flags); + var egl_context = new EglWinContext(handle, egl_window, shareContext, major, minor, flags); + angle_window.EglContext = egl_context; + return egl_context; + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(Platform.Egl.Egl.GetCurrentContext()); + }; + } + + private static bool FlagEnabled(GraphicsContextFlags flags, GraphicsContextFlags flag) + { + return (flags & flag) != 0; + } + + private EglWindowInfo CreateWindowInfo(IAngleWindowInfoInternal window_info, + int major, GraphicsContextFlags flags) + { + var egl_display = GetAngleDisplay(window_info.DeviceContext, flags, major); + var egl_window = new EglWindowInfo(window_info.Handle, egl_display); + window_info.EglWindowInfo = egl_window; + return egl_window; + } + + private IntPtr GetAngleDisplay(IntPtr dc, GraphicsContextFlags flags, int major) + { + // default to D3D9 for ES2, but use D3D11 for ES3 as required by Angle. + var platform_type = major == 2 + ? Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE + : Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE; + if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D11)) + { + platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE; + } + else if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D9)) + { + platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE; + } + else if (FlagEnabled(flags, GraphicsContextFlags.AngleOpenGL)) + { + platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + } + else + { + // make sure the correct flag is set. + switch (platform_type) + { + case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + flags |= GraphicsContextFlags.AngleD3D9; + break; + case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + flags |= GraphicsContextFlags.AngleD3D11; + break; + case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + flags |= GraphicsContextFlags.AngleOpenGL; + break; + } + } + + var attribs = new[] + { + Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_ANGLE, platform_type, + Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, Platform.Egl.Egl.DONT_CARE, + Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, Platform.Egl.Egl.DONT_CARE, + Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE, + Platform.Egl.Egl.NONE + }; + + return Platform.Egl.Egl.GetPlatformDisplay( + Platform.Egl.Egl.PLATFORM_ANGLE_ANGLE, + dc, + attribs + ); + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Egl/EglContext.cs b/GLWidget/OpenTK/Platform/Egl/EglContext.cs new file mode 100644 index 0000000..f0cb259 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglContext.cs @@ -0,0 +1,268 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + internal abstract class EglContext : EmbeddedGraphicsContext + { + protected readonly RenderableFlags Renderable; + internal EglWindowInfo WindowInfo; + + internal GraphicsContextFlags GraphicsContextFlags { get; set; } + + internal IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } } + private int swap_interval = 1; // Default interval is defined as 1 in EGL. + + public EglContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + { + if (mode == null) + { + throw new ArgumentNullException("mode"); + } + if (window == null) + { + throw new ArgumentNullException("window"); + } + + EglContext shared = GetSharedEglContext(sharedContext); + + WindowInfo = window; + + // Select an EGLConfig that matches the desired mode. We cannot use the 'mode' + // parameter directly, since it may have originated on a different system (e.g. GLX) + // and it may not support the desired renderer. + + Renderable = RenderableFlags.GL; + if ((flags & GraphicsContextFlags.Embedded) != 0) + { + switch (major) + { + case 3: + Renderable = RenderableFlags.ES3; + break; + case 2: + Renderable = RenderableFlags.ES2; + break; + default: + Renderable = RenderableFlags.ES; + break; + } + } + + RenderApi api = (Renderable & RenderableFlags.GL) != 0 ? RenderApi.GL : RenderApi.ES; + Debug.Print("[EGL] Binding {0} rendering API.", api); + if (!Egl.BindAPI(api)) + { + Debug.Print("[EGL] Failed to bind rendering API. Error: {0}", Egl.GetError()); + } + + bool offscreen = (flags & GraphicsContextFlags.Offscreen) != 0; + + SurfaceType surfaceType = offscreen + ? SurfaceType.PBUFFER_BIT + : SurfaceType.WINDOW_BIT; + + Mode = new EglGraphicsMode().SelectGraphicsMode(surfaceType, + window.Display, mode.ColorFormat, mode.Depth, mode.Stencil, + mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo, + Renderable); + + if (!Mode.Index.HasValue) + { + throw new GraphicsModeException("Invalid or unsupported GraphicsMode."); + } + IntPtr config = Mode.Index.Value; + + if (window.Surface == IntPtr.Zero) + { + if (!offscreen) + { + window.CreateWindowSurface(config); + } + else + { + window.CreatePbufferSurface(config); + } + } + + int[] attribList = { Egl.CONTEXT_CLIENT_VERSION, major, Egl.NONE }; + var shareContext = shared?.HandleAsEGLContext ?? IntPtr.Zero; + HandleAsEGLContext = Egl.CreateContext(window.Display, config, shareContext, attribList); + + GraphicsContextFlags = flags; + } + + public EglContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + { + if (handle == ContextHandle.Zero) + { + throw new ArgumentException("handle"); + } + if (window == null) + { + throw new ArgumentNullException("window"); + } + + Handle = handle; + } + + public override void SwapBuffers() + { + if (!Egl.SwapBuffers(WindowInfo.Display, WindowInfo.Surface)) + { + throw new GraphicsContextException(string.Format("Failed to swap buffers for context {0} current. Error: {1}", Handle, Egl.GetError())); + } + } + + public override void MakeCurrent(IWindowInfo window) + { + // Ignore 'window', unless it actually is an EGL window. In other words, + // trying to make the EglContext current on a non-EGL window will do, + // nothing (the EglContext will remain current on the previous EGL window + // or the window it was constructed on (which may not be EGL)). + if (window != null) + { + if (window is EglWindowInfo) + { + WindowInfo = (EglWindowInfo)window; + } + else if (window is IAngleWindowInfoInternal) + { + WindowInfo = ((IAngleWindowInfoInternal)window).EglWindowInfo; + } + if (!Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, HandleAsEGLContext)) + { + throw new GraphicsContextException(string.Format("Failed to make context {0} current. Error: {1}", Handle, Egl.GetError())); + } + } + else + { + Egl.MakeCurrent(WindowInfo.Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + } + } + + public override bool IsCurrent + { + get { return Egl.GetCurrentContext() == HandleAsEGLContext; } + } + + public override int SwapInterval + { + get + { + // Egl.GetSwapInterval does not exist, so store and return the current interval. + // The default interval is defined as 1 (true). + return swap_interval; + } + set + { + if (value < 0) + { + // EGL does not offer EXT_swap_control_tear yet + value = 1; + } + + if (Egl.SwapInterval(WindowInfo.Display, value)) + { + swap_interval = value; + } + else + { + Debug.Print("[Warning] Egl.SwapInterval({0}, {1}) failed. Error: {2}", + WindowInfo.Display, value, Egl.GetError()); + } + } + } + + public override void Update(IWindowInfo window) + { + MakeCurrent(window); + // ANGLE updates the width and height of the back buffer surfaces in the WaitClient function. + // So without this calling this function, the surface won't match the size of the window after it + // was resized. + // https://bugs.chromium.org/p/angleproject/issues/detail?id=1438 + if (!Egl.WaitClient()) + { + Debug.Print("[Warning] Egl.WaitClient() failed. Error: {0}", Egl.GetError()); + } + } + + public override IntPtr GetAddress(IntPtr function) + { + // Try loading a static export from ES1 or ES2 + IntPtr address = GetStaticAddress(function, Renderable); + + // If a static export is not available, try retrieving an extension + // function pointer with eglGetProcAddress + if (address == IntPtr.Zero) + { + address = Egl.GetProcAddress(function); + } + + return address; + } + + protected abstract IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable); + + // Todo: cross-reference the specs. What should happen if the context is destroyed from a different + // thread? + protected override void Dispose(bool manual) + { + if (!IsDisposed) + { + if (manual) + { + if (IsCurrent) + { + Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, IntPtr.Zero); + } + Egl.DestroyContext(WindowInfo.Display, HandleAsEGLContext); + } + IsDisposed = true; + } + } + + private EglContext GetSharedEglContext(IGraphicsContext sharedContext) + { + if (sharedContext == null) + { + return null; + } + + var internalContext = sharedContext as IGraphicsContextInternal; + if (internalContext != null) + { + return (EglContext)internalContext.Implementation; + } + return (EglContext)sharedContext; + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglException.cs b/GLWidget/OpenTK/Platform/Egl/EglException.cs new file mode 100644 index 0000000..391fb92 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglException.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp) +// This file is distributed under GPL v3. See LICENSE.md for details. + +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + /// + /// Represents an Egl exception. + /// + public class EglException : GraphicsContextException + { + /// + /// Gets the EGL error code. + /// + public ErrorCode ErrorCode { get; private set; } + + internal EglException(string message, ErrorCode errorCode) : base(message) + { + ErrorCode = errorCode; + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Egl/EglGraphicsMode.cs b/GLWidget/OpenTK/Platform/Egl/EglGraphicsMode.cs new file mode 100644 index 0000000..c66385b --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglGraphicsMode.cs @@ -0,0 +1,101 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + internal class EglGraphicsMode + { + public GraphicsMode SelectGraphicsMode(EglWindowInfo window, + GraphicsMode mode, RenderableFlags flags) + { + return SelectGraphicsMode(window, + mode.ColorFormat, mode.Depth, mode.Stencil, + mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo, + flags); + } + + public GraphicsMode SelectGraphicsMode(EglWindowInfo window, + ColorFormat color, int depth, int stencil, + int samples, ColorFormat accum, int buffers, bool stereo, + RenderableFlags renderableFlags) + { + return SelectGraphicsMode( + SurfaceType.WINDOW_BIT, + window.Display, + color, depth, stencil, samples, accum, buffers, stereo, renderableFlags); + } + + public GraphicsMode SelectGraphicsMode(SurfaceType surfaceType, + IntPtr display, ColorFormat color, int depth, int stencil, + int samples, ColorFormat accum, int buffers, bool stereo, + RenderableFlags renderableFlags) + { + IntPtr[] configs = new IntPtr[1]; + int[] attribList = new int[] + { + Egl.SURFACE_TYPE, (int)surfaceType, + Egl.RENDERABLE_TYPE, (int)renderableFlags, + + Egl.RED_SIZE, color.Red, + Egl.GREEN_SIZE, color.Green, + Egl.BLUE_SIZE, color.Blue, + Egl.ALPHA_SIZE, color.Alpha, + + Egl.DEPTH_SIZE, depth > 0 ? depth : 0, + Egl.STENCIL_SIZE, stencil > 0 ? stencil : 0, + + Egl.SAMPLE_BUFFERS, samples > 0 ? 1 : 0, + Egl.SAMPLES, samples > 0 ? samples : 0, + + Egl.NONE, + }; + + int numConfigs; + if (!Egl.ChooseConfig(display, attribList, configs, configs.Length, out numConfigs) || numConfigs == 0) + { + throw new GraphicsModeException(String.Format("Failed to retrieve GraphicsMode, error {0}", Egl.GetError())); + } + + // See what we really got + IntPtr activeConfig = configs[0]; + int r, g, b, a; + Egl.GetConfigAttrib(display, activeConfig, Egl.RED_SIZE, out r); + Egl.GetConfigAttrib(display, activeConfig, Egl.GREEN_SIZE, out g); + Egl.GetConfigAttrib(display, activeConfig, Egl.BLUE_SIZE, out b); + Egl.GetConfigAttrib(display, activeConfig, Egl.ALPHA_SIZE, out a); + int d, s; + Egl.GetConfigAttrib(display, activeConfig, Egl.DEPTH_SIZE, out d); + Egl.GetConfigAttrib(display, activeConfig, Egl.STENCIL_SIZE, out s); + int sampleBuffers; + Egl.GetConfigAttrib(display, activeConfig, Egl.SAMPLES, out sampleBuffers); + Egl.GetConfigAttrib(display, activeConfig, Egl.SAMPLES, out samples); + + return new GraphicsMode(activeConfig, new ColorFormat(r, g, b, a), d, s, sampleBuffers > 0 ? samples : 0, 0, 2, false); + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglMacPlatformFactory.cs b/GLWidget/OpenTK/Platform/Egl/EglMacPlatformFactory.cs new file mode 100644 index 0000000..a0e793f --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglMacPlatformFactory.cs @@ -0,0 +1,44 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; +using OpenTK.Platform.MacOS; + +namespace OpenTK.Platform.Egl +{ + internal class EglMacPlatformFactory : MacOSFactory + { + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + throw new NotImplementedException(); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + throw new NotImplementedException(); + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglUnixContext.cs b/GLWidget/OpenTK/Platform/Egl/EglUnixContext.cs new file mode 100644 index 0000000..2136978 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglUnixContext.cs @@ -0,0 +1,135 @@ +// +// EglUnixContext.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.Reflection; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + internal class EglUnixContext : EglContext + { + private IntPtr ES1 = OpenTK.Platform.X11.DL.Open("libGLESv1_CM", X11.DLOpenFlags.Lazy); + private IntPtr ES2 = OpenTK.Platform.X11.DL.Open("libGLESv2", X11.DLOpenFlags.Lazy); + private IntPtr GL = OpenTK.Platform.X11.DL.Open("libGL", X11.DLOpenFlags.Lazy); + + public EglUnixContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + : base(mode, window, sharedContext, major, minor, flags) + { + } + + public EglUnixContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + : base(handle, window, sharedContext, major, minor, flags) + { + } + + protected override IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable) + { + if ((renderable & (RenderableFlags.ES2 | RenderableFlags.ES3)) != 0 && ES2 != IntPtr.Zero) + { + return X11.DL.Symbol(ES2, function); + } + else if ((renderable & RenderableFlags.ES) != 0 && ES1 != IntPtr.Zero) + { + return X11.DL.Symbol(ES1, function); + } + else if ((renderable & RenderableFlags.GL) != 0 && GL != IntPtr.Zero) + { + return X11.DL.Symbol(GL, function); + } + return IntPtr.Zero; + } + + protected override void Dispose(bool manual) + { + if (ES1 != IntPtr.Zero) + { + X11.DL.Close(ES1); + } + if (ES2 != IntPtr.Zero) + { + X11.DL.Close(ES2); + } + if (GL != IntPtr.Zero) + { + X11.DL.Close(GL); + } + + GL = ES1 = ES2 = IntPtr.Zero; + + base.Dispose(manual); + } + + public override void LoadAll() + { + // Modern unices can use EGL to create + // both GL and ES contexts, so we need + // to load all entry points. This is + // especially true on KMS, Wayland and Mir. + + Stopwatch time = Stopwatch.StartNew(); + + 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 GTKBindingHelper(); + + 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"); + + Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds); + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglWinContext.cs b/GLWidget/OpenTK/Platform/Egl/EglWinContext.cs new file mode 100644 index 0000000..ac1ddc6 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglWinContext.cs @@ -0,0 +1,79 @@ +// +// EglWinContext.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + internal class EglWinContext : EglContext + { + private IntPtr ES1 = OpenTK.Platform.Windows.Functions.LoadLibrary("libGLESv1_CM"); + private IntPtr ES2 = OpenTK.Platform.Windows.Functions.LoadLibrary("libGLESv2"); + + public EglWinContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + : base(mode, window, sharedContext, major, minor, flags) + { + } + + public EglWinContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + : base(handle, window, sharedContext, major, minor, flags) + { + } + + protected override IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable) + { + if ((renderable & (RenderableFlags.ES2 | RenderableFlags.ES3)) != 0 && ES2 != IntPtr.Zero) + { + return Windows.Functions.GetProcAddress(ES2, function); + } + else if ((renderable & RenderableFlags.ES) != 0 && ES1 != IntPtr.Zero) + { + return Windows.Functions.GetProcAddress(ES1, function); + } + return IntPtr.Zero; + } + + protected override void Dispose(bool manual) + { + if (ES1 != IntPtr.Zero) + { + Windows.Functions.FreeLibrary(ES1); + } + if (ES2 != IntPtr.Zero) + { + Windows.Functions.FreeLibrary(ES2); + } + + ES1 = ES2 = IntPtr.Zero; + + base.Dispose(manual); + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Egl/EglWinPlatformFactory.cs b/GLWidget/OpenTK/Platform/Egl/EglWinPlatformFactory.cs new file mode 100644 index 0000000..115f95f --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglWinPlatformFactory.cs @@ -0,0 +1,70 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; +using OpenTK.Platform.Windows; + +namespace OpenTK.Platform.Egl +{ + // EGL factory for the Windows platform. + internal class EglWinPlatformFactory : WinFactory + { + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + WinWindowInfo win_win = (WinWindowInfo)window; + IntPtr egl_display = GetDisplay(win_win.DeviceContext); + EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(win_win.Handle, egl_display); + return new EglWinContext(mode, egl_win, shareContext, major, minor, flags); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + WinWindowInfo win_win = (WinWindowInfo)window; + IntPtr egl_display = GetDisplay(win_win.DeviceContext); + EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(win_win.Handle, egl_display); + return new EglWinContext(handle, egl_win, shareContext, major, minor, flags); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(Egl.GetCurrentContext()); + }; + } + + private IntPtr GetDisplay(IntPtr dc) + { + IntPtr display = Egl.GetDisplay(dc); + if (display == IntPtr.Zero) + { + display = Egl.GetDisplay(IntPtr.Zero); + } + + return display; + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglWindowInfo.cs b/GLWidget/OpenTK/Platform/Egl/EglWindowInfo.cs new file mode 100644 index 0000000..ecdec26 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglWindowInfo.cs @@ -0,0 +1,186 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Egl +{ + // Holds information about an EGL window. + internal class EglWindowInfo : IWindowInfo + { + private IntPtr surface; + private bool disposed; + + public EglWindowInfo(IntPtr handle, IntPtr display) + : this(handle, display, IntPtr.Zero) + { + } + + public EglWindowInfo(IntPtr handle, IntPtr display, IntPtr surface) + { + Handle = handle; + Surface = surface; + + if (display == IntPtr.Zero) + { + display = Egl.GetDisplay(IntPtr.Zero); + } + + Display = display; + + int dummyMajor, dummyMinor; + if (!Egl.Initialize(Display, out dummyMajor, out dummyMinor)) + { + throw new GraphicsContextException(String.Format("Failed to initialize EGL, error {0}.", Egl.GetError())); + } + } + + public IntPtr Handle { get; set; } + + public IntPtr Display { get; private set; } + + public IntPtr Surface { get { return surface; } private set { surface = value; } } + + public void CreateWindowSurface(IntPtr config) + { + Surface = Egl.CreateWindowSurface(Display, config, Handle, IntPtr.Zero); + if (Surface == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format( + "[EGL] Failed to create window surface, error {0}.", Egl.GetError())); + } + } + + //public void CreatePixmapSurface(EGLConfig config) + //{ + // Surface = Egl.CreatePixmapSurface(Display, config, Handle, null); + //} + + public void CreatePbufferSurface(IntPtr config) + { + int[] attribs = new int[]{Egl.NONE}; + Surface = Egl.CreatePbufferSurface(Display, config, attribs); + if (Surface == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format( + "[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError())); + } + } + + public void CreatePbufferSurface(IntPtr config, int width, int height) + { + if (surface != IntPtr.Zero) + { + DestroySurface(); + } + CreatePbufferSurface(config, width, height, out surface); + } + + public void CreatePbufferSurface(IntPtr config, int width, int height, out IntPtr bufferSurface) + { + int[] attribs = new int[] + { + Egl.WIDTH, width, + Egl.HEIGHT, height, + Egl.TEXTURE_TARGET, Egl.TEXTURE_2D, + Egl.TEXTURE_FORMAT, Egl.TEXTURE_RGBA, + Egl.NONE + }; + bufferSurface = Egl.CreatePbufferSurface(Display, config, attribs); + if (bufferSurface == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format( + "[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError())); + } + } + + public void DestroySurface() + { + DestroySurface(ref surface); + } + + public void DestroySurface(ref IntPtr bufferSurface) + { + if (bufferSurface == IntPtr.Zero) + { + return; + } + + if (Egl.GetCurrentSurface(Egl.DRAW) == Surface) + { + Egl.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + } + if (Egl.DestroySurface(Display, bufferSurface)) + { + bufferSurface = IntPtr.Zero; + return; + } + + Debug.Print("[Warning] Failed to destroy {0}:{1}.", Surface.GetType().Name, Surface); + Surface = IntPtr.Zero; + } + + public void TerminateDisplay() + { + if (Display != IntPtr.Zero) + { + if (!Egl.Terminate(Display)) + { + Debug.Print("[Warning] Failed to terminate display {0}.", Display); + } + Display = IntPtr.Zero; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + DestroySurface(); + disposed = true; + } + else + { + Debug.Print("[Warning] Failed to destroy {0}:{1}.", this.GetType().Name, Handle); + } + } + } + + ~EglWindowInfo() + { + Dispose(false); + } + } +} diff --git a/GLWidget/OpenTK/Platform/Egl/EglX11PlatformFactory.cs b/GLWidget/OpenTK/Platform/Egl/EglX11PlatformFactory.cs new file mode 100644 index 0000000..3e024b8 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Egl/EglX11PlatformFactory.cs @@ -0,0 +1,55 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using OpenTK.Graphics; +using OpenTK.Platform.X11; + +namespace OpenTK.Platform.Egl +{ + internal class EglX11PlatformFactory : X11Factory + { + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + X11WindowInfo x11_win = (X11WindowInfo)window; + EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(x11_win.Handle, Egl.GetDisplay(x11_win.Display)); + return new EglUnixContext(mode, egl_win, shareContext, major, minor, flags); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + X11WindowInfo x11_win = (X11WindowInfo)window; + EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(x11_win.Handle, Egl.GetDisplay(x11_win.Display)); + return new EglUnixContext(handle, egl_win, shareContext, major, minor, flags); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(Egl.GetCurrentContext()); + }; + } + } +} diff --git a/GLWidget/OpenTK/Platform/EmbeddedGraphicsContext.cs b/GLWidget/OpenTK/Platform/EmbeddedGraphicsContext.cs new file mode 100644 index 0000000..7a6fa0e --- /dev/null +++ b/GLWidget/OpenTK/Platform/EmbeddedGraphicsContext.cs @@ -0,0 +1,78 @@ + // + // The Open Toolkit Library License + // + // Copyright (c) 2006 - 2009 the Open Toolkit library. + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights to + // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + // the Software, and to permit persons to whom the Software is furnished to do + // so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + // OTHER DEALINGS IN THE SOFTWARE. + // + +using System.Diagnostics; +using System.Reflection; +using OpenTK.Graphics; + +namespace OpenTK.Platform +{ + // Provides the foundation for all desktop IGraphicsContext implementations. + internal abstract class EmbeddedGraphicsContext : GraphicsContextBase + { + public override void LoadAll() + { + // Modern unices can use EGL to create + // both GL and ES contexts, so we need + // to load all entry points. This is + // especially true on KMS, Wayland and Mir. + + Stopwatch time = Stopwatch.StartNew(); + + 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 GTKBindingHelper(); + + 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"); + + Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds); + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Factory.cs b/GLWidget/OpenTK/Platform/Factory.cs new file mode 100644 index 0000000..eba1ec3 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Factory.cs @@ -0,0 +1,192 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; + +namespace OpenTK.Platform +{ + using Graphics; + + internal sealed class Factory : IPlatformFactory + { + private bool disposed; + + static Factory() + { + Toolkit.Init(); + } + + public Factory() + { + // Ensure we are correctly initialized. + Toolkit.Init(); + + // Create regular platform backend + if (Configuration.RunningOnWindows) + { + Default = new Windows.WinFactory(); + } + else if (Configuration.RunningOnMacOS) + { + Default = new MacOS.MacOSFactory(); + } + else if (Configuration.RunningOnX11) + { + Default = new X11.X11Factory(); + } + else if (Configuration.RunningOnLinux) + { + Default = new Linux.LinuxFactory(); + } + if (Default == null) + { + Default = new UnsupportedPlatform(); + } + + if (Egl.Egl.IsSupported) + { + if (Configuration.RunningOnLinux) + { + Embedded = Default; + } + else if (Configuration.RunningOnX11) + { + Embedded = new Egl.EglX11PlatformFactory(); + } + else if (Configuration.RunningOnWindows) + { + Embedded = new Egl.EglWinPlatformFactory(); + } + else if (Configuration.RunningOnMacOS) + { + Embedded = new Egl.EglMacPlatformFactory(); + } + else + { + Embedded = new UnsupportedPlatform(); + } + Angle = new Egl.EglAnglePlatformFactory(Embedded); + } + else + { + Embedded = new UnsupportedPlatform(); + Angle = Embedded; + } + + if (Default is UnsupportedPlatform && !(Embedded is UnsupportedPlatform)) + { + Default = Embedded; + } + } + + public static IPlatformFactory Default { get; private set; } + + public static IPlatformFactory Embedded { get; private set; } + + public static IPlatformFactory Angle { get; private set; } + + public IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + return Default.CreateDisplayDeviceDriver(); + } + + public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return Default.CreateGLContext(mode, window, shareContext, directRendering, major, minor, flags); + } + + public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return Default.CreateGLContext(handle, window, shareContext, directRendering, major, minor, flags); + } + + public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return Default.CreateGetCurrentGraphicsContext(); + } + + public void RegisterResource(IDisposable resource) + { + Default.RegisterResource(resource); + } + + private class UnsupportedPlatform : PlatformFactoryBase + { + private static readonly string error_string = "Please, refer to http://www.opentk.com for more information."; + + public override IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + throw new PlatformNotSupportedException(error_string); + } + + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + throw new PlatformNotSupportedException(error_string); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + throw new PlatformNotSupportedException(error_string); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + throw new PlatformNotSupportedException(error_string); + } + } + + private void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + Default.Dispose(); + if (Embedded != Default) + { + Embedded.Dispose(); + } + } + else + { + Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType()); + } + disposed = true; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~Factory() + { + Dispose(false); + } + } +} diff --git a/GLWidget/OpenTK/Platform/IDisplayDeviceDriver.cs b/GLWidget/OpenTK/Platform/IDisplayDeviceDriver.cs new file mode 100644 index 0000000..8ae9c37 --- /dev/null +++ b/GLWidget/OpenTK/Platform/IDisplayDeviceDriver.cs @@ -0,0 +1,34 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace OpenTK.Platform +{ + internal interface IDisplayDeviceDriver + { + bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution); + bool TryRestoreResolution(DisplayDevice device); + DisplayDevice GetDisplay(DisplayIndex displayIndex); + } +} diff --git a/GLWidget/OpenTK/Platform/IPlatformFactory.cs b/GLWidget/OpenTK/Platform/IPlatformFactory.cs new file mode 100644 index 0000000..22b0e70 --- /dev/null +++ b/GLWidget/OpenTK/Platform/IPlatformFactory.cs @@ -0,0 +1,43 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using OpenTK.Graphics; + +namespace OpenTK.Platform +{ + internal interface IPlatformFactory : IDisposable + { + IDisplayDeviceDriver CreateDisplayDeviceDriver(); + + IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags); + + IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags); + + GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext(); + + void RegisterResource(IDisposable resource); + } +} diff --git a/GLWidget/OpenTK/Platform/IWindowInfo.cs b/GLWidget/OpenTK/Platform/IWindowInfo.cs new file mode 100644 index 0000000..ced32cd --- /dev/null +++ b/GLWidget/OpenTK/Platform/IWindowInfo.cs @@ -0,0 +1,19 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; + +namespace OpenTK.Platform +{ + /// Describes an OS window. + public interface IWindowInfo : IDisposable + { + /// + /// Retrieves a platform-specific handle to this window. + /// + IntPtr Handle { get; } + } +} diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Drm.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Drm.cs new file mode 100644 index 0000000..b803e91 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Drm.cs @@ -0,0 +1,209 @@ +// +// Drm.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +#pragma warning disable 0649 // field is never assigned + +namespace OpenTK.Platform.Linux +{ + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void VBlankCallback(int fd, + int sequence, + int tv_sec, + int tv_usec, + IntPtr user_data); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void PageFlipCallback(int fd, + int sequence, + int tv_sec, + int tv_usec, + IntPtr user_data); + + internal class Drm + { + private const string lib = "libdrm"; + + [DllImport(lib, EntryPoint = "drmHandleEvent", CallingConvention = CallingConvention.Cdecl)] + public static extern int HandleEvent(int fd, ref EventContext evctx); + + [DllImport(lib, EntryPoint = "drmModeAddFB", CallingConvention = CallingConvention.Cdecl)] + public static extern int ModeAddFB(int fd, int width, int height, byte depth, + byte bpp, int pitch, int bo_handle, + out int buf_id); + + [DllImport(lib, EntryPoint = "drmModeRmFB", CallingConvention = CallingConvention.Cdecl)] + public static extern int ModeRmFB(int fd, int bufferId); + + [DllImport(lib, EntryPoint = "drmModeFreeCrtc", CallingConvention = CallingConvention.Cdecl)] + public static extern void ModeFreeCrtc(IntPtr ptr); + + [DllImport(lib, EntryPoint = "drmModeGetCrtc", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ModeGetCrtc(int fd, int crtcId); + + [DllImport(lib, EntryPoint = "drmModeFreeConnector", CallingConvention = CallingConvention.Cdecl)] + public static extern void ModeFreeConnector(IntPtr ptr); + + [DllImport(lib, EntryPoint = "drmModeFreeEncoder", CallingConvention = CallingConvention.Cdecl)] + public static extern void ModeFreeEncoder(IntPtr ptr); + + [DllImport(lib, EntryPoint = "drmModeGetConnector", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ModeGetConnector(int fd, int connector_id); + + [DllImport(lib, EntryPoint = "drmModeGetEncoder", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ModeGetEncoder(int fd, int encoder_id); + + [DllImport(lib, EntryPoint = "drmModeGetResources", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ModeGetResources(int fd); + + [DllImport(lib, EntryPoint = "drmModePageFlip", CallingConvention = CallingConvention.Cdecl)] + public static extern int ModePageFlip(int fd, int crtc_id, int fb_id, + PageFlipFlags flags, IntPtr user_data); + + [DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)] + unsafe public static extern int ModeSetCrtc(int fd, int crtcId, int bufferId, + int x, int y, int* connectors, int count, ModeInfo* mode); + + [DllImport(lib, EntryPoint = "drmModeSetCursor2", CallingConvention = CallingConvention.Cdecl)] + public static extern int SetCursor(int fd, int crtcId, int bo_handle, int width, int height, int hot_x, int hot_y); + + [DllImport(lib, EntryPoint = "drmModeMoveCursor", CallingConvention = CallingConvention.Cdecl)] + public static extern int MoveCursor(int fd, int crtcId, int x, int y); + + } + + internal enum ModeConnection + { + Connected = 1, + Disconnected = 2, + Unknown = 3 + } + + internal enum ModeSubPixel + { + Unknown = 1, + HorizontalRgb = 2, + HorizontalBgr = 3, + VerticalRgb = 4, + VerticalBgr = 5, + None = 6 + } + + [Flags] + internal enum PageFlipFlags + { + FlipEvent = 0x01, + FlipAsync = 0x02, + FlipFlags = FlipEvent | FlipAsync + } + + [StructLayout(LayoutKind.Sequential)] + internal struct EventContext + { + public int version; + public IntPtr vblank_handler; + public IntPtr page_flip_handler; + + public static readonly int Version = 2; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct ModeConnector + { + public int connector_id; + public int encoder_id; + public int connector_type; + public int connector_type_id; + public ModeConnection connection; + public int mmWidth, mmHeight; + public ModeSubPixel subpixel; + + public int count_modes; + public ModeInfo* modes; + + public int count_props; + public int *props; + public long *prop_values; + + public int count_encoders; + public int *encoders; + } + + internal struct ModeCrtc + { + public int crtc_id; + public int buffer_id; + + public int x, y; + public int width, height; + public int mode_valid; + public ModeInfo mode; + + public int gamma_size; + } + + internal struct ModeEncoder + { + public int encoder_id; + public int encoder_type; + public int crtc_id; + public int possible_crtcs; + public int possible_clones; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct ModeInfo + { + public uint clock; + public ushort hdisplay, hsync_start, hsync_end, htotal, hskew; + public ushort vdisplay, vsync_start, vsync_end, vtotal, vscan; + + public int vrefresh; // refresh rate * 1000 + + public uint flags; + public uint type; + public fixed sbyte name[32]; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct ModeRes + { + public int count_fbs; + public int* fbs; + public int count_crtcs; + public int* crtcs; + public int count_connectors; + public int* connectors; + public int count_encoders; + public int* encoders; + public int min_width, max_width; + public int min_height, max_height; + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Gbm.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Gbm.cs new file mode 100644 index 0000000..699da27 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Gbm.cs @@ -0,0 +1,272 @@ +// +// Gbm.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Linux +{ + using Device = IntPtr; // struct gbm_device* + using Surface = IntPtr; + using BufferObjectHandle = IntPtr; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void DestroyUserDataCallback(BufferObject bo, IntPtr data); + + internal class Gbm + { + private const string lib = "gbm"; + + [DllImport(lib, EntryPoint = "gbm_bo_create", CallingConvention = CallingConvention.Cdecl)] + public static extern BufferObject CreateBuffer(Device gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags); + + [DllImport(lib, EntryPoint = "gbm_bo_destroy", CallingConvention = CallingConvention.Cdecl)] + public static extern void DestroyBuffer(BufferObject bo); + + [DllImport(lib, EntryPoint = "gbm_bo_write", CallingConvention = CallingConvention.Cdecl)] + public static extern int BOWrite(IntPtr bo, IntPtr buf, IntPtr count); + + [DllImport(lib, EntryPoint = "gbm_bo_get_device", CallingConvention = CallingConvention.Cdecl)] + public static extern Device BOGetDevice(IntPtr bo); + + [DllImport(lib, EntryPoint = "gbm_bo_get_handle", CallingConvention = CallingConvention.Cdecl)] + public static extern BufferObjectHandle BOGetHandle(IntPtr bo); + + [DllImport(lib, EntryPoint = "gbm_bo_get_height", CallingConvention = CallingConvention.Cdecl)] + public static extern int BOGetHeight(IntPtr bo); + + [DllImport(lib, EntryPoint = "gbm_bo_get_width", CallingConvention = CallingConvention.Cdecl)] + public static extern int BOGetWidth(IntPtr bo); + + [DllImport(lib, EntryPoint = "gbm_bo_get_stride", CallingConvention = CallingConvention.Cdecl)] + public static extern int BOGetStride(IntPtr bo); + + [DllImport(lib, EntryPoint = "gbm_bo_set_user_data", CallingConvention = CallingConvention.Cdecl)] + public static extern void BOSetUserData(IntPtr bo, IntPtr data, DestroyUserDataCallback callback); + + [DllImport(lib, EntryPoint = "gbm_create_device", CallingConvention = CallingConvention.Cdecl)] + public static extern Device CreateDevice(int fd); + + [DllImport(lib, EntryPoint = "gbm_device_destroy", CallingConvention = CallingConvention.Cdecl)] + public static extern void DestroyDevice(Device gbm); + + [DllImport(lib, EntryPoint = "gbm_device_get_fd", CallingConvention = CallingConvention.Cdecl)] + public static extern int DeviceGetFD(IntPtr gbm); + + [DllImport(lib, EntryPoint = "gbm_surface_create", CallingConvention = CallingConvention.Cdecl)] + public static extern Surface CreateSurface(Device gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags); + + [DllImport(lib, EntryPoint = "gbm_surface_destroy", CallingConvention = CallingConvention.Cdecl)] + public static extern void DestroySurface(IntPtr surface); + + [DllImport(lib, EntryPoint = "gbm_device_is_format_supported", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsFormatSupported(Device gbm, SurfaceFormat format, SurfaceFlags usage); + + [DllImport(lib, EntryPoint = "gbm_surface_lock_front_buffer", CallingConvention = CallingConvention.Cdecl)] + public static extern BufferObject LockFrontBuffer(Surface surface); + + [DllImport(lib, EntryPoint = "gbm_surface_release_buffer", CallingConvention = CallingConvention.Cdecl)] + public static extern void ReleaseBuffer(Surface surface, BufferObject buffer); + } + + internal enum SurfaceFormat + { + BigEndian = 1 << 31, + C8 = ((int)('C') | ((int)('8') << 8) | ((int)(' ') << 16) | ((int)(' ') << 24)), + + RGB332 = ((int)('R') | ((int)('G') << 8) | ((int)('B') << 16) | ((int)('8') << 24)), + BGR233 = ((int)('B') | ((int)('G') << 8) | ((int)('R') << 16) | ((int)('8') << 24)), + + XRGB4444 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + XBGR4444 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + RGBX4444 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + BGRX4444 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + + ARGB4444 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + ABGR4444 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + RGBA4444 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + BGRA4444 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + + XRGB1555 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + XBGR1555 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + RGBX5551 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + BGRX5551 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + + ARGB1555 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + ABGR1555 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + RGBA5551 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + BGRA5551 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)), + + RGB565 = ((int)('R') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)), + BGR565 = ((int)('B') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)), + + RGB888 = ((int)('R') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + BGR888 = ((int)('B') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + + XRGB8888 = ((int)('X') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + XBGR8888 = ((int)('X') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + RGBX8888 = ((int)('R') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + BGRX8888 = ((int)('B') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + + ARGB8888 = ((int)('A') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + ABGR8888 = ((int)('A') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + RGBA8888 = ((int)('R') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + BGRA8888 = ((int)('B') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + + XRGB2101010 = ((int)('X') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + XBGR2101010 = ((int)('X') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + RGBX1010102 = ((int)('R') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + BGRX1010102 = ((int)('B') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + + ARGB2101010 = ((int)('A') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + ABGR2101010 = ((int)('A') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + RGBA1010102 = ((int)('R') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + BGRA1010102 = ((int)('B') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)), + + YUYV = ((int)('Y') | ((int)('U') << 8) | ((int)('Y') << 16) | ((int)('V') << 24)), + YVYU = ((int)('Y') | ((int)('V') << 8) | ((int)('Y') << 16) | ((int)('U') << 24)), + UYVY = ((int)('U') | ((int)('Y') << 8) | ((int)('V') << 16) | ((int)('Y') << 24)), + VYUY = ((int)('V') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('Y') << 24)), + + AYUV = ((int)('A') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('V') << 24)), + + NV12 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + NV21 = ((int)('N') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('1') << 24)), + NV16 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)), + NV61 = ((int)('N') | ((int)('V') << 8) | ((int)('6') << 16) | ((int)('1') << 24)), + + YUV410 = ((int)('Y') | ((int)('U') << 8) | ((int)('V') << 16) | ((int)('9') << 24)), + YVU410 = ((int)('Y') | ((int)('V') << 8) | ((int)('U') << 16) | ((int)('9') << 24)), + YUV411 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('1') << 24)), + YVU411 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('1') << 24)), + YUV420 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + YVU420 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)), + YUV422 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('6') << 24)), + YVU422 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)), + YUV444 = ((int)('Y') | ((int)('U') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + YVU444 = ((int)('Y') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('4') << 24)), + } + + [Flags] + internal enum SurfaceFlags + { + Scanout = (1 << 0), + Cursor64x64 = (1 << 1), + Rendering = (1 << 2), + Write = (1 << 3), + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BufferObject : IEquatable + { + private IntPtr buffer; + + public static readonly BufferObject Zero = + default(BufferObject); + + public int Write(byte[] data) + { + unsafe + { + fixed (byte* pdata = data) + { + return Gbm.BOWrite(buffer, (IntPtr)pdata, (IntPtr)data.Length); + } + } + } + + public void SetUserData(IntPtr data, DestroyUserDataCallback destroyFB) + { + Gbm.BOSetUserData(buffer, data, destroyFB); + } + + public Device Device + { + get { return Gbm.BOGetDevice(buffer); } + } + + public int Handle + { + get { return Gbm.BOGetHandle(buffer).ToInt32(); } + } + + public int Width + { + get { return Gbm.BOGetWidth(buffer); } + } + + public int Height + { + get { return Gbm.BOGetHeight(buffer); } + } + + public int Stride + { + get { return Gbm.BOGetStride(buffer); } + } + + public void Dispose() + { + Gbm.DestroyBuffer(this); + buffer = IntPtr.Zero; + } + + public static bool operator ==(BufferObject left, BufferObject right) + { + return left.Equals(right); + } + + public static bool operator !=(BufferObject left, BufferObject right) + { + return !left.Equals(right); + } + + public override bool Equals(object obj) + { + return + obj is BufferObject && + this.Equals((BufferObject)obj); + } + + public override int GetHashCode() + { + return buffer.GetHashCode(); + } + + public override string ToString() + { + return string.Format("[BufferObject: {0}]", buffer); + } + + public bool Equals(BufferObject other) + { + return buffer == other.buffer; + } + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Kms.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Kms.cs new file mode 100644 index 0000000..c9c17cc --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Kms.cs @@ -0,0 +1,44 @@ +// +// Kms.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Linux +{ + internal class Kms + { + private const string lib = "libkms"; + + [DllImport(lib, EntryPoint = "kms_bo_map", CallingConvention = CallingConvention.Cdecl)] + public static extern int MapBuffer(IntPtr bo, out IntPtr @out); + + [DllImport(lib, EntryPoint = "kms_bo_unmap", CallingConvention = CallingConvention.Cdecl)] + public static extern int UnmapBuffer(IntPtr bo); + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Libc.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Libc.cs new file mode 100644 index 0000000..cb1faa5 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Libc.cs @@ -0,0 +1,181 @@ +// +// Linux.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; +using System.Text; + +#pragma warning disable 0649 // field is never assigned + +namespace OpenTK.Platform.Linux +{ + internal partial class Libc + { + private const string lib = "libc"; + + [DllImport(lib)] + public static extern int dup(int file); + + [DllImport(lib)] + public static extern int dup2(int file1, int file2); + + [DllImport(lib)] + public static extern int ioctl(int d, JoystickIoctlCode request, ref int data); + + [DllImport(lib)] + public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data); + + [DllImport(lib)] + public static extern int ioctl(int d, uint request, [Out] IntPtr data); + + [DllImport(lib)] + public static extern int ioctl(int d, KeyboardIoctlCode request, ref IntPtr data); + + [DllImport(lib)] + public static extern int ioctl(int d, KeyboardIoctlCode request, int data); + + [DllImport(lib)] + public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags); + + [DllImport(lib)] + public static extern int open(IntPtr pathname, OpenFlags flags); + + [DllImport(lib)] + public static extern int close(int fd); + + [DllImport(lib)] + unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count); + + public static int read(int fd, out byte b) + { + unsafe + { + fixed (byte* pb = &b) + { + return read(fd, pb, (UIntPtr)1).ToInt32(); + } + } + } + + public static int read(int fd, out short s) + { + unsafe + { + fixed (short* ps = &s) + { + return read(fd, ps, (UIntPtr)2).ToInt32(); + } + } + } + + [DllImport(lib)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool isatty(int fd); + } + + internal enum ErrorNumber + { + Interrupted = 4, + Again = 11, + InvalidValue = 22, + } + + [Flags] + internal enum DirectionFlags + { + None = 0, + Write = 1, + Read = 2 + } + + [Flags] + internal enum OpenFlags + { + ReadOnly = 0x0000, + WriteOnly = 0x0001, + ReadWrite = 0x0002, + NonBlock = 0x0800, + CloseOnExec = 0x0080000 + } + + [Flags] + internal enum JoystickEventType : byte + { + Button = 0x01, // button pressed/released + Axis = 0x02, // joystick moved + Init = 0x80 // initial state of device + } + + internal enum JoystickIoctlCode : uint + { + Version = 0x80046a01, + Axes = 0x80016a11, + Buttons = 0x80016a12, + Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len) + } + + internal enum KeyboardIoctlCode + { + GetMode = 0x4b44, + SetMode = 0x4b45, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Stat + { + public IntPtr dev; /* ID of device containing file */ + public IntPtr ino; /* inode number */ + public IntPtr mode; /* protection */ + public IntPtr nlink; /* number of hard links */ + public IntPtr uid; /* user ID of owner */ + public IntPtr gid; /* group ID of owner */ + public IntPtr rdev; /* device ID (if special file) */ + public IntPtr size; /* total size, in bytes */ + public IntPtr blksize; /* blocksize for file system I/O */ + public IntPtr blocks; /* number of 512B blocks allocated */ + public IntPtr atime; /* time of last access */ + public IntPtr mtime; /* time of last modification */ + public IntPtr ctime; /* time of last status change */ + } + + internal struct EvdevInputId + { + public ushort BusType; + public ushort Vendor; + public ushort Product; + public ushort Version; + } + + internal struct JoystickEvent + { + public uint Time; // (u32) event timestamp in milliseconds + public short Value; // (s16) value + public JoystickEventType Type; // (u8) event type + public byte Number; // (u8) axis/button number + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Poll.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Poll.cs new file mode 100644 index 0000000..2c7e8e2 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Poll.cs @@ -0,0 +1,63 @@ +// +// Poll.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Linux +{ + internal partial class Libc + { + [DllImport("libc", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + public static extern int poll(ref PollFD fd, IntPtr fd_count, int timeout); + + public static int poll(ref PollFD fd, int fd_count, int timeout) + { + return poll(ref fd, (IntPtr)fd_count, timeout); + } + } + + [Flags] + internal enum PollFlags : short + { + In = 0x01, + Pri = 0x02, + Out = 0x04, + Error = 0x08, + Hup = 0x10, + Invalid = 0x20, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct PollFD + { + public int fd; + public PollFlags events; + public PollFlags revents; + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Terminal.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Terminal.cs new file mode 100644 index 0000000..e83786b --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Terminal.cs @@ -0,0 +1,168 @@ +// +// Terminal.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Linux +{ + internal class Terminal + { + private const string lib = "libc"; + + [DllImport(lib, EntryPoint = "isatty", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I4)] + public static extern bool IsTerminal(int fd); + + [DllImport(lib, EntryPoint = "tcgetattr", CallingConvention = CallingConvention.Cdecl)] + public static extern int GetAttributes(int fd, out TerminalState state); + + [DllImport(lib, EntryPoint = "tcsetattr", CallingConvention = CallingConvention.Cdecl)] + public static extern int SetAttributes(int fd, OptionalActions actions, ref TerminalState state); + } + + [Flags] + internal enum InputFlags + { + IGNBRK = 1 << 0, + BRKINT = 1 << 1, + IGNPAR = 1 << 2, + PARMRK = 1 << 3, + INPCK = 1 << 4, + ISTRIP = 1 << 5, + INLCR = 1 << 6, + IGNCR = 1 << 7, + ICRNL = 1 << 8, + IUCLC = 1 << 9, + IXON = 1 << 10, + IXANY = 1 << 11, + IXOFF = 1 << 12, + IMAXBEL = 1 << 13, + IUTF8 = 1 << 14, + } + + [Flags] + internal enum OutputFlags + { + OPOST = 1 << 1, + OLCUC = 1 << 2, + ONLCR = 1 << 3, + OCRNL = 1 << 4, + ONOCR = 1 << 5, + ONLRET = 1 << 6, + OFILL = 1 << 7, + OFDEL = 1 << 8, + } + + [Flags] + internal enum ControlFlags + { + B0 = 0, // hang up + B50, + B75, + B110, + B134, + B150, + B200, + B300, + B600, + B1200, + B1800, + B2400, + B4800, + B9600, + B19200, + B38400, + } + + [Flags] + internal enum LocalFlags + { + ISIG = 0x01, + ICANON = 0x02, + ECHO = 0x08, + } + + internal enum OptionalActions + { + NOW = 0, + DRAIN = 1, + FLUSH = 2 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TerminalState + { + public InputFlags InputMode; + public OutputFlags OutputMode; + public ControlFlags ControlMode; + public LocalFlags LocalMode; + public byte LineDiscipline; + public ControlCharacters ControlCharacters; + public int InputSpeed; + public int OutputSpeed; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ControlCharacters + { + public byte VINTR; + public byte VQUIT; + public byte VERASE; + public byte VKILL; + public byte VEOF; + public byte VTIME; + public byte VMIN; + public byte VSWTC; + public byte VSTART; + public byte VSTOP; + public byte VSUSP; + public byte VEOL; + public byte VREPRINT; + public byte VDISCARD; + public byte VWERASE; + public byte VLNEXT; + public byte VEOL2; + public byte C17; + public byte C18; + public byte C19; + public byte C20; + public byte C21; + public byte C22; + public byte C23; + public byte C24; + public byte C25; + public byte C26; + public byte C27; + public byte C28; + public byte C29; + public byte C30; + public byte C31; + + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/Bindings/Udev.cs b/GLWidget/OpenTK/Platform/Linux/Bindings/Udev.cs new file mode 100644 index 0000000..5171d9a --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/Bindings/Udev.cs @@ -0,0 +1,44 @@ +// +// Udev.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Linux +{ + internal class Udev + { + private const string lib = "libudev"; + + [DllImport(lib, EntryPoint = "udev_new", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr New(); + + [DllImport(lib, EntryPoint = "udev_destroy", CallingConvention = CallingConvention.Cdecl)] + public static extern void Destroy(IntPtr Udev); + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/LinuxDisplayDriver.cs b/GLWidget/OpenTK/Platform/Linux/LinuxDisplayDriver.cs new file mode 100644 index 0000000..dec3b60 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/LinuxDisplayDriver.cs @@ -0,0 +1,413 @@ +// +// LinuxDisplayDriver.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; + +namespace OpenTK.Platform.Linux +{ + // Stores platform-specific information about a display + internal class LinuxDisplay + { + public int FD; + public IntPtr Connector; + public IntPtr Crtc; + public IntPtr Encoder; + + unsafe public ModeConnector* pConnector { get { return (ModeConnector*)Connector; } } + unsafe public ModeCrtc* pCrtc { get { return (ModeCrtc*)Crtc; } } + unsafe public ModeEncoder* pEncoder { get { return (ModeEncoder*)Encoder; } } + /* + public ModeInfo Mode + { + get + { + if (Crtc == IntPtr.Zero) + throw new InvalidOperationException(); + + unsafe + { + return pCrtc->mode; + } + } + } + */ + + public ModeInfo OriginalMode; + + public int Id + { + get + { + if (Crtc == IntPtr.Zero) + { + throw new InvalidOperationException(); + } + + unsafe + { + return (int)pCrtc->crtc_id; + } + } + } + + public LinuxDisplay(int fd, IntPtr c, IntPtr e, IntPtr r) + { + FD = fd; + Connector = c; + Encoder = e; + Crtc = r; + unsafe + { + OriginalMode = pCrtc->mode; // in case we change resolution later on + } + } + } + + internal class LinuxDisplayDriver : DisplayDeviceBase + { + private readonly int FD; + + private readonly Dictionary DisplayIds = + new Dictionary(); + + public LinuxDisplayDriver(int fd) + { + Debug.Print("[KMS] Creating LinuxDisplayDriver for fd:{0}", fd); + Debug.Indent(); + try + { + FD = fd; + UpdateDisplays(fd); + } + finally + { + Debug.Unindent(); + } + } + + /// \internal + /// + /// Queries the specified GPU for connected displays and, optionally, + /// returns the list of displays. + /// + /// true, if at least one display is connected, false otherwise. + /// The fd for the GPU to query, obtained through open("/dev/dri/card0"). + /// + /// If not null, this will contain a list instances, + /// one for each connected display. + /// + internal static bool QueryDisplays(int fd, List displays) + { + unsafe + { + bool has_displays = false; + if (displays != null) + { + displays.Clear(); + } + + ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd); + if (resources == null) + { + Debug.Print("[KMS] Drm.ModeGetResources failed."); + return false; + } + Debug.Print("[KMS] DRM found {0} connectors", resources->count_connectors); + + // Search for a valid connector + ModeConnector* connector = null; + for (int i = 0; i < resources->count_connectors; i++) + { + connector = (ModeConnector*)Drm.ModeGetConnector(fd, + *(resources->connectors + i)); + if (connector != null) + { + bool success = false; + LinuxDisplay display = null; + try + { + if (connector->connection == ModeConnection.Connected && + connector->count_modes > 0) + { + success = QueryDisplay(fd, connector, out display); + has_displays |= success; + } + } + catch (Exception e) + { + Debug.Print("[KMS] Failed to add display. Error: {0}", e); + } + + if (success && displays != null) + { + displays.Add(display); + } + else + { + Drm.ModeFreeConnector((IntPtr)connector); + connector = null; + } + } + } + + return has_displays; + } + } + + private void UpdateDisplays(int fd) + { + unsafe + { + lock (this) + { + AvailableDevices.Clear(); + DisplayIds.Clear(); + + List displays = new List(); + if (QueryDisplays(fd, displays)) + { + foreach (LinuxDisplay display in displays) + { + AddDisplay(display); + } + } + + if (AvailableDevices.Count == 0) + { + Debug.Print("[KMS] Failed to find any active displays"); + } + } + } + } + + private unsafe static ModeEncoder* GetEncoder(int fd, ModeConnector* c) + { + ModeEncoder* encoder = null; + for (int i = 0; i < c->count_encoders && encoder == null; i++) + { + ModeEncoder* e = (ModeEncoder*)Drm.ModeGetEncoder( + fd, *(c->encoders + i)); + if (e != null) + { + if (e->encoder_id == c->encoder_id) + { + encoder = e; + } + else + { + Drm.ModeFreeEncoder((IntPtr)e); + } + } + } + + if (encoder != null) + { + Debug.Print("[KMS] Encoder {0} found for connector {1}", + encoder->encoder_id, c->connector_id); + } + else + { + Debug.Print("[KMS] Failed to find encoder for connector {0}", c->connector_id); + } + + return encoder; + } + + private unsafe static ModeCrtc* GetCrtc(int fd, ModeEncoder* encoder) + { + ModeCrtc* crtc = (ModeCrtc*)Drm.ModeGetCrtc(fd, encoder->crtc_id); + if (crtc != null) + { + Debug.Print("[KMS] CRTC {0} found for encoder {1}", + encoder->crtc_id, encoder->encoder_id); + } + else + { + Debug.Print("[KMS] Failed to find crtc {0} for encoder {1}", + encoder->crtc_id, encoder->encoder_id); + } + return crtc; + } + + private unsafe static void GetModes(LinuxDisplay display, DisplayResolution[] modes, out DisplayResolution current) + { + int mode_count = display.pConnector->count_modes; + Debug.Print("[KMS] Display supports {0} mode(s)", mode_count); + for (int i = 0; i < mode_count; i++) + { + ModeInfo* mode = display.pConnector->modes + i; + if (mode != null) + { + Debug.Print("Mode {0}: {1}x{2} @{3}", i, + mode->hdisplay, mode->vdisplay, mode->vrefresh); + DisplayResolution res = GetDisplayResolution(mode); + modes[i] = res; + } + } + + if (display.pCrtc->mode_valid != 0) + { + ModeInfo cmode = display.pCrtc->mode; + current = GetDisplayResolution(&cmode); + } + else + { + current = GetDisplayResolution(display.pConnector->modes); + } + Debug.Print("Current mode: {0}", current.ToString()); + } + + private Rectangle GetBounds(DisplayResolution current) + { + // Note: since we are not running a display manager, we are free + // to choose the display layout for multiple displays ourselves. + // We choose the simplest layout: displays are laid out side-by-side + // from left to right. Primary display is the first display we encounter. + int x = AvailableDevices.Count == 0 ? + 0 : AvailableDevices[AvailableDevices.Count - 1].Bounds.Right; + int y = 0; + + return new Rectangle( + x, y, current.Width, current.Height); + } + + private void UpdateDisplayIndices(LinuxDisplay display, DisplayDevice device) + { + if (!DisplayIds.ContainsKey(display.Id)) + { + Debug.Print("[KMS] Adding display {0} as {1}", display.Id, AvailableDevices.Count); + DisplayIds.Add(display.Id, AvailableDevices.Count); + } + int index = DisplayIds[display.Id]; + if (index >= AvailableDevices.Count) + { + AvailableDevices.Add(device); + } + else + { + AvailableDevices[index] = device; + } + } + + private unsafe static bool QueryDisplay(int fd, ModeConnector* c, out LinuxDisplay display) + { + display = null; + + // Find corresponding encoder + ModeEncoder* encoder = GetEncoder(fd, c); + if (encoder == null) + { + return false; + } + + ModeCrtc* crtc = GetCrtc(fd, encoder); + if (crtc == null) + { + return false; + } + + display = new LinuxDisplay(fd, (IntPtr)c, (IntPtr)encoder, (IntPtr)crtc); + return true; + } + + private unsafe void AddDisplay(LinuxDisplay display) + { + DisplayResolution[] modes = new DisplayResolution[display.pConnector->count_modes]; + DisplayResolution current; + GetModes(display, modes, out current); + + bool is_primary = AvailableDevices.Count == 0; + DisplayDevice device = new DisplayDevice(current, is_primary, + modes, GetBounds(current), display); + + if (is_primary) + { + Primary = device; + } + + UpdateDisplayIndices(display, device); + + Debug.Print("[KMS] Added DisplayDevice {0}", device); + } + + private unsafe static DisplayResolution GetDisplayResolution(ModeInfo* mode) + { + return new DisplayResolution( + 0, 0, + mode->hdisplay, mode->vdisplay, + 32, // This is actually part of the framebuffer, not the DisplayResolution + mode->vrefresh); + } + + private unsafe static ModeInfo* GetModeInfo(LinuxDisplay display, DisplayResolution resolution) + { + for (int i = 0; i < display.pConnector->count_modes; i++) + { + ModeInfo* mode = display.pConnector->modes + i; + if (mode != null && + mode->hdisplay == resolution.Width && + mode->vdisplay == resolution.Height) + { + return mode; + } + } + return null; + } + + public override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + { + unsafe + { + LinuxDisplay display = (LinuxDisplay)device.Id; + ModeInfo* mode = GetModeInfo(display, resolution); + int connector_id = display.pConnector->connector_id; + if (mode != null) + { + return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0, + &connector_id, 1, mode) == 0; + } + return false; + } + } + + public override bool TryRestoreResolution(DisplayDevice device) + { + unsafe + { + LinuxDisplay display = (LinuxDisplay)device.Id; + ModeInfo mode = display.OriginalMode; + int connector_id = display.pConnector->connector_id; + return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0, + &connector_id, 1, &mode) == 0; + } + } + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/LinuxFactory.cs b/GLWidget/OpenTK/Platform/Linux/LinuxFactory.cs new file mode 100644 index 0000000..c51c61f --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/LinuxFactory.cs @@ -0,0 +1,197 @@ +// +// LinuxFactory.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.IO; +using OpenTK.Graphics; +using OpenTK.Platform.Egl; + +namespace OpenTK.Platform.Linux +{ + using Egl = OpenTK.Platform.Egl.Egl; + + // Linux KMS platform + internal class LinuxFactory : PlatformFactoryBase + { + private int _fd; + private IntPtr gbm_device; + private IntPtr egl_display; + + private const string gpu_path = "/dev/dri"; // card0, card1, ... + + public LinuxFactory() + { + Debug.Print("[KMS] Using Linux/KMS backend."); + } + + private int gpu_fd + { + get + { + lock (this) + { + if (_fd == 0) + { + _fd = CreateDisplay(out gbm_device, out egl_display); + } + return _fd; + } + } + } + + private static int CreateDisplay(out IntPtr gbm_device, out IntPtr egl_display) + { + // Query all GPUs until we find one that has a connected display. + // This is necessary in multi-gpu systems, where only one GPU + // can output a signal. + // Todo: allow OpenTK to drive multiple GPUs + // Todo: allow OpenTK to run on an offscreen GPU + // Todo: allow the user to pick a GPU + int fd = 0; + gbm_device = IntPtr.Zero; + egl_display = IntPtr.Zero; + + var files = Directory.GetFiles(gpu_path); + foreach (var gpu in files) + { + if (Path.GetFileName(gpu).StartsWith("card")) + { + int test_fd = SetupDisplay(gpu, out gbm_device, out egl_display); + if (test_fd >= 0) + { + try + { + if (LinuxDisplayDriver.QueryDisplays(test_fd, null)) + { + fd = test_fd; + break; + } + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + + Debug.Print("[KMS] GPU '{0}' is not connected, skipping.", gpu); + Libc.close(test_fd); + } + } + } + + if (fd == 0) + { + Debug.Print("[Error] No valid GPU found, bailing out."); + throw new PlatformNotSupportedException(); + } + + return fd; + } + + private static int SetupDisplay(string gpu, out IntPtr gbm_device, out IntPtr egl_display) + { + Debug.Print("[KMS] Attempting to use gpu '{0}'.", gpu); + + gbm_device = IntPtr.Zero; + egl_display = IntPtr.Zero; + + int fd = Libc.open(gpu, OpenFlags.ReadWrite | OpenFlags.CloseOnExec); + if (fd < 0) + { + Debug.Print("[KMS] Failed to open gpu"); + return fd; + } + Debug.Print("[KMS] GPU '{0}' opened as fd:{1}", gpu, fd); + + gbm_device = Gbm.CreateDevice(fd); + if (gbm_device == IntPtr.Zero) + { + throw new NotSupportedException("[KMS] Failed to create GBM device"); + } + Debug.Print("[KMS] GBM {0:x} created successfully; ", gbm_device); + + egl_display = Egl.GetDisplay(gbm_device); + if (egl_display == IntPtr.Zero) + { + throw new NotSupportedException("[KMS] Failed to create EGL display"); + } + Debug.Print("[KMS] EGL display {0:x} created successfully", egl_display); + + int major, minor; + if (!Egl.Initialize(egl_display, out major, out minor)) + { + ErrorCode error = Egl.GetError(); + throw new NotSupportedException("[KMS] Failed to initialize EGL display. Error code: " + error); + } + Debug.Print("[KMS] EGL {0}.{1} initialized successfully on display {2:x}", major, minor, egl_display); + + return fd; + } + + protected override void Dispose(bool manual) + { + if (egl_display != IntPtr.Zero) + { + Debug.Print("[KMS] Terminating EGL."); + Egl.Terminate(egl_display); + egl_display = IntPtr.Zero; + } + if (gbm_device != IntPtr.Zero) + { + Debug.Print("[KMS] Destroying GBM device."); + Gbm.DestroyDevice(gbm_device); + gbm_device = IntPtr.Zero; + } + if (_fd >= 0) + { + Debug.Print("[KMS] Closing GPU fd."); + Libc.close(_fd); + } + + base.Dispose(manual); + } + + public override IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + return new LinuxDisplayDriver(gpu_fd); + } + + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return new LinuxGraphicsContext(mode, (LinuxWindowInfo)window, shareContext, major, minor, flags); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(Egl.GetCurrentContext()); + }; + } + } +} + diff --git a/GLWidget/OpenTK/Platform/Linux/LinuxGraphicsContext.cs b/GLWidget/OpenTK/Platform/Linux/LinuxGraphicsContext.cs new file mode 100644 index 0000000..efc4cb3 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/LinuxGraphicsContext.cs @@ -0,0 +1,318 @@ +// +// LinuxGraphicsContext.cs +// +// Author: +// thefiddler +// +// Copyright (c) 2006-2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Linux +{ + /// \internal + /// + /// Defines an IGraphicsContext implementation for the Linux KMS framebuffer. + /// For Linux/X11 and other Unix operating systems, use the more generic + /// instead. + /// + /// + /// Note: to display our results, we need to allocate a GBM framebuffer + /// and point the scanout address to that via Drm.ModeSetCrtc. + /// + internal class LinuxGraphicsContext : Egl.EglUnixContext + { + private BufferObject bo, bo_next; + private int fd; + private bool is_flip_queued; + private int swap_interval; + + public LinuxGraphicsContext(GraphicsMode mode, LinuxWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + : base(mode, window, sharedContext, major, minor, flags) + { + if (mode.Buffers < 1) + { + throw new ArgumentException(); + } + fd = window.FD; + + PageFlip = HandlePageFlip; + PageFlipPtr = Marshal.GetFunctionPointerForDelegate(PageFlip); + } + + public override void SwapBuffers() + { + base.SwapBuffers(); + + if (is_flip_queued) + { + // Todo: if we don't wait for the page flip, + // we drop all rendering buffers and get a crash + // in Egl.SwapBuffers(). We need to fix that + // before we can disable vsync. + WaitFlip(true); // WaitFlip(SwapInterval > 0) + if (is_flip_queued) + { + Debug.Print("[KMS] Dropping frame"); + return; + } + } + + bo_next = LockSurface(); + int fb = GetFramebuffer(bo_next); + QueueFlip(fb); + } + + public override void Update(IWindowInfo window) + { + WaitFlip(true); + + base.SwapBuffers(); + + bo = LockSurface(); + int fb = GetFramebuffer(bo); + SetScanoutRegion(fb); + } + + public override int SwapInterval + { + get + { + return swap_interval; + } + set + { + // We only support a SwapInterval of 0 (immediate) + // or 1 (vsynced). + // Todo: add support for SwapInterval of -1 (adaptive). + // This requires a small change in WaitFlip(). + swap_interval = Math.Clamp(value, 0, 1); + } + } + + private void WaitFlip(bool block) + { + PollFD fds = new PollFD(); + fds.fd = fd; + fds.events = PollFlags.In; + + EventContext evctx = new EventContext(); + evctx.version = EventContext.Version; + evctx.page_flip_handler = PageFlipPtr; + + int timeout = block ? -1 : 0; + + while (is_flip_queued) + { + fds.revents = 0; + if (Libc.poll(ref fds, 1, timeout) < 0) + { + break; + } + + if ((fds.revents & (PollFlags.Hup | PollFlags.Error)) != 0) + { + break; + } + + if ((fds.revents & PollFlags.In) != 0) + { + Drm.HandleEvent(fd, ref evctx); + } + else + { + break; + } + } + + // Page flip has taken place, update buffer objects + if (!is_flip_queued) + { + IntPtr gbm_surface = WindowInfo.Handle; + Gbm.ReleaseBuffer(gbm_surface, bo); + bo = bo_next; + } + } + + private void QueueFlip(int buffer) + { + LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo; + if (wnd == null) + { + throw new InvalidOperationException(); + } + + unsafe + { + int ret = Drm.ModePageFlip(fd, wnd.DisplayDevice.Id, buffer, + PageFlipFlags.FlipEvent, IntPtr.Zero); + + if (ret < 0) + { + Debug.Print("[KMS] Failed to enqueue framebuffer flip. Error: {0}", ret); + } + + is_flip_queued = true; + } + } + + private void SetScanoutRegion(int buffer) + { + LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo; + if (wnd == null) + { + throw new InvalidOperationException(); + } + + unsafe + { + ModeInfo* mode = wnd.DisplayDevice.pConnector->modes; + int connector_id = wnd.DisplayDevice.pConnector->connector_id; + int crtc_id = wnd.DisplayDevice.Id; + + int x = 0; + int y = 0; + int connector_count = 1; + int ret = Drm.ModeSetCrtc(fd, crtc_id, buffer, x, y, + &connector_id, connector_count, mode); + + if (ret != 0) + { + Debug.Print("[KMS] Drm.ModeSetCrtc{0}, {1}, {2}, {3}, {4:x}, {5}, {6:x}) failed. Error: {7}", + fd, crtc_id, buffer, x, y, (IntPtr)connector_id, connector_count, (IntPtr)mode, ret); + } + } + } + + private BufferObject LockSurface() + { + IntPtr gbm_surface = WindowInfo.Handle; + return Gbm.LockFrontBuffer(gbm_surface); + } + + private int GetFramebuffer(BufferObject bo) + { + if (bo == BufferObject.Zero) + { + goto fail; + } + + int bo_handle = bo.Handle; + if (bo_handle == 0) + { + Debug.Print("[KMS] Gbm.BOGetHandle({0:x}) failed.", bo); + goto fail; + } + + int width = bo.Width; + int height = bo.Height; + int bpp = Mode.ColorFormat.BitsPerPixel; + int depth = Mode.Depth; + int stride = bo.Stride; + + if (width == 0 || height == 0 || bpp == 0) + { + Debug.Print("[KMS] Invalid framebuffer format: {0}x{1} {2} {3} {4}", + width, height, stride, bpp, depth); + goto fail; + } + + int buffer; + int ret = Drm.ModeAddFB( + fd, width, height, + (byte)depth, (byte)bpp, stride, bo_handle, + out buffer); + if (ret != 0) + { + Debug.Print("[KMS] Drm.ModeAddFB({0}, {1}, {2}, {3}, {4}, {5}, {6}) failed. Error: {7}", + fd, width, height, depth, bpp, stride, bo_handle, ret); + goto fail; + } + + bo.SetUserData((IntPtr)buffer, DestroyFB); + return buffer; + + fail: + Debug.Print("[Error] Failed to create framebuffer."); + return -1; + } + + private readonly IntPtr PageFlipPtr; + private readonly PageFlipCallback PageFlip; + + private void HandlePageFlip(int fd, + int sequence, + int tv_sec, + int tv_usec, + IntPtr user_data) + { + is_flip_queued = false; + } + + private static readonly DestroyUserDataCallback DestroyFB = HandleDestroyFB; + + private static void HandleDestroyFB(BufferObject bo, IntPtr data) + { + IntPtr gbm = bo.Device; + int fb = data.ToInt32(); + Debug.Print("[KMS] Destroying framebuffer {0}", fb); + + if (fb != 0) + { + Drm.ModeRmFB(Gbm.DeviceGetFD(gbm), fb); + } + } + + protected override void Dispose(bool manual) + { + if (manual) + { + // Reset the scanout region + LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo; + if (wnd != null) + { + unsafe + { + int connector_id = wnd.DisplayDevice.pConnector->connector_id; + ModeInfo mode = wnd.DisplayDevice.OriginalMode; + Drm.ModeSetCrtc(fd, + wnd.DisplayDevice.pCrtc->crtc_id, + wnd.DisplayDevice.pCrtc->buffer_id, + wnd.DisplayDevice.pCrtc->x, + wnd.DisplayDevice.pCrtc->y, + &connector_id, + 1, + &mode); + } + } + } + base.Dispose(manual); + } + } +} + + + diff --git a/GLWidget/OpenTK/Platform/Linux/LinuxWindowInfo.cs b/GLWidget/OpenTK/Platform/Linux/LinuxWindowInfo.cs new file mode 100644 index 0000000..dcacc8c --- /dev/null +++ b/GLWidget/OpenTK/Platform/Linux/LinuxWindowInfo.cs @@ -0,0 +1,55 @@ +// +// LinuxWindowInfo.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using OpenTK.Platform.Egl; + +namespace OpenTK.Platform.Linux +{ + internal class LinuxWindowInfo : EglWindowInfo + { + public int FD { get; private set; } + public LinuxDisplay DisplayDevice { get; private set; } + public IntPtr BufferManager { get; private set; } + + public LinuxWindowInfo(IntPtr display, int fd, IntPtr gbm, LinuxDisplay display_device) + : base(IntPtr.Zero, display, IntPtr.Zero) + { + if (display_device == null) + { + throw new ArgumentNullException(); + } + + FD = fd; + BufferManager = gbm; + DisplayDevice = display_device; + // The window handle and surface handle must + // be filled in manually once they are known. + } + } +} + diff --git a/GLWidget/OpenTK/Platform/MacOS/Carbon/Cgl.cs b/GLWidget/OpenTK/Platform/MacOS/Carbon/Cgl.cs new file mode 100644 index 0000000..d5ef328 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Carbon/Cgl.cs @@ -0,0 +1,141 @@ +// +// Cgl.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + using CGLPixelFormat = IntPtr; + using CGLContext = IntPtr; + + internal static class Cgl + { + internal enum PixelFormatBool + { + None = 0, + AllRenderers = 1, + Doublebuffer = 5, + Stereo = 6, + AuxBuffers = 7, + MinimumPolicy = 51, + MaximumPolicy = 52, + Offscreen = 53, + AuxDepthStencil = 57, + ColorFloat = 58, + Multisample = 59, + Supersample = 60, + SampleALpha = 61, + SingleRenderer = 71, + NoRecovery = 72, + Accelerated = 73, + ClosestPolicy = 74, + BackingStore = 76, + Window = 80, + Compliant = 83, + PBuffer = 90, + RemotePBuffer = 91, + } + + internal enum PixelFormatInt + { + ColorSize = 8, + AlphaSize = 11, + DepthSize = 12, + StencilSize = 13, + AccumSize = 14, + SampleBuffers = 55, + Samples = 56, + RendererID = 70, + DisplayMask = 84, + OpenGLProfile = 99, + VScreenCount = 128, + } + + internal enum OpenGLProfileVersion + { + Legacy = 0x100, + Core3_2 = 0x3200, + } + + internal enum ParameterNames + { + SwapInterval = 222, + } + + internal enum Error + { + None = 0x000, + } + + private const string cgl = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"; + private const string cgs = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon"; + + [DllImport(cgl, EntryPoint = "CGLGetError")] + internal static extern Error GetError(); + [DllImport(cgl, EntryPoint = "CGLErrorString")] + private static extern IntPtr CGLErrorString(Error code); + internal static string ErrorString(Error code) + { + return Marshal.PtrToStringAnsi(CGLErrorString(code)); + } + + [DllImport(cgl, EntryPoint = "CGLChoosePixelFormat")] + internal static extern Error ChoosePixelFormat(int []attribs, ref CGLPixelFormat format, ref int numPixelFormats); + [DllImport(cgl, EntryPoint = "CGLDescribePixelFormat")] + internal static extern Error DescribePixelFormat(CGLPixelFormat pix, int pix_num, PixelFormatInt attrib, out int value); + [DllImport(cgl, EntryPoint = "CGLDescribePixelFormat")] + internal static extern Error DescribePixelFormat(CGLPixelFormat pix, int pix_num, PixelFormatBool attrib, out bool value); + [DllImport(cgl, EntryPoint = "CGLGetPixelFormat")] + internal static extern CGLPixelFormat GetPixelFormat(CGLContext context); + [DllImport(cgl, EntryPoint = "CGLCreateContext")] + internal static extern Error CreateContext(CGLPixelFormat format, CGLContext share, ref CGLContext context); + [DllImport(cgl, EntryPoint = "CGLDestroyPixelFormat")] + internal static extern Error DestroyPixelFormat(CGLPixelFormat format); + [DllImport(cgl, EntryPoint = "CGLGetCurrentContext")] + internal static extern CGLContext GetCurrentContext(); + [DllImport(cgl, EntryPoint = "CGLSetCurrentContext")] + internal static extern Error SetCurrentContext(CGLContext context); + [DllImport(cgl, EntryPoint = "CGLDestroyContext")] + internal static extern Error DestroyContext(CGLContext context); + [DllImport(cgl, EntryPoint = "CGLSetParameter")] + internal static extern Error SetParameter(CGLContext context, int parameter, ref int value); + [DllImport(cgl, EntryPoint = "CGLFlushDrawable")] + internal static extern Error FlushDrawable(CGLContext context); + + [DllImport(cgl, EntryPoint = "CGLSetSurface")] + internal static extern Error SetSurface(CGLContext context, int conId, int winId, int surfId); + [DllImport(cgl, EntryPoint = "CGLUpdateContext")] + internal static extern Error UpdateContext(CGLContext context); + + [DllImport(cgs, EntryPoint = "CGSMainConnectionID")] + internal static extern int MainConnectionID(); + [DllImport(cgs, EntryPoint = "CGSGetSurfaceCount")] + internal static extern Error GetSurfaceCount(int conId, int winId, ref int count); + [DllImport(cgs, EntryPoint = "CGSGetSurfaceList")] + internal static extern Error GetSurfaceList(int conId, int winId, int count, ref int ids, ref int filled); + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Carbon/MacOSKeys.cs b/GLWidget/OpenTK/Platform/MacOS/Carbon/MacOSKeys.cs new file mode 100644 index 0000000..ed15c9d --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Carbon/MacOSKeys.cs @@ -0,0 +1,158 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + // + // http://web.archive.org/web/20100501161453/http://www.classicteck.com/rbarticles/mackeyboard.php + + internal enum MacOSKeyCode + { + A = 0, + B = 11, + C = 8, + D = 2, + E = 14, + F = 3, + G = 5, + H = 4, + I = 34, + J = 38, + K = 40, + L = 37, + M = 46, + N = 45, + O = 31, + P = 35, + Q = 12, + R = 15, + S = 1, + T = 17, + U = 32, + V = 9, + W = 13, + X = 7, + Y = 16, + Z = 6, + + Key_1 = 18, + Key_2 = 19, + Key_3 = 20, + Key_4 = 21, + Key_5 = 23, + Key_6 = 22, + Key_7 = 26, + Key_8 = 28, + Key_9 = 25, + Key_0 = 29, + + Space = 49, + Tilde = 50, + + Minus = 27, + Equals = 24, + BracketLeft = 33, + BracketRight = 30, + Backslash = 42, + Semicolon = 41, + Quote = 39, + Comma = 43, + Period = 47, + Slash = 44, + + Enter = 36, + Tab = 48, + Backspace = 51, + Return = 52, + Esc = 53, + + Command = 55, + Shift = 56, + CapsLock = 57, + OptionAlt = 58, + Control = 59, + + KeyPad_Decimal = 65, + KeyPad_Multiply = 67, + KeyPad_Add = 69, + KeyPad_Divide = 75, + KeyPad_Enter = 76, + KeyPad_Subtract = 78, + KeyPad_Equal = 81, + KeyPad_0 = 82, + KeyPad_1 = 83, + KeyPad_2 = 84, + KeyPad_3 = 85, + KeyPad_4 = 86, + KeyPad_5 = 87, + KeyPad_6 = 88, + KeyPad_7 = 89, + KeyPad_8 = 91, + KeyPad_9 = 92, + + F1 = 122, + F2 = 120, + F3 = 99, + F4 = 118, + F5 = 96, + F6 = 97, + F7 = 98, + F8 = 100, + F9 = 101, + F10 = 109, + F11 = 103, + F12 = 111, + F13 = 105, + F14 = 107, + F15 = 113, + + Menu = 110, + + Insert = 114, + Home = 115, + Pageup = 116, + Del = 117, + End = 119, + Pagedown = 121, + Up = 126, + Down = 125, + Left = 123, + Right = 124, + + + } + [Flags] + internal enum MacOSKeyModifiers + { + None = 0, + Shift = 0x0200, + CapsLock = 0x0400, + Control = 0x1000, // + Command = 0x0100, // Open-Apple - Windows key + Option = 0x0800, // Option key is same position as the alt key on non-mac keyboards. + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/CarbonWindowInfo.cs b/GLWidget/OpenTK/Platform/MacOS/CarbonWindowInfo.cs new file mode 100644 index 0000000..406a560 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/CarbonWindowInfo.cs @@ -0,0 +1,119 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + /// \internal + /// + /// Describes a Carbon window. + /// + internal sealed class CarbonWindowInfo : IWindowInfo + { + private bool ownHandle = false; + private bool disposed = false; + + /// + /// Constructs a new instance with the specified parameters. + /// + /// A valid Carbon window reference. + /// + /// + public CarbonWindowInfo(IntPtr windowRef, bool ownHandle, bool isControl) + { + this.Handle = windowRef; + this.ownHandle = ownHandle; + this.IsControl = isControl; + } + + public CarbonWindowInfo(IntPtr windowRef, bool ownHandle, bool isControl, GetInt getX, GetInt getY) : this(windowRef, ownHandle, isControl) + { + this.XOffset = getX; + this.YOffset = getY; + } + + /// + /// Gets the window reference for this instance. + /// + public IntPtr Handle { get; set; } + + internal bool GoFullScreenHack { get; set; } = false; + + internal bool GoWindowedHack { get; set; } = false; + + /// + /// Gets a value indicating whether this instance refers to a System.Windows.Forms.Control. + /// + public bool IsControl { get; } = true; + + /// Returns a System.String that represents the current window. + /// A System.String that represents the current window. + public override string ToString() + { + return String.Format("MacOS.CarbonWindowInfo: Handle {0}", this.Handle); + } + + // For compatibility with whoever thought it would be + // a good idea to access internal APIs through reflection + // (e.g. MonoGame) + public IntPtr WindowHandle { get { return Handle; } set { Handle = value; } } + + public GetInt XOffset { get; set; } + + public GetInt YOffset { get; set; } + + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + + } + + if (ownHandle) + { + Handle = IntPtr.Zero; + } + + disposed = true; + } + + ~CarbonWindowInfo() + { + Dispose(false); + } + + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/Class.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Class.cs new file mode 100644 index 0000000..f292dc7 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Class.cs @@ -0,0 +1,97 @@ +// +// Class.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System.Runtime.InteropServices; +using System; + +namespace OpenTK.Platform.MacOS +{ + internal static class Class + { + public static readonly IntPtr NSAutoreleasePool = Get("NSAutoreleasePool"); + public static readonly IntPtr NSDictionary = Get("NSDictionary"); + public static readonly IntPtr NSNumber = Get("NSNumber"); + public static readonly IntPtr NSUserDefaults = Get("NSUserDefaults"); + + [DllImport (Cocoa.LibObjC)] + private extern static IntPtr class_getName(IntPtr handle); + + [DllImport (Cocoa.LibObjC)] + private extern static bool class_addMethod(IntPtr classHandle, IntPtr selector, IntPtr method, string types); + + [DllImport (Cocoa.LibObjC)] + private extern static IntPtr objc_getClass(string name); + + [DllImport (Cocoa.LibObjC)] + private extern static IntPtr objc_allocateClassPair(IntPtr parentClass, string name, int extraBytes); + + [DllImport (Cocoa.LibObjC)] + private extern static void objc_registerClassPair(IntPtr classToRegister); + + [DllImport (Cocoa.LibObjC)] + private extern static void objc_disposeClassPair(IntPtr cls); + + public static IntPtr Get(string name) + { + var id = objc_getClass(name); + if (id == IntPtr.Zero) + { + throw new ArgumentException("Unknown class: " + name); + } + return id; + } + + public static IntPtr AllocateClass(string className, string parentClass) + { + return objc_allocateClassPair(Get(parentClass), className, 0); + } + + public static void RegisterClass(IntPtr handle) + { + objc_registerClassPair(handle); + } + + public static void DisposeClass(IntPtr handle) + { + objc_disposeClassPair(handle); + } + + public static void RegisterMethod(IntPtr handle, Delegate d, string selector, string typeString) + { + // TypeString info: + // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html + + IntPtr p = Marshal.GetFunctionPointerForDelegate(d); + bool r = class_addMethod(handle, Selector.Get(selector), p, typeString); + + if (!r) + { + throw new ArgumentException("Could not register method " + d + " in class + " + class_getName(handle)); + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/Cocoa.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Cocoa.cs new file mode 100644 index 0000000..f6feed6 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Cocoa.cs @@ -0,0 +1,284 @@ +// +// Cocoa.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System.Runtime.InteropServices; +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace OpenTK.Platform.MacOS +{ + internal static class Cocoa + { + private static readonly IntPtr selUTF8String = Selector.Get("UTF8String"); + + internal const string LibObjC = "/usr/lib/libobjc.dylib"; + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, ulong ulong1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSSize size); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, int int1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3, IntPtr intPtr4, IntPtr intPtr5); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, NSPoint p2); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, bool p1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSPoint p1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1, int int1, int int2, bool bool1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, uint uint1, IntPtr intPtr1, IntPtr intPtr2, bool bool1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1, int int1, IntPtr intPtr1, IntPtr intPtr2); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, int p2, int p3, int p4, int p5, int p6, int p7, IntPtr p8, NSBitmapFormat p9, int p10, int p11); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static bool SendBool(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static bool SendBool(IntPtr receiver, IntPtr selector, int int1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, uint uint1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, uint uint1, IntPtr intPtr1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1, int int1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, int int1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, bool bool1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSPoint point1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSRect rect1, bool bool1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSRect rect1, IntPtr intPtr1); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static int SendInt(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static uint SendUint(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + public extern static ushort SendUshort(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend_fpret")] + private extern static float SendFloat_i386(IntPtr receiver, IntPtr selector); + + // On x64 using selector that return CGFloat give you 64 bit == double + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + private extern static double SendFloat_x64(IntPtr receiver, IntPtr selector); + + [DllImport(LibObjC, EntryPoint="objc_msgSend")] + private extern static float SendFloat_ios(IntPtr receiver, IntPtr selector); + + public static float SendFloat(IntPtr receiver, IntPtr selector) + { + if (IntPtr.Size == 4) + { + return SendFloat_i386(receiver, selector); + } + else + { + return (float)SendFloat_x64(receiver, selector); + } + } + + // Not the _stret version, perhaps because a NSPoint fits in one register? + // thefiddler: gcc is indeed using objc_msgSend for NSPoint on i386 + [DllImport (LibObjC, EntryPoint="objc_msgSend")] + public extern static NSPointF SendPointF(IntPtr receiver, IntPtr selector); + [DllImport (LibObjC, EntryPoint="objc_msgSend")] + public extern static NSPointD SendPointD(IntPtr receiver, IntPtr selector); + + public static NSPoint SendPoint(IntPtr receiver, IntPtr selector) + { + NSPoint r = new NSPoint(); + + unsafe + { + if (IntPtr.Size == 4) + { + NSPointF pf = SendPointF(receiver, selector); + r.X.Value = *(IntPtr *)&pf.X; + r.Y.Value = *(IntPtr *)&pf.Y; + } + else + { + NSPointD pd = SendPointD(receiver, selector); + r.X.Value = *(IntPtr *)&pd.X; + r.Y.Value = *(IntPtr *)&pd.Y; + } + } + + return r; + } + + [DllImport (LibObjC, EntryPoint="objc_msgSend_stret")] + private extern static void SendRect(out NSRect retval, IntPtr receiver, IntPtr selector); + + [DllImport (LibObjC, EntryPoint="objc_msgSend_stret")] + private extern static void SendRect(out NSRect retval, IntPtr receiver, IntPtr selector, NSRect rect1); + + public static NSRect SendRect(IntPtr receiver, IntPtr selector) + { + NSRect r; + SendRect(out r, receiver, selector); + return r; + } + + public static NSRect SendRect(IntPtr receiver, IntPtr selector, NSRect rect1) + { + NSRect r; + SendRect(out r, receiver, selector, rect1); + return r; + } + + public static IntPtr ToNSString(string str) + { + if (str == null) + { + return IntPtr.Zero; + } + + unsafe + { + fixed (char* ptrFirstChar = str) + { + var handle = Cocoa.SendIntPtr(Class.Get("NSString"), Selector.Alloc); + handle = Cocoa.SendIntPtr(handle, Selector.Get("initWithCharacters:length:"), (IntPtr)ptrFirstChar, str.Length); + return handle; + } + } + } + + public static string FromNSString(IntPtr handle) + { + return Marshal.PtrToStringAuto(SendIntPtr(handle, selUTF8String)); + } + + public static unsafe IntPtr ToNSImage(Image img) + { + using (System.IO.MemoryStream s = new System.IO.MemoryStream()) + { + img.Save(s, ImageFormat.Png); + byte[] b = s.ToArray(); + + fixed (byte* pBytes = b) + { + IntPtr nsData = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSData"), Selector.Alloc), + Selector.Get("initWithBytes:length:"), (IntPtr)pBytes, b.Length); + + IntPtr nsImage = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSImage"), Selector.Alloc), + Selector.Get("initWithData:"), nsData); + + Cocoa.SendVoid(nsData, Selector.Release); + return nsImage; + } + } + } + + public static IntPtr GetStringConstant(IntPtr handle, string symbol) + { + var indirect = NS.GetSymbol(handle, symbol); + if (indirect == IntPtr.Zero) + { + return IntPtr.Zero; + } + + var actual = Marshal.ReadIntPtr(indirect); + if (actual == IntPtr.Zero) + { + return IntPtr.Zero; + } + + return actual; + } + + public static IntPtr AppKitLibrary; + public static IntPtr FoundationLibrary; + + public static void Initialize() + { + if (AppKitLibrary != IntPtr.Zero) + { + return; + } + + AppKitLibrary = NS.LoadLibrary("/System/Library/Frameworks/AppKit.framework/AppKit"); + FoundationLibrary = NS.LoadLibrary("/System/Library/Frameworks/Foundation.framework/Foundation"); + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplication.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplication.cs new file mode 100644 index 0000000..ba8f468 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplication.cs @@ -0,0 +1,138 @@ +// +// NSApplication.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; + +namespace OpenTK.Platform.MacOS +{ + internal static class NSApplication + { + internal static IntPtr Handle; + + private static readonly IntPtr selQuit = Selector.Get("quit"); + + private static readonly int ThreadId = + System.Threading.Thread.CurrentThread.ManagedThreadId; + + internal static void Initialize() { } + + static NSApplication() + { + Cocoa.Initialize(); + + // Register a Quit method to be called on cmd-q + IntPtr nsapp = Class.Get("NSApplication"); + Class.RegisterMethod(nsapp, OnQuitHandler, "quit", "v@:"); + + // Fetch the application handle + Handle = Cocoa.SendIntPtr(nsapp, Selector.Get("sharedApplication")); + + // Setup the application + Cocoa.SendBool(Handle, Selector.Get("setActivationPolicy:"), (int)NSApplicationActivationPolicy.Regular); + Cocoa.SendVoid(Handle, Selector.Get("discardEventsMatchingMask:beforeEvent:"), uint.MaxValue, IntPtr.Zero); + Cocoa.SendVoid(Handle, Selector.Get("activateIgnoringOtherApps:"), true); + + if (Cocoa.SendIntPtr(Handle, Selector.Get("mainMenu")) == IntPtr.Zero) + { + // Create the menu bar + var menubar = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc); + var menuItem = Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc); + + // Add menu item to bar, and bar to application + Cocoa.SendIntPtr(menubar, Selector.Get("addItem:"), menuItem); + Cocoa.SendIntPtr(Handle, Selector.Get("setMainMenu:"), menubar); + + // Add a "Quit" menu item and bind the button. + var appMenu = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc); + var quitMenuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc), + Selector.Get("initWithTitle:action:keyEquivalent:"), Cocoa.ToNSString("Quit"), selQuit, Cocoa.ToNSString("q")); + + Cocoa.SendIntPtr(appMenu, Selector.Get("addItem:"), quitMenuItem); + Cocoa.SendIntPtr(menuItem, Selector.Get("setSubmenu:"), appMenu); + + // Tell cocoa we're ready to run the application (usually called by [NSApp run]). + // Note: if a main menu exists, then this method has already been called and + // calling it again will result in a crash. For this reason, we only call it + // when we create our own main menu. + Cocoa.SendVoid(Handle, Selector.Get("finishLaunching")); + } + + // Disable momentum scrolling and long-press key pop-ups + IntPtr settings = Cocoa.SendIntPtr(Class.NSDictionary, Selector.Alloc); + //IntPtr momentum_scrolling = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false); + IntPtr press_and_hold = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false); + + // Initialize and register the settings dictionary + settings = + Cocoa.SendIntPtr(settings, Selector.Get("initWithObjectsAndKeys:"), + //momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"), + press_and_hold, Cocoa.ToNSString("ApplePressAndHoldEnabled"), + IntPtr.Zero); + Cocoa.SendVoid( + Cocoa.SendIntPtr(Class.NSUserDefaults, Selector.Get("standardUserDefaults")), + Selector.Get("registerDefaults:"), + settings); + Cocoa.SendVoid(settings, Selector.Release); + } + + internal static bool IsUIThread + { + get + { + int thread_id = Thread.CurrentThread.ManagedThreadId; + bool is_ui_thread = thread_id == NSApplication.ThreadId; + if (!is_ui_thread) + { + Debug.Print("[Warning] UI resources must be disposed in the UI thread #{0}, not #{1}.", + NSApplication.ThreadId, thread_id); + } + return is_ui_thread; + } + } + + internal static event EventHandler Quit = delegate { }; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate void OnQuitDelegate(IntPtr self, IntPtr cmd); + + private static OnQuitDelegate OnQuitHandler = OnQuit; + + private static void OnQuit(IntPtr self, IntPtr cmd) + { + var e = new CancelEventArgs(); + Quit(null, e); + if (!e.Cancel) + { + Cocoa.SendVoid(Handle, Selector.Get("terminate:"), Handle); + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationActivationPolicy.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationActivationPolicy.cs new file mode 100644 index 0000000..b4c0d00 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationActivationPolicy.cs @@ -0,0 +1,36 @@ +// +// NSApplicationActivationPolicy.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + internal enum NSApplicationActivationPolicy + { + Regular, + Accessory, + Prohibited, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationPresentationOptions.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationPresentationOptions.cs new file mode 100644 index 0000000..eb9d336 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSApplicationPresentationOptions.cs @@ -0,0 +1,46 @@ +// +// NSApplicationPresentationOptions.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + internal enum NSApplicationPresentationOptions + { + Default = 0, + AutoHideDock = 1, + HideDock = 2, + AutoHideMenuBar = 4, + HideMenuBar = 8, + DisableAppleMenu = 16, + DisableProcessSwitching = 32, + DisableForceQuit = 64, + DisableSessionTermination = 128, + DisableHideApplication = 256, + DisableMenuBarTransparency = 512, + FullScreen = 1024, + AutoHideToolbar = 2048, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs new file mode 100644 index 0000000..e6ba6c4 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs @@ -0,0 +1,34 @@ +using System; + +namespace OpenTK.Platform.MacOS +{ + /// + /// The class is a wrapper around the native objective-C NSAutoreleasePool. + /// In particular, this construct mimics the usage of an @autorelease block and can be used in much the same way, + /// only with a C# using block instead. + /// + public sealed class NSAutoreleasePool : IDisposable + { + private readonly IntPtr _autoreleasePool; + + /// + /// Allocates and initializes a new . + /// + public NSAutoreleasePool() + { + var uninitializedPool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc); + _autoreleasePool = Cocoa.SendIntPtr(uninitializedPool, Selector.Init); + } + + /// + /// Disposes of the instance, draining it. + /// + public void Dispose() + { + if (_autoreleasePool != IntPtr.Zero) + { + Cocoa.SendVoid(_autoreleasePool, Selector.Get("drain")); + } + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBackingStore.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBackingStore.cs new file mode 100644 index 0000000..1defe9f --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBackingStore.cs @@ -0,0 +1,36 @@ +// +// NSBackingStore.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + internal enum NSBackingStore + { + Retained, + Nonretained, + Buffered, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBitmapFormat.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBitmapFormat.cs new file mode 100644 index 0000000..9032f96 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSBitmapFormat.cs @@ -0,0 +1,40 @@ +// +// NSBitmapFormat.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + [Flags] + internal enum NSBitmapFormat + { + AlphaFirst = 1 << 0, + AlphaNonpremultiplied = 1 << 1, + FloatingPointSamples = 1 << 2 + } +} + diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSDragOperation.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSDragOperation.cs new file mode 100644 index 0000000..b067eb2 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSDragOperation.cs @@ -0,0 +1,23 @@ +using System; + +namespace OpenTK.Platform.MacOS +{ + /// + /// Used by draggingSourceOperationMask() to get permission for dropped object + /// also used for respones to drag source + /// Values for enum can be found here https://developer.apple.com/documentation/appkit/nsdragoperation?language=objc + /// or for Mac users /System/Library/Frameworks/AppKit.framework/Headers + /// + internal enum NSDragOperation : int + { + None = 0, + Copy = 1, + Link = 2, + Generic = 4, + Private = 8, + AllObsolete = 15, + Move = 16, + Delete = 32, + Every = Int32.MaxValue, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventModifierMask.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventModifierMask.cs new file mode 100644 index 0000000..eeffd9d --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventModifierMask.cs @@ -0,0 +1,45 @@ +// +// NSEventModifierMask.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + [Flags] + internal enum NSEventModifierMask : uint + { + AlphaShiftKeyMask = 65536U, + ShiftKeyMask = 131072U, + ControlKeyMask = 262144U, + AlternateKeyMask = 524288U, + CommandKeyMask = 1048576U, + NumericPadKeyMask = 2097152U, + HelpKeyMask = 4194304U, + FunctionKeyMask = 8388608U, + DeviceIndependentModifierFlagsMask = 4294901760U, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventType.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventType.cs new file mode 100644 index 0000000..f8fd6a0 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSEventType.cs @@ -0,0 +1,64 @@ +// +// NSEventType.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + internal enum NSEventType + { + LeftMouseDown = 1, + LeftMouseUp = 2, + RightMouseDown = 3, + RightMouseUp = 4, + MouseMoved = 5, + LeftMouseDragged = 6, + RightMouseDragged = 7, + MouseEntered = 8, + MouseExited = 9, + KeyDown = 10, + KeyUp = 11, + FlagsChanged = 12, + AppKitDefined = 13, + SystemDefined = 14, + ApplicationDefined = 15, + Periodic = 16, + CursorUpdate = 17, + Rotate = 18, + BeginGesture = 19, + EndGesture = 20, + ScrollWheel = 22, + TabletPoint = 23, + TabletProximity = 24, + OtherMouseDown = 25, + OtherMouseUp = 26, + OtherMouseDragged = 27, + Gesture = 29, + Magnify = 30, + Swipe = 31, + SmartMagnify = 32, + QuickLook = 33, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSFloat.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSFloat.cs new file mode 100644 index 0000000..242063a --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSFloat.cs @@ -0,0 +1,201 @@ +// +// NSFloat.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + // NSFloat is defined as float on 32bit systems and double on 64bit. + // We have to account for this peculiarity in order to run OpenTK on + // 64bit Mac platforms. + // We do this by adding implicit conversions between IntPtr and float/double. + // Note that this conversion is against C# best practices, as it can lose information. + // However, NSFloat is used internally in places where this precision loss does not matter. + internal struct NSFloat + { + private IntPtr _value; + + public IntPtr Value + { + get { return _value; } + set { _value = value; } + } + + public static implicit operator NSFloat(float v) + { + NSFloat f = new NSFloat(); + unsafe + { + if (IntPtr.Size == 4) + { + f.Value = *(IntPtr*)&v; + } + else + { + double d = v; + f.Value = *(IntPtr*)&d; + } + } + return f; + } + + public static implicit operator NSFloat(double v) + { + NSFloat f = new NSFloat(); + unsafe + { + if (IntPtr.Size == 4) + { + float fv = (float)v; + f.Value = *(IntPtr*)&fv; + } + else + { + f.Value = *(IntPtr*)&v; + } + } + return f; + } + + public static implicit operator float(NSFloat f) + { + unsafe + { + if (IntPtr.Size == 4) + { + return *(float*)&f._value; + } + else + { + return (float)*(double*)&f._value; + } + } + } + + public static implicit operator double(NSFloat f) + { + unsafe + { + if (IntPtr.Size == 4) + { + return (double)*(float*)&f._value; + } + else + { + return *(double*)&f._value; + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NSPoint + { + public NSFloat X; + public NSFloat Y; + + public static implicit operator NSPoint(PointF p) + { + return new NSPoint + { + X = p.X, + Y = p.Y + }; + } + + public static implicit operator PointF(NSPoint s) + { + return new PointF(s.X, s.Y); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NSSize + { + public NSFloat Width; + public NSFloat Height; + + public static implicit operator NSSize(SizeF s) + { + return new NSSize + { + Width = s.Width, + Height = s.Height + }; + } + + public static implicit operator SizeF(NSSize s) + { + return new SizeF(s.Width, s.Height); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NSRect + { + public NSPoint Location; + public NSSize Size; + + public NSFloat Width { get { return Size.Width; } } + public NSFloat Height { get { return Size.Height; } } + public NSFloat X { get { return Location.X; } } + public NSFloat Y { get { return Location.Y; } } + + public static implicit operator NSRect(RectangleF s) + { + return new NSRect + { + Location = s.Location, + Size = s.Size + }; + } + + public static implicit operator RectangleF(NSRect s) + { + return new RectangleF(s.Location, s.Size); + } + } + + // Using IntPtr in NSFloat cause that if imported function + // return struct that consist of them you will get wrong data + // This types are used for such function. + [StructLayout(LayoutKind.Sequential)] + internal struct NSPointF + { + public float X; + public float Y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NSPointD + { + public double X; + public double Y; + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLContextParameter.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLContextParameter.cs new file mode 100644 index 0000000..dbc6596 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLContextParameter.cs @@ -0,0 +1,50 @@ +// +// NSOpenGLContextParameter.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + internal enum NSOpenGLContextParameter + { + [Obsolete] SwapRectangle = 200, + [Obsolete] SwapRectangleEnable = 201, + [Obsolete] RasterizationEnable = 221, + SwapInterval = 222, + SurfaceOrder = 235, + SurfaceOpacity = 236, + [Obsolete] StateValidation = 301, + SurfaceBackingSize = 304, // Lion + [Obsolete] SurfaceSurfaceVolatile = 306, + ReclaimResources = 308, // Lion + CurrentRendererID = 309, // Lion + GpuVertexProcessing = 310, // Lion + GpuFragmentProcessing = 311, // Lion + HasDrawable = 314, // Lion + MpsSwapsInFlight = 315, // Lion + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLPixelFormatAttribute.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLPixelFormatAttribute.cs new file mode 100644 index 0000000..117bb93 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLPixelFormatAttribute.cs @@ -0,0 +1,74 @@ +// +// NSOpenGLPixelFormatAttribute.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + internal enum NSOpenGLPixelFormatAttribute + { + AllRenderers = 1, + TrippleBuffer = 3, // Lion + DoubleBuffer = 5, + Stereo = 6, + AuxBuffers = 7, + ColorSize = 8, + AlphaSize = 11, + DepthSize = 12, + StencilSize = 13, + AccumSize = 14, + MinimumPolicy = 51, + MaximumPolicy = 52, + OffScreen = 53, + FullScreen = 54, + SampleBuffers = 55, + Samples = 56, + AuxDepthStencil = 57, + ColorFloat = 58, + Multisample = 59, + Supersample = 60, + SampleAlpha = 61, + RendererID = 70, + SingleRenderer = 71, + NoRecovery = 72, + Accelerated = 73, + ClosestPolicy = 74, + [Obsolete] Robust = 75, + BackingStore = 76, + [Obsolete] MPSafe = 78, + Window = 80, + [Obsolete] MultiScreen = 81, + Compliant = 83, + ScreenMask = 84, + PixelBuffer = 90, + RemotePixelBuffer = 91, + AllowOfflineRenderers = 96, + AcceleratedCompute = 97, + OpenGLProfile = 99, // Lion + VirtualScreenCount = 128, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLProfile.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLProfile.cs new file mode 100644 index 0000000..7249538 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSOpenGLProfile.cs @@ -0,0 +1,35 @@ +// +// NSOpenGLProfile.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + internal enum NSOpenGLProfile + { + VersionLegacy = 4096, + Version3_2Core = 12800, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSTrackingAreaOptions.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSTrackingAreaOptions.cs new file mode 100644 index 0000000..0fc31c3 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSTrackingAreaOptions.cs @@ -0,0 +1,46 @@ +// +// NSTrackingAreaOptions.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + [Flags] + internal enum NSTrackingAreaOptions + { + MouseEnteredAndExited = 1, + MouseMoved = 2, + CursorUpdate = 4, + ActiveWhenFirstResponder = 16, + ActiveInKeyWindow = 32, + ActiveInActiveApp = 64, + ActiveAlways = 128, + AssumeInside = 256, + InVisibleRect = 512, + EnabledDuringMouseDrag = 1024, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSWindowStyle.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSWindowStyle.cs new file mode 100644 index 0000000..9797975 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/NSWindowStyle.cs @@ -0,0 +1,49 @@ +// +// NSWindowStyle.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; + +namespace OpenTK.Platform.MacOS +{ + [Flags] + internal enum NSWindowStyle + { + Borderless = 0, + Titled = 1, + Closable = 2, + Miniaturizable = 4, + Resizable = 8, + Utility = 16, + DocModal = 64, + NonactivatingPanel = 128, + TexturedBackground = 256, + Unscaled = 2048, + UnifiedTitleAndToolbar = 4096, + Hud = 8192, + FullScreenWindow = 16384, + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Cocoa/Selector.cs b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Selector.cs new file mode 100644 index 0000000..b410d59 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Cocoa/Selector.cs @@ -0,0 +1,46 @@ +// +// Selector.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + internal static class Selector + { + // Frequently used selectors + public static readonly IntPtr Init = Selector.Get("init"); + public static readonly IntPtr InitWithCoder = Selector.Get("initWithCoder:"); + public static readonly IntPtr Alloc = Selector.Get("alloc"); + public static readonly IntPtr Retain = Selector.Get("retain"); + public static readonly IntPtr Release = Selector.Get("release"); + public static readonly IntPtr Autorelease = Selector.Get("autorelease"); + + [DllImport ("/usr/lib/libobjc.dylib", EntryPoint="sel_registerName")] + public extern static IntPtr Get(string name); + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/CocoaContext.cs b/GLWidget/OpenTK/Platform/MacOS/CocoaContext.cs new file mode 100644 index 0000000..eaae832 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/CocoaContext.cs @@ -0,0 +1,410 @@ +// +// CocoaContext.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using OpenTK.Platform; +using OpenTK.Graphics; +using OpenTK.Platform.MacOS; +using System.Diagnostics; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + internal class CocoaContext : DesktopGraphicsContext + { + private CocoaWindowInfo cocoaWindow; + private IntPtr shareContextRef; + + private static readonly IntPtr NSOpenGLContext = Class.Get("NSOpenGLContext"); + private static readonly IntPtr selCurrentContext = Selector.Get("currentContext"); + private static readonly IntPtr selFlushBuffer = Selector.Get("flushBuffer"); + private static readonly IntPtr selMakeCurrentContext = Selector.Get("makeCurrentContext"); + private static readonly IntPtr selUpdate = Selector.Get("update"); + + private static readonly IntPtr opengl = NS.AddImage( + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + AddImageFlags.ReturnOnError); + + private static readonly IntPtr opengles = NS.AddImage( + "/System/Library/Frameworks/OpenGL.framework/OpenGLES", + AddImageFlags.ReturnOnError); + + static CocoaContext() + { + Cocoa.Initialize(); + } + + public CocoaContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int majorVersion, int minorVersion) + { + Debug.Print("Context Type: {0}", shareContext); + Debug.Print("Window info: {0}", window); + + cocoaWindow = (CocoaWindowInfo)window; + + if (shareContext is CocoaContext) + { + shareContextRef = ((CocoaContext)shareContext).Handle.Handle; + } + + if (shareContext is GraphicsContext) + { + ContextHandle shareHandle = shareContext != null ? (shareContext as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero; + shareContextRef = shareHandle.Handle; + } + + if (shareContextRef == IntPtr.Zero) + { + Debug.Print("No context sharing will take place."); + } + + CreateContext(mode, cocoaWindow, shareContextRef, majorVersion, minorVersion, true); + } + + public CocoaContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int majorVersion, int minorVersion) + { + if (handle == ContextHandle.Zero) + { + throw new ArgumentException("handle"); + } + if (window == null) + { + throw new ArgumentNullException("window"); + } + + Handle = handle; + cocoaWindow = (CocoaWindowInfo)window; + } + + private void AddPixelAttrib(List attributes, NSOpenGLPixelFormatAttribute attribute) + { + Debug.Print(attribute.ToString()); + + attributes.Add(attribute); + } + + private void AddPixelAttrib(List attributes, NSOpenGLPixelFormatAttribute attribute, int value) + { + Debug.Print("{0} : {1}", attribute, value); + + attributes.Add(attribute); + attributes.Add((NSOpenGLPixelFormatAttribute)value); + } + + private void CreateContext(GraphicsMode mode, CocoaWindowInfo cocoaWindow, IntPtr shareContextRef, int majorVersion, int minorVersion, bool fullscreen) + { + // Prepare attributes + IntPtr pixelFormat = SelectPixelFormat(mode, majorVersion, minorVersion); + if (pixelFormat == IntPtr.Zero) + { + throw new GraphicsException(String.Format( + "Failed to contruct NSOpenGLPixelFormat for GraphicsMode '{0}'", + mode)); + } + + // Create context + var context = Cocoa.SendIntPtr(NSOpenGLContext, Selector.Alloc); + context = Cocoa.SendIntPtr(context, Selector.Get("initWithFormat:shareContext:"), pixelFormat, shareContextRef); + if (context == IntPtr.Zero) + { + throw new GraphicsException(String.Format( + "Failed to construct NSOpenGLContext", + mode)); + } + + // Release pixel format + Cocoa.SendVoid(pixelFormat, Selector.Release); + pixelFormat = IntPtr.Zero; + + // Attach the view + Cocoa.SendVoid(context, Selector.Get("setView:"), cocoaWindow.ViewHandle); + Cocoa.SendVoid(cocoaWindow.ViewHandle, Selector.Get("setWantsBestResolutionOpenGLSurface:"), true); + + // Finalize + Handle = new ContextHandle(context); + Mode = GetGraphicsMode(context); + + Update(cocoaWindow); + } + + private IntPtr SelectPixelFormat(GraphicsMode mode, int majorVersion, int minorVersion) + { + List attributes = new List(); + + var profile = NSOpenGLProfile.VersionLegacy; + if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2)) + { + profile = NSOpenGLProfile.Version3_2Core; + Debug.Print("Running the OpenGL core profile."); + } + else + { + Debug.Print("Running the legacy OpenGL profile. Start with version major=3, minor=2 or later for the 3.2 profile."); + } + + Debug.Print("NSGL pixel format attributes:"); + Debug.Indent(); + + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.OpenGLProfile, (int)profile); + + if (mode.ColorFormat.BitsPerPixel > 0) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.ColorSize, mode.ColorFormat.BitsPerPixel); + } + + if (mode.Depth > 0) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.DepthSize, mode.Depth); + } + + if (mode.Stencil > 0) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.StencilSize, mode.Stencil); + } + + if (mode.AccumulatorFormat.BitsPerPixel > 0) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.AccumSize, mode.AccumulatorFormat.BitsPerPixel); + } + + if (mode.Samples > 1) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.SampleBuffers, 1); + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.Samples, mode.Samples); + } + + if (mode.Buffers > 1) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.DoubleBuffer); + } + + // If at least a single accelerated pixel format is available, + // then use that. If no accelerated formats are available, fall + // back to software rendering. + if (IsAccelerationSupported()) + { + AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.Accelerated); + } + + AddPixelAttrib(attributes, (NSOpenGLPixelFormatAttribute)0); + + Debug.Unindent(); + + Debug.Write("Attribute array: "); + for (int i = 0; i < attributes.Count; i++) + { + Debug.Write(attributes[i].ToString() + " "); + } + Debug.WriteLine(""); + + // Create pixel format + var pixelFormat = Cocoa.SendIntPtr(Class.Get("NSOpenGLPixelFormat"), Selector.Alloc); + + unsafe + { + fixed (NSOpenGLPixelFormatAttribute* ptr = attributes.ToArray()) + { + pixelFormat = Cocoa.SendIntPtr(pixelFormat, Selector.Get("initWithAttributes:"), (IntPtr)ptr); + } + } + + return pixelFormat; + } + + private bool IsAccelerationSupported() + { + IntPtr pf = IntPtr.Zero; + int count = 0; + Cgl.ChoosePixelFormat(new int[] { (int)Cgl.PixelFormatBool.Accelerated, 0 }, + ref pf, ref count); + + if (pf != IntPtr.Zero) + { + Cgl.DestroyPixelFormat(pf); + } + + return pf != IntPtr.Zero; + } + + private GraphicsMode GetGraphicsMode(IntPtr context) + { + IntPtr cgl_context = Cocoa.SendIntPtr(context, Selector.Get("CGLContextObj")); + IntPtr cgl_format = Cgl.GetPixelFormat(cgl_context); + + int id = 0; // CGL does not support the concept of a pixel format id + int color, depth, stencil, samples, accum; + bool doublebuffer, stereo; + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.ColorSize, out color); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.DepthSize, out depth); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.StencilSize, out stencil); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.Samples, out samples); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.AccumSize, out accum); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatBool.Doublebuffer, out doublebuffer); + Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatBool.Stereo, out stereo); + + return new GraphicsMode((IntPtr)id, color, depth, stencil, samples, accum, doublebuffer ? 2 : 1, stereo); + } + + public override void SwapBuffers() + { + Cocoa.SendVoid(Handle.Handle, selFlushBuffer); + } + + public override void MakeCurrent(IWindowInfo window) + { + Cocoa.SendVoid(Handle.Handle, selMakeCurrentContext); + } + + public override bool IsCurrent + { + get + { + return Handle.Handle == CurrentContext; + } + } + + public static IntPtr CurrentContext + { + get + { + return Cocoa.SendIntPtr(NSOpenGLContext, selCurrentContext); + } + } + + private unsafe void SetContextValue (int val, NSOpenGLContextParameter par) + { + int* p = &val; + Cocoa.SendVoid(Handle.Handle, Selector.Get("setValues:forParameter:"), (IntPtr)p, (int)par); + } + + private unsafe int GetContextValue (NSOpenGLContextParameter par) + { + int ret; + int* p = &ret; + Cocoa.SendVoid(Handle.Handle, Selector.Get("getValues:forParameter:"), (IntPtr)p, (int)par); + return ret; + } + + public override int SwapInterval + { + get + { + return GetContextValue(NSOpenGLContextParameter.SwapInterval); + } + set + { + if (value < 0) + { + // NSOpenGL does not offer EXT_swap_control_tear yet + value = 1; + } + SetContextValue(value, NSOpenGLContextParameter.SwapInterval); + } + } + + public override void Update(IWindowInfo window) + { + Cocoa.SendVoid(Handle.Handle, selUpdate); + } + + protected override void Dispose(bool disposing) + { + if (IsDisposed || Handle.Handle == IntPtr.Zero) + { + return; + } + + Debug.Print("Disposing of Cocoa context."); + + if (!NSApplication.IsUIThread) + { + return; + } + + using (var pool = new NSAutoreleasePool()) + { + if (IsCurrent) + { + Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext")); + } + + Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); + Cocoa.SendVoid(Handle.Handle, Selector.Get("release")); + } + + Handle = ContextHandle.Zero; + + IsDisposed = true; + } + + public override IntPtr GetAddress(IntPtr function) + { + unsafe + { + // Add a leading underscore to the function name + // As of OpenGL 4.4, all functions are < 64 bytes + // in length. Double that just to be sure. + const int max = 128; + byte* fun = stackalloc byte[max]; + byte* ptr = fun; + byte* cur = (byte*)function.ToPointer(); + int i = 0; + + *ptr++ = (byte)'_'; + while (*cur != 0 && ++i < max) + { + *ptr++ = *cur++; + } + + if (i >= max - 1) + { + Debug.Print("Function {0} too long. Loading will fail.", + Marshal.PtrToStringAnsi(function)); + } + + IntPtr address = IntPtr.Zero; + IntPtr symbol = IntPtr.Zero; + if (opengl != IntPtr.Zero) + { + symbol = NS.LookupSymbolInImage(opengl, new IntPtr(fun), + SymbolLookupFlags.Bind | SymbolLookupFlags.ReturnOnError); + } + if (symbol == IntPtr.Zero && opengles != IntPtr.Zero) + { + symbol = NS.LookupSymbolInImage(opengles, new IntPtr(fun), + SymbolLookupFlags.Bind | SymbolLookupFlags.ReturnOnError); + } + if (symbol != IntPtr.Zero) + { + address = NS.AddressOfSymbol(symbol); + } + return address; + } + } + } +} + diff --git a/GLWidget/OpenTK/Platform/MacOS/CocoaWindowInfo.cs b/GLWidget/OpenTK/Platform/MacOS/CocoaWindowInfo.cs new file mode 100644 index 0000000..bfef467 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/CocoaWindowInfo.cs @@ -0,0 +1,113 @@ +// +// CocoaWindowInfo.cs +// +// Author: +// Olle Håkansson +// +// Copyright (c) 2014 Olle Håkansson +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Diagnostics; + +namespace OpenTK.Platform.MacOS +{ + /// \internal + /// + /// Describes a Cocoa window. + /// + internal sealed class CocoaWindowInfo : IWindowInfo + { + private static readonly IntPtr selContentView = Selector.Get("contentView"); + + private bool disposed = false; + + /// + /// Constructs a new instance with the specified parameters. + /// + /// This constructor assumes that the NSWindow's contentView is the NSView we want to attach to our context. + /// A valid NSWindow reference. + public CocoaWindowInfo(IntPtr nsWindowRef) : this(nsWindowRef, Cocoa.SendIntPtr(nsWindowRef, selContentView)) + { + + } + + /// + /// Constructs a new instance with the specified parameters. + /// + /// A valid NSWindow reference. + /// A valid NSView reference. + public CocoaWindowInfo(IntPtr nsWindowRef, IntPtr nsViewRef) + { + this.Handle = nsWindowRef; + this.ViewHandle = nsViewRef; + Cocoa.SendVoid(nsWindowRef, Selector.Retain); + } + + /// + /// Gets the window reference for this instance. + /// + public IntPtr Handle { get; } + + /// + /// Gets the view reference for this instance. + /// + public IntPtr ViewHandle { get; } + + /// Returns a System.String that represents the current window. + /// A System.String that represents the current window. + public override string ToString() + { + return String.Format("MacOS.CocoaWindowInfo: NSWindow {0}, NSView {1}", Handle, ViewHandle); + } + + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + Cocoa.SendVoid(Handle, Selector.Release); + } + else + { + Debug.Print("CocoaWindowInfo:{0} leaked, did you forget to call Dispose()?", Handle); + } + + disposed = true; + } + + #if DEBUG + ~CocoaWindowInfo() + { + Dispose(false); + } + #endif + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/MacOS/CoreVideo.cs b/GLWidget/OpenTK/Platform/MacOS/CoreVideo.cs new file mode 100644 index 0000000..24ec94c --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/CoreVideo.cs @@ -0,0 +1,34 @@ +// See License.txt file for copyright details + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + [StructLayout(LayoutKind.Sequential)] + internal struct CVTime + { + public Int64 timeValue; + public Int32 timeScale; + public Int32 flags; + } + + internal class CV + { + private const string LibPath = "/System/Library/Frameworks/CoreVideo.framework/Versions/Current/CoreVideo"; + + internal enum TimeFlags : Int32 + { + TimeIsIndefinite = 1 << 0 + } + + [DllImport(LibPath, EntryPoint = "CVDisplayLinkCreateWithCGDisplay")] + public extern static IntPtr DisplayLinkCreateWithCGDisplay(IntPtr currentDisplay, out IntPtr displayLink); + + [DllImport(LibPath, EntryPoint = "CVDisplayLinkGetNominalOutputVideoRefreshPeriod")] + public extern static CVTime DisplayLinkGetNominalOutputVideoRefreshPeriod(IntPtr displayLink); + + [DllImport(LibPath, EntryPoint = "CVDisplayLinkRelease")] + public extern static void DisplayLinkRelease(IntPtr displayLink); + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/MacOSException.cs b/GLWidget/OpenTK/Platform/MacOS/MacOSException.cs new file mode 100644 index 0000000..0b364ae --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/MacOSException.cs @@ -0,0 +1,117 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +// Created by Erik Ylvisaker on 3/17/08. + +using System; + +namespace OpenTK.Platform.MacOS +{ + internal class MacOSException : Exception + { + public MacOSException() + {} + public MacOSException(OSStatus errorCode) + : base("Error Code " + ((int)errorCode).ToString() + ": " + errorCode.ToString()) + { + this.ErrorCode = errorCode; + } + public MacOSException(OSStatus errorCode, string message) + : base(message) + { + this.ErrorCode = errorCode; + } + internal MacOSException(int errorCode, string message) + : base(message) + { + this.ErrorCode = (OSStatus)errorCode; + } + + public OSStatus ErrorCode { get; } + } + + internal enum OSStatus + { + NoError = 0, + + ParameterError = -50, /*error in user parameter list*/ + NoHardwareError = -200, /*Sound Manager Error Returns*/ + NotEnoughHardwareError = -201, /*Sound Manager Error Returns*/ + UserCanceledError = -128, + QueueError = -1, /*queue element not found during deletion*/ + VTypErr = -2, /*invalid queue element*/ + CorErr = -3, /*core routine number out of range*/ + UnimpErr = -4, /*unimplemented core routine*/ + SlpTypeErr = -5, /*invalid queue element*/ + SeNoDB = -8, /*no debugger installed to handle debugger command*/ + ControlErr = -17, /*I/O System Errors*/ + StatusErr = -18, /*I/O System Errors*/ + ReadErr = -19, /*I/O System Errors*/ + WritErr = -20, /*I/O System Errors*/ + BadUnitErr = -21, /*I/O System Errors*/ + UnitEmptyErr = -22, /*I/O System Errors*/ + OpenErr = -23, /*I/O System Errors*/ + ClosErr = -24, /*I/O System Errors*/ + DRemovErr = -25, /*tried to remove an open driver*/ + DInstErr = -26, /*DrvrInstall couldn't find driver in resources*/ + + // Window Manager result codes. + InvalidWindowPtr = -5600, + UnsupportedWindowAttributesForClass = -5601, + WindowDoesNotHaveProxy = -5602, + WindowPropertyNotFound = -5604, + UnrecognizedWindowClass = -5605, + CorruptWindowDescription = -5606, + UserWantsToDragWindow = -5607, + WindowsAlreadyInitialized = -5608, + FloatingWindowsNotInitialized = -5609, + WindowNotFound = -5610, + WindowDoesNotFitOnscreen = -5611, + WindowAttributeImmutable = -5612, + WindowAttributesConflict = -5613, + WindowManagerInternalError = -5614, + WindowWrongState = -5615, + WindowGroupInvalid = -5616, + WindowAppModalStateAlreadyExists = -5617, + WindowNoAppModalState = -5618, + WindowDoesntSupportFocus = -30583, + WindowRegionCodeInvalid = -30593, + + // Event Manager result codes + EventAlreadyPosted = -9860, + EventTargetBusy = -9861, + EventDeferAccessibilityEvent = -9865, + EventInternalError = -9868, + EventParameterNotFound = -9870, + EventNotHandled = -9874, + EventLoopTimedOut = -9875, + EventLoopQuit = -9876, + EventNotInQueue = -9877, + HotKeyExists = -9878, + EventPassToNextTarget = -9880 + + } + +} diff --git a/GLWidget/OpenTK/Platform/MacOS/MacOSFactory.cs b/GLWidget/OpenTK/Platform/MacOS/MacOSFactory.cs new file mode 100644 index 0000000..08e8821 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/MacOSFactory.cs @@ -0,0 +1,74 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace OpenTK.Platform.MacOS +{ + using Graphics; + + internal class MacOSFactory : PlatformFactoryBase + { + // Todo: we can query the exact amount via + // CGEventSourceGetPixelsPerLine. This is + // approximately 0.1f + internal const float ScrollFactor = 0.1f; + internal static bool ExclusiveFullscreen = false; + + public MacOSFactory() + { + NSApplication.Initialize(); + } + + public override IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + return new QuartzDisplayDeviceDriver(); + } + + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return new CocoaContext(mode, window, shareContext, major, minor); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return new CocoaContext(handle, window, shareContext, major, minor); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(CocoaContext.CurrentContext); + }; + } + + protected override void Dispose(bool manual) + { + if (!IsDisposed) + { + base.Dispose(manual); + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/NS.cs b/GLWidget/OpenTK/Platform/MacOS/NS.cs new file mode 100644 index 0000000..8efdc79 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/NS.cs @@ -0,0 +1,170 @@ +// +// NS.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + [Flags] + internal enum AddImageFlags + { + ReturnOnError = 1, + WithSearching = 2, + ReturnOnlyIfLoaded = 4 + } + + [Flags] + internal enum SymbolLookupFlags + { + Bind = 0, + BindNow = 1, + BindFully = 2, + ReturnOnError = 4 + } + + internal class NS + { + private const string Library = "libdl.dylib"; + + [DllImport(Library, EntryPoint = "NSAddImage")] + internal static extern IntPtr AddImage(string s, AddImageFlags flags); + [DllImport(Library, EntryPoint = "NSAddressOfSymbol")] + internal static extern IntPtr AddressOfSymbol(IntPtr symbol); + [DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")] + internal static extern bool IsSymbolNameDefined(string s); + [DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")] + internal static extern bool IsSymbolNameDefined(IntPtr s); + [DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")] + internal static extern IntPtr LookupAndBindSymbol(string s); + [DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")] + internal static extern IntPtr LookupAndBindSymbol(IntPtr s); + [DllImport(Library, EntryPoint = "NSLookupSymbolInImage")] + internal static extern IntPtr LookupSymbolInImage(IntPtr image, IntPtr symbolName, SymbolLookupFlags options); + + // Unfortunately, these are slower even if they are more + // portable and simpler to use. + [DllImport(Library)] + internal static extern IntPtr dlopen(String fileName, int flags); + [DllImport(Library)] + internal static extern int dlclose(IntPtr handle); + [DllImport (Library)] + internal static extern IntPtr dlsym (IntPtr handle, string symbol); + [DllImport (Library)] + internal static extern IntPtr dlsym (IntPtr handle, IntPtr symbol); + + public static IntPtr GetAddress(string function) + { + // Instead of allocating and combining strings in managed memory + // we do that directly in unmanaged memory. This way, we avoid + // 2 string allocations every time this function is called. + + // must add a '_' prefix and null-terminate the function name, + // hence we allocate +2 bytes + IntPtr ptr = Marshal.AllocHGlobal(function.Length + 2); + try + { + Marshal.WriteByte(ptr, (byte)'_'); + for (int i = 0; i < function.Length; i++) + { + Marshal.WriteByte(ptr, i + 1, (byte)function[i]); + } + Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate + + IntPtr symbol = GetAddressInternal(ptr); + return symbol; + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + public static IntPtr GetAddress(IntPtr function) + { + unsafe + { + const int max = 64; + byte* symbol = stackalloc byte[max]; + byte* ptr = symbol; + byte* cur = (byte*)function.ToPointer(); + int i = 0; + + *ptr++ = (byte)'_'; + while (*cur != 0 && ++i < max) + { + *ptr++ = *cur++; + } + + if (i >= max - 1) + { + throw new NotSupportedException(String.Format( + "Function {0} is too long. Please report a bug at https://github.com/opentk/issues/issues", + Marshal.PtrToStringAnsi(function))); + } + + return GetAddressInternal(new IntPtr(symbol)); + } + } + + private static IntPtr GetAddressInternal(IntPtr function) + { + IntPtr symbol = IntPtr.Zero; + if (IsSymbolNameDefined(function)) + { + symbol = LookupAndBindSymbol(function); + if (symbol != IntPtr.Zero) + { + symbol = AddressOfSymbol(symbol); + } + } + return symbol; + } + + public static IntPtr GetSymbol(IntPtr handle, string symbol) + { + return dlsym(handle, symbol); + } + + public static IntPtr GetSymbol(IntPtr handle, IntPtr symbol) + { + return dlsym(handle, symbol); + } + + public static IntPtr LoadLibrary(string fileName) + { + const int RTLD_NOW = 2; + return dlopen(fileName, RTLD_NOW); + } + + public static void FreeLibrary(IntPtr handle) + { + dlclose(handle); + } + } +} + diff --git a/GLWidget/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs b/GLWidget/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs new file mode 100644 index 0000000..22837e7 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Quartz/CoreFoundation.cs @@ -0,0 +1,244 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace OpenTK.Platform.MacOS.Carbon +{ + using CFAllocatorRef = IntPtr; + using CFIndex = System.IntPtr; + using CFRunLoop = System.IntPtr; + using CFRunLoopRef = IntPtr; + using CFRunLoopSourceRef = IntPtr; + using CFStringRef = System.IntPtr; + using CFTypeRef = System.IntPtr; + using CFMachPortRef = IntPtr; + + internal struct CFArray + { + public IntPtr Ref { get; set; } + + public CFArray(IntPtr reference) + { + Ref = reference; + } + + public int Count + { + get { return CF.CFArrayGetCount(Ref); } + } + public IntPtr this[int index] + { + get + { + if (index >= Count || index < 0) + { + throw new IndexOutOfRangeException(); + } + + return CF.CFArrayGetValueAtIndex(Ref, index); + } + } + } + + internal struct CFDictionary + { + public CFDictionary(IntPtr reference) + { + Ref = reference; + } + + public IntPtr Ref { get; set; } + + public int Count + { + get + { + return CF.CFDictionaryGetCount(Ref); + } + } + + public double GetNumberValue(string key) + { + double retval; + IntPtr cfnum = CF.CFDictionaryGetValue(Ref, + CF.CFSTR(key)); + + CF.CFNumberGetValue(cfnum, CF.CFNumberType.kCFNumberDoubleType, out retval); + + return retval; + } + } + + internal class CF + { + private const string appServices = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices"; + + [DllImport(appServices)] + internal static extern int CFArrayGetCount(IntPtr theArray); + + [DllImport(appServices)] + internal static extern IntPtr CFArrayGetValueAtIndex(IntPtr theArray, int idx); + + [DllImport(appServices)] + internal static extern int CFDictionaryGetCount(IntPtr theDictionary); + + [DllImport(appServices)] + internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey); + + [DllImport(appServices)] + internal static extern IntPtr CFGetTypeID(IntPtr v); + + [DllImport(appServices)] + internal static extern IntPtr CFRetain(CFTypeRef cf); + + [DllImport(appServices)] + internal static extern void CFRelease(CFTypeRef cf); + + // this mirrors the definition in CFString.h. + // I don't know why, but __CFStringMakeConstantString is marked as "private and should not be used directly" + // even though the CFSTR macro just calls it. + [DllImport(appServices)] + private static extern IntPtr __CFStringMakeConstantString(string cStr); + internal static IntPtr CFSTR(string cStr) + { + return __CFStringMakeConstantString(cStr); + } + + [DllImport(appServices)] + internal static extern Boolean CFStringGetCString( + CFStringRef theString, + byte[] buffer, + CFIndex bufferSize, + CFStringEncoding encoding + ); + + internal static string CFStringGetCString(IntPtr cfstr) + { + CFIndex length = CFStringGetLength(cfstr); + if (length != IntPtr.Zero) + { + byte[] utf8_chars = new byte[length.ToInt32() + 1]; + if (CFStringGetCString(cfstr, utf8_chars, new IntPtr(utf8_chars.Length), CFStringEncoding.UTF8)) + { + return Encoding.UTF8.GetString(utf8_chars); + } + } + return String.Empty; + } + + [DllImport(appServices)] + internal static extern CFIndex CFStringGetLength( + CFStringRef theString + ); + + [DllImport(appServices)] + internal static extern bool CFNumberGetValue (IntPtr number, CFNumberType theType, out int valuePtr); + [DllImport(appServices)] + internal static extern bool CFNumberGetValue (IntPtr number, CFNumberType theType, out long valuePtr); + [DllImport(appServices)] + internal static extern bool CFNumberGetValue(IntPtr number, CFNumberType theType, out double valuePtr); + + internal enum CFNumberType + { + kCFNumberSInt8Type = 1, + kCFNumberSInt16Type = 2, + kCFNumberSInt32Type = 3, + kCFNumberSInt64Type = 4, + kCFNumberFloat32Type = 5, + kCFNumberFloat64Type = 6, + kCFNumberCharType = 7, + kCFNumberShortType = 8, + kCFNumberIntType = 9, + kCFNumberLongType = 10, + kCFNumberLongLongType = 11, + kCFNumberFloatType = 12, + kCFNumberDoubleType = 13, + kCFNumberCFIndexType = 14, + kCFNumberNSIntegerType = 15, + kCFNumberCGFloatType = 16, + kCFNumberMaxType = 16 + }; + + public enum CFRunLoopExitReason + { + Finished = 1, + Stopped = 2, + TimedOut = 3, + HandledSource = 4 + } + + public enum CFStringEncoding + { + MacRoman = 0, + WindowsLatin1 = 0x0500, + ISOLatin1 = 0x0201, + NextStepLatin = 0x0B01, + ASCII = 0x0600, + Unicode = 0x0100, + UTF8 = 0x08000100, + NonLossyASCII = 0x0BFF, + + UTF16 = 0x0100, + UTF16BE = 0x10000100, + UTF16LE = 0x14000100, + UTF32 = 0x0c000100, + UTF32BE = 0x18000100, + UTF32LE = 0x1c000100 + } + + public static readonly IntPtr RunLoopModeDefault = CF.CFSTR("kCFRunLoopDefaultMode"); + + [DllImport(appServices)] + internal static extern CFRunLoop CFRunLoopGetCurrent(); + + [DllImport(appServices)] + internal static extern CFRunLoop CFRunLoopGetMain(); + + [DllImport(appServices)] + internal static extern CFRunLoopExitReason CFRunLoopRunInMode( + IntPtr cfstrMode, double interval, bool returnAfterSourceHandled); + + [DllImport(appServices, EntryPoint = "CFMachPortCreateRunLoopSource")] + internal static extern CFRunLoopSourceRef MachPortCreateRunLoopSource( + CFAllocatorRef allocator, + CFMachPortRef port, + CFIndex order); + + [DllImport(appServices, EntryPoint = "CFRunLoopAddSource")] + internal static extern void RunLoopAddSource( + CFRunLoopRef rl, + CFRunLoopSourceRef source, + CFStringRef mode); + + [DllImport(appServices, EntryPoint = "CFRunLoopRemoveSource")] + internal static extern void RunLoopRemoveSource( + CFRunLoopRef rl, + CFRunLoopSourceRef source, + CFStringRef mode); + } +} diff --git a/GLWidget/OpenTK/Platform/MacOS/Quartz/DisplayServices.cs b/GLWidget/OpenTK/Platform/MacOS/Quartz/DisplayServices.cs new file mode 100644 index 0000000..c37bb48 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Quartz/DisplayServices.cs @@ -0,0 +1,132 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + using CGDirectDisplayID = System.IntPtr; + + // Quartz Display services used here are available in MacOS X 10.3 and later. + + internal enum CGDisplayErr + { + + } + + internal enum CGError + { + Success = 0, + Failure = 1000, + IllegalArgument = 1001, + InvalidConnection = 1002, + InvalidContext = 1003, + CannotComplete = 1004, + NotImplemented = 1006, + RangeCheck = 1007, + TypeCheck = 1008, + InvalidOperation = 1010, + NoneAvailable = 1011, + } + + internal partial class CG + { + private const string lib = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices"; + + // CGPoint -> NSPoint + // CGSize -> NSSize + // CGRect -> NSRect + + [DllImport(lib, EntryPoint="CGGetActiveDisplayList")] + internal unsafe static extern CGDisplayErr GetActiveDisplayList(int maxDisplays, IntPtr* activeDspys, out int dspyCnt); + + [DllImport(lib, EntryPoint="CGMainDisplayID")] + internal static extern IntPtr MainDisplayID(); + + // Note: sizeof(HIRect) == 16, which is larger than 8 bytes. + // The x86 and x64 Mac ABIs pass such structs as pointers in the + // first parameter slot. This is normally handled automatically + // by gcc/clang, but here we have to do it ourselves. + // See "Listing 4" on https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW3 + internal unsafe static NSRect DisplayBounds(IntPtr display) + { + NSRect rect; + DisplayBounds(out rect, display); + return rect; + } + + [DllImport(lib, EntryPoint = "CGDisplayBounds")] + private unsafe static extern void DisplayBounds(out NSRect rect, IntPtr display); + + [DllImport(lib, EntryPoint="CGDisplayPixelsWide")] + internal static extern int DisplayPixelsWide(IntPtr display); + + [DllImport(lib, EntryPoint="CGDisplayPixelsHigh")] + internal static extern int DisplayPixelsHigh(IntPtr display); + + [DllImport(lib, EntryPoint="CGDisplayCurrentMode")] + internal static extern IntPtr DisplayCurrentMode(IntPtr display); + + [DllImport(lib, EntryPoint="CGDisplayCapture")] + internal static extern CGDisplayErr DisplayCapture(IntPtr display); + + [DllImport(lib, EntryPoint="CGCaptureAllDisplays")] + internal static extern CGDisplayErr CaptureAllDisplays(); + + [DllImport(lib, EntryPoint="CGShieldingWindowLevel")] + internal static extern uint ShieldingWindowLevel(); + + [DllImport(lib, EntryPoint="CGDisplayRelease")] + internal static extern CGDisplayErr DisplayRelease(IntPtr display); + + [DllImport(lib, EntryPoint="CGReleaseAllDisplays")] + internal static extern CGDisplayErr DisplayReleaseAll(); + + [DllImport(lib, EntryPoint = "CGDisplayAvailableModes")] + internal static extern IntPtr DisplayAvailableModes(IntPtr display); + + [DllImport(lib, EntryPoint = "CGDisplaySwitchToMode")] + internal static extern IntPtr DisplaySwitchToMode(IntPtr display, IntPtr displayMode); + + [DllImport(lib, EntryPoint = "CGWarpMouseCursorPosition")] + internal static extern CGError WarpMouseCursorPosition(NSPoint newCursorPosition); + + [DllImport(lib, EntryPoint = "CGCursorIsVisible")] + internal static extern bool CursorIsVisible(); + + [DllImport(lib, EntryPoint = "CGDisplayShowCursor")] + internal static extern CGError DisplayShowCursor(CGDirectDisplayID display); + + [DllImport(lib, EntryPoint = "CGDisplayHideCursor")] + internal static extern CGError DisplayHideCursor(CGDirectDisplayID display); + + [DllImport(lib, EntryPoint = "CGAssociateMouseAndMouseCursorPosition")] + internal static extern CGError AssociateMouseAndMouseCursorPosition(bool connected); + + [DllImport(lib, EntryPoint="CGSetLocalEventsSuppressionInterval")] + internal static extern CGError SetLocalEventsSuppressionInterval(double seconds); + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/MacOS/Quartz/EventServices.cs b/GLWidget/OpenTK/Platform/MacOS/Quartz/EventServices.cs new file mode 100644 index 0000000..d0d3619 --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/Quartz/EventServices.cs @@ -0,0 +1,221 @@ +// +// EventServices.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.MacOS +{ + using CGEventTapProxy = IntPtr; + using CGEventRef = IntPtr; + using CFMachPortRef = IntPtr; + + internal partial class CG + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate CGEventRef EventTapCallBack( + CGEventTapProxy proxy, + CGEventType type, + CGEventRef @event, + IntPtr refcon); + + [DllImport(lib, EntryPoint = "CGEventTapCreate")] + public static extern CFMachPortRef EventTapCreate( + CGEventTapLocation tap, + CGEventTapPlacement place, + CGEventTapOptions options, + CGEventMask eventsOfInterest, + [MarshalAs(UnmanagedType.FunctionPtr)] + EventTapCallBack callback, + IntPtr refcon); + + [DllImport(lib, EntryPoint = "CGEventGetDoubleValueField")] + internal static extern double EventGetDoubleValueField( + CGEventRef @event, + CGEventField field); + + [DllImport(lib, EntryPoint = "CGEventGetIntegerValueField")] + internal static extern int EventGetIntegerValueField( + CGEventRef @event, + CGEventField field); + + [DllImport(lib, EntryPoint = "CGEventGetLocation")] + internal static extern NSPointF EventGetLocationF(CGEventRef @event); + [DllImport(lib, EntryPoint = "CGEventGetLocation")] + internal static extern NSPointD EventGetLocationD(CGEventRef @event); + + internal static NSPoint EventGetLocation(CGEventRef @event) + { + NSPoint r = new NSPoint(); + + unsafe { + if (IntPtr.Size == 4) + { + NSPointF pf = EventGetLocationF(@event); + r.X.Value = *(IntPtr *)&pf.X; + r.Y.Value = *(IntPtr *)&pf.Y; + } + else + { + NSPointD pd = EventGetLocationD(@event); + r.X.Value = *(IntPtr *)&pd.X; + r.Y.Value = *(IntPtr *)&pd.Y; + } + } + + return r; + } + + } + + internal enum CGEventTapLocation + { + HIDEventTap = 0, + SessionEventTap, + AnnotatedSessionEventTap + } + + internal enum CGEventTapPlacement + { + HeadInsert = 0, + TailAppend + } + + internal enum CGEventTapOptions + { + Default = 0x00000000, + ListenOnly = 0x00000001 + } + + [Flags] + internal enum CGEventMask : long + { + LeftMouseDown = 1 << CGEventType.LeftMouseDown, + LeftMouseUp = 1 << CGEventType.LeftMouseUp, + RightMouseDown = 1 << CGEventType.RightMouseDown, + RightMouseUp = 1 << CGEventType.RightMouseUp, + MouseMoved = 1 << CGEventType.MouseMoved, + LeftMouseDragged = 1 << CGEventType.LeftMouseDown, + RightMouseDragged = 1 << CGEventType.RightMouseDown, + KeyDown = 1 << CGEventType.KeyDown, + KeyUp = 1 << CGEventType.KeyUp, + FlagsChanged = 1 << CGEventType.FlagsChanged, + ScrollWheel = 1 << CGEventType.ScrollWheel, + TabletPointer = 1 << CGEventType.TabletPointer, + TabletProximity = 1 << CGEventType.TabletProximity, + OtherMouseDown = 1 << CGEventType.OtherMouseDown, + OtherMouseUp = 1 << CGEventType.OtherMouseUp, + OtherMouseDragged = 1 << CGEventType.OtherMouseDragged, + All = -1, + AllMouse = + LeftMouseDown | LeftMouseUp | LeftMouseDragged | + RightMouseDown | RightMouseUp | RightMouseDragged | + OtherMouseDown | OtherMouseUp | OtherMouseDragged | + ScrollWheel | MouseMoved + } + + internal enum CGEventType + { + Null = 0, + LeftMouseDown = 1, + LeftMouseUp = 2, + RightMouseDown = 3, + RightMouseUp = 4, + MouseMoved = 5, + LeftMouseDragged = 6, + RightMouseDragged = 7, + KeyDown = 10, + KeyUp = 11, + FlagsChanged = 12, + ScrollWheel = 22, + TabletPointer = 23, + TabletProximity = 24, + OtherMouseDown = 25, + OtherMouseUp = 26, + OtherMouseDragged = 27, + TapDisabledByTimeout = -2, + TapDisabledByUserInput = -1 + } + + internal enum CGEventField + { + MouseEventNumber = 0, + MouseEventClickState = 1, + MouseEventPressure = 2, + MouseEventButtonNumber = 3, + MouseEventDeltaX = 4, + MouseEventDeltaY = 5, + MouseEventInstantMouser = 6, + MouseEventSubtype = 7, + KeyboardEventAutorepeat = 8, + KeyboardEventKeycode = 9, + KeyboardEventKeyboardType = 10, + ScrollWheelEventDeltaAxis1 = 11, + ScrollWheelEventDeltaAxis2 = 12, + ScrollWheelEventDeltaAxis3 = 13, + ScrollWheelEventFixedPtDeltaAxis1 = 93, + ScrollWheelEventFixedPtDeltaAxis2 = 94, + ScrollWheelEventFixedPtDeltaAxis3 = 95, + ScrollWheelEventPointDeltaAxis1 = 96, + ScrollWheelEventPointDeltaAxis2 = 97, + ScrollWheelEventPointDeltaAxis3 = 98, + ScrollWheelEventInstantMouser = 14, + TabletEventPointX = 15, + TabletEventPointY = 16, + TabletEventPointZ = 17, + TabletEventPointButtons = 18, + TabletEventPointPressure = 19, + TabletEventTiltX = 20, + TabletEventTiltY = 21, + TabletEventRotation = 22, + TabletEventTangentialPressure = 23, + TabletEventDeviceID = 24, + TabletEventVendor1 = 25, + TabletEventVendor2 = 26, + TabletEventVendor3 = 27, + TabletProximityEventVendorID = 28, + TabletProximityEventTabletID = 29, + TabletProximityEventPointerID = 30, + TabletProximityEventDeviceID = 31, + TabletProximityEventSystemTabletID = 32, + TabletProximityEventVendorPointerType = 33, + TabletProximityEventVendorPointerSerialNumber = 34, + TabletProximityEventVendorUniqueID = 35, + TabletProximityEventCapabilityMask = 36, + TabletProximityEventPointerType = 37, + TabletProximityEventEnterProximity = 38, + EventTargetProcessSerialNumber = 39, + EventTargetUnixProcessID = 40, + EventSourceUnixProcessID = 41, + EventSourceUserData = 42, + EventSourceUserID = 43, + EventSourceGroupID = 44, + EventSourceStateID = 45, + ScrollWheelEventIsContinuous = 88 + } +} + diff --git a/GLWidget/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs b/GLWidget/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs new file mode 100644 index 0000000..666a8bd --- /dev/null +++ b/GLWidget/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs @@ -0,0 +1,209 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using OpenTK.Platform.MacOS.Carbon; + +namespace OpenTK.Platform.MacOS +{ + internal sealed class QuartzDisplayDeviceDriver : DisplayDeviceBase + { + private static object display_lock = new object(); + + public QuartzDisplayDeviceDriver() + { + lock (display_lock) + { + // To minimize the need to add static methods to OpenTK.Graphics.DisplayDevice + // we only allow settings to be set through its constructor. + // Thus, we save all necessary parameters in temporary variables + // and construct the device when every needed detail is available. + // The main DisplayDevice constructor adds the newly constructed device + // to the list of available devices. + const int maxDisplayCount = 20; + IntPtr[] displays = new IntPtr[maxDisplayCount]; + int displayCount; + + unsafe + { + fixed (IntPtr* displayPtr = displays) + { + CG.GetActiveDisplayList(maxDisplayCount, displayPtr, out displayCount); + } + } + + Debug.Print("CoreGraphics reported {0} display(s).", displayCount); + Debug.Indent(); + + for (int i = 0; i < displayCount; i++) + { + IntPtr currentDisplay = displays[i]; + + // according to docs, first element in the array is always the + // main display. + bool primary = (i == 0); + + // gets current settings + int currentWidth = CG.DisplayPixelsWide(currentDisplay); + int currentHeight = CG.DisplayPixelsHigh(currentDisplay); + Debug.Print("Display {0} is at {1}x{2}", i, currentWidth, currentHeight); + + IntPtr displayModesPtr = CG.DisplayAvailableModes(currentDisplay); + CFArray displayModes = new CFArray(displayModesPtr); + Debug.Print("Supports {0} display modes.", displayModes.Count); + + DisplayResolution opentk_dev_current_res = null; + List opentk_dev_available_res = new List(); + IntPtr currentModePtr = CG.DisplayCurrentMode(currentDisplay); + CFDictionary currentMode = new CFDictionary(currentModePtr); + + for (int j = 0; j < displayModes.Count; j++) + { + CFDictionary dict = new CFDictionary(displayModes[j]); + + int width = (int)dict.GetNumberValue("Width"); + int height = (int)dict.GetNumberValue("Height"); + int bpp = (int)dict.GetNumberValue("BitsPerPixel"); + double freq = dict.GetNumberValue("RefreshRate"); + bool current = currentMode.Ref == dict.Ref; + + if (freq <= 0) + { + IntPtr displayLink; + CV.DisplayLinkCreateWithCGDisplay(currentDisplay, out displayLink); + + CVTime t = CV.DisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink); + if ((t.flags & (Int32)CV.TimeFlags.TimeIsIndefinite) != (Int32)CV.TimeFlags.TimeIsIndefinite) + { + freq = (double)t.timeScale / t.timeValue; + } + + CV.DisplayLinkRelease(displayLink); + } + + //if (current) Debug.Write(" * "); + //else Debug.Write(" "); + + //Debug.Print("Mode {0} is {1}x{2}x{3} @ {4}.", j, width, height, bpp, freq); + + DisplayResolution thisRes = new DisplayResolution(0, 0, width, height, bpp, (float)freq); + opentk_dev_available_res.Add(thisRes); + + if (current) + { + opentk_dev_current_res = thisRes; + } + } + + NSRect bounds = CG.DisplayBounds(currentDisplay); + Rectangle newRect = new Rectangle((int)bounds.Location.X, (int)bounds.Location.Y, (int)bounds.Size.Width, (int)bounds.Size.Height); + + Debug.Print("Display {0} bounds: {1}", i, newRect); + + DisplayDevice opentk_dev = new DisplayDevice(opentk_dev_current_res, + primary, opentk_dev_available_res, newRect, currentDisplay); + + AvailableDevices.Add(opentk_dev); + + if (primary) + { + Primary = opentk_dev; + } + } + + Debug.Unindent(); + } + } + + static internal IntPtr HandleTo(DisplayDevice displayDevice) + { + return (IntPtr)displayDevice.Id; + } + + private Dictionary storedModes = new Dictionary(); + private List displaysCaptured = new List(); + + public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + { + IntPtr display = HandleTo(device); + IntPtr currentModePtr = CG.DisplayCurrentMode(display); + + if (storedModes.ContainsKey(display) == false) + { + storedModes.Add(display, currentModePtr); + } + + IntPtr displayModesPtr = CG.DisplayAvailableModes(display); + CFArray displayModes = new CFArray(displayModesPtr); + + for (int j = 0; j < displayModes.Count; j++) + { + CFDictionary dict = new CFDictionary(displayModes[j]); + + int width = (int)dict.GetNumberValue("Width"); + int height = (int)dict.GetNumberValue("Height"); + int bpp = (int)dict.GetNumberValue("BitsPerPixel"); + double freq = dict.GetNumberValue("RefreshRate"); + + if (width == resolution.Width && height == resolution.Height && bpp == resolution.BitsPerPixel && System.Math.Abs(freq - resolution.RefreshRate) < 1e-6) + { +// if (displaysCaptured.Contains(display) == false) +// { +// CG.DisplayCapture(display); +// } + + Debug.Print("Changing resolution to {0}x{1}x{2}@{3}.", width, height, bpp, freq); + + CG.DisplaySwitchToMode(display, displayModes[j]); + + return true; + } + + } + return false; + } + + public sealed override bool TryRestoreResolution(DisplayDevice device) + { + IntPtr display = HandleTo(device); + + if (storedModes.ContainsKey(display)) + { + Debug.Print("Restoring resolution."); + + CG.DisplaySwitchToMode(display, storedModes[display]); + //CG.DisplayRelease(display); + displaysCaptured.Remove(display); + + return true; + } + + return false; + } + } +} diff --git a/GLWidget/OpenTK/Platform/PlatformException.cs b/GLWidget/OpenTK/Platform/PlatformException.cs new file mode 100644 index 0000000..abc3b87 --- /dev/null +++ b/GLWidget/OpenTK/Platform/PlatformException.cs @@ -0,0 +1,29 @@ +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ + +using System; + +namespace OpenTK +{ + /// + /// Defines a plaftorm-specific exception. + /// + public class PlatformException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public PlatformException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message explaining the cause for this exception. + public PlatformException(string message) : base(message) { } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/PlatformFactoryBase.cs b/GLWidget/OpenTK/Platform/PlatformFactoryBase.cs new file mode 100644 index 0000000..2f6c644 --- /dev/null +++ b/GLWidget/OpenTK/Platform/PlatformFactoryBase.cs @@ -0,0 +1,106 @@ +// +// PlatformFactoryBase.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using OpenTK.Graphics; + +namespace OpenTK.Platform +{ + /// \internal + /// + /// Implements IPlatformFactory functionality that is common + /// for all platform backends. IPlatformFactory implementations + /// should inherit from this class. + /// + internal abstract class PlatformFactoryBase : IPlatformFactory + { + private static readonly object sync = new object(); + private readonly List Resources = new List(); + + protected bool IsDisposed; + + public PlatformFactoryBase() + { + } + public abstract IDisplayDeviceDriver CreateDisplayDeviceDriver(); + + public abstract IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags); + + public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + throw new NotImplementedException(); + } + + public abstract GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext(); + + public void RegisterResource(IDisposable resource) + { + lock (sync) + { + Resources.Add(resource); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool manual) + { + if (!IsDisposed) + { + if (manual) + { + lock (sync) + { + foreach (var resource in Resources) + { + resource.Dispose(); + } + Resources.Clear(); + } + } + else + { + Debug.Print("[OpenTK] {0} leaked with {1} live resources, did you forget to call Dispose()?", + GetType().FullName, Resources.Count); + } + IsDisposed = true; + } + } + + ~PlatformFactoryBase() + { + Dispose(false); + } + } +} + diff --git a/GLWidget/OpenTK/Platform/Utilities.cs b/GLWidget/OpenTK/Platform/Utilities.cs new file mode 100644 index 0000000..bf202c9 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Utilities.cs @@ -0,0 +1,401 @@ +/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos + * See license.txt for license info + */ + +using System; +using System.Reflection; +using System.Diagnostics; +using OpenTK.Graphics; + +namespace OpenTK.Platform +{ + namespace MacOS + { + /// + /// This delegate represents any method that takes no arguments and returns an int. + /// I would have used Func but that requires .NET 4 + /// + /// The int value that your method returns + public delegate int GetInt(); + } + + /// + /// Provides cross-platform utilities to help interact with the underlying platform. + /// + public static class Utilities + { + private static bool throw_on_error; + internal static bool ThrowOnX11Error + { + get { return throw_on_error; } + set + { + if (value && !throw_on_error) + { + Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms") + .GetField("ErrorExceptions", System.Reflection.BindingFlags.Static | + System.Reflection.BindingFlags.NonPublic) + .SetValue(null, true); + throw_on_error = true; + } + else if (!value && throw_on_error) + { + Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms") + .GetField("ErrorExceptions", System.Reflection.BindingFlags.Static | + System.Reflection.BindingFlags.NonPublic) + .SetValue(null, false); + throw_on_error = false; + } + } + } + + private delegate Delegate LoadDelegateFunction(string name, Type signature); + + /// + /// Loads all extensions for the specified class. This function is intended + /// for OpenGL, Wgl, Glx, OpenAL etc. + /// The class to load extensions for. + /// + /// The Type must contain a nested class called "Delegates". + /// + /// The Type must also implement a static function called LoadDelegate with the + /// following signature: + /// static Delegate LoadDelegate(string name, Type signature) + /// + /// This function allocates memory. + /// + internal static void LoadExtensions(Type type) + { + // Using reflection is more than 3 times faster than directly loading delegates on the first + // run, probably due to code generation overhead. Subsequent runs are faster with direct loading + // than with reflection, but the first time is more significant. + + int supported = 0; + Type extensions_class = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (extensions_class == null) + { + throw new InvalidOperationException("The specified type does not have any loadable extensions."); + } + + FieldInfo[] delegates = extensions_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (delegates == null) + { + throw new InvalidOperationException("The specified type does not have any loadable extensions."); + } + + MethodInfo load_delegate_method_info = type.GetMethod("LoadDelegate", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (load_delegate_method_info == null) + { + throw new InvalidOperationException(type.ToString() + " does not contain a static LoadDelegate method."); + } + LoadDelegateFunction LoadDelegate = (LoadDelegateFunction)Delegate.CreateDelegate( + typeof(LoadDelegateFunction), load_delegate_method_info); + + Debug.Write("Load extensions for " + type.ToString() + "... "); + + System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch(); + time.Reset(); + time.Start(); + + foreach (FieldInfo f in delegates) + { + Delegate d = LoadDelegate(f.Name, f.FieldType); + if (d != null) + { + ++supported; + } + + f.SetValue(null, d); + } + + FieldInfo rebuildExtensionList = type.GetField("rebuildExtensionList", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (rebuildExtensionList != null) + { + rebuildExtensionList.SetValue(null, true); + } + + time.Stop(); + Debug.Print("{0} extensions loaded in {1} ms.", supported, time.ElapsedMilliseconds); + time.Reset(); + } + + /// + /// Loads the specified extension for the specified class. This function is intended + /// for OpenGL, Wgl, Glx, OpenAL etc. + /// The class to load extensions for. + /// The extension to load. + /// + /// The Type must contain a nested class called "Delegates". + /// + /// The Type must also implement a static function called LoadDelegate with the + /// following signature: + /// static Delegate LoadDelegate(string name, Type signature) + /// + /// This function allocates memory. + /// + internal static bool TryLoadExtension(Type type, string extension) + { + Type extensions_class = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (extensions_class == null) + { + Debug.Print(type.ToString(), " does not contain extensions."); + return false; + } + + LoadDelegateFunction LoadDelegate = (LoadDelegateFunction)Delegate.CreateDelegate(typeof(LoadDelegateFunction), + type.GetMethod("LoadDelegate", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)); + if (LoadDelegate == null) + { + Debug.Print(type.ToString(), " does not contain a static LoadDelegate method."); + return false; + } + + FieldInfo f = extensions_class.GetField(extension, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (f == null) + { + Debug.Print("Extension \"", extension, "\" not found in ", type.ToString()); + return false; + } + + Delegate old = f.GetValue(null) as Delegate; + Delegate @new = LoadDelegate(f.Name, f.FieldType); + if ((old != null ? old.Target : null) != (@new != null ? @new.Target : null)) + { + f.SetValue(null, @new); + FieldInfo rebuildExtensionList = type.GetField("rebuildExtensionList", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (rebuildExtensionList != null) + { + rebuildExtensionList.SetValue(null, true); + } + } + return @new != null; + } + + internal static GraphicsContext.GetAddressDelegate CreateGetAddress() + { + if (Configuration.RunningOnWindows) + { + return Platform.Windows.Wgl.GetAddress; + } + if (Configuration.RunningOnX11) + { + return Platform.X11.Glx.GetProcAddress; + } + if (Configuration.RunningOnMacOS) + { + return Platform.MacOS.NS.GetAddress; + } + + // Other platforms: still allow dummy contexts to be created (if no Loader is required) + return EmptyGetAddress; + } + + private static IntPtr EmptyGetAddress(string function) + { + return IntPtr.Zero; + } + + /// + /// Constructs a new IWindowInfo instance for the X11 platform. + /// + /// The display connection. + /// The screen. + /// The handle for the window. + /// The root window for screen. + /// A pointer to a XVisualInfo structure obtained through XGetVisualInfo. + /// A new IWindowInfo instance. + public static IWindowInfo CreateX11WindowInfo(IntPtr display, int screen, IntPtr windowHandle, IntPtr rootWindow, IntPtr visualInfo) + { + Platform.X11.X11WindowInfo window = new OpenTK.Platform.X11.X11WindowInfo(); + window.Display = display; + window.Screen = screen; + window.Handle = windowHandle; + window.RootWindow = rootWindow; + window.Visual = visualInfo; + return window; + } + + /// + /// Creates an IWindowInfo instance for the windows platform. + /// + /// The handle of the window. + /// A new IWindowInfo instance. + public static IWindowInfo CreateWindowsWindowInfo(IntPtr windowHandle) + { + return new OpenTK.Platform.Windows.WinWindowInfo(windowHandle, null); + } + + /// + /// Creates an IWindowInfo instance for the Mac OS X platform. + /// + /// The handle of the window. + /// Ignored. This is reserved for future use. + /// Set to true if windowHandle corresponds to a System.Windows.Forms control. + /// A new IWindowInfo instance. + public static IWindowInfo CreateMacOSCarbonWindowInfo(IntPtr windowHandle, bool ownHandle, bool isControl) + { + return CreateMacOSCarbonWindowInfo(windowHandle, ownHandle, isControl, null, null); + } + + /// + /// Creates an IWindowInfo instance for the Mac OS X platform with an X and Y offset for the GL viewport location. + /// + /// The handle of the window. + /// Ignored. This is reserved for future use. + /// Set to true if windowHandle corresponds to a System.Windows.Forms control. + /// The X offset for the GL viewport + /// The Y offset for the GL viewport + /// A new IWindowInfo instance. + public static IWindowInfo CreateMacOSCarbonWindowInfo(IntPtr windowHandle, bool ownHandle, bool isControl, + OpenTK.Platform.MacOS.GetInt xOffset, OpenTK.Platform.MacOS.GetInt yOffset) + { + return new OpenTK.Platform.MacOS.CarbonWindowInfo(windowHandle, false, isControl, xOffset, yOffset); + } + + /// + /// Creates an IWindowInfo instance for the Mac OS X platform. + /// + /// The handle of the NSWindow. + /// Assumes that the NSWindow's contentView is the NSView we want to attach to our context. + /// A new IWindowInfo instance. + public static IWindowInfo CreateMacOSWindowInfo(IntPtr windowHandle) + { + return new OpenTK.Platform.MacOS.CocoaWindowInfo(windowHandle); + } + + /// + /// Creates an IWindowInfo instance for the Mac OS X platform. + /// + /// The handle of the NSWindow. + /// The handle of the NSView. + /// A new IWindowInfo instance. + public static IWindowInfo CreateMacOSWindowInfo(IntPtr windowHandle, IntPtr viewHandle) + { + return new OpenTK.Platform.MacOS.CocoaWindowInfo(windowHandle, viewHandle); + } + + /// + /// Creates an IWindowInfo instance for the dummy platform. + /// + /// A new IWindowInfo instance. + public static IWindowInfo CreateDummyWindowInfo() + { + return new Dummy.DummyWindowInfo(); + } + + /// + /// Creates an IWindowInfo instance for Angle rendering, based on + /// supplied platform window (e.g. a window created with + /// CreateWindowsWindowInfo, or CreateDummyWindowInfo). + /// + /// + /// + public static Egl.IAngleWindowInfo CreateAngleWindowInfo(IWindowInfo platformWindow) + { + return new Egl.AngleWindowInfo(platformWindow); + } + internal static bool RelaxGraphicsMode(ref GraphicsMode mode) + { + ColorFormat color = mode.ColorFormat; + int depth = mode.Depth; + int stencil = mode.Stencil; + int samples = mode.Samples; + ColorFormat accum = mode.AccumulatorFormat; + int buffers = mode.Buffers; + bool stereo = mode.Stereo; + + bool success = RelaxGraphicsMode( + ref color, ref depth, ref stencil, ref samples, + ref accum, ref buffers, ref stereo); + + mode = new GraphicsMode( + color, depth, stencil, samples, + accum, buffers, stereo); + + return success; + } + + /// \internal + /// + /// Relaxes graphics mode parameters. Use this function to increase compatibility + /// on systems that do not directly support a requested GraphicsMode. For example: + /// - user requested stereoscopic rendering, but GPU does not support stereo + /// - user requseted 16x antialiasing, but GPU only supports 4x + /// + /// true, if a graphics mode parameter was relaxed, false otherwise. + /// Color bits. + /// Depth bits. + /// Stencil bits. + /// Number of antialiasing samples. + /// Accumulator buffer bits. + /// Number of rendering buffers (1 for single buffering, 2+ for double buffering, 0 for don't care). + /// Stereoscopic rendering enabled/disabled. + internal static bool RelaxGraphicsMode(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, ref ColorFormat accum, ref int buffers, ref bool stereo) + { + // Parameters are relaxed in order of importance. + // - Accumulator buffers are way outdated as a concept, + // so they go first. + // - Triple+ buffering is generally not supported by the + // core WGL/GLX/AGL/CGL/EGL specs, so we clamp + // to double-buffering as a second step. (If this doesn't help + // we will also fall back to undefined single/double buffering + // as a last resort). + // - AA samples are an easy way to increase compatibility + // so they go next. + // - Stereoscopic is only supported on very few GPUs + // (Quadro/FirePro series) so it goes next. + // - The rest of the parameters then follow. + + if (accum != 0) + { + accum = 0; + return true; + } + + if (buffers > 2) + { + buffers = 2; + return true; + } + + if (samples > 0) + { + samples = Math.Max(samples - 1, 0); + return true; + } + + if (stereo) + { + stereo = false; + return true; + } + + if (stencil != 0) + { + stencil = 0; + return true; + } + + if (depth != 0) + { + depth = 0; + return true; + } + + if (color != 24) + { + color = 24; + return true; + } + + if (buffers != 0) + { + buffers = 0; + return true; + } + + // no parameters left to relax, fail + return false; + } + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/API.cs b/GLWidget/OpenTK/Platform/Windows/API.cs new file mode 100644 index 0000000..a3a97c7 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/API.cs @@ -0,0 +1,3012 @@ +// +// WinRawJoystick.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006 Stefanos Apostolopoulos +// Copyright (c) 2007 Erik Ylvisaker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Security; + +/* TODO: Update the description of TimeBeginPeriod and other native methods. Update Timer. */ + +#pragma warning disable 3019 // CLS-compliance checking +#pragma warning disable 0649 // struct members not explicitly initialized +#pragma warning disable 0169 // field / method is never used. +#pragma warning disable 0414 // field assigned but never used. + +namespace OpenTK.Platform.Windows +{ + using HWND = System.IntPtr; + using HINSTANCE = System.IntPtr; + using HMENU = System.IntPtr; + using HICON = System.IntPtr; + using HBRUSH = System.IntPtr; + using HCURSOR = System.IntPtr; + using HKEY = System.IntPtr; + using PHKEY = System.IntPtr; + + using HDROP = System.IntPtr; + + using LRESULT = System.IntPtr; + using LPVOID = System.IntPtr; + using LPCTSTR = System.String; + + using WPARAM = System.IntPtr; + using LPARAM = System.IntPtr; + using HANDLE = System.IntPtr; + using HRAWINPUT = System.IntPtr; + + using BYTE = System.Byte; + using SHORT = System.Int16; + using USHORT = System.UInt16; + using LONG = System.Int32; + using ULONG = System.UInt32; + using WORD = System.Int16; + using DWORD = System.Int32; + using BOOL = System.Boolean; + using INT = System.Int32; + using UINT = System.UInt32; + using LONG_PTR = System.IntPtr; + using ATOM = System.Int32; + + using COLORREF = System.Int32; + using RECT = OpenTK.Platform.Windows.Win32Rectangle; + using WNDPROC = System.IntPtr; + using LPDEVMODE = DeviceMode; + using HDEVNOTIFY = System.IntPtr; + + using HRESULT = System.IntPtr; + using HMONITOR = System.IntPtr; + + using DWORD_PTR = System.IntPtr; + using UINT_PTR = System.UIntPtr; + + using TIMERPROC = Functions.TimerProc; + + using REGSAM = System.UInt32; + using System.Diagnostics; + + /// \internal + /// + /// For internal use by OpenTK only! + /// Exposes useful native WINAPI methods and structures. + /// + internal static class API + { + // Prevent BeforeFieldInit optimization, and initialize 'size' fields. + static API() + { + PixelFormatDescriptorVersion = 1; + PixelFormatDescriptorSize = (short)Marshal.SizeOf(typeof(PixelFormatDescriptor)); + WindowInfoSize = Marshal.SizeOf(typeof(WindowInfo)); + } + + internal static readonly short PixelFormatDescriptorSize; + internal static readonly short PixelFormatDescriptorVersion; + internal static readonly int WindowInfoSize; + } + + internal static class Functions + { + [DllImport("shell32.dll", CharSet = CharSet.Auto)] + internal static extern bool DragAcceptFiles( + IntPtr handle, + [MarshalAs(UnmanagedType.Bool)] bool fAccept + ); + + [DllImport("shell32.dll", CharSet = CharSet.Auto)] + internal static extern uint DragQueryFile( + HDROP hDrop, + uint iFile, + IntPtr lpszFile, + uint cch + ); + + [DllImport("shell32.dll")] + internal static extern void DragFinish( + HDROP hDrop + ); + + // WINUSERAPI BOOL WINAPI SetWindowPos(__in HWND hWnd, __in_opt HWND hWndInsertAfter, + // __in int X, __in int Y, __in int cx, __in int cy, __in UINT uFlags); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetWindowPos( + IntPtr handle, + IntPtr insertAfter, + int x, int y, int cx, int cy, + SetWindowPosFlags flags + ); + + /// + /// Calculates the required size of the window rectangle, based on the desired client-rectangle size. The window rectangle can then be passed to the CreateWindow function to create a window whose client area is the desired size. + /// + /// [in, out] Pointer to a RECT structure that contains the coordinates of the top-left and bottom-right corners of the desired client area. When the function returns, the structure contains the coordinates of the top-left and bottom-right corners of the window to accommodate the desired client area. + /// [in] Specifies the window style of the window whose required size is to be calculated. Note that you cannot specify the WS_OVERLAPPED style. + /// [in] Specifies whether the window has a menu. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + /// + /// A client rectangle is the smallest rectangle that completely encloses a client area. A window rectangle is the smallest rectangle that completely encloses the window, which includes the client area and the nonclient area. + /// The AdjustWindowRect function does not add extra space when a menu bar wraps to two or more rows. + /// The AdjustWindowRect function does not take the WS_VSCROLL or WS_HSCROLL styles into account. To account for the scroll bars, call the GetSystemMetrics function with SM_CXVSCROLL or SM_CYHSCROLL. + /// Found Winuser.h, user32.dll + /// + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal static extern BOOL AdjustWindowRect([In, Out] ref Win32Rectangle lpRect, WindowStyle dwStyle, BOOL bMenu); + + [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", CallingConvention = CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool AdjustWindowRectEx( + ref Win32Rectangle lpRect, + WindowStyle dwStyle, + [MarshalAs(UnmanagedType.Bool)] bool bMenu, + ExtendedWindowStyle dwExStyle); + + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern IntPtr CreateWindowEx( + ExtendedWindowStyle ExStyle, + IntPtr ClassAtom, + IntPtr WindowName, + WindowStyle Style, + int X, int Y, + int Width, int Height, + IntPtr HandleToParentWindow, + IntPtr Menu, + IntPtr Instance, + IntPtr Param); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DestroyWindow(IntPtr windowHandle); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern ushort RegisterClass(ref WindowClass window_class); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern ushort RegisterClassEx(ref ExtendedWindowClass window_class); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern BOOL IsWindowUnicode(HWND hwnd); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern short UnregisterClass([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR className, IntPtr instance); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern short UnregisterClass(IntPtr className, IntPtr instance); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern BOOL GetClassInfoEx(HINSTANCE hinst, + [MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszClass, ref ExtendedWindowClass lpwcx); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern BOOL GetClassInfoEx(HINSTANCE hinst, UIntPtr lpszClass, ref ExtendedWindowClass lpwcx); + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, WindowMessage Msg, + WPARAM wParam, LPARAM lParam); + + // SetWindowLongPtr does not exist on x86 platforms (it's a macro that resolves to SetWindowLong). + // We need to detect if we are on x86 or x64 at runtime and call the correct function + // (SetWindowLongPtr on x64 or SetWindowLong on x86). Fun! + internal static IntPtr SetWindowLong(IntPtr handle, GetWindowLongOffsets item, IntPtr newValue) + { + // SetWindowPos defines its error condition as an IntPtr.Zero retval and a non-0 GetLastError. + // We need to SetLastError(0) to ensure we are not detecting on older error condition (from another function). + + IntPtr retval = IntPtr.Zero; + SetLastError(0); + + if (IntPtr.Size == 4) + { + retval = new IntPtr(SetWindowLongInternal(handle, item, newValue.ToInt32())); + } + else + { + retval = SetWindowLongPtrInternal(handle, item, newValue); + } + + if (retval == IntPtr.Zero) + { + int error = Marshal.GetLastWin32Error(); + if (error != 0) + { + throw new PlatformException(String.Format("Failed to modify window border. Error: {0}", error)); + } + } + + return retval; + } + + internal static IntPtr SetWindowLong(IntPtr handle, WindowProcedure newValue) + { + return SetWindowLong(handle, GetWindowLongOffsets.WNDPROC, Marshal.GetFunctionPointerForDelegate(newValue)); + } + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")] + private static extern LONG SetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex, LONG dwNewLong); + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")] + private static extern LONG_PTR SetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex, LONG_PTR dwNewLong); + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")] + private static extern LONG SetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex, + [MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong); + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")] + private static extern LONG_PTR SetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex, + [MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong); + + internal static UIntPtr GetWindowLong(IntPtr handle, GetWindowLongOffsets index) + { + if (IntPtr.Size == 4) + { + return (UIntPtr)GetWindowLongInternal(handle, index); + } + + return GetWindowLongPtrInternal(handle, index); + } + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLong")] + private static extern ULONG GetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex); + + [SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLongPtr")] + private static extern UIntPtr GetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex); + + /// + /// Low-level WINAPI function that checks the next message in the queue. + /// + /// The pending message (if any) is stored here. + /// Not used + /// Not used + /// Not used + /// Not used + /// True if there is a message pending. + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Unicode), CLSCompliant(false)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool PeekMessage(ref MSG msg, IntPtr hWnd, int messageFilterMin, int messageFilterMax, PeekMessageFlags flags); + + /// + /// Low-level WINAPI function that retrieves the next message in the queue. + /// + /// The pending message (if any) is stored here. + /// Not used + /// Not used + /// Not used + /// + /// Nonzero indicates that the function retrieves a message other than WM_QUIT. + /// Zero indicates that the function retrieves the WM_QUIT message, or that lpMsg is an invalid pointer. + /// –1 indicates that an error occurred — for example, the function fails if hWnd is an invalid window handle. + /// To get extended error information, call GetLastError. + /// + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Unicode), CLSCompliant(false)] + //[return: MarshalAs(UnmanagedType.Bool)] + internal static extern INT GetMessage(ref MSG msg, + IntPtr windowHandle, int messageFilterMin, int messageFilterMax); + + /// + /// Retrieves the message time for the last message retrieved by the + /// GetMessage function. The time is a long integer that specifies the + /// elapsed time, in milliseconds, from the time the system was started + /// to the time the message was created (that is, placed in the thread's + /// message queue). + /// + /// The return value specifies the message time. + [DllImport("User32.dll")] + internal static extern int GetMessageTime(); + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + internal static extern LRESULT SendMessage(HWND hWnd, WindowMessage Msg, WPARAM wParam, LPARAM lParam); + + [CLSCompliant(false)] + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern BOOL PostMessage( + HWND hWnd, + WindowMessage Msg, + WPARAM wParam, + LPARAM lParam + ); + + [DllImport("User32.dll", CharSet = CharSet.Auto)] + internal static extern void PostQuitMessage(int exitCode); + + [SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Unicode), CLSCompliant(false)] + internal static extern LRESULT DispatchMessage(ref MSG msg); + + [SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Unicode), CLSCompliant(false)] + internal static extern BOOL TranslateMessage(ref MSG lpMsg); + + /// + /// Indicates the type of messages found in the calling thread's message queue. + /// + /// + /// + /// The high-order word of the return value indicates the types of messages currently in the queue. + /// The low-order word indicates the types of messages that have been added to the queue and that are still + /// in the queue since the last call to the GetQueueStatus, GetMessage, or PeekMessage function. + /// + /// + /// The presence of a QS_ flag in the return value does not guarantee that + /// a subsequent call to the GetMessage or PeekMessage function will return a message. + /// GetMessage and PeekMessage perform some internal filtering that may cause the message + /// to be processed internally. For this reason, the return value from GetQueueStatus + /// should be considered only a hint as to whether GetMessage or PeekMessage should be called. + /// + /// The QS_ALLPOSTMESSAGE and QS_POSTMESSAGE flags differ in when they are cleared. + /// QS_POSTMESSAGE is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages. + /// QS_ALLPOSTMESSAGE is cleared when you call GetMessage or PeekMessage without filtering messages + /// (wMsgFilterMin and wMsgFilterMax are 0). This can be useful when you call PeekMessage multiple times + /// to get messages in different ranges. + /// + /// + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("User32.dll", CharSet = CharSet.Auto)] + internal static extern DWORD GetQueueStatus([MarshalAs(UnmanagedType.U4)] QueueStatusFlags flags); + + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + public extern static IntPtr DefWindowProc(HWND hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam); + + /// + /// Sets the timing resolution of the GetTime (?) method. + /// + /// Timing resolution in msec (?) + /// (?) + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("winmm.dll")] + internal static extern IntPtr TimeBeginPeriod(int period); + + /// + /// + /// + /// + /// + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency); + + /// + /// + /// + /// + /// + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool QueryPerformanceCounter(ref long PerformanceCount); + + /// + /// + /// + /// + /// + [DllImport("user32.dll")] + internal static extern IntPtr GetDC(IntPtr hwnd); + + /// + /// + /// + /// + /// + /// + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool ReleaseDC(IntPtr hwnd, IntPtr DC); + + [DllImport("gdi32.dll")] + internal static extern int ChoosePixelFormat(IntPtr dc, ref PixelFormatDescriptor pfd); + + [DllImport("gdi32.dll")] + internal static extern int DescribePixelFormat(IntPtr deviceContext, int pixel, int pfdSize, ref PixelFormatDescriptor pixelFormat); + + /// + /// + /// + /// + /// + /// + /// + [DllImport("gdi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetPixelFormat(IntPtr dc, int format, ref PixelFormatDescriptor pfd); + + [SuppressUnmanagedCodeSecurity] + [DllImport("gdi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SwapBuffers(IntPtr dc); + + [DllImport("kernel32.dll")] + internal static extern IntPtr GetProcAddress(IntPtr handle, string funcname); + + [DllImport("kernel32.dll")] + internal static extern IntPtr GetProcAddress(IntPtr handle, IntPtr funcname); + + + [DllImport("kernel32.dll")] + internal static extern void SetLastError(DWORD dwErrCode); + + [DllImport("kernel32.dll")] + internal static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPTStr)]string module_name); + + /// + /// + /// + /// + /// + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr LoadLibrary(string dllName); + + /// + /// + /// + /// + /// + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary(IntPtr handle); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true)] + internal static extern SHORT GetAsyncKeyState(VirtualKeys vKey); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true)] + internal static extern SHORT GetKeyState(VirtualKeys vKey); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true)] + internal static extern UINT MapVirtualKey(UINT uCode, MapVirtualKeyType uMapType); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport("user32.dll", SetLastError = true)] + internal static extern UINT MapVirtualKey(VirtualKeys vkey, MapVirtualKeyType uMapType); + + /// + /// The ShowWindow function sets the specified window's show state. + /// + /// [in] Handle to the window. + /// [in] Specifies how the window is to be shown. This parameter is ignored the first time an application calls ShowWindow, if the program that launched the application provides a STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should be the value obtained by the WinMain function in its nCmdShow parameter. In subsequent calls, this parameter can be one of the ShowWindowEnum values. + /// If the window was previously visible, the return value is true. Otherwise false. + /// + /// To perform certain special effects when showing or hiding a window, use AnimateWindow. + /// The first time an application calls ShowWindow, it should use the WinMain function's nCmdShow parameter as its nCmdShow parameter. Subsequent calls to ShowWindow must use one of the values in the given list, instead of the one specified by the WinMain function's nCmdShow parameter. + /// As noted in the discussion of the nCmdShow parameter, the nCmdShow value is ignored in the first call to ShowWindow if the program that launched the application specifies startup information in the structure. In this case, ShowWindow uses the information specified in the STARTUPINFO structure to show the window. On subsequent calls, the application must call ShowWindow with nCmdShow set to SW_SHOWDEFAULT to use the startup information provided by the program that launched the application. This behavior is designed for the following situations: + /// + /// Applications create their main window by calling CreateWindow with the WS_VISIBLE flag set. + /// Applications create their main window by calling CreateWindow with the WS_VISIBLE flag cleared, and later call ShowWindow with the SW_SHOW flag set to make it visible. + /// + /// + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal static extern BOOL ShowWindow(HWND hWnd, ShowWindowCommand nCmdShow); + + /// + /// The SetWindowText function changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed. However, SetWindowText cannot change the text of a control in another application. + /// + /// [in] Handle to the window or control whose text is to be changed. + /// [in] Pointer to a null-terminated string to be used as the new title or control text. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + /// + /// If the target window is owned by the current process, SetWindowText causes a WM_SETTEXT message to be sent to the specified window or control. If the control is a list box control created with the WS_CAPTION style, however, SetWindowText sets the text for the control, not for the list box entries. + /// To set the text of a control in another process, send the WM_SETTEXT message directly instead of calling SetWindowText. + /// The SetWindowText function does not expand tab characters (ASCII code 0x09). Tab characters are displayed as vertical bar (|) characters. + /// Windows 95/98/Me: SetWindowTextW is supported by the Microsoft Layer for Unicode (MSLU). To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems . + /// + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern BOOL SetWindowText(HWND hWnd, [MarshalAs(UnmanagedType.LPTStr)] string lpString); + + /// + /// The GetWindowText function copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied. However, GetWindowText cannot retrieve the text of a control in another application. + /// + /// [in] Handle to the window or control containing the text. + /// [out] Pointer to the buffer that will receive the text. If the string is as long or longer than the buffer, the string is truncated and terminated with a NULL character. + /// [in] Specifies the maximum number of characters to copy to the buffer, including the NULL character. If the text exceeds this limit, it is truncated. + /// + /// If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating NULL character. If the window has no title bar or text, if the title bar is empty, or if the window or control handle is invalid, the return value is zero. To get extended error information, call GetLastError. + /// This function cannot retrieve the text of an edit control in another application. + /// + /// + /// If the target window is owned by the current process, GetWindowText causes a WM_GETTEXT message to be sent to the specified window or control. If the target window is owned by another process and has a caption, GetWindowText retrieves the window caption text. If the window does not have a caption, the return value is a null string. This behavior is by design. It allows applications to call GetWindowText without becoming unresponsive if the process that owns the target window is not responding. However, if the target window is not responding and it belongs to the calling application, GetWindowText will cause the calling application to become unresponsive. + /// To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead of calling GetWindowText. + /// Windows 95/98/Me: GetWindowTextW is supported by the Microsoft Layer for Unicode (MSLU). To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me + /// + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern int GetWindowText(HWND hWnd, [MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder lpString, int nMaxCount); + + /// + /// Converts the screen coordinates of a specified point on the screen to client-area coordinates. + /// + /// Handle to the window whose client area will be used for the conversion. + /// Pointer to a POINT structure that specifies the screen coordinates to be converted. + /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. Windows NT/2000/XP: To get extended error information, call GetLastError. + /// + /// The function uses the window identified by the hWnd parameter and the screen coordinates given in the POINT structure to compute client coordinates. It then replaces the screen coordinates with the client coordinates. The new coordinates are relative to the upper-left corner of the specified window's client area. + /// The ScreenToClient function assumes the specified point is in screen coordinates. + /// All coordinates are in device units. + /// Do not use ScreenToClient when in a mirroring situation, that is, when changing from left-to-right layout to right-to-left layout. Instead, use MapWindowPoints. For more information, see "Window Layout and Mirroring" in Window Features. + /// + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + //internal static extern BOOL ScreenToClient(HWND hWnd, ref POINT point); + internal static extern BOOL ScreenToClient(HWND hWnd, ref Point point); + + /// + /// Converts the client-area coordinates of a specified point to screen coordinates. + /// + /// Handle to the window whose client area will be used for the conversion. + /// Pointer to a POINT structure that contains the client coordinates to be converted. The new screen coordinates are copied into this structure if the function succeeds. + /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. Windows NT/2000/XP: To get extended error information, call GetLastError. + /// + /// The ClientToScreen function replaces the client-area coordinates in the POINT structure with the screen coordinates. The screen coordinates are relative to the upper-left corner of the screen. Note, a screen-coordinate point that is above the window's client area has a negative y-coordinate. Similarly, a screen coordinate to the left of a client area has a negative x-coordinate. + /// All coordinates are device coordinates. + /// + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal static extern BOOL ClientToScreen(HWND hWnd, ref Point point); + + /// + /// The GetClientRect function retrieves the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0). + /// + /// Handle to the window whose client coordinates are to be retrieved. + /// Pointer to a RECT structure that receives the client coordinates. The left and top members are zero. The right and bottom members contain the width and height of the window. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + /// In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle. + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal extern static BOOL GetClientRect(HWND windowHandle, out Win32Rectangle clientRectangle); + + /// + /// The GetWindowRect function retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + /// + /// Handle to the window whose client coordinates are to be retrieved. + /// Pointer to a structure that receives the screen coordinates of the upper-left and lower-right corners of the window. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + /// In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle. + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal extern static BOOL GetWindowRect(HWND windowHandle, out Win32Rectangle windowRectangle); + + [DllImport("user32.dll"), SuppressUnmanagedCodeSecurity] + internal static extern BOOL GetWindowInfo(HWND hwnd, ref WindowInfo wi); + + [DllImport("dwmapi.dll")] + unsafe public static extern HRESULT DwmGetWindowAttribute(HWND hwnd, DwmWindowAttribute dwAttribute, void* pvAttribute, DWORD cbAttribute); + + [DllImport("user32.dll")] + public static extern HWND GetFocus(); + + [DllImport("user32.dll")] + public static extern bool IsWindowVisible(IntPtr intPtr); + + [DllImport("user32.dll")] + public static extern HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName); + + [DllImport("user32.dll")] + public static extern HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName); + + [DllImport("user32.dll")] + public static extern HCURSOR LoadCursor(HINSTANCE hInstance, IntPtr lpCursorName); + + public static HCURSOR LoadCursor(CursorName lpCursorName) + { + return LoadCursor(IntPtr.Zero, new IntPtr((int)lpCursorName)); + } + + /// + /// Creates an icon or cursor from an IconInfo structure. + /// + /// + /// A pointer to an IconInfo structure the function uses to create the + /// icon or cursor. + /// + /// + /// If the function succeeds, the return value is a handle to the icon + /// or cursor that is created. + /// + /// If the function fails, the return value is null. To get extended + /// error information, call Marshal.GetLastWin32Error. + /// + /// + /// The system copies the bitmaps in the IconInfo structure before + /// creating the icon or cursor. Because the system may temporarily + /// select the bitmaps in a device context, the hbmMask and hbmColor + /// members of the IconInfo structure should not already be selected + /// into a device context. The application must continue to manage the + /// original bitmaps and delete them when they are no longer necessary. + /// When you are finished using the icon, destroy it using the + /// DestroyIcon function. + /// + [DllImport("user32.dll", SetLastError = true)] + public static extern HICON CreateIconIndirect(ref IconInfo iconInfo); + + /// + /// Retrieves information about the specified icon or cursor. + /// + /// A handle to the icon or cursor. + /// + /// A pointer to an IconInfo structure. The function fills in the + /// structure's members. + /// + /// + /// If the function succeeds, the return value is nonzero and the + /// function fills in the members of the specified IconInfo structure. + /// + /// If the function fails, the return value is zero. To get extended + /// error information, call Marshal.GetLastWin32Error. + /// + /// + /// GetIconInfo creates bitmaps for the hbmMask and hbmColor members + /// of IconInfo. The calling application must manage these bitmaps and + /// delete them when they are no longer necessary. + /// + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL GetIconInfo(HICON hIcon, out IconInfo pIconInfo); + + /// + /// Destroys an icon and frees any memory the icon occupied. + /// + /// + /// A handle to the icon to be destroyed. The icon must not be in use. + /// + /// + /// If the function succeeds, the return value is nonzero. + /// + /// If the function fails, the return value is zero. To get extended + /// error information, call Marshal.GetLastWin32Error. + /// + /// + /// It is only necessary to call DestroyIcon for icons and cursors + /// created with the following functions: CreateIconFromResourceEx + /// (if called without the LR_SHARED flag), CreateIconIndirect, and + /// CopyIcon. Do not use this function to destroy a shared icon. A + /// shared icon is valid as long as the module from which it was loaded + /// remains in memory. The following functions obtain a shared icon. + /// + /// LoadIcon + /// LoadImage (if you use the LR_SHARED flag) + /// CopyImage (if you use the LR_COPYRETURNORG flag and the hImage parameter is a shared icon) + /// CreateIconFromResource + /// CreateIconFromResourceEx (if you use the LR_SHARED flag) + /// + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL DestroyIcon(HICON hIcon); + + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL SetForegroundWindow(HWND hWnd); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL BringWindowToTop(HWND hWnd); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL SetParent(HWND child, HWND newParent); + + [DllImport("user32.dll", SetLastError = true)] + public static extern HDEVNOTIFY RegisterDeviceNotification(HANDLE hRecipient, + LPVOID NotificationFilter, DeviceNotification Flags); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL UnregisterDeviceNotification(HDEVNOTIFY Handle); + + /// + /// The ChangeDisplaySettings function changes the settings of the default display device to the specified graphics mode. + /// + /// [in] Pointer to a DEVMODE structure that describes the new graphics mode. If lpDevMode is NULL, all the values currently in the registry will be used for the display setting. Passing NULL for the lpDevMode parameter and 0 for the dwFlags parameter is the easiest way to return to the default mode after a dynamic mode change. + /// [in] Indicates how the graphics mode should be changed. + /// + /// To change the settings of a specified display device, use the ChangeDisplaySettingsEx function. + /// To ensure that the DEVMODE structure passed to ChangeDisplaySettings is valid and contains only values supported by the display driver, use the DEVMODE returned by the EnumDisplaySettings function. + /// When the display mode is changed dynamically, the WM_DISPLAYCHANGE message is sent to all running applications. + /// + [DllImport("user32.dll", SetLastError = true)] + internal static extern int ChangeDisplaySettings(DeviceMode device_mode, ChangeDisplaySettingsEnum flags); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern LONG ChangeDisplaySettingsEx([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszDeviceName, + LPDEVMODE lpDevMode, HWND hwnd, ChangeDisplaySettingsEnum dwflags, LPVOID lParam); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern BOOL EnumDisplayDevices([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpDevice, + DWORD iDevNum, [In, Out] WindowsDisplayDevice lpDisplayDevice, DWORD dwFlags); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPTStr)] string device_name, + int graphics_mode, [In, Out] DeviceMode device_mode); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPTStr)] string device_name, + DisplayModeSettingsEnum graphics_mode, [In, Out] DeviceMode device_mode); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern BOOL EnumDisplaySettingsEx([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszDeviceName, DisplayModeSettingsEnum iModeNum, + [In, Out] DeviceMode lpDevMode, DWORD dwFlags); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern BOOL EnumDisplaySettingsEx([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszDeviceName, DWORD iModeNum, + [In, Out] DeviceMode lpDevMode, DWORD dwFlags); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi); + + [DllImport("user32.dll", SetLastError = true)] + public static extern HMONITOR MonitorFromPoint(POINT pt, MonitorFrom dwFlags); + + [DllImport("user32.dll", SetLastError = true)] + public static extern HMONITOR MonitorFromWindow(HWND hwnd, MonitorFrom dwFlags); + + /// + /// Sets the current process as dots per inch (dpi) aware. + /// Note: SetProcessDPIAware is subject to a possible race condition + /// if a DLL caches dpi settings during initialization. + /// For this reason, it is recommended that dpi-aware be set through + /// the application (.exe) manifest rather than by calling SetProcessDPIAware. + /// + /// + /// If the function succeeds, the return value is true. + /// Otherwise, the return value is false. + /// + /// + /// DLLs should accept the dpi setting of the host process + /// rather than call SetProcessDPIAware themselves. + /// To be set properly, dpiAware should be specified as part + /// of the application (.exe) manifest. + /// + [DllImport("user32.dll")] + internal static extern BOOL SetProcessDPIAware(); + + [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] + public static extern int GetDeviceCaps(IntPtr hDC, DeviceCaps nIndex); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL TrackMouseEvent(ref TrackMouseEventStructure lpEventTrack); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] + public static extern bool ReleaseCapture(); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern IntPtr SetCapture(IntPtr hwnd); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern IntPtr GetCapture(); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern IntPtr SetFocus(IntPtr hwnd); + + [DllImport("gdi32.dll", SetLastError = true)] + internal static extern IntPtr GetStockObject(StockObjects fnObject); + + [DllImport("gdi32.dll", SetLastError = true)] + internal static extern BOOL DeleteObject([In]IntPtr hObject); + + + [DllImport("user32.dll", SetLastError = true)] + public static extern UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc); + + [DllImport("user32.dll", SetLastError = true)] + public static extern BOOL KillTimer(HWND hWnd, UINT_PTR uIDEvent); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate void TimerProc(HWND hwnd, WindowMessage uMsg, UINT_PTR idEvent, DWORD dwTime); + + [DllImport("shell32.dll")] + public static extern DWORD_PTR SHGetFileInfo(LPCTSTR pszPath, DWORD dwFileAttributes, ref SHFILEINFO psfi, UINT cbFileInfo, ShGetFileIconFlags uFlags); + + [DllImport("Advapi32.dll")] + internal static extern int RegOpenKeyEx( + HKEY hKey, + [MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpSubKey, + DWORD ulOptions, + REGSAM samDesired, + out PHKEY phkResult); + + [DllImport("Advapi32.dll")] + internal static extern int RegGetValue( + HKEY hkey, + [MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpSubKey, + [MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpValue, + DWORD dwFlags, + out DWORD pdwType, + StringBuilder pvData, + ref DWORD pcbData); + } + + internal static class Constants + { + // Found in winuser.h + internal const int KEYBOARD_OVERRUN_MAKE_CODE = 0xFF; + + // WM_ACTIVATE state values (found in winuser.h) + internal const int WA_INACTIVE = 0; + internal const int WA_ACTIVE = 1; + internal const int WA_CLICKACTIVE = 2; + + // Window Messages (found in winuser.h) + internal const int WM_NULL = 0x0000; + internal const int WM_CREATE = 0x0001; + internal const int WM_DESTROY = 0x0002; + internal const int WM_MOVE = 0x0003; + internal const int WM_SIZE = 0x0005; + internal const int WM_ACTIVATE = 0x0006; + internal const int WM_SETFOCUS = 0x0007; + internal const int WM_KILLFOCUS = 0x0008; + internal const int WM_ENABLE = 0x000A; + internal const int WM_SETREDRAW = 0x000B; + internal const int WM_SETTEXT = 0x000C; + internal const int WM_GETTEXT = 0x000D; + internal const int WM_GETTEXTLENGTH = 0x000E; + internal const int WM_PAINT = 0x000F; + internal const int WM_CLOSE = 0x0010; + // _WIN32_WCE + internal const int WM_QUERYENDSESSION = 0x0011; + internal const int WM_QUERYOPEN = 0x0013; + internal const int WM_ENDSESSION = 0x0016; + internal const int WM_QUIT = 0x0012; + internal const int WM_ERASEBKGND = 0x0014; + internal const int WM_SYSCOLORCHANGE = 0x0015; + internal const int WM_SHOWWINDOW = 0x0018; + internal const int WM_WININICHANGE = 0x001A; + // WINVER >= 0x400 + internal const int WM_SETTINGCHANGE = WM_WININICHANGE; + + internal const int WM_DEVMODECHANGE = 0x001B; + internal const int WM_ACTIVATEAPP = 0x001C; + internal const int WM_FONTCHANGE = 0x001D; + internal const int WM_TIMECHANGE = 0x001E; + internal const int WM_CANCELMODE = 0x001F; + internal const int WM_SETCURSOR = 0x0020; + internal const int WM_MOUSEACTIVATE = 0x0021; + internal const int WM_CHILDACTIVATE = 0x0022; + internal const int WM_QUEUESYNC = 0x0023; + + internal const int WM_GETMINMAXINFO = 0x0024; + + internal const int WM_WINDOWPOSCHANGING = 0x0046; + internal const int WM_WINDOWPOSCHANGED = 0x0047; + + // Keyboard events (found in winuser.h) + internal const int WM_INPUT = 0x00FF; // Raw input. XP and higher only. + internal const int WM_KEYDOWN = 0x0100; + internal const int WM_KEYUP = 0x101; + internal const int WM_SYSKEYDOWN = 0x0104; + internal const int WM_SYSKEYUP = 0x0105; + internal const int WM_COMMAND = 0x0111; + internal const int WM_SYSCOMMAND = 0x0112; + internal const int WM_ENTERIDLE = 0x121; + + // Pixel types (found in wingdi.h) + internal const byte PFD_TYPE_RGBA = 0; + internal const byte PFD_TYPE_COLORINDEX = 1; + + // Layer types (found in wingdi.h) + internal const byte PFD_MAIN_PLANE = 0; + internal const byte PFD_OVERLAY_PLANE = 1; + internal const byte PFD_UNDERLAY_PLANE = unchecked((byte)-1); + + // Device mode types (found in wingdi.h) + internal const int DM_LOGPIXELS = 0x00020000; + internal const int DM_BITSPERPEL = 0x00040000; + internal const int DM_PELSWIDTH = 0x00080000; + internal const int DM_PELSHEIGHT = 0x00100000; + internal const int DM_DISPLAYFLAGS = 0x00200000; + internal const int DM_DISPLAYFREQUENCY = 0x00400000; + + // ChangeDisplaySettings results (found in winuser.h) + internal const int DISP_CHANGE_SUCCESSFUL = 0; + internal const int DISP_CHANGE_RESTART = 1; + internal const int DISP_CHANGE_FAILED = -1; + + // (found in winuser.h) + internal const int ENUM_REGISTRY_SETTINGS = -2; + internal const int ENUM_CURRENT_SETTINGS = -1; + + internal static readonly IntPtr MESSAGE_ONLY = new IntPtr(-3); + + internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002)); + + // System Error Codes + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx + + /// + /// The point passed to GetMouseMovePoints is not in the buffer. + /// + internal const int ERROR_POINT_NOT_FOUND = 1171; + + /// + /// Retrieves the points using the display resolution. + /// + internal const int GMMP_USE_DISPLAY_POINTS = 1; + + /// + /// Retrieves high resolution points. Points can range from zero to + /// 65,535 (0xFFFF) in both x and y coordinates. This is the resolution + /// provided by absolute coordinate pointing devices such as drawing + /// tablets. + /// + internal const int GMMP_USE_HIGH_RESOLUTION_POINTS = 2; + } + + internal struct CreateStruct + { + /// + /// Contains additional data which may be used to create the window. + /// + /// + /// If the window is being created as a result of a call to the CreateWindow + /// or CreateWindowEx function, this member contains the value of the lpParam + /// parameter specified in the function call. + /// + /// If the window being created is a multiple-document interface (MDI) client window, + /// this member contains a pointer to a CLIENTCREATESTRUCT structure. If the window + /// being created is a MDI child window, this member contains a pointer to an + /// MDICREATESTRUCT structure. + /// + /// + /// Windows NT/2000/XP: If the window is being created from a dialog template, + /// this member is the address of a SHORT value that specifies the size, in bytes, + /// of the window creation data. The value is immediately followed by the creation data. + /// + /// + /// Windows NT/2000/XP: You should access the data represented by the lpCreateParams member + /// using a pointer that has been declared using the UNALIGNED type, because the pointer + /// may not be DWORD aligned. + /// + /// + internal LPVOID lpCreateParams; + /// + /// Handle to the module that owns the new window. + /// + internal HINSTANCE hInstance; + /// + /// Handle to the menu to be used by the new window. + /// + internal HMENU hMenu; + /// + /// Handle to the parent window, if the window is a child window. + /// If the window is owned, this member identifies the owner window. + /// If the window is not a child or owned window, this member is NULL. + /// + internal HWND hwndParent; + /// + /// Specifies the height of the new window, in pixels. + /// + internal int cy; + /// + /// Specifies the width of the new window, in pixels. + /// + internal int cx; + /// + /// Specifies the y-coordinate of the upper left corner of the new window. + /// If the new window is a child window, coordinates are relative to the parent window. + /// Otherwise, the coordinates are relative to the screen origin. + /// + internal int y; + /// + /// Specifies the x-coordinate of the upper left corner of the new window. + /// If the new window is a child window, coordinates are relative to the parent window. + /// Otherwise, the coordinates are relative to the screen origin. + /// + internal int x; + /// + /// Specifies the style for the new window. + /// + internal LONG style; + /// + /// Pointer to a null-terminated string that specifies the name of the new window. + /// + [MarshalAs(UnmanagedType.LPTStr)] + internal LPCTSTR lpszName; + /// + /// Either a pointer to a null-terminated string or an atom that specifies the class name + /// of the new window. + /// + /// Note Because the lpszClass member can contain a pointer to a local (and thus inaccessable) atom, + /// do not obtain the class name by using this member. Use the GetClassName function instead. + /// + /// + [MarshalAs(UnmanagedType.LPTStr)] + internal LPCTSTR lpszClass; + /// + /// Specifies the extended window style for the new window. + /// + internal DWORD dwExStyle; + } + + internal struct StyleStruct + { + public WindowStyle Old; + public WindowStyle New; + } + + internal struct ExtendedStyleStruct + { + public ExtendedWindowStyle Old; + public ExtendedWindowStyle New; + } + + /// \internal + /// + /// Describes a pixel format. It is used when interfacing with the WINAPI to create a new Context. + /// Found in WinGDI.h + /// + [StructLayout(LayoutKind.Sequential)] + internal struct PixelFormatDescriptor + { + internal short Size; + internal short Version; + internal PixelFormatDescriptorFlags Flags; + internal PixelType PixelType; + internal byte ColorBits; + internal byte RedBits; + internal byte RedShift; + internal byte GreenBits; + internal byte GreenShift; + internal byte BlueBits; + internal byte BlueShift; + internal byte AlphaBits; + internal byte AlphaShift; + internal byte AccumBits; + internal byte AccumRedBits; + internal byte AccumGreenBits; + internal byte AccumBlueBits; + internal byte AccumAlphaBits; + internal byte DepthBits; + internal byte StencilBits; + internal byte AuxBuffers; + internal byte LayerType; + private byte Reserved; + internal int LayerMask; + internal int VisibleMask; + internal int DamageMask; + } + + + + /// \internal + /// + /// Describes the pixel format of a drawing surface. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct LayerPlaneDescriptor + { + internal static readonly WORD Size = (WORD)Marshal.SizeOf(typeof(LayerPlaneDescriptor)); + internal WORD Version; + internal DWORD Flags; + internal BYTE PixelType; + internal BYTE ColorBits; + internal BYTE RedBits; + internal BYTE RedShift; + internal BYTE GreenBits; + internal BYTE GreenShift; + internal BYTE BlueBits; + internal BYTE BlueShift; + internal BYTE AlphaBits; + internal BYTE AlphaShift; + internal BYTE AccumBits; + internal BYTE AccumRedBits; + internal BYTE AccumGreenBits; + internal BYTE AccumBlueBits; + internal BYTE AccumAlphaBits; + internal BYTE DepthBits; + internal BYTE StencilBits; + internal BYTE AuxBuffers; + internal BYTE LayerPlane; + private BYTE Reserved; + internal COLORREF crTransparent; + } + + /// \internal + /// + /// The GlyphMetricsFloat structure contains information about the placement and orientation of a glyph in a + /// character cell. + /// + /// The values of GlyphMetricsFloat are specified as notional units. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct GlyphMetricsFloat + { + /// + /// Specifies the width of the smallest rectangle (the glyph's black box) that completely encloses the glyph. + /// + internal float BlackBoxX; + /// + /// Specifies the height of the smallest rectangle (the glyph's black box) that completely encloses the glyph. + /// + internal float BlackBoxY; + /// + /// Specifies the x and y coordinates of the upper-left corner of the smallest rectangle that completely encloses the glyph. + /// + internal PointFloat GlyphOrigin; + /// + /// Specifies the horizontal distance from the origin of the current character cell to the origin of the next character cell. + /// + internal float CellIncX; + /// + /// Specifies the vertical distance from the origin of the current character cell to the origin of the next character cell. + /// + internal float CellIncY; + } + + /// \internal + /// + /// The PointFloat structure contains the x and y coordinates of a point. + /// + /// + [StructLayout(LayoutKind.Sequential)] + internal struct PointFloat + { + /// + /// Specifies the horizontal (x) coordinate of a point. + /// + internal float X; + /// + /// Specifies the vertical (y) coordinate of a point. + /// + internal float Y; + }; + /* + typedef struct _devicemode { + BCHAR dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + BYTE dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + } + DWORD dmDisplayFrequency; + #if(WINVER >= 0x0400) + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + #if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400) + DWORD dmPanningWidth; + DWORD dmPanningHeight; + #endif + #endif + } DEVMODE; + */ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal class DeviceMode + { + internal DeviceMode() + { + Size = (short)Marshal.SizeOf(this); + } + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + internal string DeviceName; + internal short SpecVersion; + internal short DriverVersion; + private short Size; + internal short DriverExtra; + internal int Fields; + + //internal short Orientation; + //internal short PaperSize; + //internal short PaperLength; + //internal short PaperWidth; + //internal short Scale; + //internal short Copies; + //internal short DefaultSource; + //internal short PrintQuality; + + internal POINT Position; + internal DWORD DisplayOrientation; + internal DWORD DisplayFixedOutput; + + internal short Color; + internal short Duplex; + internal short YResolution; + internal short TTOption; + internal short Collate; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + internal string FormName; + internal short LogPixels; + internal int BitsPerPel; + internal int PelsWidth; + internal int PelsHeight; + internal int DisplayFlags; + internal int DisplayFrequency; + internal int ICMMethod; + internal int ICMIntent; + internal int MediaType; + internal int DitherType; + internal int Reserved1; + internal int Reserved2; + internal int PanningWidth; + internal int PanningHeight; + } + + /// \internal + /// + /// The DISPLAY_DEVICE structure receives information about the display device specified by the iDevNum parameter of the EnumDisplayDevices function. + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal class WindowsDisplayDevice + { + internal WindowsDisplayDevice() + { + size = (short)Marshal.SizeOf(this); + } + + private readonly DWORD size; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + internal string DeviceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + internal string DeviceString; + internal DisplayDeviceStateFlags StateFlags; // DWORD + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + internal string DeviceID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + internal string DeviceKey; + } + [StructLayout(LayoutKind.Sequential)] + internal struct WindowClass + { + internal ClassStyle Style; + [MarshalAs(UnmanagedType.FunctionPtr)] + internal WindowProcedure WindowProcedure; + internal int ClassExtraBytes; + internal int WindowExtraBytes; + //[MarshalAs(UnmanagedType. + internal IntPtr Instance; + internal IntPtr Icon; + internal IntPtr Cursor; + internal IntPtr BackgroundBrush; + //[MarshalAs(UnmanagedType.LPStr)] + internal IntPtr MenuName; + [MarshalAs(UnmanagedType.LPTStr)] + internal string ClassName; + //internal string ClassName; + + internal static int SizeInBytes = Marshal.SizeOf(default(WindowClass)); + } + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct ExtendedWindowClass + { + public UINT Size; + public ClassStyle Style; + //public WNDPROC WndProc; + [MarshalAs(UnmanagedType.FunctionPtr)] + public WindowProcedure WndProc; + public int cbClsExtra; + public int cbWndExtra; + public HINSTANCE Instance; + public HICON Icon; + public HCURSOR Cursor; + public HBRUSH Background; + public IntPtr MenuName; + public IntPtr ClassName; + public HICON IconSm; + + public static uint SizeInBytes = (uint)Marshal.SizeOf(default(ExtendedWindowClass)); + } + + /// \internal + /// + /// Struct pointed to by WM_GETMINMAXINFO lParam + /// + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + private Point Reserved; + public Size MaxSize; + public Point MaxPosition; + public Size MinTrackSize; + public Size MaxTrackSize; + } + + /// \internal + /// + /// The WindowPosition structure contains information about the size and position of a window. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct WindowPosition + { + /// + /// Handle to the window. + /// + internal HWND hwnd; + /// + /// Specifies the position of the window in Z order (front-to-back position). + /// This member can be a handle to the window behind which this window is placed, + /// or can be one of the special values listed with the SetWindowPos function. + /// + internal HWND hwndInsertAfter; + /// + /// Specifies the position of the left edge of the window. + /// + internal int x; + /// + /// Specifies the position of the top edge of the window. + /// + internal int y; + /// + /// Specifies the window width, in pixels. + /// + internal int cx; + /// + /// Specifies the window height, in pixels. + /// + internal int cy; + /// + /// Specifies the window position. + /// + [MarshalAs(UnmanagedType.U4)] + internal SetWindowPosFlags flags; + } + + [Flags] + internal enum SetWindowPosFlags : int + { + /// + /// Retains the current size (ignores the cx and cy parameters). + /// + NOSIZE = 0x0001, + /// + /// Retains the current position (ignores the x and y parameters). + /// + NOMOVE = 0x0002, + /// + /// Retains the current Z order (ignores the hwndInsertAfter parameter). + /// + NOZORDER = 0x0004, + /// + /// Does not redraw changes. If this flag is set, no repainting of any kind occurs. + /// This applies to the client area, the nonclient area (including the title bar and scroll bars), + /// and any part of the parent window uncovered as a result of the window being moved. + /// When this flag is set, the application must explicitly invalidate or redraw any parts + /// of the window and parent window that need redrawing. + /// + NOREDRAW = 0x0008, + /// + /// Does not activate the window. If this flag is not set, + /// the window is activated and moved to the top of either the topmost or non-topmost group + /// (depending on the setting of the hwndInsertAfter member). + /// + NOACTIVATE = 0x0010, + /// + /// Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. + /// If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed. + /// + FRAMECHANGED = 0x0020, /* The frame changed: send WM_NCCALCSIZE */ + /// + /// Displays the window. + /// + SHOWWINDOW = 0x0040, + /// + /// Hides the window. + /// + HIDEWINDOW = 0x0080, + /// + /// Discards the entire contents of the client area. If this flag is not specified, + /// the valid contents of the client area are saved and copied back into the client area + /// after the window is sized or repositioned. + /// + NOCOPYBITS = 0x0100, + /// + /// Does not change the owner window's position in the Z order. + /// + NOOWNERZORDER = 0x0200, /* Don't do owner Z ordering */ + /// + /// Prevents the window from receiving the WM_WINDOWPOSCHANGING message. + /// + NOSENDCHANGING = 0x0400, /* Don't send WM_WINDOWPOSCHANGING */ + + /// + /// Draws a frame (defined in the window's class description) around the window. + /// + DRAWFRAME = FRAMECHANGED, + /// + /// Same as the NOOWNERZORDER flag. + /// + NOREPOSITION = NOOWNERZORDER, + + DEFERERASE = 0x2000, + ASYNCWINDOWPOS = 0x4000 + } + + /// \internal + /// + /// Defines the coordinates of the upper-left and lower-right corners of a rectangle. + /// + /// + /// By convention, the right and bottom edges of the rectangle are normally considered exclusive. In other words, the pixel whose coordinates are (right, bottom) lies immediately outside of the the rectangle. For example, when RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECTL structure. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct Win32Rectangle + { + /// + /// Specifies the x-coordinate of the upper-left corner of the rectangle. + /// + internal LONG left; + /// + /// Specifies the y-coordinate of the upper-left corner of the rectangle. + /// + internal LONG top; + /// + /// Specifies the x-coordinate of the lower-right corner of the rectangle. + /// + internal LONG right; + /// + /// Specifies the y-coordinate of the lower-right corner of the rectangle. + /// + internal LONG bottom; + + internal int Width { get { return right - left; } } + internal int Height { get { return bottom - top; } } + + public override string ToString() + { + return String.Format("({0},{1})-({2},{3})", left, top, right, bottom); + } + + internal Rectangle ToRectangle() + { + return Rectangle.FromLTRB(left, top, right, bottom); + } + + internal static Win32Rectangle From(Rectangle value) + { + Win32Rectangle rect = new Win32Rectangle(); + rect.left = value.Left; + rect.right = value.Right; + rect.top = value.Top; + rect.bottom = value.Bottom; + return rect; + } + + internal static Win32Rectangle From(Size value) + { + Win32Rectangle rect = new Win32Rectangle(); + rect.left = 0; + rect.right = value.Width; + rect.top = 0; + rect.bottom = value.Height; + return rect; + } + } + + /// \internal + /// + /// Contains window information. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct WindowInfo + { + /// + /// The size of the structure, in bytes. + /// + public DWORD Size; + /// + /// Pointer to a RECT structure that specifies the coordinates of the window. + /// + public RECT Window; + /// + /// Pointer to a RECT structure that specifies the coordinates of the client area. + /// + public RECT Client; + /// + /// The window styles. For a table of window styles, see CreateWindowEx. + /// + public WindowStyle Style; + /// + /// The extended window styles. For a table of extended window styles, see CreateWindowEx. + /// + public ExtendedWindowStyle ExStyle; + /// + /// The window status. If this member is WS_ACTIVECAPTION, the window is active. Otherwise, this member is zero. + /// + public DWORD WindowStatus; + /// + /// The width of the window border, in pixels. + /// + public UINT WindowBordersX; + /// + /// The height of the window border, in pixels. + /// + public UINT WindowBordersY; + /// + /// The window class atom (see RegisterClass). + /// + public ATOM WindowType; + /// + /// The Microsoft Windows version of the application that created the window. + /// + public WORD CreatorVersion; + } + + internal struct MonitorInfo + { + public DWORD Size; + public RECT Monitor; + public RECT Work; + public DWORD Flags; + + public static readonly int SizeInBytes = Marshal.SizeOf(default(MonitorInfo)); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct NcCalculateSize + { + public Win32Rectangle NewBounds; + public Win32Rectangle OldBounds; + public Win32Rectangle OldClientRectangle; + unsafe public WindowPosition* Position; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct SHFILEINFO + { + public IntPtr hIcon; + public int iIcon; + public uint dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public string szTypeName; + }; + + internal struct TrackMouseEventStructure + { + public DWORD Size; + public TrackMouseEventFlags Flags; + public HWND TrackWindowHandle; + public DWORD HoverTime; + + public static readonly int SizeInBytes = Marshal.SizeOf(typeof(TrackMouseEventStructure)); + } + + internal struct BroadcastHeader + { + public DWORD Size; + public DeviceBroadcastType DeviceType; + private DWORD dbch_reserved; + } + + internal struct BroadcastDeviceInterface + { + public DWORD Size; + public DeviceBroadcastType DeviceType; + private DWORD dbcc_reserved; + public Guid ClassGuid; + public char dbcc_name; + } + /// \internal + /// + /// Contains information about an icon or a cursor. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct IconInfo + { + /// + /// Specifies whether this structure defines an icon or a cursor. A + /// value of TRUE specifies an icon; FALSE specifies a cursor + /// + public bool fIcon; + + /// + /// The x-coordinate of a cursor's hot spot. If this structure defines + /// an icon, the hot spot is always in the center of the icon, and + /// this member is ignored. + /// + public Int32 xHotspot; + + /// + /// The y-coordinate of a cursor's hot spot. If this structure defines + /// an icon, the hot spot is always in the center of the icon, and + /// this member is ignored. + /// + public Int32 yHotspot; + + /// + /// The icon bitmask bitmap. If this structure defines a black and + /// white icon, this bitmask is formatted so that the upper half is + /// the icon AND bitmask and the lower half is the icon XOR bitmask. + /// Under this condition, the height should be an even multiple of + /// two. If this structure defines a color icon, this mask only + /// defines the AND bitmask of the icon. + /// + public IntPtr hbmMask; + + /// + /// A handle to the icon color bitmap. This member can be optional if + /// this structure defines a black and white icon. The AND bitmask of + /// hbmMask is applied with the SRCAND flag to the destination; + /// subsequently, the color bitmap is applied (using XOR) to the + /// destination by using the SRCINVERT flag. + /// + public IntPtr hbmColor; + } + + /// + /// Window field offsets for GetWindowLong() and GetWindowLongPtr(). + /// + internal enum GWL + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12), + } + + internal enum SizeMessage + { + MAXHIDE = 4, + MAXIMIZED = 2, + MAXSHOW = 3, + MINIMIZED = 1, + RESTORED = 0 + } + + internal enum NcCalcSizeOptions + { + ALIGNTOP = 0x10, + ALIGNRIGHT = 0x80, + ALIGNLEFT = 0x20, + ALIGNBOTTOM = 0x40, + HREDRAW = 0x100, + VREDRAW = 0x200, + REDRAW = (HREDRAW | VREDRAW), + VALIDRECTS = 0x400 + } + + internal enum DeviceCaps + { + LogPixelsX = 88, + LogPixelsY = 90 + } + + internal enum DisplayModeSettingsEnum + { + CurrentSettings = -1, + RegistrySettings = -2 + } + + [Flags] + internal enum DisplayDeviceStateFlags + { + None = 0x00000000, + AttachedToDesktop = 0x00000001, + MultiDriver = 0x00000002, + PrimaryDevice = 0x00000004, + MirroringDriver = 0x00000008, + VgaCompatible = 0x00000010, + Removable = 0x00000020, + ModesPruned = 0x08000000, + Remote = 0x04000000, + Disconnect = 0x02000000, + + // Child device state + Active = 0x00000001, + Attached = 0x00000002, + } + + [Flags] + internal enum ChangeDisplaySettingsEnum + { + // ChangeDisplaySettings types (found in winuser.h) + UpdateRegistry = 0x00000001, + Test = 0x00000002, + Fullscreen = 0x00000004, + } + + [Flags] + internal enum WindowStyle : uint + { + Overlapped = 0x00000000, + Popup = 0x80000000, + Child = 0x40000000, + Minimize = 0x20000000, + Visible = 0x10000000, + Disabled = 0x08000000, + ClipSiblings = 0x04000000, + ClipChildren = 0x02000000, + Maximize = 0x01000000, + Caption = 0x00C00000, // Border | DialogFrame + Border = 0x00800000, + DialogFrame = 0x00400000, + VScroll = 0x00200000, + HScreen = 0x00100000, + SystemMenu = 0x00080000, + ThickFrame = 0x00040000, + Group = 0x00020000, + TabStop = 0x00010000, + + MinimizeBox = 0x00020000, + MaximizeBox = 0x00010000, + + Tiled = Overlapped, + Iconic = Minimize, + SizeBox = ThickFrame, + TiledWindow = OverlappedWindow, + + // Common window styles: + OverlappedWindow = Overlapped | Caption | SystemMenu | ThickFrame | MinimizeBox | MaximizeBox, + PopupWindow = Popup | Border | SystemMenu, + ChildWindow = Child + } + + [Flags] + internal enum ExtendedWindowStyle : uint + { + DialogModalFrame = 0x00000001, + NoParentNotify = 0x00000004, + Topmost = 0x00000008, + AcceptFiles = 0x00000010, + Transparent = 0x00000020, + + // #if(WINVER >= 0x0400) + MdiChild = 0x00000040, + ToolWindow = 0x00000080, + WindowEdge = 0x00000100, + ClientEdge = 0x00000200, + ContextHelp = 0x00000400, + // #endif + + // #if(WINVER >= 0x0400) + Right = 0x00001000, + Left = 0x00000000, + RightToLeftReading = 0x00002000, + LeftToRightReading = 0x00000000, + LeftScrollbar = 0x00004000, + RightScrollbar = 0x00000000, + + ControlParent = 0x00010000, + StaticEdge = 0x00020000, + ApplicationWindow = 0x00040000, + + OverlappedWindow = WindowEdge | ClientEdge, + PaletteWindow = WindowEdge | ToolWindow | Topmost, + // #endif + + // #if(_WIN32_WINNT >= 0x0500) + Layered = 0x00080000, + // #endif + + // #if(WINVER >= 0x0500) + NoInheritLayout = 0x00100000, // Disable inheritence of mirroring by children + RightToLeftLayout = 0x00400000, // Right to left mirroring + // #endif /* WINVER >= 0x0500 */ + + // #if(_WIN32_WINNT >= 0x0501) + Composited = 0x02000000, + // #endif /* _WIN32_WINNT >= 0x0501 */ + + // #if(_WIN32_WINNT >= 0x0500) + NoActivate = 0x08000000 + // #endif /* _WIN32_WINNT >= 0x0500 */ + } + + internal enum GetWindowLongOffsets : int + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12), + } + [Flags] + internal enum PixelFormatDescriptorFlags : int + { + // PixelFormatDescriptor flags + DOUBLEBUFFER = 0x01, + STEREO = 0x02, + DRAW_TO_WINDOW = 0x04, + DRAW_TO_BITMAP = 0x08, + SUPPORT_GDI = 0x10, + SUPPORT_OPENGL = 0x20, + GENERIC_FORMAT = 0x40, + NEED_PALETTE = 0x80, + NEED_SYSTEM_PALETTE = 0x100, + SWAP_EXCHANGE = 0x200, + SWAP_COPY = 0x400, + SWAP_LAYER_BUFFERS = 0x800, + GENERIC_ACCELERATED = 0x1000, + SUPPORT_DIRECTDRAW = 0x2000, + SUPPORT_COMPOSITION = 0x8000, + + // PixelFormatDescriptor flags for use in ChoosePixelFormat only + DEPTH_DONTCARE = unchecked((int)0x20000000), + DOUBLEBUFFER_DONTCARE = unchecked((int)0x40000000), + STEREO_DONTCARE = unchecked((int)0x80000000) + } + internal enum PixelType : byte + { + RGBA = 0, + INDEXED = 1 + } + + internal enum WindowPlacementOptions + { + TOP = 0, + BOTTOM = 1, + TOPMOST = -1, + NOTOPMOST = -2 + } + [Flags] + internal enum ClassStyle + { + //None = 0x0000, + VRedraw = 0x0001, + HRedraw = 0x0002, + DoubleClicks = 0x0008, + OwnDC = 0x0020, + ClassDC = 0x0040, + ParentDC = 0x0080, + NoClose = 0x0200, + SaveBits = 0x0800, + ByteAlignClient = 0x1000, + ByteAlignWindow = 0x2000, + GlobalClass = 0x4000, + + Ime = 0x00010000, + + // #if(_WIN32_WINNT >= 0x0501) + DropShadow = 0x00020000 + // #endif /* _WIN32_WINNT >= 0x0501 */ + } + [Flags] + internal enum RawInputDeviceFlags : int + { + /// + /// If set, this removes the top level collection from the inclusion list. + /// This tells the operating system to stop reading from a device which matches the top level collection. + /// + REMOVE = 0x00000001, + /// + /// If set, this specifies the top level collections to exclude when reading a complete usage page. + /// This flag only affects a TLC whose usage page is already specified with RawInputDeviceEnum.PAGEONLY. + /// + EXCLUDE = 0x00000010, + /// + /// If set, this specifies all devices whose top level collection is from the specified UsagePage. + /// Note that usUsage must be zero. To exclude a particular top level collection, use EXCLUDE. + /// + PAGEONLY = 0x00000020, + /// + /// If set, this prevents any devices specified by UsagePage or Usage from generating legacy messages. + /// This is only for the mouse and keyboard. See RawInputDevice Remarks. + /// + NOLEGACY = 0x00000030, + /// + /// If set, this enables the caller to receive the input even when the caller is not in the foreground. + /// Note that Target must be specified in RawInputDevice. + /// + INPUTSINK = 0x00000100, + /// + /// If set, the mouse button click does not activate the other window. + /// + CAPTUREMOUSE = 0x00000200, // effective when mouse nolegacy is specified, otherwise it would be an error + /// + /// If set, the application-defined keyboard device hotkeys are not handled. + /// However, the system hotkeys; for example, ALT+TAB and CTRL+ALT+DEL, are still handled. + /// By default, all keyboard hotkeys are handled. + /// NOHOTKEYS can be specified even if NOLEGACY is not specified and Target is NULL in RawInputDevice. + /// + NOHOTKEYS = 0x00000200, // effective for keyboard. + /// + /// Microsoft Windows XP Service Pack 1 (SP1): If set, the application command keys are handled. APPKEYS can be specified only if NOLEGACY is specified for a keyboard device. + /// + APPKEYS = 0x00000400, // effective for keyboard. + /// + /// If set, this enables the caller to receive input in the background only if the foreground application + /// does not process it. In other words, if the foreground application is not registered for raw input, + /// then the background application that is registered will receive the input. + /// + EXINPUTSINK = 0x00001000, + DEVNOTIFY = 0x00002000, + //EXMODEMASK = 0x000000F0 + } + + internal enum GetRawInputDataEnum + { + INPUT = 0x10000003, + HEADER = 0x10000005 + } + + internal enum RawInputDeviceInfoEnum + { + PREPARSEDDATA = 0x20000005, + DEVICENAME = 0x20000007, // the return valus is the character length, not the byte size + DEVICEINFO = 0x2000000b + } + + [Flags] + internal enum RawInputMouseState : ushort + { + LEFT_BUTTON_DOWN = 0x0001, // Left Button changed to down. + LEFT_BUTTON_UP = 0x0002, // Left Button changed to up. + RIGHT_BUTTON_DOWN = 0x0004, // Right Button changed to down. + RIGHT_BUTTON_UP = 0x0008, // Right Button changed to up. + MIDDLE_BUTTON_DOWN = 0x0010, // Middle Button changed to down. + MIDDLE_BUTTON_UP = 0x0020, // Middle Button changed to up. + + BUTTON_1_DOWN = LEFT_BUTTON_DOWN, + BUTTON_1_UP = LEFT_BUTTON_UP, + BUTTON_2_DOWN = RIGHT_BUTTON_DOWN, + BUTTON_2_UP = RIGHT_BUTTON_UP, + BUTTON_3_DOWN = MIDDLE_BUTTON_DOWN, + BUTTON_3_UP = MIDDLE_BUTTON_UP, + + BUTTON_4_DOWN = 0x0040, + BUTTON_4_UP = 0x0080, + BUTTON_5_DOWN = 0x0100, + BUTTON_5_UP = 0x0200, + + WHEEL = 0x0400, + HWHEEL = 0x0800, + } + + internal enum RawInputKeyboardDataFlags : short //: ushort + { + MAKE = 0, + BREAK = 1, + E0 = 2, + E1 = 4, + TERMSRV_SET_LED = 8, + TERMSRV_SHADOW = 0x10 + } + + internal enum RawInputDeviceType : int + { + MOUSE = 0, + KEYBOARD = 1, + HID = 2 + } + + /// + /// Mouse indicator flags (found in winuser.h). + /// + [Flags] + internal enum RawMouseFlags : ushort + { + /// + /// LastX/Y indicate relative motion. + /// + MOUSE_MOVE_RELATIVE = 0x00, + /// + /// LastX/Y indicate absolute motion. + /// + MOUSE_MOVE_ABSOLUTE = 0x01, + /// + /// The coordinates are mapped to the virtual desktop. + /// + MOUSE_VIRTUAL_DESKTOP = 0x02, + /// + /// Requery for mouse attributes. + /// + MOUSE_ATTRIBUTES_CHANGED = 0x04, + } + + internal enum VirtualKeys : short + { + /* + * Virtual Key, Standard Set + */ + LBUTTON = 0x01, + RBUTTON = 0x02, + CANCEL = 0x03, + MBUTTON = 0x04, /* NOT contiguous with L & RBUTTON */ + + XBUTTON1 = 0x05, /* NOT contiguous with L & RBUTTON */ + XBUTTON2 = 0x06, /* NOT contiguous with L & RBUTTON */ + + /* + * 0x07 : unassigned + */ + + BACK = 0x08, + TAB = 0x09, + + /* + * 0x0A - 0x0B : reserved + */ + + CLEAR = 0x0C, + RETURN = 0x0D, + + SHIFT = 0x10, + CONTROL = 0x11, + MENU = 0x12, + PAUSE = 0x13, + CAPITAL = 0x14, + + KANA = 0x15, + HANGEUL = 0x15, /* old name - should be here for compatibility */ + HANGUL = 0x15, + JUNJA = 0x17, + FINAL = 0x18, + HANJA = 0x19, + KANJI = 0x19, + + ESCAPE = 0x1B, + + CONVERT = 0x1C, + NONCONVERT = 0x1D, + ACCEPT = 0x1E, + MODECHANGE = 0x1F, + + SPACE = 0x20, + PRIOR = 0x21, + NEXT = 0x22, + END = 0x23, + HOME = 0x24, + LEFT = 0x25, + UP = 0x26, + RIGHT = 0x27, + DOWN = 0x28, + SELECT = 0x29, + PRINT = 0x2A, + EXECUTE = 0x2B, + SNAPSHOT = 0x2C, + INSERT = 0x2D, + DELETE = 0x2E, + HELP = 0x2F, + + /* + * 0 - 9 are the same as ASCII '0' - '9' (0x30 - 0x39) + * 0x40 : unassigned + * A - Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) + */ + + LWIN = 0x5B, + RWIN = 0x5C, + APPS = 0x5D, + + /* + * 0x5E : reserved + */ + + SLEEP = 0x5F, + + NUMPAD0 = 0x60, + NUMPAD1 = 0x61, + NUMPAD2 = 0x62, + NUMPAD3 = 0x63, + NUMPAD4 = 0x64, + NUMPAD5 = 0x65, + NUMPAD6 = 0x66, + NUMPAD7 = 0x67, + NUMPAD8 = 0x68, + NUMPAD9 = 0x69, + MULTIPLY = 0x6A, + ADD = 0x6B, + SEPARATOR = 0x6C, + SUBTRACT = 0x6D, + DECIMAL = 0x6E, + DIVIDE = 0x6F, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7A, + F12 = 0x7B, + F13 = 0x7C, + F14 = 0x7D, + F15 = 0x7E, + F16 = 0x7F, + F17 = 0x80, + F18 = 0x81, + F19 = 0x82, + F20 = 0x83, + F21 = 0x84, + F22 = 0x85, + F23 = 0x86, + F24 = 0x87, + + /* + * 0x88 - 0x8F : unassigned + */ + + NUMLOCK = 0x90, + SCROLL = 0x91, + + /* + * NEC PC-9800 kbd definitions + */ + OEM_NEC_EQUAL = 0x92, // '=' key on numpad + + /* + * Fujitsu/OASYS kbd definitions + */ + OEM_FJ_JISHO = 0x92, // 'Dictionary' key + OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key + OEM_FJ_TOUROKU = 0x94, // 'Register word' key + OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key + OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key + + /* + * 0x97 - 0x9F : unassigned + */ + + /* + * L* & R* - left and right Alt, Ctrl and Shift virtual keys. + * Used only as parameters to GetAsyncKeyState() and GetKeyState(). + * No other API or message will distinguish left and right keys in this way. + */ + LSHIFT = 0xA0, + RSHIFT = 0xA1, + LCONTROL = 0xA2, + RCONTROL = 0xA3, + LMENU = 0xA4, + RMENU = 0xA5, + + BROWSER_BACK = 0xA6, + BROWSER_FORWARD = 0xA7, + BROWSER_REFRESH = 0xA8, + BROWSER_STOP = 0xA9, + BROWSER_SEARCH = 0xAA, + BROWSER_FAVORITES = 0xAB, + BROWSER_HOME = 0xAC, + + VOLUME_MUTE = 0xAD, + VOLUME_DOWN = 0xAE, + VOLUME_UP = 0xAF, + MEDIA_NEXT_TRACK = 0xB0, + MEDIA_PREV_TRACK = 0xB1, + MEDIA_STOP = 0xB2, + MEDIA_PLAY_PAUSE = 0xB3, + LAUNCH_MAIL = 0xB4, + LAUNCH_MEDIA_SELECT = 0xB5, + LAUNCH_APP1 = 0xB6, + LAUNCH_APP2 = 0xB7, + + /* + * 0xB8 - 0xB9 : reserved + */ + + OEM_1 = 0xBA, // ';:' for US + OEM_PLUS = 0xBB, // '+' any country + OEM_COMMA = 0xBC, // ',' any country + OEM_MINUS = 0xBD, // '-' any country + OEM_PERIOD = 0xBE, // '.' any country + OEM_2 = 0xBF, // '/?' for US + OEM_3 = 0xC0, // '`~' for US + + /* + * 0xC1 - 0xD7 : reserved + */ + + /* + * 0xD8 - 0xDA : unassigned + */ + + OEM_4 = 0xDB, // '[{' for US + OEM_5 = 0xDC, // '\|' for US + OEM_6 = 0xDD, // ']}' for US + OEM_7 = 0xDE, // ''"' for US + OEM_8 = 0xDF, + + /* + * 0xE0 : reserved + */ + + /* + * Various extended or enhanced keyboards + */ + OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd + OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key kbd. + ICO_HELP = 0xE3, // Help key on ICO + ICO_00 = 0xE4, // 00 key on ICO + + PROCESSKEY = 0xE5, + + ICO_CLEAR = 0xE6, + + + PACKET = 0xE7, + + /* + * 0xE8 : unassigned + */ + + /* + * Nokia/Ericsson definitions + */ + OEM_RESET = 0xE9, + OEM_JUMP = 0xEA, + OEM_PA1 = 0xEB, + OEM_PA2 = 0xEC, + OEM_PA3 = 0xED, + OEM_WSCTRL = 0xEE, + OEM_CUSEL = 0xEF, + OEM_ATTN = 0xF0, + OEM_FINISH = 0xF1, + OEM_COPY = 0xF2, + OEM_AUTO = 0xF3, + OEM_ENLW = 0xF4, + OEM_BACKTAB = 0xF5, + + ATTN = 0xF6, + CRSEL = 0xF7, + EXSEL = 0xF8, + EREOF = 0xF9, + PLAY = 0xFA, + ZOOM = 0xFB, + NONAME = 0xFC, + PA1 = 0xFD, + OEM_CLEAR = 0xFE, + + Last + } + + /// + /// Enumerates available mouse keys (suitable for use in WM_MOUSEMOVE messages). + /// + internal enum MouseKeys + { + // Summary: + // No mouse button was pressed. + None = 0, + // + // Summary: + // The left mouse button was pressed. + Left = 0x0001, + // + // Summary: + // The right mouse button was pressed. + Right = 0x0002, + // + // Summary: + // The middle mouse button was pressed. + Middle = 0x0010, + // + // Summary: + // The first XButton was pressed. + XButton1 = 0x0020, + // + // Summary: + // The second XButton was pressed. + XButton2 = 0x0040, + } + + /// \internal + /// + /// Queue status flags for GetQueueStatus() and MsgWaitForMultipleObjects() + /// + [Flags] + internal enum QueueStatusFlags + { + /// + /// A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue. + /// + KEY = 0x0001, + /// + /// A WM_MOUSEMOVE message is in the queue. + /// + MOUSEMOVE = 0x0002, + /// + /// A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on). + /// + MOUSEBUTTON = 0x0004, + /// + /// A posted message (other than those listed here) is in the queue. + /// + POSTMESSAGE = 0x0008, + /// + /// A WM_TIMER message is in the queue. + /// + TIMER = 0x0010, + /// + /// A WM_PAINT message is in the queue. + /// + PAINT = 0x0020, + /// + /// A message sent by another thread or application is in the queue. + /// + SENDMESSAGE = 0x0040, + /// + /// A WM_HOTKEY message is in the queue. + /// + HOTKEY = 0x0080, + /// + /// A posted message (other than those listed here) is in the queue. + /// + ALLPOSTMESSAGE = 0x0100, + /// + /// A raw input message is in the queue. For more information, see Raw Input. + /// Windows XP and higher only. + /// + RAWINPUT = 0x0400, + /// + /// A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on). + /// + MOUSE = MOUSEMOVE | MOUSEBUTTON, + /// + /// An input message is in the queue. This is composed of KEY, MOUSE and RAWINPUT. + /// Windows XP and higher only. + /// + INPUT = MOUSE | KEY | RAWINPUT, + /// + /// An input message is in the queue. This is composed of QS_KEY and QS_MOUSE. + /// Windows 2000 and earlier. + /// + INPUT_LEGACY = MOUSE | KEY, + /// + /// An input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue. + /// + ALLEVENTS = INPUT | POSTMESSAGE | TIMER | PAINT | HOTKEY, + /// + /// Any message is in the queue. + /// + ALLINPUT = INPUT | POSTMESSAGE | TIMER | PAINT | HOTKEY | SENDMESSAGE + } + + internal enum WindowMessage : int + { + NULL = 0x0000, + CREATE = 0x0001, + DESTROY = 0x0002, + MOVE = 0x0003, + SIZE = 0x0005, + ACTIVATE = 0x0006, + SETFOCUS = 0x0007, + KILLFOCUS = 0x0008, + // internal const uint SETVISIBLE = 0x0009; + ENABLE = 0x000A, + SETREDRAW = 0x000B, + SETTEXT = 0x000C, + GETTEXT = 0x000D, + GETTEXTLENGTH = 0x000E, + PAINT = 0x000F, + CLOSE = 0x0010, + QUERYENDSESSION = 0x0011, + QUIT = 0x0012, + QUERYOPEN = 0x0013, + ERASEBKGND = 0x0014, + SYSCOLORCHANGE = 0x0015, + ENDSESSION = 0x0016, + // internal const uint SYSTEMERROR = 0x0017; + SHOWWINDOW = 0x0018, + CTLCOLOR = 0x0019, + WININICHANGE = 0x001A, + SETTINGCHANGE = 0x001A, + DEVMODECHANGE = 0x001B, + ACTIVATEAPP = 0x001C, + FONTCHANGE = 0x001D, + TIMECHANGE = 0x001E, + CANCELMODE = 0x001F, + SETCURSOR = 0x0020, + MOUSEACTIVATE = 0x0021, + CHILDACTIVATE = 0x0022, + QUEUESYNC = 0x0023, + GETMINMAXINFO = 0x0024, + PAINTICON = 0x0026, + ICONERASEBKGND = 0x0027, + NEXTDLGCTL = 0x0028, + // internal const uint ALTTABACTIVE = 0x0029; + SPOOLERSTATUS = 0x002A, + DRAWITEM = 0x002B, + MEASUREITEM = 0x002C, + DELETEITEM = 0x002D, + VKEYTOITEM = 0x002E, + CHARTOITEM = 0x002F, + SETFONT = 0x0030, + GETFONT = 0x0031, + SETHOTKEY = 0x0032, + GETHOTKEY = 0x0033, + // internal const uint FILESYSCHANGE = 0x0034; + // internal const uint ISACTIVEICON = 0x0035; + // internal const uint QUERYPARKICON = 0x0036; + QUERYDRAGICON = 0x0037, + COMPAREITEM = 0x0039, + // internal const uint TESTING = 0x003a; + // internal const uint OTHERWINDOWCREATED = 0x003c; + GETOBJECT = 0x003D, + // internal const uint ACTIVATESHELLWINDOW = 0x003e; + COMPACTING = 0x0041, + COMMNOTIFY = 0x0044, + WINDOWPOSCHANGING = 0x0046, + WINDOWPOSCHANGED = 0x0047, + POWER = 0x0048, + COPYDATA = 0x004A, + CANCELJOURNAL = 0x004B, + NOTIFY = 0x004E, + INPUTLANGCHANGEREQUEST = 0x0050, + INPUTLANGCHANGE = 0x0051, + TCARD = 0x0052, + HELP = 0x0053, + USERCHANGED = 0x0054, + NOTIFYFORMAT = 0x0055, + CONTEXTMENU = 0x007B, + STYLECHANGING = 0x007C, + STYLECHANGED = 0x007D, + DISPLAYCHANGE = 0x007E, + GETICON = 0x007F, + + // Non-Client messages + SETICON = 0x0080, + NCCREATE = 0x0081, + NCDESTROY = 0x0082, + NCCALCSIZE = 0x0083, + NCHITTEST = 0x0084, + NCPAINT = 0x0085, + NCACTIVATE = 0x0086, + GETDLGCODE = 0x0087, + SYNCPAINT = 0x0088, + // internal const uint SYNCTASK = 0x0089; + NCMOUSEMOVE = 0x00A0, + NCLBUTTONDOWN = 0x00A1, + NCLBUTTONUP = 0x00A2, + NCLBUTTONDBLCLK = 0x00A3, + NCRBUTTONDOWN = 0x00A4, + NCRBUTTONUP = 0x00A5, + NCRBUTTONDBLCLK = 0x00A6, + NCMBUTTONDOWN = 0x00A7, + NCMBUTTONUP = 0x00A8, + NCMBUTTONDBLCLK = 0x00A9, + /// + /// Windows 2000 and higher only. + /// + NCXBUTTONDOWN = 0x00ab, + /// + /// Windows 2000 and higher only. + /// + NCXBUTTONUP = 0x00ac, + /// + /// Windows 2000 and higher only. + /// + NCXBUTTONDBLCLK = 0x00ad, + + INPUT = 0x00FF, + + KEYDOWN = 0x0100, + KEYFIRST = 0x0100, + KEYUP = 0x0101, + CHAR = 0x0102, + DEADCHAR = 0x0103, + SYSKEYDOWN = 0x0104, + SYSKEYUP = 0x0105, + SYSCHAR = 0x0106, + SYSDEADCHAR = 0x0107, + KEYLAST = 0x0108, + UNICHAR = 0x0109, + + + + IME_STARTCOMPOSITION = 0x010D, + IME_ENDCOMPOSITION = 0x010E, + IME_COMPOSITION = 0x010F, + IME_KEYLAST = 0x010F, + INITDIALOG = 0x0110, + COMMAND = 0x0111, + SYSCOMMAND = 0x0112, + TIMER = 0x0113, + HSCROLL = 0x0114, + VSCROLL = 0x0115, + INITMENU = 0x0116, + INITMENUPOPUP = 0x0117, + // internal const uint SYSTIMER = 0x0118; + MENUSELECT = 0x011F, + MENUCHAR = 0x0120, + ENTERIDLE = 0x0121, + MENURBUTTONUP = 0x0122, + MENUDRAG = 0x0123, + MENUGETOBJECT = 0x0124, + UNINITMENUPOPUP = 0x0125, + MENUCOMMAND = 0x0126, + + CHANGEUISTATE = 0x0127, + UPDATEUISTATE = 0x0128, + QUERYUISTATE = 0x0129, + + // internal const uint LBTRACKPOINT = 0x0131; + CTLCOLORMSGBOX = 0x0132, + CTLCOLOREDIT = 0x0133, + CTLCOLORLISTBOX = 0x0134, + CTLCOLORBTN = 0x0135, + CTLCOLORDLG = 0x0136, + CTLCOLORSCROLLBAR = 0x0137, + CTLCOLORSTATIC = 0x0138, + MOUSEMOVE = 0x0200, + MOUSEFIRST = 0x0200, + LBUTTONDOWN = 0x0201, + LBUTTONUP = 0x0202, + LBUTTONDBLCLK = 0x0203, + RBUTTONDOWN = 0x0204, + RBUTTONUP = 0x0205, + RBUTTONDBLCLK = 0x0206, + MBUTTONDOWN = 0x0207, + MBUTTONUP = 0x0208, + MBUTTONDBLCLK = 0x0209, + MOUSEWHEEL = 0x020A, + /// + /// Windows 2000 and higher only. + /// + XBUTTONDOWN = 0x020B, + /// + /// Windows 2000 and higher only. + /// + XBUTTONUP = 0x020C, + /// + /// Windows 2000 and higher only. + /// + XBUTTONDBLCLK = 0x020D, + /// + /// Windows Vista and higher only. + /// + MOUSEHWHEEL = 0x020E, + PARENTNOTIFY = 0x0210, + ENTERMENULOOP = 0x0211, + EXITMENULOOP = 0x0212, + NEXTMENU = 0x0213, + SIZING = 0x0214, + CAPTURECHANGED = 0x0215, + MOVING = 0x0216, + // internal const uint POWERBROADCAST = 0x0218; + DEVICECHANGE = 0x0219, + MDICREATE = 0x0220, + MDIDESTROY = 0x0221, + MDIACTIVATE = 0x0222, + MDIRESTORE = 0x0223, + MDINEXT = 0x0224, + MDIMAXIMIZE = 0x0225, + MDITILE = 0x0226, + MDICASCADE = 0x0227, + MDIICONARRANGE = 0x0228, + MDIGETACTIVE = 0x0229, + /* D&D messages */ + // internal const uint DROPOBJECT = 0x022A; + // internal const uint QUERYDROPOBJECT = 0x022B; + // internal const uint BEGINDRAG = 0x022C; + // internal const uint DRAGLOOP = 0x022D; + // internal const uint DRAGSELECT = 0x022E; + // internal const uint DRAGMOVE = 0x022F; + MDISETMENU = 0x0230, + ENTERSIZEMOVE = 0x0231, + EXITSIZEMOVE = 0x0232, + DROPFILES = 0x0233, + MDIREFRESHMENU = 0x0234, + IME_SETCONTEXT = 0x0281, + IME_NOTIFY = 0x0282, + IME_CONTROL = 0x0283, + IME_COMPOSITIONFULL = 0x0284, + IME_SELECT = 0x0285, + IME_CHAR = 0x0286, + IME_REQUEST = 0x0288, + IME_KEYDOWN = 0x0290, + IME_KEYUP = 0x0291, + NCMOUSEHOVER = 0x02A0, + MOUSEHOVER = 0x02A1, + NCMOUSELEAVE = 0x02A2, + MOUSELEAVE = 0x02A3, + CUT = 0x0300, + COPY = 0x0301, + PASTE = 0x0302, + CLEAR = 0x0303, + UNDO = 0x0304, + RENDERFORMAT = 0x0305, + RENDERALLFORMATS = 0x0306, + DESTROYCLIPBOARD = 0x0307, + DRAWCLIPBOARD = 0x0308, + PAINTCLIPBOARD = 0x0309, + VSCROLLCLIPBOARD = 0x030A, + SIZECLIPBOARD = 0x030B, + ASKCBFORMATNAME = 0x030C, + CHANGECBCHAIN = 0x030D, + HSCROLLCLIPBOARD = 0x030E, + QUERYNEWPALETTE = 0x030F, + PALETTEISCHANGING = 0x0310, + PALETTECHANGED = 0x0311, + HOTKEY = 0x0312, + PRINT = 0x0317, + PRINTCLIENT = 0x0318, + HANDHELDFIRST = 0x0358, + HANDHELDLAST = 0x035F, + AFXFIRST = 0x0360, + AFXLAST = 0x037F, + PENWINFIRST = 0x0380, + PENWINLAST = 0x038F, + APP = 0x8000, + USER = 0x0400, + + // Our "private" ones + MOUSE_ENTER = 0x0401, + ASYNC_MESSAGE = 0x0403, + REFLECT = USER + 0x1c00, + CLOSE_INTERNAL = USER + 0x1c01, + + // NotifyIcon (Systray) Balloon messages + BALLOONSHOW = USER + 0x0002, + BALLOONHIDE = USER + 0x0003, + BALLOONTIMEOUT = USER + 0x0004, + BALLOONUSERCLICK = USER + 0x0005 + } + + [Flags] + internal enum PeekMessageFlags : uint + { + NoRemove = 0, + Remove = 1, + NoYield = 2 + } + + /// + /// ShowWindow() Commands + /// + internal enum ShowWindowCommand + { + /// + /// Hides the window and activates another window. + /// + HIDE = 0, + /// + /// Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. + /// + SHOWNORMAL = 1, + NORMAL = 1, + /// + /// Activates the window and displays it as a minimized window. + /// + SHOWMINIMIZED = 2, + /// + /// Activates the window and displays it as a maximized window. + /// + SHOWMAXIMIZED = 3, + MAXIMIZE = 3, + /// + /// Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated. + /// + SHOWNOACTIVATE = 4, + /// + /// Activates the window and displays it in its current size and position. + /// + SHOW = 5, + /// + /// Minimizes the specified window and activates the next top-level window in the Z order. + /// + MINIMIZE = 6, + /// + /// Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated. + /// + SHOWMINNOACTIVE = 7, + /// + /// Displays the window in its current size and position. This value is similar to SW_SHOW, except the window is not activated. + /// + SHOWNA = 8, + /// + /// Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window. + /// + RESTORE = 9, + /// + /// Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. + /// + SHOWDEFAULT = 10, + /// + /// Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing windows from a different thread. + /// + FORCEMINIMIZE = 11, + //MAX = 11, + + // Old ShowWindow() Commands + //HIDE_WINDOW = 0, + //SHOW_OPENWINDOW = 1, + //SHOW_ICONWINDOW = 2, + //SHOW_FULLSCREEN = 3, + //SHOW_OPENNOACTIVATE= 4, + } + + /// + /// Identifiers for the WM_SHOWWINDOW message + /// + internal enum ShowWindowMessageIdentifiers + { + PARENTCLOSING = 1, + OTHERZOOM = 2, + PARENTOPENING = 3, + OTHERUNZOOM = 4, + } + + /// + /// Enumerates the available character sets. + /// + internal enum GdiCharset + { + Ansi = 0, + Default = 1, + Symbol = 2, + ShiftJIS = 128, + Hangeul = 129, + Hangul = 129, + GB2312 = 134, + ChineseBig5 = 136, + OEM = 255, + //#if(WINVER >= 0x0400) + Johab = 130, + Hebrew = 177, + Arabic = 178, + Greek = 161, + Turkish = 162, + Vietnamese = 163, + Thai = 222, + EastEurope = 238, + Russian = 204, + Mac = 77, + Baltic = 186, + } + + /// + /// Identifiers for the GetStockObject method. + /// + internal enum StockObjects + { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + OEM_FIXED_FONT = 10, + ANSI_FIXED_FONT = 11, + ANSI_VAR_FONT = 12, + SYSTEM_FONT = 13, + DEVICE_DEFAULT_FONT = 14, + DEFAULT_PALETTE = 15, + SYSTEM_FIXED_FONT = 16, + DEFAULT_GUI_FONT = 17, + DC_BRUSH = 18, + DC_PEN = 19, + } + + internal enum MapVirtualKeyType + { + /// uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. + VirtualKeyToScanCode = 0, + /// uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. + ScanCodeToVirtualKey = 1, + /// uCode is a virtual-key code and is translated into an unshifted character value in the low-order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. + VirtualKeyToCharacter = 2, + /// Windows NT/2000/XP: uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. + ScanCodeToVirtualKeyExtended = 3, + VirtualKeyToScanCodeExtended = 4, + } + + internal enum DwmWindowAttribute + { + NCRENDERING_ENABLED = 1, + NCRENDERING_POLICY, + TRANSITIONS_FORCEDISABLED, + ALLOW_NCPAINT, + CAPTION_BUTTON_BOUNDS, + NONCLIENT_RTL_LAYOUT, + FORCE_ICONIC_REPRESENTATION, + FLIP3D_POLICY, + EXTENDED_FRAME_BOUNDS, + HAS_ICONIC_BITMAP, + DISALLOW_PEEK, + EXCLUDED_FROM_PEEK, + LAST + } + + [Flags] + internal enum ShGetFileIconFlags : int + { + /// get icon + Icon = 0x000000100, + /// get display name + DisplayName = 0x000000200, + /// get type name + TypeName = 0x000000400, + /// get attributes + Attributes = 0x000000800, + /// get icon location + IconLocation = 0x000001000, + /// return exe type + ExeType = 0x000002000, + /// get system icon index + SysIconIndex = 0x000004000, + /// put a link overlay on icon + LinkOverlay = 0x000008000, + /// show icon in selected state + Selected = 0x000010000, + /// get only specified attributes + Attr_Specified = 0x000020000, + /// get large icon + LargeIcon = 0x000000000, + /// get small icon + SmallIcon = 0x000000001, + /// get open icon + OpenIcon = 0x000000002, + /// get shell size icon + ShellIconSize = 0x000000004, + /// pszPath is a pidl + PIDL = 0x000000008, + /// use passed dwFileAttribute + UseFileAttributes = 0x000000010, + /// apply the appropriate overlays + AddOverlays = 0x000000020, + /// Get the index of the overlay in the upper 8 bits of the iIcon + OverlayIndex = 0x000000040, + } + + internal enum MonitorFrom + { + Null = 0, + Primary = 1, + Nearest = 2, + } + + internal enum CursorName : int + { + Arrow = 32512 + } + + [Flags] + internal enum TrackMouseEventFlags : uint + { + HOVER = 0x00000001, + LEAVE = 0x00000002, + NONCLIENT = 0x00000010, + QUERY = 0x40000000, + CANCEL = 0x80000000, + } + + internal enum MouseActivate + { + ACTIVATE = 1, + ACTIVATEANDEAT = 2, + NOACTIVATE = 3, + NOACTIVATEANDEAT = 4, + } + + internal enum DeviceNotification + { + WINDOW_HANDLE = 0x00000000, + SERVICE_HANDLE = 0x00000001, + ALL_INTERFACE_CLASSES = 0x00000004, + } + + internal enum DeviceBroadcastType + { + OEM = 0, + VOLUME = 2, + PORT = 3, + INTERFACE = 5, + HANDLE = 6, + } + + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + internal delegate IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam); + + [StructLayout(LayoutKind.Sequential), CLSCompliant(false)] + internal struct MSG + { + internal IntPtr HWnd; + internal WindowMessage Message; + internal IntPtr WParam; + internal IntPtr LParam; + internal uint Time; + internal POINT Point; + //internal object RefObject; + + public override string ToString() + { + return String.Format("msg=0x{0:x} ({1}) hwnd=0x{2:x} wparam=0x{3:x} lparam=0x{4:x} pt=0x{5:x}", (int)Message, Message.ToString(), HWnd.ToInt32(), WParam.ToInt32(), LParam.ToInt32(), Point); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct POINT + { + internal int X; + internal int Y; + + internal POINT(int x, int y) + { + this.X = x; + this.Y = y; + } + + internal Point ToPoint() + { + return new Point(X, Y); + } + + public override string ToString() + { + return "Point {" + X.ToString() + ", " + Y.ToString() + ")"; + } + } +} + +#pragma warning restore 3019 +#pragma warning restore 0649 +#pragma warning restore 0169 +#pragma warning restore 0414 diff --git a/GLWidget/OpenTK/Platform/Windows/Bindings/Wgl.cs b/GLWidget/OpenTK/Platform/Windows/Bindings/Wgl.cs new file mode 100644 index 0000000..c2a6db7 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/Bindings/Wgl.cs @@ -0,0 +1,159 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2013 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; +using System.Security; +using OpenTK.Core.Native; + +namespace OpenTK.Platform.Windows +{ +#pragma warning disable 3019 +#pragma warning disable 1591 + + internal partial class Wgl + { + static Wgl() + { + EntryPointNames = new string[] + { + "wglCreateContextAttribsARB", + "wglGetExtensionsStringARB", + "wglGetPixelFormatAttribivARB", + "wglGetPixelFormatAttribfvARB", + "wglChoosePixelFormatARB", + "wglMakeContextCurrentARB", + "wglGetCurrentReadDCARB", + "wglCreatePbufferARB", + "wglGetPbufferDCARB", + "wglReleasePbufferDCARB", + "wglDestroyPbufferARB", + "wglQueryPbufferARB", + "wglBindTexImageARB", + "wglReleaseTexImageARB", + "wglSetPbufferAttribARB", + "wglGetExtensionsStringEXT", + "wglSwapIntervalEXT", + "wglGetSwapIntervalEXT", + }; + EntryPoints = new IntPtr[EntryPointNames.Length]; + } + + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglCreateContext", ExactSpelling = true, SetLastError = true)] + internal extern static IntPtr CreateContext(IntPtr hDc); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglDeleteContext", ExactSpelling = true, SetLastError = true)] + internal extern static Boolean DeleteContext(IntPtr oldContext); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglGetCurrentContext", ExactSpelling = true, SetLastError = true)] + internal extern static IntPtr GetCurrentContext(); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglMakeCurrent", ExactSpelling = true, SetLastError = true)] + internal extern static Boolean MakeCurrent(IntPtr hDc, IntPtr newContext); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglChoosePixelFormat", ExactSpelling = true, SetLastError = true)] + internal extern static unsafe int ChoosePixelFormat(IntPtr hDc, ref PixelFormatDescriptor pPfd); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglDescribePixelFormat", ExactSpelling = true, SetLastError = true)] + internal extern static unsafe int DescribePixelFormat(IntPtr hdc, int ipfd, int cjpfd, ref PixelFormatDescriptor ppfd); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglGetCurrentDC", ExactSpelling = true, SetLastError = true)] + internal extern static IntPtr GetCurrentDC(); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglGetProcAddress", ExactSpelling = true, SetLastError = true)] + internal extern static IntPtr GetProcAddress(String lpszProc); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglGetProcAddress", ExactSpelling = true, SetLastError = true)] + internal extern static IntPtr GetProcAddress(IntPtr lpszProc); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglGetPixelFormat", ExactSpelling = true, SetLastError = true)] + internal extern static int GetPixelFormat(IntPtr hdc); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglSetPixelFormat", ExactSpelling = true, SetLastError = true)] + internal extern static Boolean SetPixelFormat(IntPtr hdc, int ipfd, ref PixelFormatDescriptor ppfd); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglSwapBuffers", ExactSpelling = true, SetLastError = true)] + internal extern static Boolean SwapBuffers(IntPtr hdc); + [SuppressUnmanagedCodeSecurity] + [DllImport(Wgl.Library, EntryPoint = "wglShareLists", ExactSpelling = true, SetLastError = true)] + internal extern static Boolean ShareLists(IntPtr hrcSrvShare, IntPtr hrcSrvSource); + + [Slot(0)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern IntPtr wglCreateContextAttribsARB(IntPtr hDC, IntPtr hShareContext, int* attribList); + [Slot(1)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr wglGetExtensionsStringARB(IntPtr hdc); + [Slot(2)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern Boolean wglGetPixelFormatAttribivARB(IntPtr hdc, int iPixelFormat, int iLayerPlane, UInt32 nAttributes, int* piAttributes, [Out] int* piValues); + [Slot(3)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern Boolean wglGetPixelFormatAttribfvARB(IntPtr hdc, int iPixelFormat, int iLayerPlane, UInt32 nAttributes, int* piAttributes, [Out] Single* pfValues); + [Slot(4)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern Boolean wglChoosePixelFormatARB(IntPtr hdc, int* piAttribIList, Single* pfAttribFList, UInt32 nMaxFormats, [Out] int* piFormats, [Out] UInt32* nNumFormats); + [Slot(5)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern Boolean wglMakeContextCurrentARB(IntPtr hDrawDC, IntPtr hReadDC, IntPtr hglrc); + [Slot(6)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr wglGetCurrentReadDCARB(); + [Slot(7)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern IntPtr wglCreatePbufferARB(IntPtr hDC, int iPixelFormat, int iWidth, int iHeight, int* piAttribList); + [Slot(8)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr wglGetPbufferDCARB(IntPtr hPbuffer); + [Slot(9)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int wglReleasePbufferDCARB(IntPtr hPbuffer, IntPtr hDC); + [Slot(10)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern Boolean wglDestroyPbufferARB(IntPtr hPbuffer); + [Slot(11)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern Boolean wglQueryPbufferARB(IntPtr hPbuffer, int iAttribute, [Out] int* piValue); + [Slot(12)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern Boolean wglBindTexImageARB(IntPtr hPbuffer, int iBuffer); + [Slot(13)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern Boolean wglReleaseTexImageARB(IntPtr hPbuffer, int iBuffer); + [Slot(14)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal unsafe static extern Boolean wglSetPbufferAttribARB(IntPtr hPbuffer, int* piAttribList); + [Slot(15)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr wglGetExtensionsStringEXT(); + [Slot(16)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern Boolean wglSwapIntervalEXT(int interval); + [Slot(17)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int wglGetSwapIntervalEXT(); + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/Bindings/WglEnums.cs b/GLWidget/OpenTK/Platform/Windows/Bindings/WglEnums.cs new file mode 100644 index 0000000..6b4dc73 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/Bindings/WglEnums.cs @@ -0,0 +1,521 @@ +namespace OpenTK.Platform.Windows +{ +#pragma warning disable 3019 +#pragma warning disable 1591 + + public enum ArbCreateContext + { + CoreProfileBit = 0x0001, + CompatibilityProfileBit = 0x0002, + DebugBit = 0x0001, + ForwardCompatibleBit = 0x0002, + MajorVersion = 0x2091, + MinorVersion = 0x2092, + LayerPlane = 0x2093, + ContextFlags = 0x2094, + ErrorInvalidVersion = 0x2095, + ProfileMask = 0x9126 + } + + public enum WGL_ARB_buffer_region + { + BackColorBufferBitArb = ((int)0x00000002), + StencilBufferBitArb = ((int)0x00000008), + FrontColorBufferBitArb = ((int)0x00000001), + DepthBufferBitArb = ((int)0x00000004), + } + + public enum WGL_EXT_pixel_format + { + SupportGdiExt = ((int)0x200f), + TypeColorindexExt = ((int)0x202c), + AccelerationExt = ((int)0x2003), + GreenBitsExt = ((int)0x2017), + DrawToWindowExt = ((int)0x2001), + SwapCopyExt = ((int)0x2029), + DrawToBitmapExt = ((int)0x2002), + TransparentExt = ((int)0x200a), + SwapMethodExt = ((int)0x2007), + SwapLayerBuffersExt = ((int)0x2006), + PixelTypeExt = ((int)0x2013), + AlphaShiftExt = ((int)0x201c), + AccumRedBitsExt = ((int)0x201e), + FullAccelerationExt = ((int)0x2027), + SupportOpenglExt = ((int)0x2010), + BlueShiftExt = ((int)0x201a), + RedBitsExt = ((int)0x2015), + NoAccelerationExt = ((int)0x2025), + StereoExt = ((int)0x2012), + GreenShiftExt = ((int)0x2018), + BlueBitsExt = ((int)0x2019), + AlphaBitsExt = ((int)0x201b), + RedShiftExt = ((int)0x2016), + DepthBitsExt = ((int)0x2022), + TypeRgbaExt = ((int)0x202b), + GenericAccelerationExt = ((int)0x2026), + AccumAlphaBitsExt = ((int)0x2021), + AccumGreenBitsExt = ((int)0x201f), + TransparentValueExt = ((int)0x200b), + AccumBlueBitsExt = ((int)0x2020), + ShareDepthExt = ((int)0x200c), + ShareAccumExt = ((int)0x200e), + SwapExchangeExt = ((int)0x2028), + AccumBitsExt = ((int)0x201d), + NumberUnderlaysExt = ((int)0x2009), + StencilBitsExt = ((int)0x2023), + DoubleBufferExt = ((int)0x2011), + NeedPaletteExt = ((int)0x2004), + ColorBitsExt = ((int)0x2014), + SwapUndefinedExt = ((int)0x202a), + NeedSystemPaletteExt = ((int)0x2005), + NumberOverlaysExt = ((int)0x2008), + AuxBuffersExt = ((int)0x2024), + NumberPixelFormatsExt = ((int)0x2000), + ShareStencilExt = ((int)0x200d), + } + + public enum WGL_ARB_pixel_format + { + ShareStencilArb = ((int)0x200d), + AccumBitsArb = ((int)0x201d), + NumberUnderlaysArb = ((int)0x2009), + StereoArb = ((int)0x2012), + MaxPbufferHeightArb = ((int)0x2030), + TypeRgbaArb = ((int)0x202b), + SupportGdiArb = ((int)0x200f), + NeedSystemPaletteArb = ((int)0x2005), + AlphaBitsArb = ((int)0x201b), + ShareDepthArb = ((int)0x200c), + SupportOpenglArb = ((int)0x2010), + ColorBitsArb = ((int)0x2014), + AccumRedBitsArb = ((int)0x201e), + MaxPbufferWidthArb = ((int)0x202f), + NumberOverlaysArb = ((int)0x2008), + MaxPbufferPixelsArb = ((int)0x202e), + NeedPaletteArb = ((int)0x2004), + RedShiftArb = ((int)0x2016), + AccelerationArb = ((int)0x2003), + GreenBitsArb = ((int)0x2017), + TransparentGreenValueArb = ((int)0x2038), + PixelTypeArb = ((int)0x2013), + AuxBuffersArb = ((int)0x2024), + DrawToWindowArb = ((int)0x2001), + RedBitsArb = ((int)0x2015), + NumberPixelFormatsArb = ((int)0x2000), + GenericAccelerationArb = ((int)0x2026), + BlueBitsArb = ((int)0x2019), + PbufferLargestArb = ((int)0x2033), + AccumAlphaBitsArb = ((int)0x2021), + TransparentArb = ((int)0x200a), + FullAccelerationArb = ((int)0x2027), + ShareAccumArb = ((int)0x200e), + SwapExchangeArb = ((int)0x2028), + SwapUndefinedArb = ((int)0x202a), + TransparentAlphaValueArb = ((int)0x203a), + PbufferHeightArb = ((int)0x2035), + TransparentBlueValueArb = ((int)0x2039), + SwapMethodArb = ((int)0x2007), + StencilBitsArb = ((int)0x2023), + DepthBitsArb = ((int)0x2022), + GreenShiftArb = ((int)0x2018), + TransparentRedValueArb = ((int)0x2037), + DoubleBufferArb = ((int)0x2011), + NoAccelerationArb = ((int)0x2025), + TypeColorindexArb = ((int)0x202c), + SwapLayerBuffersArb = ((int)0x2006), + AccumBlueBitsArb = ((int)0x2020), + DrawToPbufferArb = ((int)0x202d), + AccumGreenBitsArb = ((int)0x201f), + PbufferWidthArb = ((int)0x2034), + TransparentIndexValueArb = ((int)0x203b), + AlphaShiftArb = ((int)0x201c), + DrawToBitmapArb = ((int)0x2002), + BlueShiftArb = ((int)0x201a), + SwapCopyArb = ((int)0x2029), + } + + public enum WGL_EXT_pbuffer + { + DrawToPbufferExt = ((int)0x202d), + PbufferLargestExt = ((int)0x2033), + OptimalPbufferWidthExt = ((int)0x2031), + MaxPbufferPixelsExt = ((int)0x202e), + MaxPbufferHeightExt = ((int)0x2030), + PbufferWidthExt = ((int)0x2034), + MaxPbufferWidthExt = ((int)0x202f), + OptimalPbufferHeightExt = ((int)0x2032), + PbufferHeightExt = ((int)0x2035), + } + + public enum WGL_ARB_pbuffer + { + PbufferWidthArb = ((int)0x2034), + TransparentGreenValueArb = ((int)0x2038), + PbufferHeightArb = ((int)0x2035), + PbufferLostArb = ((int)0x2036), + DrawToPbufferArb = ((int)0x202d), + TransparentIndexValueArb = ((int)0x203b), + TransparentRedValueArb = ((int)0x2037), + MaxPbufferPixelsArb = ((int)0x202e), + TransparentAlphaValueArb = ((int)0x203a), + MaxPbufferWidthArb = ((int)0x202f), + MaxPbufferHeightArb = ((int)0x2030), + TransparentBlueValueArb = ((int)0x2039), + PbufferLargestArb = ((int)0x2033), + } + + public enum WGL_EXT_depth_float + { + DepthFloatExt = ((int)0x2040), + } + + public enum WGL_EXT_multisample + { + SampleBuffersExt = ((int)0x2041), + SamplesExt = ((int)0x2042), + } + + public enum WGL_ARB_multisample + { + SampleBuffersArb = ((int)0x2041), + SamplesArb = ((int)0x2042), + } + + public enum WGL_EXT_make_current_read + { + ErrorInvalidPixelTypeExt = ((int)0x2043), + } + + public enum WGL_ARB_make_current_read + { + ErrorInvalidPixelTypeArb = ((int)0x2043), + ErrorIncompatibleDeviceContextsArb = ((int)0x2054), + } + + public enum WGL_I3D_genlock + { + GenlockSourceMultiviewI3d = ((int)0x2044), + GenlockSourceEdgeBothI3d = ((int)0x204c), + GenlockSourceEdgeRisingI3d = ((int)0x204b), + GenlockSourceDigitalSyncI3d = ((int)0x2048), + GenlockSourceExtenalFieldI3d = ((int)0x2046), + GenlockSourceDigitalFieldI3d = ((int)0x2049), + GenlockSourceExtenalSyncI3d = ((int)0x2045), + GenlockSourceEdgeFallingI3d = ((int)0x204a), + GenlockSourceExtenalTtlI3d = ((int)0x2047), + } + + public enum WGL_I3D_gamma + { + GammaExcludeDesktopI3d = ((int)0x204f), + GammaTableSizeI3d = ((int)0x204e), + } + + public enum WGL_I3D_digital_video_control + { + DigitalVideoCursorAlphaFramebufferI3d = ((int)0x2050), + DigitalVideoGammaCorrectedI3d = ((int)0x2053), + DigitalVideoCursorAlphaValueI3d = ((int)0x2051), + DigitalVideoCursorIncludedI3d = ((int)0x2052), + } + + public enum WGL_3DFX_multisample + { + SampleBuffers3dfx = ((int)0x2060), + Samples3dfx = ((int)0x2061), + } + + public enum WGL_ARB_render_texture + { + TextureCubeMapPositiveXArb = ((int)0x207d), + TextureCubeMapPositiveYArb = ((int)0x207f), + Aux0Arb = ((int)0x2087), + Texture1dArb = ((int)0x2079), + Aux6Arb = ((int)0x208d), + TextureCubeMapArb = ((int)0x2078), + TextureFormatArb = ((int)0x2072), + BackRightArb = ((int)0x2086), + BindToTextureRgbArb = ((int)0x2070), + MipmapLevelArb = ((int)0x207b), + CubeMapFaceArb = ((int)0x207c), + TextureCubeMapNegativeXArb = ((int)0x207e), + Aux7Arb = ((int)0x208e), + Aux8Arb = ((int)0x208f), + MipmapTextureArb = ((int)0x2074), + NoTextureArb = ((int)0x2077), + Aux3Arb = ((int)0x208a), + Texture2DArb = ((int)0x207a), + Aux1Arb = ((int)0x2088), + TextureCubeMapPositiveZArb = ((int)0x2081), + BindToTextureRgbaArb = ((int)0x2071), + TextureCubeMapNegativeYArb = ((int)0x2080), + TextureRgbaArb = ((int)0x2076), + FrontRightArb = ((int)0x2084), + Aux5Arb = ((int)0x208c), + Aux4Arb = ((int)0x208b), + TextureTargetArb = ((int)0x2073), + FrontLeftArb = ((int)0x2083), + Aux9Arb = ((int)0x2090), + TextureRgbArb = ((int)0x2075), + BackLeftArb = ((int)0x2085), + TextureCubeMapNegativeZArb = ((int)0x2082), + Aux2Arb = ((int)0x2089), + } + + public enum WGL_NV_render_texture_rectangle + { + BindToTextureRectangleRgbNv = ((int)0x20a0), + BindToTextureRectangleRgbaNv = ((int)0x20a1), + TextureRectangleNv = ((int)0x20a2), + } + + public enum WGL_NV_render_depth_texture + { + DepthTextureFormatNv = ((int)0x20a5), + TextureDepthComponentNv = ((int)0x20a6), + BindToTextureDepthNv = ((int)0x20a3), + DepthComponentNv = ((int)0x20a7), + BindToTextureRectangleDepthNv = ((int)0x20a4), + } + + public enum WGL_NV_float_buffer + { + BindToTextureRectangleFloatRNv = ((int)0x20b1), + TextureFloatRNv = ((int)0x20b5), + TextureFloatRgbNv = ((int)0x20b7), + TextureFloatRgNv = ((int)0x20b6), + TextureFloatRgbaNv = ((int)0x20b8), + BindToTextureRectangleFloatRgbaNv = ((int)0x20b4), + FloatComponentsNv = ((int)0x20b0), + BindToTextureRectangleFloatRgNv = ((int)0x20b2), + BindToTextureRectangleFloatRgbNv = ((int)0x20b3), + } + + public enum WGL_ARB_pixel_format_float + { + TypeRgbaFloatArb = ((int)0x21a0), + } + + public enum WGL_ATI_pixel_format_float + { + TypeRgbaFloatAti = ((int)0x21a0), + } + + public enum WGL_font_type + { + FontLines = ((int)0), + } + + public enum All + { + SwapCopyExt = ((int)0x2029), + BackColorBufferBitArb = ((int)0x00000002), + FullAccelerationArb = ((int)0x2027), + AccelerationExt = ((int)0x2003), + GenlockSourceMultiviewI3d = ((int)0x2044), + Aux3Arb = ((int)0x208a), + TextureCubeMapNegativeYArb = ((int)0x2080), + DoubleBufferArb = ((int)0x2011), + SwapUndefinedExt = ((int)0x202a), + SupportGdiArb = ((int)0x200f), + Aux2Arb = ((int)0x2089), + TextureCubeMapArb = ((int)0x2078), + SwapLayerBuffersExt = ((int)0x2006), + SwapCopyArb = ((int)0x2029), + ErrorIncompatibleDeviceContextsArb = ((int)0x2054), + TypeColorindexArb = ((int)0x202c), + DigitalVideoCursorIncludedI3d = ((int)0x2052), + NeedPaletteExt = ((int)0x2004), + RedBitsArb = ((int)0x2015), + TextureCubeMapNegativeXArb = ((int)0x207e), + SampleBuffersExt = ((int)0x2041), + GenericAccelerationExt = ((int)0x2026), + BindToTextureRectangleRgbaNv = ((int)0x20a1), + NoTextureArb = ((int)0x2077), + FrontColorBufferBitArb = ((int)0x00000001), + TransparentValueExt = ((int)0x200b), + AlphaBitsArb = ((int)0x201b), + RedBitsExt = ((int)0x2015), + PbufferHeightArb = ((int)0x2035), + BindToTextureRectangleFloatRgbaNv = ((int)0x20b4), + SampleBuffersArb = ((int)0x2041), + MipmapLevelArb = ((int)0x207b), + NeedSystemPaletteExt = ((int)0x2005), + Aux4Arb = ((int)0x208b), + TextureFormatArb = ((int)0x2072), + AccumBitsExt = ((int)0x201d), + AccumBlueBitsExt = ((int)0x2020), + BackLeftArb = ((int)0x2085), + AlphaBitsExt = ((int)0x201b), + StencilBitsArb = ((int)0x2023), + DrawToPbufferExt = ((int)0x202d), + FullAccelerationExt = ((int)0x2027), + ColorBitsExt = ((int)0x2014), + BindToTextureRectangleFloatRgNv = ((int)0x20b2), + DepthBufferBitArb = ((int)0x00000004), + BindToTextureRgbaArb = ((int)0x2071), + AccumGreenBitsArb = ((int)0x201f), + AccumBitsArb = ((int)0x201d), + TypeRgbaFloatArb = ((int)0x21a0), + NeedPaletteArb = ((int)0x2004), + ShareAccumArb = ((int)0x200e), + TransparentArb = ((int)0x200a), + ShareStencilArb = ((int)0x200d), + Aux5Arb = ((int)0x208c), + ImageBufferLockI3d = ((int)0x00000002), + TextureFloatRNv = ((int)0x20b5), + DepthComponentNv = ((int)0x20a7), + FloatComponentsNv = ((int)0x20b0), + TransparentGreenValueArb = ((int)0x2038), + GenlockSourceExtenalTtlI3d = ((int)0x2047), + NeedSystemPaletteArb = ((int)0x2005), + BlueBitsExt = ((int)0x2019), + GreenShiftExt = ((int)0x2018), + OptimalPbufferWidthExt = ((int)0x2031), + AuxBuffersExt = ((int)0x2024), + TypeRgbaFloatAti = ((int)0x21a0), + FrontRightArb = ((int)0x2084), + DepthBitsExt = ((int)0x2022), + GammaTableSizeI3d = ((int)0x204e), + AccumAlphaBitsArb = ((int)0x2021), + Aux0Arb = ((int)0x2087), + TransparentIndexValueArb = ((int)0x203b), + AccumGreenBitsExt = ((int)0x201f), + TransparentBlueValueArb = ((int)0x2039), + NoAccelerationArb = ((int)0x2025), + MaxPbufferPixelsArb = ((int)0x202e), + GammaExcludeDesktopI3d = ((int)0x204f), + MaxPbufferPixelsExt = ((int)0x202e), + AccumBlueBitsArb = ((int)0x2020), + SwapUndefinedArb = ((int)0x202a), + ShareDepthExt = ((int)0x200c), + GenlockSourceEdgeBothI3d = ((int)0x204c), + Samples3dfx = ((int)0x2061), + DoubleBufferExt = ((int)0x2011), + BindToTextureRectangleFloatRgbNv = ((int)0x20b3), + SwapMethodExt = ((int)0x2007), + ErrorInvalidPixelTypeArb = ((int)0x2043), + GreenShiftArb = ((int)0x2018), + TextureFloatRgbaNv = ((int)0x20b8), + Aux1Arb = ((int)0x2088), + GreenBitsArb = ((int)0x2017), + NumberPixelFormatsExt = ((int)0x2000), + NumberOverlaysExt = ((int)0x2008), + PixelTypeArb = ((int)0x2013), + SwapLayerBuffersArb = ((int)0x2006), + DrawToBitmapArb = ((int)0x2002), + NumberPixelFormatsArb = ((int)0x2000), + PbufferLostArb = ((int)0x2036), + Aux9Arb = ((int)0x2090), + TextureCubeMapPositiveZArb = ((int)0x2081), + MaxPbufferHeightArb = ((int)0x2030), + TransparentExt = ((int)0x200a), + PbufferLargestArb = ((int)0x2033), + SwapMethodArb = ((int)0x2007), + TextureRgbaArb = ((int)0x2076), + PbufferWidthExt = ((int)0x2034), + OptimalPbufferHeightExt = ((int)0x2032), + StencilBitsExt = ((int)0x2023), + ShareStencilExt = ((int)0x200d), + DepthFloatExt = ((int)0x2040), + BindToTextureRgbArb = ((int)0x2070), + BindToTextureRectangleRgbNv = ((int)0x20a0), + GenlockSourceDigitalSyncI3d = ((int)0x2048), + AccumAlphaBitsExt = ((int)0x2021), + GenlockSourceExtenalSyncI3d = ((int)0x2045), + RedShiftExt = ((int)0x2016), + GenlockSourceDigitalFieldI3d = ((int)0x2049), + FrontLeftArb = ((int)0x2083), + BlueShiftArb = ((int)0x201a), + PbufferWidthArb = ((int)0x2034), + CubeMapFaceArb = ((int)0x207c), + StencilBufferBitArb = ((int)0x00000008), + NumberOverlaysArb = ((int)0x2008), + SwapExchangeExt = ((int)0x2028), + BackRightArb = ((int)0x2086), + DepthTextureFormatNv = ((int)0x20a5), + TextureFloatRgNv = ((int)0x20b6), + Texture1dArb = ((int)0x2079), + DepthBitsArb = ((int)0x2022), + BindToTextureDepthNv = ((int)0x20a3), + DrawToWindowArb = ((int)0x2001), + TypeRgbaExt = ((int)0x202b), + DigitalVideoCursorAlphaValueI3d = ((int)0x2051), + ErrorInvalidPixelTypeExt = ((int)0x2043), + AccumRedBitsExt = ((int)0x201e), + GreenBitsExt = ((int)0x2017), + TypeRgbaArb = ((int)0x202b), + DigitalVideoCursorAlphaFramebufferI3d = ((int)0x2050), + AuxBuffersArb = ((int)0x2024), + AccumRedBitsArb = ((int)0x201e), + TextureFloatRgbNv = ((int)0x20b7), + TypeColorindexExt = ((int)0x202c), + TransparentAlphaValueArb = ((int)0x203a), + BlueShiftExt = ((int)0x201a), + RedShiftArb = ((int)0x2016), + PbufferHeightExt = ((int)0x2035), + GenlockSourceEdgeRisingI3d = ((int)0x204b), + Texture2DArb = ((int)0x207a), + NumberUnderlaysArb = ((int)0x2009), + NumberUnderlaysExt = ((int)0x2009), + DrawToBitmapExt = ((int)0x2002), + ShareDepthArb = ((int)0x200c), + TextureDepthComponentNv = ((int)0x20a6), + NoAccelerationExt = ((int)0x2025), + PixelTypeExt = ((int)0x2013), + SupportOpenglArb = ((int)0x2010), + TextureCubeMapPositiveYArb = ((int)0x207f), + DrawToWindowExt = ((int)0x2001), + PbufferLargestExt = ((int)0x2033), + DrawToPbufferArb = ((int)0x202d), + SupportOpenglExt = ((int)0x2010), + SampleBuffers3dfx = ((int)0x2060), + GenlockSourceExtenalFieldI3d = ((int)0x2046), + MaxPbufferHeightExt = ((int)0x2030), + SupportGdiExt = ((int)0x200f), + Aux7Arb = ((int)0x208e), + DigitalVideoGammaCorrectedI3d = ((int)0x2053), + ColorBitsArb = ((int)0x2014), + Aux6Arb = ((int)0x208d), + ShareAccumExt = ((int)0x200e), + StereoArb = ((int)0x2012), + TextureRgbArb = ((int)0x2075), + AccelerationArb = ((int)0x2003), + TextureCubeMapPositiveXArb = ((int)0x207d), + TransparentRedValueArb = ((int)0x2037), + BlueBitsArb = ((int)0x2019), + SwapExchangeArb = ((int)0x2028), + SamplesExt = ((int)0x2042), + AlphaShiftExt = ((int)0x201c), + SamplesArb = ((int)0x2042), + TextureTargetArb = ((int)0x2073), + BindToTextureRectangleDepthNv = ((int)0x20a4), + AlphaShiftArb = ((int)0x201c), + Aux8Arb = ((int)0x208f), + MaxPbufferWidthExt = ((int)0x202f), + GenlockSourceEdgeFallingI3d = ((int)0x204a), + StereoExt = ((int)0x2012), + MaxPbufferWidthArb = ((int)0x202f), + TextureRectangleNv = ((int)0x20a2), + ImageBufferMinAccessI3d = ((int)0x00000001), + TextureCubeMapNegativeZArb = ((int)0x2082), + MipmapTextureArb = ((int)0x2074), + GenericAccelerationArb = ((int)0x2026), + BindToTextureRectangleFloatRNv = ((int)0x20b1), + FontLines = ((int)0), + } + + public enum WGL_ARB_extensions_string + { + } + + public enum WGL_I3D_image_buffer + { + ImageBufferMinAccessI3d = ((int)0x00000001), + ImageBufferLockI3d = ((int)0x00000002), + } + + public enum WGL_I3D_swap_frame_lock + { + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Windows/WglHelper.cs b/GLWidget/OpenTK/Platform/Windows/WglHelper.cs new file mode 100644 index 0000000..630fb49 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WglHelper.cs @@ -0,0 +1,130 @@ +/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos + * See license.txt for license info + * + * Date: 12/8/2007 + * Time: 6:43 �� + */ + +using System; +using System.Collections.Generic; + +namespace OpenTK.Platform.Windows +{ + internal partial class Wgl + { + private static IntPtr[] EntryPoints; + private static string[] EntryPointNames; + + internal const string Library = "OPENGL32.DLL"; + + private readonly static Dictionary extensions = + new Dictionary(); + + private static readonly object sync = new object(); + + public Wgl() + { + } + + public static bool SupportsExtension(string name) + { + return SupportsExtension(Wgl.GetCurrentDC(), name); + } + + /// + /// Checks if a Wgl extension is supported by the given context. + /// + /// The device context. + /// The extension to check. + /// True if the extension is supported by the given context, false otherwise + public static bool SupportsExtension(IntPtr dc, string name) + { + lock (sync) + { + if (extensions.Count == 0) + { + // We cache this locally, as another thread might create a context which doesn't support this method. + // The design is far from ideal, but there's no good solution to this issue as long as we are using + // static WGL/GL classes. Fortunately, this issue is extremely unlikely to arise in practice, as you'd + // have to create one accelerated and one non-accelerated context in the same application, with the + // non-accelerated context coming second. + bool get_arb = SupportsFunction("wglGetExtensionsStringARB"); + bool get_ext = SupportsFunction("wglGetExtensionsStringEXT"); + string str = + get_arb ? OpenGL.Wgl.GetExtensionsStringARB(dc) : + get_ext ? OpenGL.Wgl.GetExtensionsStringEXT(): + String.Empty; + + if (!String.IsNullOrEmpty(str)) + { + foreach (string ext in str.Split(' ')) + { + extensions.Add(ext, true); + } + } + } + } + + if (extensions.Count > 0) + { + return extensions.ContainsKey(name); + } + return false; + } + + /// + /// Checks whether an extension function is supported. + /// Do not use with core WGL functions, as this function + /// will incorrectly return false. + /// + /// The extension function to check (e.g. "wglGetExtensionsStringARB" + /// True if the extension function is supported; otherwise, false. + public static bool SupportsFunction(string name) + { + int index = Array.IndexOf(EntryPointNames, name); + if (index >= 0) + { + return EntryPoints[index] != IntPtr.Zero; + } + return false; + } + + private object SyncRoot + { + get { return sync; } + } + + internal static IntPtr GetAddress(string function_string) + { + IntPtr address = Wgl.GetProcAddress(function_string); + if (!IsValid(address)) + { + address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string); + } + return address; + } + + private static bool IsValid(IntPtr address) + { + // See https://www.opengl.org/wiki/Load_OpenGL_Functions + long a = address.ToInt64(); + bool is_valid = (a < -1) || (a > 3); + return is_valid; + } + + internal void LoadEntryPoints() + { + lock (SyncRoot) + { + if (Wgl.GetCurrentContext() != IntPtr.Zero) + { + for (int i = 0; i < EntryPointNames.Length; i++) + { + EntryPoints[i] = GetAddress(EntryPointNames[i]); + } + extensions.Clear(); + } + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/WinDisplayDevice.cs b/GLWidget/OpenTK/Platform/Windows/WinDisplayDevice.cs new file mode 100644 index 0000000..7e42444 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WinDisplayDevice.cs @@ -0,0 +1,200 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Win32; + +namespace OpenTK.Platform.Windows +{ + internal sealed class WinDisplayDeviceDriver : DisplayDeviceBase + { + private readonly object display_lock = new object(); + + public WinDisplayDeviceDriver() + { + RefreshDisplayDevices(); + SystemEvents.DisplaySettingsChanged += + HandleDisplaySettingsChanged; + } + + public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + { + DeviceMode mode = null; + + if (resolution != null) + { + mode = new DeviceMode(); + mode.PelsWidth = resolution.Width; + mode.PelsHeight = resolution.Height; + mode.BitsPerPel = resolution.BitsPerPixel; + mode.DisplayFrequency = (int)resolution.RefreshRate; + mode.Fields = Constants.DM_BITSPERPEL + | Constants.DM_PELSWIDTH + | Constants.DM_PELSHEIGHT + | Constants.DM_DISPLAYFREQUENCY; + } + + return Constants.DISP_CHANGE_SUCCESSFUL == + Functions.ChangeDisplaySettingsEx((string)device.Id, mode, IntPtr.Zero, + ChangeDisplaySettingsEnum.Fullscreen, IntPtr.Zero); + } + + public sealed override bool TryRestoreResolution(DisplayDevice device) + { + return TryChangeResolution(device, null); + } + + public void RefreshDisplayDevices() + { + lock (display_lock) + { + // Store an array of the current available DisplayDevice objects. + // This is needed to preserve the original resolution. + DisplayDevice[] previousDevices = AvailableDevices.ToArray(); + + AvailableDevices.Clear(); + + // We save all necessary parameters in temporary variables + // and construct the device when every needed detail is available. + // The main DisplayDevice constructor adds the newly constructed device + // to the list of available devices. + DisplayDevice opentk_dev; + DisplayResolution opentk_dev_current_res = null; + List opentk_dev_available_res = new List(); + bool opentk_dev_primary = false; + int device_count = 0, mode_count = 0; + + // Get available video adapters and enumerate all monitors + WindowsDisplayDevice dev1 = new WindowsDisplayDevice(); + while (Functions.EnumDisplayDevices(null, device_count++, dev1, 0)) + { + if ((dev1.StateFlags & DisplayDeviceStateFlags.AttachedToDesktop) == DisplayDeviceStateFlags.None) + { + continue; + } + + DeviceMode monitor_mode = new DeviceMode(); + + // The second function should only be executed when the first one fails + // (e.g. when the monitor is disabled) + if (Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.CurrentSettings, monitor_mode, 0) || + Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.RegistrySettings, monitor_mode, 0)) + { + VerifyMode(dev1, monitor_mode); + + float scale = GetScale(ref monitor_mode); + opentk_dev_current_res = new DisplayResolution( + (int)(monitor_mode.Position.X / scale), (int)(monitor_mode.Position.Y / scale), + (int)(monitor_mode.PelsWidth / scale), (int)(monitor_mode.PelsHeight / scale), + monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency); + + opentk_dev_primary = + (dev1.StateFlags & DisplayDeviceStateFlags.PrimaryDevice) != DisplayDeviceStateFlags.None; + } + + opentk_dev_available_res.Clear(); + mode_count = 0; + while (Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), mode_count++, monitor_mode, 0)) + { + VerifyMode(dev1, monitor_mode); + + float scale = GetScale(ref monitor_mode); + DisplayResolution res = new DisplayResolution( + (int)(monitor_mode.Position.X / scale), (int)(monitor_mode.Position.Y / scale), + (int)(monitor_mode.PelsWidth / scale), (int)(monitor_mode.PelsHeight / scale), + monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency); + + opentk_dev_available_res.Add(res); + } + + // Construct the OpenTK DisplayDevice through the accumulated parameters. + // The constructor will automatically add the DisplayDevice to the list + // of available devices. + #pragma warning disable 612,618 + opentk_dev = new DisplayDevice( + opentk_dev_current_res, + opentk_dev_primary, + opentk_dev_available_res, + opentk_dev_current_res.Bounds, + dev1.DeviceName); + #pragma warning restore 612,618 + + // Set the original resolution if the DisplayDevice was previously available. + foreach (DisplayDevice existingDevice in previousDevices) + { + if ((string)existingDevice.Id == (string)opentk_dev.Id) + { + opentk_dev.OriginalResolution = existingDevice.OriginalResolution; + } + } + + AvailableDevices.Add(opentk_dev); + + if (opentk_dev_primary) + { + Primary = opentk_dev; + } + + Debug.Print("DisplayDevice {0} ({1}) supports {2} resolutions.", + device_count, opentk_dev.IsPrimary ? "primary" : "secondary", opentk_dev.AvailableResolutions.Count); + } + } + } + + private float GetScale(ref DeviceMode monitor_mode) + { + float scale = 1.0f; + if ((monitor_mode.Fields & Constants.DM_LOGPIXELS) != 0) + { + scale = monitor_mode.LogPixels / 96.0f; + } + return scale; + } + + private static void VerifyMode(WindowsDisplayDevice device, DeviceMode mode) + { + if (mode.BitsPerPel == 0) + { + Debug.Print( + "[Warning] DisplayDevice '{0}' reported a mode with 0 bpp. Please create a bug report at https://github.com/opentk/opentk/issues", + device.DeviceName.ToString()); + mode.BitsPerPel = 32; + } + } + + private void HandleDisplaySettingsChanged(object sender, EventArgs e) + { + RefreshDisplayDevices(); + } + + ~WinDisplayDeviceDriver() + { + SystemEvents.DisplaySettingsChanged -= + HandleDisplaySettingsChanged; + } + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/WinFactory.cs b/GLWidget/OpenTK/Platform/Windows/WinFactory.cs new file mode 100644 index 0000000..2d85cd4 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WinFactory.cs @@ -0,0 +1,109 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using OpenTK.Graphics; + +namespace OpenTK.Platform.Windows +{ + internal class WinFactory : PlatformFactoryBase + { + private readonly object SyncRoot = new object(); + + // The input drivers must be constructed lazily, *after* the + // WinFactory constructor has finished running. The reason is + // that they call WinFactory methods internally. + internal static IntPtr OpenGLHandle { get; private set; } + private const string OpenGLName = "OPENGL32.DLL"; + + public WinFactory() + { + if (System.Environment.OSVersion.Version.Major <= 4) + { + throw new PlatformNotSupportedException("OpenTK requires Windows XP or higher"); + } + + // Dynamically load opengl32.dll in order to use the extension loading capabilities of Wgl. + // Note: opengl32.dll must be loaded before gdi32.dll, otherwise strange failures may occur + // (such as "error: 2000" when calling wglSetPixelFormat or slowness/lag on specific GPUs). + LoadOpenGL(); + + if (System.Environment.OSVersion.Version.Major >= 6) + { + if (Toolkit.Options.EnableHighResolution) + { + // Enable high-dpi support + // Only available on Windows Vista and higher + bool result = Functions.SetProcessDPIAware(); + Debug.Print("SetProcessDPIAware() returned {0}", result); + } + } + } + + private static void LoadOpenGL() + { + OpenGLHandle = Functions.LoadLibrary(OpenGLName); + if (OpenGLHandle == IntPtr.Zero) + { + throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}", + OpenGLName, Marshal.GetLastWin32Error())); + } + Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", OpenGLHandle)); + } + + public override IDisplayDeviceDriver CreateDisplayDeviceDriver() + { + return new WinDisplayDeviceDriver(); + } + + public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return new WinGLContext(mode, (WinWindowInfo)window, shareContext, major, minor, flags); + } + + public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + { + return new WinGLContext(handle, (WinWindowInfo)window, shareContext, major, minor, flags); + } + + public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + { + return (GraphicsContext.GetCurrentContextDelegate)delegate + { + return new ContextHandle(Wgl.GetCurrentContext()); + }; + } + + protected override void Dispose(bool manual) + { + if (!IsDisposed) + { + base.Dispose(manual); + } + } + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/WinGLContext.cs b/GLWidget/OpenTK/Platform/Windows/WinGLContext.cs new file mode 100644 index 0000000..1661cd2 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WinGLContext.cs @@ -0,0 +1,455 @@ +/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos + * Contributions from Erik Ylvisaker + * See license.txt for license info + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Diagnostics; + +using OpenTK.Graphics; + +namespace OpenTK.Platform.Windows +{ + /// \internal + /// + /// Provides methods to create and control an opengl context on the Windows platform. + /// This class supports OpenTK, and is not intended for use by OpenTK programs. + /// + internal sealed class WinGLContext : DesktopGraphicsContext + { + private static readonly object LoadLock = new object(); + + private bool vsync_supported; + private bool vsync_tear_supported; + + private readonly WinGraphicsMode ModeSelector; + + // We need to create a temp context in order to load + // wgl extensions (e.g. for multisampling or GL3). + // We cannot rely on any WGL extensions before + // we load them with the temporary context. + private class TemporaryContext : IDisposable + { + public ContextHandle Context; + + public TemporaryContext(IntPtr native) + { + Debug.WriteLine("[WGL] Creating temporary context to load extensions"); + + if (native == null) + { + throw new ArgumentNullException(); + } + + // Create temporary context and load WGL entry points + // First, set a compatible pixel format to the device context + // of the temp window + WinWindowInfo window = new WinWindowInfo + { + Handle = native + }; + WinGraphicsMode selector = new WinGraphicsMode(window.DeviceContext); + WinGLContext.SetGraphicsModePFD(selector, GraphicsMode.Default, window); + + bool success = false; + + // Then, construct a temporary context and load all wgl extensions + Context = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + if (Context != ContextHandle.Zero) + { + // Make the context current. + // Note: on some video cards and on some virtual machines, wglMakeCurrent + // may fail with an errorcode of 6 (INVALID_HANDLE). The suggested workaround + // is to call wglMakeCurrent in a loop until it succeeds. + // See https://www.opengl.org/discussion_boards/showthread.php/171058-nVidia-wglMakeCurrent()-multiple-threads + // Sigh... + for (int retry = 0; retry < 5 && !success; retry++) + { + success = Wgl.MakeCurrent(window.DeviceContext, Context.Handle); + if (!success) + { + Debug.Print("wglMakeCurrent failed with error: {0}. Retrying", Marshal.GetLastWin32Error()); + System.Threading.Thread.Sleep(10); + } + } + } + else + { + Debug.Print("[WGL] CreateContext failed with error: {0}", Marshal.GetLastWin32Error()); + } + + if (!success) + { + Debug.WriteLine("[WGL] Failed to create temporary context"); + } + } + + public void Dispose() + { + if (Context != ContextHandle.Zero) + { + Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); + Wgl.DeleteContext(Context.Handle); + } + } + } + + public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + { + // There are many ways this code can break when accessed by multiple threads. The biggest offender is + // the sharedContext stuff, which will only become valid *after* this constructor returns. + // The easiest solution is to serialize all context construction - hence the big lock, below. + lock (LoadLock) + { + if (window == null) + { + throw new ArgumentNullException("window", "Must point to a valid window."); + } + if (window.Handle == IntPtr.Zero) + { + throw new ArgumentException("window", "Must be a valid window."); + } + + IntPtr current_context = Wgl.GetCurrentContext(); + TemporaryContext temp_context = null; + try + { + if (current_context == IntPtr.Zero) + { + // Create temporary context to load WGL extensions + temp_context = new TemporaryContext(window.Handle); + current_context = Wgl.GetCurrentContext(); + if (current_context != IntPtr.Zero && current_context == temp_context.Context.Handle) + { + new Wgl().LoadEntryPoints(); + } + } + + Debug.Print("OpenGL will be bound to window:{0} on thread:{1}", window.Handle, + System.Threading.Thread.CurrentThread.ManagedThreadId); + + ModeSelector = new WinGraphicsMode(window.DeviceContext); + Mode = SetGraphicsModePFD(ModeSelector, format, (WinWindowInfo)window); + + if (Wgl.SupportsFunction("wglCreateContextAttribsARB")) + { + try + { + Debug.Write("Using WGL_ARB_create_context... "); + + List attributes = new List(); + attributes.Add((int)ArbCreateContext.MajorVersion); + attributes.Add(major); + attributes.Add((int)ArbCreateContext.MinorVersion); + attributes.Add(minor); + if (flags != 0) + { + attributes.Add((int)ArbCreateContext.ContextFlags); + attributes.Add((int)GetARBContextFlags(flags)); + attributes.Add((int)ArbCreateContext.ProfileMask); + attributes.Add((int)GetARBContextProfile(flags)); + } + // According to the docs, " specifies a list of attributes for the context. + // The list consists of a sequence of pairs terminated by the + // value 0. [...]" + // Is this a single 0, or a <0, 0> pair? (Defensive coding: add two zeroes just in case). + attributes.Add(0); + attributes.Add(0); + + Handle = new ContextHandle( + OpenGL.Wgl.CreateContextAttribsARB( + window.DeviceContext, + sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero, + attributes.ToArray())); + if (Handle == ContextHandle.Zero) + { + Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error()); + } + } + catch (Exception e) { Debug.Print(e.ToString()); } + } + + if (Handle == ContextHandle.Zero) + { + // Failed to create GL3-level context, fall back to GL2. + Debug.Write("Falling back to GL2... "); + Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + if (Handle == ContextHandle.Zero) + { + Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + } + if (Handle == ContextHandle.Zero) + { + throw new GraphicsContextException( + String.Format("Context creation failed. Wgl.CreateContext() error: {0}.", + Marshal.GetLastWin32Error())); + } + } + + Debug.WriteLine(String.Format("success! (id: {0})", Handle)); + } + finally + { + if (temp_context != null) + { + temp_context.Dispose(); + temp_context = null; + } + } + } + + // Todo: is this comment still true? + // On intel drivers, wgl entry points appear to change + // when creating multiple contexts. As a workaround, + // we reload Wgl entry points every time we create a + // new context - this solves the issue without any apparent + // side-effects (i.e. the old contexts can still be handled + // using the new entry points.) + // Sigh... + MakeCurrent(window); + new Wgl().LoadEntryPoints(); + + if (sharedContext != null) + { + Marshal.GetLastWin32Error(); + Debug.Write(String.Format("Sharing state with context {0}: ", sharedContext)); + bool result = Wgl.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle); + Debug.WriteLine(result ? "success!" : "failed with win32 error " + Marshal.GetLastWin32Error()); + } + } + + private static ArbCreateContext GetARBContextFlags(GraphicsContextFlags flags) + { + ArbCreateContext result = 0; + result |= (flags & GraphicsContextFlags.ForwardCompatible) != 0 ? + ArbCreateContext.CoreProfileBit : ArbCreateContext.CompatibilityProfileBit; + return result; + } + + private static ArbCreateContext GetARBContextProfile(GraphicsContextFlags flags) + { + ArbCreateContext result = 0; + result |= (flags & GraphicsContextFlags.Debug) != 0 ? ArbCreateContext.DebugBit : 0; + return result; + } + + public WinGLContext(ContextHandle handle, WinWindowInfo window, IGraphicsContext sharedContext, + int major, int minor, GraphicsContextFlags flags) + { + if (handle == ContextHandle.Zero) + { + throw new ArgumentException("handle"); + } + if (window == null) + { + throw new ArgumentNullException("window"); + } + + Handle = handle; + } + + public override void SwapBuffers() + { + if (!Functions.SwapBuffers(DeviceContext)) + { + throw new GraphicsContextException(String.Format( + "Failed to swap buffers for context {0} current. Error: {1}", this, Marshal.GetLastWin32Error())); + } + } + + public override void MakeCurrent(IWindowInfo window) + { + lock (LoadLock) + { + bool success; + + WinWindowInfo wnd = window as WinWindowInfo; + if (wnd != null) + { + if (wnd.Handle == IntPtr.Zero) + { + throw new ArgumentException("window", "Must point to a valid window."); + } + + success = Wgl.MakeCurrent(wnd.DeviceContext, Handle.Handle); + DeviceContext = wnd.DeviceContext; + } + else + { + success = Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); + DeviceContext = IntPtr.Zero; + } + + if (!success) + { + throw new GraphicsContextException(String.Format( + "Failed to make context {0} current. Error: {1}", this, Marshal.GetLastWin32Error())); + } + } + } + + public override bool IsCurrent + { + get { return Wgl.GetCurrentContext() == Handle.Handle; } + } + + public override int SwapInterval + { + get + { + lock (LoadLock) + { + if (vsync_supported) + { + return OpenGL.Wgl.GetSwapIntervalEXT(); + } + else + { + return 0; + } + } + } + set + { + lock (LoadLock) + { + if (vsync_supported) + { + if (value < 0 && !vsync_tear_supported) + { + value = 1; + } + if (!OpenGL.Wgl.SwapIntervalEXT(value)) + { + Debug.Print("wglSwapIntervalEXT call failed."); + } + } + } + } + } + + public override void LoadAll() + { + lock (LoadLock) + { + new Wgl().LoadEntryPoints(); + vsync_supported = + Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_control") && + Wgl.SupportsFunction("wglGetSwapIntervalEXT") && + Wgl.SupportsFunction("wglSwapIntervalEXT"); + vsync_tear_supported = + Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_control_tear"); + } + + base.LoadAll(); + } + /* + IWindowInfo IGraphicsContextInternal.Info + { + get { return (IWindowInfo)windowInfo; } + } + */ + + public override IntPtr GetAddress(IntPtr function_string) + { + IntPtr address = Wgl.GetProcAddress(function_string); + if (!IsValid(address)) + { + address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string); + } + return address; + } + + private static bool IsValid(IntPtr address) + { + // See https://www.opengl.org/wiki/Load_OpenGL_Functions + long a = address.ToInt64(); + bool is_valid = (a < -1) || (a > 3); + return is_valid; + } + + // Note: there is no relevant ARB function. + internal static GraphicsMode SetGraphicsModePFD(WinGraphicsMode mode_selector, + GraphicsMode mode, WinWindowInfo window) + { + Debug.Write("Setting pixel format... "); + if (window == null) + { + throw new ArgumentNullException("window", "Must point to a valid window."); + } + + if (!mode.Index.HasValue) + { + mode = mode_selector.SelectGraphicsMode( + mode.ColorFormat, mode.Depth, mode.Stencil, + mode.Samples, mode.AccumulatorFormat, + mode.Buffers, mode.Stereo); + } + + PixelFormatDescriptor pfd = new PixelFormatDescriptor(); + Functions.DescribePixelFormat( + window.DeviceContext, (int)mode.Index.Value, + API.PixelFormatDescriptorSize, ref pfd); + + Debug.WriteLine(mode.Index.ToString()); + + if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) + { + throw new GraphicsContextException(String.Format( + "Requested GraphicsMode not available. SetPixelFormat error: {0}", + Marshal.GetLastWin32Error())); + } + + return mode; + } + + internal IntPtr DeviceContext { get; private set; } + + /// Returns a System.String describing this OpenGL context. + /// A System.String describing this OpenGL context. + public override string ToString() + { + return (this as IGraphicsContextInternal).Context.ToString(); + } + + protected override void Dispose(bool calledManually) + { + if (!IsDisposed) + { + if (calledManually) + { + DestroyContext(); + } + IsDisposed = true; + } + } + + private void DestroyContext() + { + if (Handle != ContextHandle.Zero) + { + try + { + // This will fail if the user calls Dispose() on thread X when the context is current on thread Y. + if (!Wgl.DeleteContext(Handle.Handle)) + { + Debug.Print("Failed to destroy OpenGL context {0}. Error: {1}", + Handle.ToString(), Marshal.GetLastWin32Error()); + } + } + catch (AccessViolationException e) + { + Debug.WriteLine("An access violation occured while destroying the OpenGL context. Please report at https://github.com/opentk/opentk/issues"); + Debug.Indent(); + Debug.Print("Marshal.GetLastWin32Error(): {0}", Marshal.GetLastWin32Error().ToString()); + Debug.WriteLine(e.ToString()); + Debug.Unindent(); + } + Handle = ContextHandle.Zero; + } + } + } +} \ No newline at end of file diff --git a/GLWidget/OpenTK/Platform/Windows/WinGraphicsMode.cs b/GLWidget/OpenTK/Platform/Windows/WinGraphicsMode.cs new file mode 100644 index 0000000..8c5cd21 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -0,0 +1,403 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using OpenTK.Graphics; + +namespace OpenTK.Platform.Windows +{ + internal class WinGraphicsMode : IGraphicsMode + { + private enum AccelerationType + { + // Software acceleration + None = 0, + // Partial acceleration (Direct3D emulation) + MCD, + // Full acceleration + ICD, + } + + private readonly IntPtr Device; + + public WinGraphicsMode(IntPtr device) + { + if (device == IntPtr.Zero) + { + throw new ArgumentException(); + } + + Device = device; + } + + public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, + ColorFormat accum, int buffers, bool stereo) + { + GraphicsMode mode = new GraphicsMode(color, depth, stencil, samples, accum, buffers, stereo); + GraphicsMode created_mode = ChoosePixelFormatARB(Device, mode); + + // If ChoosePixelFormatARB failed, iterate through all acceleration types in turn (ICD, MCD, None) + // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.ICD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.MCD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.None); + + if (created_mode == null) + { + throw new GraphicsModeException("The requested GraphicsMode is not supported"); + } + + return created_mode; + } + + // Queries pixel formats through the WGL_ARB_pixel_format extension + // This method only returns accelerated formats. If no format offers + // hardware acceleration (e.g. we are running in a VM or in a remote desktop + // connection), this method will return 0 formats and we will fall back to + // ChoosePixelFormatPFD. + private GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode desired_mode) + { + GraphicsMode created_mode = null; + GraphicsMode mode = new GraphicsMode(desired_mode); + if (Wgl.SupportsExtension("WGL_ARB_pixel_format") && + Wgl.SupportsFunction("wglChoosePixelFormatARB")) + { + int[] format = new int[1]; + List attributes = new List(); + bool retry = false; + + do + { + attributes.Clear(); + attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); + attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); + attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb); + attributes.Add(1); + + if (mode.ColorFormat.Red > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb); + attributes.Add(mode.ColorFormat.Red); + } + + if (mode.ColorFormat.Green > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); + attributes.Add(mode.ColorFormat.Green); + } + + if (mode.ColorFormat.Blue > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); + attributes.Add(mode.ColorFormat.Blue); + } + + if (mode.ColorFormat.Alpha > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); + attributes.Add(mode.ColorFormat.Alpha); + } + + if (mode.Depth > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb); + attributes.Add(mode.Depth); + } + + if (mode.Stencil > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb); + attributes.Add(mode.Stencil); + } + + if (mode.AccumulatorFormat.Red > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); + attributes.Add(mode.AccumulatorFormat.Red); + } + + if (mode.AccumulatorFormat.Green > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); + attributes.Add(mode.AccumulatorFormat.Green); + } + + if (mode.AccumulatorFormat.Blue > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); + attributes.Add(mode.AccumulatorFormat.Blue); + } + + if (mode.AccumulatorFormat.Alpha > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); + attributes.Add(mode.AccumulatorFormat.Alpha); + } + + if (mode.Samples > 0 && + Wgl.SupportsExtension("WGL_ARB_multisample")) + { + attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb); + attributes.Add(1); + attributes.Add((int)WGL_ARB_multisample.SamplesArb); + attributes.Add(mode.Samples); + } + + if (mode.Buffers > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); + attributes.Add(mode.Buffers > 1 ? 1 : 0); + } + + if (mode.Stereo) + { + attributes.Add((int)WGL_ARB_pixel_format.StereoArb); + attributes.Add(1); + } + + attributes.Add(0); + attributes.Add(0); + + uint[] count = new uint[attributes.Count]; + + if (OpenGL.Wgl.ChoosePixelFormatARB(device, attributes.ToArray(), null, (uint)format.Length, format, count) + && count.Length > 0) + { + created_mode = DescribePixelFormatARB(device, format[0]); + retry = false; + } + else + { + Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error()); + retry = Utilities.RelaxGraphicsMode(ref mode); + } + } + while (retry); + } + else + { + Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context"); + } + + return created_mode; + } + + private static bool Compare(int got, int requested, ref int distance) + { + bool valid = true; + if (got == 0 && requested != 0) + { + // mode does not support the requested feature. + valid = false; + } + else if (got >= requested) + { + // mode supports the requested feature, + // calculate the distance from an "ideal" mode + // that matches this feature exactly. + distance += got - requested; + } + else + { + // mode supports the requested feature, + // but at a suboptimal level. For example: + // - requsted AA = 8x, got 4x + // - requested color = 32bpp, got 16bpp + // We can still use this mode but only if + // no better mode exists. + const int penalty = 8; + distance += penalty * Math.Abs(got - requested); + } + return valid; + } + + private static AccelerationType GetAccelerationType(ref PixelFormatDescriptor pfd) + { + AccelerationType type = AccelerationType.ICD; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) + { + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) + { + type = AccelerationType.MCD; + } + else + { + type = AccelerationType.None; + } + } + return type; + } + + private GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) + { + PixelFormatDescriptor pfd = new PixelFormatDescriptor(); + PixelFormatDescriptorFlags flags = 0; + flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; + + if (mode.Stereo) + { + flags |= PixelFormatDescriptorFlags.STEREO; + } + + if (System.Environment.OSVersion.Version.Major >= 6 && + requested_acceleration_type != AccelerationType.None) + { + // Request a compositor-capable mode when running on + // Vista+ and using hardware acceleration. Without this, + // some modes will cause the compositor to turn off, + // which is very annoying to the user. + // Note: compositor-capable modes require hardware + // acceleration. Don't set this flag when running + // with software acceleration (e.g. over Remote Desktop + // as described in bug https://github.com/opentk/opentk/issues/35) + flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; + } + + int count = Functions.DescribePixelFormat(device, 1, API.PixelFormatDescriptorSize, ref pfd); + + int best = 0; + int best_dist = int.MaxValue; + for (int index = 1; index <= count; index++) + { + int dist = 0; + bool valid = Functions.DescribePixelFormat(device, index, API.PixelFormatDescriptorSize, ref pfd) != 0; + valid &= GetAccelerationType(ref pfd) == requested_acceleration_type; + valid &= (pfd.Flags & flags) == flags; + valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported + // heavily penalize single-buffered modes when the user requests double buffering + if ((pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) == 0 && mode.Buffers > 1) + { + dist += 1000; + } + valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist); + valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist); + valid &= Compare(pfd.BlueBits, mode.ColorFormat.Blue, ref dist); + valid &= Compare(pfd.AlphaBits, mode.ColorFormat.Alpha, ref dist); + valid &= Compare(pfd.AccumBits, mode.AccumulatorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.AccumRedBits, mode.AccumulatorFormat.Red, ref dist); + valid &= Compare(pfd.AccumGreenBits, mode.AccumulatorFormat.Green, ref dist); + valid &= Compare(pfd.AccumBlueBits, mode.AccumulatorFormat.Blue, ref dist); + valid &= Compare(pfd.AccumAlphaBits, mode.AccumulatorFormat.Alpha, ref dist); + valid &= Compare(pfd.DepthBits, mode.Depth, ref dist); + valid &= Compare(pfd.StencilBits, mode.Stencil, ref dist); + + if (valid && dist < best_dist) + { + best = index; + best_dist = dist; + } + } + + return DescribePixelFormatPFD(device, ref pfd, best); + } + + private static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, + int pixelformat) + { + GraphicsMode created_mode = null; + if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) + { + created_mode = new GraphicsMode( + new IntPtr(pixelformat), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + pfd.DepthBits, + pfd.StencilBits, + 0, // MSAA not supported when using PixelFormatDescriptor + new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), + (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, + (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + } + return created_mode; + } + + private GraphicsMode DescribePixelFormatARB(IntPtr device, int pixelformat) + { + GraphicsMode created_mode = null; + // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for more details + if (Wgl.SupportsFunction("wglGetPixelFormatAttribivARB")) + { + // Define the list of attributes we are interested in. + // The results will be stored in the 'values' array below. + int[] attribs = new int[] + { + (int)WGL_ARB_pixel_format.AccelerationArb, + + (int)WGL_ARB_pixel_format.RedBitsArb, + (int)WGL_ARB_pixel_format.GreenBitsArb, + (int)WGL_ARB_pixel_format.BlueBitsArb, + (int)WGL_ARB_pixel_format.AlphaBitsArb, + (int)WGL_ARB_pixel_format.ColorBitsArb, + + (int)WGL_ARB_pixel_format.DepthBitsArb, + (int)WGL_ARB_pixel_format.StencilBitsArb, + + (int)WGL_ARB_multisample.SampleBuffersArb, + (int)WGL_ARB_multisample.SamplesArb, + + (int)WGL_ARB_pixel_format.AccumRedBitsArb, + (int)WGL_ARB_pixel_format.AccumGreenBitsArb, + (int)WGL_ARB_pixel_format.AccumBlueBitsArb, + (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, + (int)WGL_ARB_pixel_format.AccumBitsArb, + + (int)WGL_ARB_pixel_format.DoubleBufferArb, + (int)WGL_ARB_pixel_format.StereoArb, + 0 + }; + + // Allocate storage for the results of GetPixelFormatAttrib queries + int[] values = new int[attribs.Length]; + + // Get the format attributes for this pixel format + if (!OpenGL.Wgl.GetPixelFormatAttribARB(device, pixelformat, 0, (uint)attribs.Length - 1, attribs, values)) + { + Debug.Print("[Warning] Failed to detect attributes for PixelFormat: {0}.", pixelformat); + } + + // Skip formats that don't offer full hardware acceleration + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)values[0]; + if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb) + { + // Construct a new GraphicsMode to describe this format + created_mode = new GraphicsMode(new IntPtr(pixelformat), + new ColorFormat(values[1], values[2], values[3], values[4]), + values[6], + values[7], + values[8] != 0 ? values[9] : 0, + new ColorFormat(values[10], values[11], values[12], values[13]), + values[15] == 1 ? 2 : 1, + values[16] == 1 ? true : false); + } + } + return created_mode; + } + } +} diff --git a/GLWidget/OpenTK/Platform/Windows/WinWindowInfo.cs b/GLWidget/OpenTK/Platform/Windows/WinWindowInfo.cs new file mode 100644 index 0000000..f23f238 --- /dev/null +++ b/GLWidget/OpenTK/Platform/Windows/WinWindowInfo.cs @@ -0,0 +1,162 @@ +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Windows +{ + /// \internal + /// Describes a win32 window. + internal sealed class WinWindowInfo : IWindowInfo + { + private IntPtr handle, dc; + private bool disposed; + + /// + /// Constructs a new instance. + /// + public WinWindowInfo() + { + } + + /// + /// Constructs a new instance with the specified window handle and paren.t + /// + /// The window handle for this instance. + /// The parent window of this instance (may be null). + public WinWindowInfo(IntPtr handle, WinWindowInfo parent) + { + this.handle = handle; + this.Parent = parent; + } + + /// + /// Gets or sets the handle of the window. + /// + public IntPtr Handle { get { return handle; } set { handle = value; } } + + /// + /// Gets or sets the Parent of the window (may be null). + /// + public WinWindowInfo Parent { get; set; } + + /// + /// Gets the device context for this window instance. + /// + public IntPtr DeviceContext + { + get + { + if (dc == IntPtr.Zero) + { + dc = Functions.GetDC(this.Handle); + } + + return dc; + } + } + + // For compatibility with whoever thought it would be + // a good idea to access internal APIs through reflection + // (e.g. MonoGame) + public IntPtr WindowHandle { get { return Handle; } set { Handle = value; } } + + /// Returns a System.String that represents the current window. + /// A System.String that represents the current window. + public override string ToString() + { + return String.Format("Windows.WindowInfo: Handle {0}, Parent ({1})", + this.Handle, this.Parent != null ? this.Parent.ToString() : "null"); + } + + /// Checks if this and obj reference the same win32 window. + /// The object to check against. + /// True if this and obj reference the same win32 window; false otherwise. + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + if (this.GetType() != obj.GetType()) + { + return false; + } + WinWindowInfo info = (WinWindowInfo)obj; + + if (info == null) + { + return false; + } + // TODO: Assumes windows will always have unique handles. + return handle.Equals(info.handle); + } + + /// Returns the hash code for this instance. + /// A hash code for the current WinWindowInfo. + public override int GetHashCode() + { + return handle.GetHashCode(); + } + + /// Releases the unmanaged resources consumed by this instance. + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!disposed) + { + if (this.dc != IntPtr.Zero) + { + if (!Functions.ReleaseDC(this.handle, this.dc)) + { + Debug.Print("[Warning] Failed to release device context {0}. Windows error: {1}.", this.dc, Marshal.GetLastWin32Error()); + } + } + + if (manual) + { + if (Parent != null) + { + Parent.Dispose(); + } + } + + disposed = true; + } + } + + ~WinWindowInfo() + { + this.Dispose(false); + } + } +} diff --git a/GLWidget/OpenTK/Platform/X11/API.cs b/GLWidget/OpenTK/Platform/X11/API.cs new file mode 100644 index 0000000..5a9f0ee --- /dev/null +++ b/GLWidget/OpenTK/Platform/X11/API.cs @@ -0,0 +1,1633 @@ +/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos + * Contributions from Erik Ylvisaker + * See license.txt for license info + */ + +using System; +using System.Runtime.InteropServices; +using System.Diagnostics; + +// ReSharper disable UnusedMember.Global +// ReSharper disable InconsistentNaming +#pragma warning disable 1591 // Missing XML comments +#pragma warning disable 3019 // CLS-compliance checking +#pragma warning disable 0649 // struct members not explicitly initialized +#pragma warning disable 0169 // field / method is never used. +#pragma warning disable 0414 // field assigned but never used. + +namespace OpenTK.Platform.X11 +{ + // using XID = System.Int32; + using Window = System.IntPtr; + using Drawable = System.IntPtr; + using Font = System.IntPtr; + using Pixmap = System.IntPtr; + using Cursor = System.IntPtr; + using Colormap = System.IntPtr; + using GContext = System.IntPtr; + using KeySym = System.IntPtr; + using Mask = System.IntPtr; + using Atom = System.IntPtr; + using VisualID = System.IntPtr; + using Time = System.IntPtr; + using KeyCode = System.Byte; // Or maybe ushort? + + using Display = System.IntPtr; + using XPointer = System.IntPtr; + + using XcursorBool = System.Int32; + using XcursorUInt = System.UInt32; + using XcursorDim = System.UInt32; + using XcursorPixel = System.UInt32; + + // Randr and Xrandr + using Bool = System.Boolean; + using XRRScreenConfiguration = System.IntPtr; // opaque datatype + using Rotation = System.UInt16; + using Status = System.Int32; + using SizeID = System.UInt16; + + /// + /// X11 has some defined values they are defined with c's #define in X.h + /// + internal static class Consts + { + /// + /// Universal null resource or null atom. From header: #define None 0L + /// + public static readonly IntPtr None = IntPtr.Zero; + // + /// + /// Special time value. From header: #define CurrentTime 0L + /// + public static readonly IntPtr CurrentTime = IntPtr.Zero; // + } + + internal static class API + { + private const string _dll_name = "libX11"; + private const string _dll_name_vid = "libXxf86vm"; + + private static Window rootWindow; + + internal static Display DefaultDisplay { get; private set; } + + private static int DefaultScreen { get; set; } + + //internal static Window RootWindow { get { return rootWindow; } } + internal static int ScreenCount { get; } + + internal static object Lock = new object(); + + static API() + { + int has_threaded_x = Functions.XInitThreads(); + Debug.Print("Initializing threaded X11: {0}.", has_threaded_x.ToString()); + + DefaultDisplay = Functions.XOpenDisplay(IntPtr.Zero); + + if (DefaultDisplay == IntPtr.Zero) + { + throw new PlatformException("Could not establish connection to the X-Server."); + } + + using (new XLock(DefaultDisplay)) + { + ScreenCount = Functions.XScreenCount(DefaultDisplay); + } + Debug.Print("Display connection: {0}, Screen count: {1}", DefaultDisplay, ScreenCount); + + //AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); + } + + private static void CurrentDomain_ProcessExit(object sender, EventArgs e) + { + if (DefaultDisplay != IntPtr.Zero) + { + Functions.XCloseDisplay(DefaultDisplay); + DefaultDisplay = IntPtr.Zero; + DefaultScreen = 0; + rootWindow = IntPtr.Zero; + } + } + + // Display management + //[DllImport(_dll_name, EntryPoint = "XOpenDisplay")] + //extern public static IntPtr OpenDisplay([MarshalAs(UnmanagedType.LPTStr)] string display_name); + + //[DllImport(_dll_name, EntryPoint = "XCloseDisplay")] + //extern public static void CloseDisplay(Display display); + + //[DllImport(_dll_name, EntryPoint = "XCreateColormap")] + //extern public static IntPtr CreateColormap(Display display, Window window, IntPtr visual, int alloc); + + [DllImport(_dll_name, EntryPoint = "XCreateSimpleWindow")] + public extern static Window CreateSimpleWindow( + Display display, + Window parent, + int x, int y, + int width, int height, + int border_width, + long border, + long background + ); + + [DllImport(_dll_name, EntryPoint = "XResizeWindow")] + public extern static int XResizeWindow(Display display, Window window, int width, int height); + + [DllImport(_dll_name, EntryPoint = "XDestroyWindow")] + public extern static void DestroyWindow(Display display, Window window); + + [DllImport(_dll_name, EntryPoint = "XMapWindow")] + extern public static void MapWindow(Display display, Window window); + + [DllImport(_dll_name, EntryPoint = "XMapRaised")] + extern public static void MapRaised(Display display, Window window); + + [DllImport(_dll_name, EntryPoint = "XDefaultVisual")] + extern public static IntPtr DefaultVisual(Display display, int screen_number); + + /// + /// Frees the memory used by an X structure. Only use on unmanaged structures! + /// + /// A pointer to the structure that will be freed. + [DllImport(_dll_name, EntryPoint = "XFree")] + extern public static void Free(IntPtr buffer); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport(_dll_name, EntryPoint = "XEventsQueued")] + extern public static int EventsQueued(Display display, int mode); + + [System.Security.SuppressUnmanagedCodeSecurity] + [DllImport(_dll_name, EntryPoint = "XPending")] + extern public static int Pending(Display display); + + //[System.Security.SuppressUnmanagedCodeSecurity] + [DllImport(_dll_name, EntryPoint = "XNextEvent")] + extern public static void NextEvent( + Display display, + [MarshalAs(UnmanagedType.AsAny)][In, Out]object e); + + [DllImport(_dll_name, EntryPoint = "XNextEvent")] + extern public static void NextEvent(Display display, [In, Out] IntPtr e); + + [DllImport(_dll_name, EntryPoint = "XPeekEvent")] + extern public static void PeekEvent( + Display display, + [MarshalAs(UnmanagedType.AsAny)][In, Out]object event_return + ); + + [DllImport(_dll_name, EntryPoint = "XPeekEvent")] + extern public static void PeekEvent(Display display, [In, Out]XEvent event_return); + + [DllImport(_dll_name, EntryPoint = "XSendEvent")] + [return: MarshalAs(UnmanagedType.Bool)] + extern public static bool SendEvent(Display display, Window window, bool propagate, + [MarshalAs(UnmanagedType.SysInt)]EventMask event_mask, ref XEvent event_send); + + /// + /// The XSelectInput() function requests that the X server report the events associated + /// with the specified event mask. + /// + /// Specifies the connection to the X server. + /// Specifies the window whose events you are interested in. + /// Specifies the event mask. + /// + /// Initially, X will not report any of these events. + /// Events are reported relative to a window. + /// If a window is not interested in a device event, + /// it usually propagates to the closest ancestor that is interested, + /// unless the do_not_propagate mask prohibits it. + /// Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients. Multiple clients can select for the same events on the same window with the following restrictions: + /// Multiple clients can select events on the same window because their event masks are disjoint. When the X server generates an event, it reports it to all interested clients. + /// Only one client at a time can select CirculateRequest, ConfigureRequest, or MapRequest events, which are associated with the event mask SubstructureRedirectMask. + /// Only one client at a time can select a ResizeRequest event, which is associated with the event mask ResizeRedirectMask. + /// Only one client at a time can select a ButtonPress event, which is associated with the event mask ButtonPressMask. + /// The server reports the event to all interested clients. + /// XSelectInput() can generate a BadWindow error. + /// + [DllImport(_dll_name, EntryPoint = "XSelectInput")] + public static extern void SelectInput(Display display, Window w, EventMask event_mask); + + /// + /// When the predicate procedure finds a match, XCheckIfEvent() copies the matched event into the client-supplied XEvent structure and returns True. (This event is removed from the queue.) If the predicate procedure finds no match, XCheckIfEvent() returns False, and the output buffer will have been flushed. All earlier events stored in the queue are not discarded. + /// + /// Specifies the connection to the X server. + /// Returns a copy of the matched event's associated structure. + /// Specifies the procedure that is to be called to determine if the next event in the queue matches what you want + /// Specifies the user-supplied argument that will be passed to the predicate procedure. + /// true if the predicate returns true for some event, false otherwise + [DllImport(_dll_name, EntryPoint = "XCheckIfEvent")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CheckIfEvent(Display display, ref XEvent event_return, + /*[MarshalAs(UnmanagedType.FunctionPtr)] */ CheckEventPredicate predicate, /*XPointer*/ IntPtr arg); + + [DllImport(_dll_name, EntryPoint = "XIfEvent")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IfEvent(Display display, ref XEvent event_return, + /*[MarshalAs(UnmanagedType.FunctionPtr)] */ CheckEventPredicate predicate, /*XPointer*/ IntPtr arg); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate bool CheckEventPredicate(Display display, ref XEvent @event, IntPtr arg); + + [DllImport(_dll_name, EntryPoint = "XCheckMaskEvent")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CheckMaskEvent(Display display, EventMask event_mask, ref XEvent event_return); + + [DllImport(_dll_name, EntryPoint = "XGrabPointer")] + extern public static ErrorCodes GrabPointer(Display display, IntPtr grab_window, + bool owner_events, int event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, + IntPtr confine_to, IntPtr cursor, int time); + + [DllImport(_dll_name, EntryPoint = "XUngrabPointer")] + extern public static ErrorCodes UngrabPointer(Display display, int time); + + [DllImport(_dll_name, EntryPoint = "XGrabKeyboard")] + extern public static ErrorCodes GrabKeyboard(Display display, IntPtr grab_window, + bool owner_events, GrabMode pointer_mode, GrabMode keyboard_mode, int time); + + [DllImport(_dll_name, EntryPoint = "XUngrabKeyboard")] + extern public static void UngrabKeyboard(Display display, int time); + + /// + /// The XGetKeyboardMapping() function returns the symbols for the specified number of KeyCodes starting with first_keycode. + /// + /// Specifies the connection to the X server. + /// Specifies the first KeyCode that is to be returned. + /// Specifies the number of KeyCodes that are to be returned + /// Returns the number of KeySyms per KeyCode. + /// + /// + /// The value specified in first_keycode must be greater than or equal to min_keycode as returned by XDisplayKeycodes(), or a BadValue error results. In addition, the following expression must be less than or equal to max_keycode as returned by XDisplayKeycodes(): + /// first_keycode + keycode_count - 1 + /// If this is not the case, a BadValue error results. The number of elements in the KeySyms list is: + /// keycode_count * keysyms_per_keycode_return + /// KeySym number N, counting from zero, for KeyCode K has the following index in the list, counting from zero: + /// (K - first_code) * keysyms_per_code_return + N + /// The X server arbitrarily chooses the keysyms_per_keycode_return value to be large enough to report all requested symbols. A special KeySym value of NoSymbol is used to fill in unused elements for individual KeyCodes. To free the storage returned by XGetKeyboardMapping(), use XFree(). + /// XGetKeyboardMapping() can generate a BadValue error. + /// Diagnostics: + /// BadValue: Some numeric value falls outside the range of values accepted by the request. Unless a specific range is specified for an argument, the full range defined by the argument's type is accepted. Any argument defined as a set of alternatives can generate this error. + /// + [DllImport(_dll_name, EntryPoint = "XGetKeyboardMapping")] + public static extern KeySym GetKeyboardMapping(Display display, KeyCode first_keycode, int keycode_count, + ref int keysyms_per_keycode_return); + + /// + /// The XDisplayKeycodes() function returns the min-keycodes and max-keycodes supported by the specified display. + /// + /// Specifies the connection to the X server. + /// Returns the minimum number of KeyCodes + /// Returns the maximum number of KeyCodes. + /// The minimum number of KeyCodes returned is never less than 8, and the maximum number of KeyCodes returned is never greater than 255. Not all KeyCodes in this range are required to have corresponding keys. + [DllImport(_dll_name, EntryPoint = "XDisplayKeycodes")] + public static extern void DisplayKeycodes(Display display, ref int min_keycodes_return, ref int max_keycodes_return); + + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeModeLine + { + public short hdisplay; /* Number of display pixels horizontally */ + public short hsyncstart; /* Horizontal sync start */ + public short hsyncend; /* Horizontal sync end */ + public short htotal; /* Total horizontal pixels */ + public short vdisplay; /* Number of display pixels vertically */ + public short vsyncstart; /* Vertical sync start */ + public short vsyncend; /* Vertical sync start */ + public short vtotal; /* Total vertical pixels */ + public int flags; /* Mode flags */ + public int privsize; /* Size of private */ + public IntPtr _private; /* Server privates */ + } + + /// + /// Specifies an XF86 display mode. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeModeInfo + { + /// + /// Pixel clock. + /// + public int dotclock; + + /// + /// Number of display pixels horizontally + /// + public short hdisplay; + + /// + /// Horizontal sync start + /// + public short hsyncstart; + + /// + /// Horizontal sync end + /// + public short hsyncend; + + /// + /// Total horizontal pixel + /// + public short htotal; + + /// + /// + /// + public short hskew; + + /// + /// Number of display pixels vertically + /// + public short vdisplay; + + /// + /// Vertical sync start + /// + public short vsyncstart; + + /// + /// Vertical sync end + /// + public short vsyncend; + + /// + /// Total vertical pixels + /// + public short vtotal; + + /// + /// + /// + public short vskew; + + /// + /// Mode flags + /// + public int flags; + + private int privsize; /* Size of private */ + private IntPtr _private; /* Server privates */ + } + + //Monitor information: + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeMonitor + { + [MarshalAs(UnmanagedType.LPStr)] private string vendor; /* Name of manufacturer */ + [MarshalAs(UnmanagedType.LPStr)] private string model; /* Model name */ + private float EMPTY; /* unused, for backward compatibility */ + + private byte nhsync; /* Number of horiz sync ranges */ + /*XF86VidModeSyncRange* */ + private IntPtr hsync; /* Horizontal sync ranges */ + + private byte nvsync; /* Number of vert sync ranges */ + /*XF86VidModeSyncRange* */ + private IntPtr vsync; /* Vertical sync ranges */ + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeSyncRange + { + private float hi; /* Top of range */ + private float lo; /* Bottom of range */ + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeNotifyEvent + { + private int type; /* of event */ + private ulong serial; /* # of last request processed by server */ + private bool send_event; /* true if this came from a SendEvent req */ + private Display display; /* Display the event was read from */ + private IntPtr root; /* root window of event screen */ + private int state; /* What happened */ + private int kind; /* What happened */ + + private bool forced; /* extents of new region */ + /* Time */ + private IntPtr time; /* event timestamp */ + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XF86VidModeGamma + { + private float red; /* Red Gamma value */ + private float green; /* Green Gamma value */ + private float blue; /* Blue Gamma value */ + } + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeQueryExtension( + Display display, + out int event_base_return, + out int error_base_return); + /* + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeSwitchMode( + Display display, + int screen, + int zoom); + */ + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeSwitchToMode( + Display display, + int screen, + IntPtr + /*XF86VidModeModeInfo* */ modeline); + + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeQueryVersion( + Display display, + out int major_version_return, + out int minor_version_return); + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeGetModeLine( + Display display, + int screen, + out int dotclock_return, + out XF86VidModeModeLine modeline); + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeGetAllModeLines( + Display display, + int screen, + out int modecount_return, + /*XF86VidModeModeInfo*** <-- yes, that's three *'s. */ + out IntPtr modesinfo); + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeGetViewPort( + Display display, + int screen, + out int x_return, + out int y_return); + + [DllImport(_dll_name_vid)] + extern public static bool XF86VidModeSetViewPort( + Display display, + int screen, + int x, + int y); + + /* +Bool XF86VidModeSetClientVersion( + Display *display); + +Bool XF86VidModeDeleteModeLine( + Display *display, + int screen, + XF86VidModeModeInfo *modeline); + +Bool XF86VidModeModModeLine( + Display *display, + int screen, + XF86VidModeModeLine *modeline); + +Status XF86VidModeValidateModeLine( + Display *display, + int screen, + XF86VidModeModeLine *modeline); + +Bool XF86VidModeLockModeSwitch( + Display *display, + int screen, + int lock); + +Bool XF86VidModeGetMonitor( + Display *display, + int screen, + XF86VidModeMonitor *monitor); + +XF86VidModeGetDotClocks( + Display *display, + int screen, + int *flags return, + int *number of clocks return, + int *max dot clock return, + int **clocks return); + +XF86VidModeGetGamma( + Display *display, + int screen, + XF86VidModeGamma *Gamma); + +XF86VidModeSetGamma( + Display *display, + int screen, + XF86VidModeGamma *Gamma); + +XF86VidModeGetGammaRamp( + Display *display, + int screen, + int size, + unsigned short *red array, + unsigned short *green array, + unsigned short *blue array); + +XF86VidModeSetGammaRamp( + Display *display, + int screen, + int size, + unsigned short *red array, + unsigned short *green array, + unsigned short *blue array); + +XF86VidModeGetGammaRampSize( + Display *display, + int screen, + int *size); + * */ + + [DllImport(_dll_name, EntryPoint = "XLookupKeysym")] + public static extern KeySym LookupKeysym(ref XKeyEvent key_event, int index); + + } + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct XcursorImage + { + public XcursorUInt version; + public XcursorDim size; + public XcursorDim width; + public XcursorDim height; + public XcursorDim xhot; + public XcursorDim yhot; + public XcursorUInt delay; + public XcursorPixel* pixels; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct XcursorImages + { + public int nimage; + public XcursorImage **images; + public char *name; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct XcursorCursors + { + public Display dpy; + public int refcount; + public int ncursor; + public Cursor *cursors; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct XcursorAnimate + { + public XcursorCursors *cursors; + public int sequence; + } + + [StructLayout(LayoutKind.Sequential)] + public struct XVisualInfo + { + public IntPtr Visual; + public VisualID 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 String.Format("id ({0}), screen ({1}), depth ({2}), class ({3})", + VisualID, Screen, Depth, Class); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SizeHints + { + public long flags; /* marks which fields in this structure are defined */ + public int x, y; /* Obsolete */ + public int width, height; /* Obsolete */ + public int min_width, min_height; + public int max_width, max_height; + public int width_inc, height_inc; + public Rectangle min_aspect, max_aspect; + public int base_width, base_height; + public int win_gravity; + internal struct Rectangle + { + public int x; /* numerator */ + public int y; /* denominator */ + private void stop_the_compiler_warnings() { x = y = 0; } + } + /* this structure may be extended in the future */ + } + + internal struct XRRScreenSize + { + internal int Width, Height; + internal int MWidth, MHeight; + }; + + unsafe internal struct Screen + { + private XExtData ext_data; /* hook for extension to hang buffer */ + private IntPtr display; /* back pointer to display structure */ /* _XDisplay */ + private Window root; /* Root window id. */ + + private int width, height; /* width and height of screen */ + private int mwidth, mheight; /* width and height of in millimeters */ + + private int ndepths; /* number of depths possible */ + //Depth *depths; /* list of allowable depths on the screen */ + private int root_depth; /* bits per pixel */ + //Visual* root_visual; /* root visual */ + private IntPtr default_gc; /* GC for the root root visual */ // GC + + private Colormap cmap; /* default color map */ + private UIntPtr white_pixel; // unsigned long + private UIntPtr black_pixel; /* White and Black pixel values */ // unsigned long + private int max_maps, min_maps; /* max and min color maps */ + + private int backing_store; /* Never, WhenMapped, Always */ + private Bool save_unders; + private long root_input_mask; /* initial root input mask */ + } + + unsafe internal class XExtData + { + private int number; /* number returned by XRegisterExtension */ + private XExtData next; /* next item on list of buffer for structure */ + + private delegate int FreePrivateDelegate(XExtData extension); + + private FreePrivateDelegate FreePrivate; /* called to free private storage */ + private XPointer private_data; /* buffer private to this extension. */ + }; + + [StructLayout(LayoutKind.Sequential)] + internal struct MotifWmHints + { + internal IntPtr flags; + internal IntPtr functions; + internal IntPtr decorations; + internal IntPtr input_mode; + internal IntPtr status; + + public override string ToString () + { + return string.Format("MotifWmHints