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 { class CocoaContext : DesktopGraphicsContext { private CocoaWindowInfo cocoaWindow; private IntPtr shareContextRef; static readonly IntPtr NSOpenGLContext = Class.Get("NSOpenGLContext"); static readonly IntPtr currentContext = Selector.Get("currentContext"); static readonly IntPtr flushBuffer = Selector.Get("flushBuffer"); static readonly IntPtr makeCurrentContext = Selector.Get("makeCurrentContext"); static readonly IntPtr update = Selector.Get("update"); 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 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); AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.DoubleBuffer); AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.Accelerated); 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); } 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); } } // Create context var context = Cocoa.SendIntPtr(NSOpenGLContext, Selector.Alloc); context = Cocoa.SendIntPtr(context, Selector.Get("initWithFormat:shareContext:"), pixelFormat, shareContextRef); // 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); Update(cocoaWindow); MakeCurrent(cocoaWindow); } public override void SwapBuffers() { Cocoa.SendVoid(Handle.Handle, flushBuffer); } public override void MakeCurrent(IWindowInfo window) { Cocoa.SendVoid(Handle.Handle, makeCurrentContext); } public override bool IsCurrent { get { return Handle.Handle == CurrentContext; } } public static IntPtr CurrentContext { get { return Cocoa.SendIntPtr(NSOpenGLContext, currentContext); } } // private unsafe void SetContextValue (int val, NSOpenGLContextParameter par) // { // int *p = &val; // context.SetValues ((IntPtr)p, par); // } // // private unsafe int GetContextValue (NSOpenGLContextParameter par) // { // int ret; // int *p = &ret; // context.GetValues ((IntPtr)p, par); // // return ret; // } public override int SwapInterval { get { return 0; //return GetContextValue(NSOpenGLContextParameter.SwapInterval); } set { //SetContextValue(value, NSOpenGLContextParameter.SwapInterval); } } public override void Update(IWindowInfo window) { Cocoa.SendVoid(Handle.Handle, update); } #region IDisposable Members ~CocoaContext() { Dispose(false); } public override void Dispose() { Dispose(true); } void Dispose(bool disposing) { if (IsDisposed || Handle.Handle == IntPtr.Zero) return; Debug.Print("Disposing of Cocoa context."); Cocoa.SendIntPtr(NSOpenGLContext, Selector.Get("clearCurrentContext")); // NSOpenGLContext.ClearCurrentContext(); // context.ClearDrawable(); // context.Dispose(); // context = null; Handle = ContextHandle.Zero; IsDisposed = true; } #endregion #region IGraphicsContextInternal Members public override IntPtr GetAddress(string function) { return NS.GetAddress(function); } public override IntPtr GetAddress(IntPtr function) { return NS.GetAddress(function); } #endregion } }