00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 using System;
00011 using System.Collections.Generic;
00012 using System.Diagnostics;
00013 using System.Runtime.InteropServices;
00014 using Control = System.Windows.Forms.Control;
00015
00016 namespace OpenTK.Platform.MacOS
00017 {
00018 using Carbon;
00019 using Graphics;
00020
00021 using AGLRendererInfo = IntPtr;
00022 using AGLPixelFormat = IntPtr;
00023 using AGLContext = IntPtr;
00024 using AGLPbuffer = IntPtr;
00025
00026 class AglContext : DesktopGraphicsContext
00027 {
00028 bool mVSync = false;
00029
00030
00031
00032 GraphicsMode graphics_mode;
00033 CarbonWindowInfo carbonWindow;
00034 IntPtr shareContextRef;
00035 DisplayDevice device;
00036 bool mIsFullscreen = false;
00037
00038 public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext)
00039 {
00040 Debug.Print("Context Type: {0}", shareContext);
00041 Debug.Print("Window info: {0}", window);
00042
00043 this.graphics_mode = mode;
00044 this.carbonWindow = (CarbonWindowInfo)window;
00045
00046 if (shareContext is AglContext)
00047 shareContextRef = ((AglContext)shareContext).Handle.Handle;
00048 if (shareContext is GraphicsContext)
00049 {
00050 ContextHandle shareHandle = shareContext != null ?
00051 (shareContext as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero;
00052
00053 shareContextRef = shareHandle.Handle;
00054 }
00055
00056 if (shareContextRef == IntPtr.Zero)
00057 {
00058 Debug.Print("No context sharing will take place.");
00059 }
00060
00061 CreateContext(mode, carbonWindow, shareContextRef, true);
00062 }
00063
00064 public AglContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext)
00065 {
00066 if (handle == ContextHandle.Zero)
00067 throw new ArgumentException("handle");
00068 if (window == null)
00069 throw new ArgumentNullException("window");
00070
00071 Handle = handle;
00072 carbonWindow = (CarbonWindowInfo)window;
00073 }
00074
00075
00076 private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pixelFormatAttribute)
00077 {
00078 Debug.Print(pixelFormatAttribute.ToString());
00079
00080 aglAttributes.Add((int)pixelFormatAttribute);
00081 }
00082 private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pixelFormatAttribute, int value)
00083 {
00084 Debug.Print("{0} : {1}", pixelFormatAttribute, value);
00085
00086 aglAttributes.Add((int)pixelFormatAttribute);
00087 aglAttributes.Add(value);
00088 }
00089 void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow,
00090 IntPtr shareContextRef, bool fullscreen)
00091 {
00092 List<int> aglAttributes = new List<int>();
00093
00094 Debug.Print("AGL pixel format attributes:");
00095 Debug.Indent();
00096
00097 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_RGBA);
00098 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_DOUBLEBUFFER);
00099 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_RED_SIZE, mode.ColorFormat.Red);
00100 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_GREEN_SIZE, mode.ColorFormat.Green);
00101 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_BLUE_SIZE, mode.ColorFormat.Blue);
00102 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ALPHA_SIZE, mode.ColorFormat.Alpha);
00103
00104 if (mode.Depth > 0)
00105 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_DEPTH_SIZE, mode.Depth);
00106
00107 if (mode.Stencil > 0)
00108 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_STENCIL_SIZE, mode.Stencil);
00109
00110 if (mode.AccumulatorFormat.BitsPerPixel > 0)
00111 {
00112 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_RED_SIZE, mode.AccumulatorFormat.Red);
00113 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_GREEN_SIZE, mode.AccumulatorFormat.Green);
00114 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_BLUE_SIZE, mode.AccumulatorFormat.Blue);
00115 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_ALPHA_SIZE, mode.AccumulatorFormat.Alpha);
00116 }
00117
00118 if (mode.Samples > 1)
00119 {
00120 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_SAMPLE_BUFFERS_ARB, 1);
00121 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_SAMPLES_ARB, mode.Samples);
00122 }
00123
00124 if (fullscreen)
00125 {
00126 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_FULLSCREEN);
00127 }
00128 AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_NONE);
00129
00130 Debug.Unindent();
00131
00132 Debug.Write("Attribute array: ");
00133 for (int i = 0; i < aglAttributes.Count; i++)
00134 Debug.Write(aglAttributes[i].ToString() + " ");
00135 Debug.WriteLine("");
00136
00137 AGLPixelFormat myAGLPixelFormat;
00138
00139
00140 if (fullscreen)
00141 {
00142 IntPtr gdevice;
00143 IntPtr cgdevice = GetQuartzDevice(carbonWindow);
00144
00145 if (cgdevice == IntPtr.Zero)
00146 cgdevice = QuartzDisplayDeviceDriver.MainDisplay;
00147
00148 OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(
00149 cgdevice, out gdevice, false);
00150
00151 if (status != OSStatus.NoError)
00152 throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
00153
00154 myAGLPixelFormat = Agl.aglChoosePixelFormat(
00155 ref gdevice, 1,
00156 aglAttributes.ToArray());
00157
00158 Agl.AglError err = Agl.GetError();
00159
00160 if (err == Agl.AglError.BadPixelFormat)
00161 {
00162 Debug.Print("Failed to create full screen pixel format.");
00163 Debug.Print("Trying again to create a non-fullscreen pixel format.");
00164
00165 CreateContext(mode, carbonWindow, shareContextRef, false);
00166 return;
00167 }
00168 }
00169 else
00170 {
00171 myAGLPixelFormat = Agl.aglChoosePixelFormat(
00172 IntPtr.Zero, 0,
00173 aglAttributes.ToArray());
00174
00175 MyAGLReportError("aglChoosePixelFormat");
00176 }
00177
00178
00179 Debug.Print("Creating AGL context. Sharing with {0}", shareContextRef);
00180
00181
00182 Handle = new ContextHandle( Agl.aglCreateContext(myAGLPixelFormat, shareContextRef));
00183 MyAGLReportError("aglCreateContext");
00184
00185
00186 Agl.aglDestroyPixelFormat(myAGLPixelFormat);
00187 MyAGLReportError("aglDestroyPixelFormat");
00188
00189 Debug.Print("IsControl: {0}", carbonWindow.IsControl);
00190
00191 SetDrawable(carbonWindow);
00192 SetBufferRect(carbonWindow);
00193 Update(carbonWindow);
00194
00195 MakeCurrent(carbonWindow);
00196
00197 Debug.Print("context: {0}", Handle.Handle);
00198 }
00199
00200 private IntPtr GetQuartzDevice(CarbonWindowInfo carbonWindow)
00201 {
00202 IntPtr windowRef = carbonWindow.WindowRef;
00203
00204 if (CarbonGLNative.WindowRefMap.ContainsKey(windowRef) == false)
00205 return IntPtr.Zero;
00206
00207 WeakReference nativeRef = CarbonGLNative.WindowRefMap[windowRef];
00208 if (nativeRef.IsAlive == false)
00209 return IntPtr.Zero;
00210
00211 CarbonGLNative window = nativeRef.Target as CarbonGLNative;
00212
00213 if (window == null)
00214 return IntPtr.Zero;
00215
00216 return QuartzDisplayDeviceDriver.HandleTo(window.TargetDisplayDevice);
00217
00218 }
00219
00220 void SetBufferRect(CarbonWindowInfo carbonWindow)
00221 {
00222 if (carbonWindow.IsControl == false)
00223 return;
00224
00225 System.Windows.Forms.Control ctrl = Control.FromHandle(carbonWindow.WindowRef);
00226
00227 if (ctrl.TopLevelControl == null)
00228 return;
00229
00230 Rect rect = API.GetControlBounds(carbonWindow.WindowRef);
00231 System.Windows.Forms.Form frm = (System.Windows.Forms.Form) ctrl.TopLevelControl;
00232
00233 System.Drawing.Point loc =
00234 frm.PointToClient(ctrl.PointToScreen(System.Drawing.Point.Empty));
00235
00236 rect.X = (short)loc.X;
00237 rect.Y = (short)loc.Y;
00238
00239 Debug.Print("Setting buffer_rect for control.");
00240 Debug.Print("MacOS Coordinate Rect: {0}", rect);
00241
00242 rect.Y = (short)(ctrl.TopLevelControl.ClientSize.Height - rect.Y - rect.Height);
00243 Debug.Print(" AGL Coordinate Rect: {0}", rect);
00244
00245 int[] glrect = new int[4];
00246
00247 glrect[0] = rect.X;
00248 glrect[1] = rect.Y;
00249 glrect[2] = rect.Width;
00250 glrect[3] = rect.Height;
00251
00252 Agl.aglSetInteger(Handle.Handle, Agl.ParameterNames.AGL_BUFFER_RECT, glrect);
00253 MyAGLReportError("aglSetInteger");
00254
00255 Agl.aglEnable(Handle.Handle, Agl.ParameterNames.AGL_BUFFER_RECT);
00256 MyAGLReportError("aglEnable");
00257
00258 }
00259 void SetDrawable(CarbonWindowInfo carbonWindow)
00260 {
00261 IntPtr windowPort = GetWindowPortForWindowInfo(carbonWindow);
00262
00263
00264 Agl.aglSetDrawable(Handle.Handle, windowPort);
00265
00266 MyAGLReportError("aglSetDrawable");
00267
00268 }
00269
00270 private static IntPtr GetWindowPortForWindowInfo(CarbonWindowInfo carbonWindow)
00271 {
00272 IntPtr windowPort;
00273 if (carbonWindow.IsControl)
00274 {
00275 IntPtr controlOwner = API.GetControlOwner(carbonWindow.WindowRef);
00276
00277 windowPort = API.GetWindowPort(controlOwner);
00278 }
00279 else
00280 windowPort = API.GetWindowPort(carbonWindow.WindowRef);
00281
00282 return windowPort;
00283 }
00284 public override void Update(IWindowInfo window)
00285 {
00286 CarbonWindowInfo carbonWindow = (CarbonWindowInfo)window;
00287
00288 if (carbonWindow.GoFullScreenHack)
00289 {
00290 carbonWindow.GoFullScreenHack = false;
00291 CarbonGLNative wind = GetCarbonWindow(carbonWindow);
00292
00293 if (wind != null)
00294 wind.SetFullscreen(this);
00295 else
00296 Debug.Print("Could not find window!");
00297
00298 return;
00299 }
00300 else if (carbonWindow.GoWindowedHack)
00301 {
00302 carbonWindow.GoWindowedHack = false;
00303 CarbonGLNative wind = GetCarbonWindow(carbonWindow);
00304
00305 if (wind != null)
00306 wind.UnsetFullscreen(this);
00307 else
00308 Debug.Print("Could not find window!");
00309
00310 }
00311
00312 if (mIsFullscreen)
00313 return;
00314
00315 SetDrawable(carbonWindow);
00316 SetBufferRect(carbonWindow);
00317
00318 Agl.aglUpdateContext(Handle.Handle);
00319 }
00320
00321 private CarbonGLNative GetCarbonWindow(CarbonWindowInfo carbonWindow)
00322 {
00323 WeakReference r = CarbonGLNative.WindowRefMap[carbonWindow.WindowRef];
00324
00325 if (r.IsAlive)
00326 {
00327 return (CarbonGLNative) r.Target;
00328 }
00329 else
00330 return null;
00331 }
00332
00333 void MyAGLReportError(string function)
00334 {
00335 Agl.AglError err = Agl.GetError();
00336
00337 if (err != Agl.AglError.NoError)
00338 throw new MacOSException((OSStatus)err, string.Format(
00339 "AGL Error from function {0}: {1} {2}",
00340 function, err, Agl.ErrorString(err)));
00341 }
00342
00343 bool firstFullScreen = false;
00344
00345 internal void SetFullScreen(CarbonWindowInfo info, out int width, out int height)
00346 {
00347 CarbonGLNative wind = GetCarbonWindow(info);
00348
00349 Debug.Print("Switching to full screen {0}x{1} on context {2}",
00350 wind.TargetDisplayDevice.Width, wind.TargetDisplayDevice.Height, Handle.Handle);
00351
00352 CG.DisplayCapture(GetQuartzDevice(info));
00353 Agl.aglSetFullScreen(Handle.Handle, wind.TargetDisplayDevice.Width, wind.TargetDisplayDevice.Height, 0, 0);
00354 MakeCurrent(info);
00355
00356 width = wind.TargetDisplayDevice.Width;
00357 height = wind.TargetDisplayDevice.Height;
00358
00359
00360
00361
00362 if (firstFullScreen == false)
00363 {
00364 firstFullScreen = true;
00365 UnsetFullScreen(info);
00366 SetFullScreen(info, out width, out height);
00367 }
00368
00369 mIsFullscreen = true;
00370 }
00371 internal void UnsetFullScreen(CarbonWindowInfo windowInfo)
00372 {
00373 Debug.Print("Unsetting AGL fullscreen.");
00374 Agl.aglSetDrawable(Handle.Handle, IntPtr.Zero);
00375 Agl.aglUpdateContext(Handle.Handle);
00376
00377 CG.DisplayRelease(GetQuartzDevice(windowInfo));
00378 Debug.Print("Resetting drawable.");
00379 SetDrawable(windowInfo);
00380
00381 mIsFullscreen = false;
00382 }
00383
00384
00385 #region IGraphicsContext Members
00386
00387 bool firstSwap = false;
00388 public override void SwapBuffers()
00389 {
00390
00391
00392 if (firstSwap == false && carbonWindow.IsControl)
00393 {
00394 Debug.WriteLine("--> Resetting drawable. <--");
00395 firstSwap = true;
00396 SetDrawable(carbonWindow);
00397 Update(carbonWindow);
00398 }
00399
00400 Agl.aglSwapBuffers(Handle.Handle);
00401 MyAGLReportError("aglSwapBuffers");
00402 }
00403
00404 public override void MakeCurrent(IWindowInfo window)
00405 {
00406 if (Agl.aglSetCurrentContext(Handle.Handle) == false)
00407 MyAGLReportError("aglSetCurrentContext");
00408 }
00409
00410 public override bool IsCurrent
00411 {
00412 get
00413 {
00414 return (Handle.Handle == Agl.aglGetCurrentContext());
00415 }
00416 }
00417
00418 public override bool VSync
00419 {
00420 get
00421 {
00422 return mVSync;
00423 }
00424 set
00425 {
00426 int intVal = value ? 1 : 0;
00427
00428 Agl.aglSetInteger(Handle.Handle, Agl.ParameterNames.AGL_SWAP_INTERVAL, ref intVal);
00429
00430 mVSync = value;
00431 }
00432 }
00433
00434 #endregion
00435
00436 #region IDisposable Members
00437
00438 ~AglContext()
00439 {
00440 Dispose(false);
00441 }
00442
00443 public override void Dispose()
00444 {
00445 Dispose(true);
00446 }
00447
00448 void Dispose(bool disposing)
00449 {
00450 if (IsDisposed || Handle.Handle == IntPtr.Zero)
00451 return;
00452
00453 Debug.Print("Disposing of AGL context.");
00454 Agl.aglSetCurrentContext(IntPtr.Zero);
00455
00456
00457
00458
00459
00460
00461
00462 Debug.Print("Destroying context");
00463 if (Agl.aglDestroyContext(Handle.Handle) == true)
00464 {
00465 Debug.Print("Context destruction completed successfully.");
00466 Handle = ContextHandle.Zero;
00467 return;
00468 }
00469
00470
00471 Debug.WriteLine("Failed to destroy context.");
00472 Debug.WriteLine(Agl.ErrorString(Agl.GetError()));
00473
00474
00475 if (disposing)
00476 {
00477 throw new MacOSException((OSStatus)Agl.GetError(), Agl.ErrorString(Agl.GetError()));
00478 }
00479
00480 IsDisposed = true;
00481 }
00482
00483 #endregion
00484
00485 #region IGraphicsContextInternal Members
00486
00487 public override void LoadAll()
00488 {
00489 base.LoadAll();
00490 }
00491
00492 private const string Library = "libdl.dylib";
00493
00494 [DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
00495 private static extern bool NSIsSymbolNameDefined(string s);
00496 [DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
00497 private static extern IntPtr NSLookupAndBindSymbol(string s);
00498 [DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
00499 private static extern IntPtr NSAddressOfSymbol(IntPtr symbol);
00500
00501 public override IntPtr GetAddress(string function)
00502 {
00503 string fname = "_" + function;
00504 if (!NSIsSymbolNameDefined(fname))
00505 return IntPtr.Zero;
00506
00507 IntPtr symbol = NSLookupAndBindSymbol(fname);
00508 if (symbol != IntPtr.Zero)
00509 symbol = NSAddressOfSymbol(symbol);
00510
00511 return symbol;
00512 }
00513
00514 #endregion
00515 }
00516 }