00001 #region --- License ---
00002
00003
00004
00005
00006 #endregion
00007
00008 #region --- Using Directives ---
00009
00010 using System;
00011 using System.Collections.Generic;
00012 using System.Text;
00013 using System.Runtime.InteropServices;
00014 using System.Diagnostics;
00015
00016 using OpenTK.Graphics;
00017 using OpenTK.Graphics.OpenGL;
00018
00019 #endregion
00020
00021 namespace OpenTK.Platform.Windows
00022 {
00028 internal sealed class WinGLContext : DesktopGraphicsContext
00029 {
00030 static object SyncRoot = new object();
00031
00032 static IntPtr opengl32Handle;
00033 static bool wgl_loaded;
00034 const string opengl32Name = "OPENGL32.DLL";
00035
00036 bool vsync_supported;
00037
00038 #region --- Contructors ---
00039
00040 static WinGLContext()
00041 {
00042 lock (SyncRoot)
00043 {
00044
00045 if (opengl32Handle == IntPtr.Zero)
00046 {
00047 opengl32Handle = Functions.LoadLibrary(opengl32Name);
00048 if (opengl32Handle == IntPtr.Zero)
00049 throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}",
00050 opengl32Name, Marshal.GetLastWin32Error()));
00051 Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", opengl32Handle));
00052 }
00053 }
00054 }
00055
00056 public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext,
00057 int major, int minor, GraphicsContextFlags flags)
00058 {
00059
00060
00061
00062 lock (SyncRoot)
00063 {
00064 if (window == null)
00065 throw new ArgumentNullException("window", "Must point to a valid window.");
00066 if (window.WindowHandle == IntPtr.Zero)
00067 throw new ArgumentException("window", "Must be a valid window.");
00068
00069 Mode = format;
00070
00071 Debug.Print("OpenGL will be bound to handle: {0}", window.WindowHandle);
00072 Debug.Write("Setting pixel format... ");
00073 this.SetGraphicsModePFD(format, (WinWindowInfo)window);
00074
00075 if (!wgl_loaded)
00076 {
00077
00078
00079 Debug.Print("Creating temporary context for wgl extensions.");
00080
00081 ContextHandle temp_context = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
00082 Wgl.Imports.MakeCurrent(window.DeviceContext, temp_context.Handle);
00083 Wgl.LoadAll();
00084 Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
00085 Wgl.DeleteContext(temp_context.Handle);
00086 wgl_loaded = true;
00087 }
00088
00089 if (Wgl.Delegates.wglCreateContextAttribsARB != null)
00090 {
00091 try
00092 {
00093 Debug.Write("Using WGL_ARB_create_context... ");
00094
00095 List<int> attributes = new List<int>();
00096 attributes.Add((int)ArbCreateContext.MajorVersion);
00097 attributes.Add(major);
00098 attributes.Add((int)ArbCreateContext.MinorVersion);
00099 attributes.Add(minor);
00100 if (flags != 0)
00101 {
00102 attributes.Add((int)ArbCreateContext.Flags);
00103 #warning "This is not entirely correct: Embedded is not a valid flag! We need to add a GetARBContextFlags(GraphicsContextFlags) method."
00104 attributes.Add((int)flags);
00105 }
00106
00107
00108
00109
00110 attributes.Add(0);
00111 attributes.Add(0);
00112
00113 Handle = new ContextHandle(
00114 Wgl.Arb.CreateContextAttribs(
00115 window.DeviceContext,
00116 sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero,
00117 attributes.ToArray()));
00118 if (Handle == ContextHandle.Zero)
00119 Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error());
00120 else
00121 Debug.Print("success!");
00122 }
00123 catch (EntryPointNotFoundException e) { Debug.Print(e.ToString()); }
00124 catch (NullReferenceException e) { Debug.Print(e.ToString()); }
00125 }
00126
00127 if (Handle == ContextHandle.Zero)
00128 {
00129
00130 Debug.Write("Falling back to GL2... ");
00131 Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
00132 if (Handle == ContextHandle.Zero)
00133 Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
00134 if (Handle == ContextHandle.Zero)
00135 throw new GraphicsContextException(
00136 String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
00137 Marshal.GetLastWin32Error()));
00138 }
00139
00140 Debug.WriteLine(String.Format("success! (id: {0})", Handle));
00141
00142 if (sharedContext != null)
00143 {
00144 Debug.Print("Sharing state with context {0}", sharedContext.ToString());
00145 Wgl.Imports.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle);
00146 }
00147 }
00148 }
00149
00150 public WinGLContext(ContextHandle handle, WinWindowInfo window, IGraphicsContext sharedContext,
00151 int major, int minor, GraphicsContextFlags flags)
00152 {
00153 if (handle == ContextHandle.Zero)
00154 throw new ArgumentException("handle");
00155 if (window == null)
00156 throw new ArgumentNullException("window");
00157
00158 Handle = handle;
00159 }
00160
00161 #endregion
00162
00163 #region --- IGraphicsContext Members ---
00164
00165 #region SwapBuffers
00166
00167 public override void SwapBuffers()
00168 {
00169 if (!Functions.SwapBuffers(Wgl.GetCurrentDC()))
00170 throw new GraphicsContextException(String.Format(
00171 "Failed to swap buffers for context {0} current. Error: {1}", this, Marshal.GetLastWin32Error()));
00172 }
00173
00174 #endregion
00175
00176 #region MakeCurrent
00177
00178 public override void MakeCurrent(IWindowInfo window)
00179 {
00180 bool success;
00181
00182 if (window != null)
00183 {
00184 if (((WinWindowInfo)window).WindowHandle == IntPtr.Zero)
00185 throw new ArgumentException("window", "Must point to a valid window.");
00186
00187 success = Wgl.Imports.MakeCurrent(((WinWindowInfo)window).DeviceContext, Handle.Handle);
00188 }
00189 else
00190 success = Wgl.Imports.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
00191
00192 if (!success)
00193 throw new GraphicsContextException(String.Format(
00194 "Failed to make context {0} current. Error: {1}", this, Marshal.GetLastWin32Error()));
00195
00196 }
00197 #endregion
00198
00199 #region IsCurrent
00200
00201 public override bool IsCurrent
00202 {
00203 get { return Wgl.GetCurrentContext() == Handle.Handle; }
00204 }
00205
00206 #endregion
00207
00208 #region public bool VSync
00209
00213 public override bool VSync
00214 {
00215 get
00216 {
00217 return vsync_supported && Wgl.Ext.GetSwapInterval() != 0;
00218 }
00219 set
00220 {
00221 if (vsync_supported)
00222 Wgl.Ext.SwapInterval(value ? 1 : 0);
00223 }
00224 }
00225
00226 #endregion
00227
00228 #endregion
00229
00230 #region --- IGLContextInternal Members ---
00231
00232 #region void LoadAll()
00233
00234 public override void LoadAll()
00235 {
00236 Wgl.LoadAll();
00237 vsync_supported = Wgl.Arb.SupportsExtension(this, "WGL_EXT_swap_control") &&
00238 Wgl.Load("wglGetSwapIntervalEXT") && Wgl.Load("wglSwapIntervalEXT");
00239
00240 base.LoadAll();
00241 }
00242
00243 #endregion
00244
00245 #region IWindowInfo IGLContextInternal.Info
00246
00247
00248
00249
00250
00251
00252 #endregion
00253
00254 #region GetAddress
00255
00256 public override IntPtr GetAddress(string function_string)
00257 {
00258 return Wgl.Imports.GetProcAddress(function_string);
00259 }
00260
00261 #endregion
00262
00263 #endregion
00264
00265 #region --- Private Methods ---
00266
00267 #region void SetGraphicsModePFD(GraphicsMode format, WinWindowInfo window)
00268
00269 void SetGraphicsModePFD(GraphicsMode mode, WinWindowInfo window)
00270 {
00271 if (!mode.Index.HasValue)
00272 throw new GraphicsModeException("Invalid or unsupported GraphicsMode.");
00273
00274 if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
00275
00276 PixelFormatDescriptor pfd = new PixelFormatDescriptor();
00277 Functions.DescribePixelFormat(window.DeviceContext, (int)mode.Index.Value,
00278 API.PixelFormatDescriptorSize, ref pfd);
00279 Debug.WriteLine(mode.Index.ToString());
00280 if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd))
00281 throw new GraphicsContextException(String.Format(
00282 "Requested GraphicsMode not available. SetPixelFormat error: {0}", Marshal.GetLastWin32Error()));
00283 }
00284 #endregion
00285
00286 #region void SetGraphicsModeARB(GraphicsMode format, IWindowInfo window)
00287
00288 void SetGraphicsModeARB(GraphicsMode format, IWindowInfo window)
00289 {
00290 throw new NotImplementedException();
00291 }
00292
00293 #endregion
00294
00295 #endregion
00296
00297 #region --- Internal Methods ---
00298
00299 #region internal IntPtr DeviceContext
00300
00301 internal IntPtr DeviceContext
00302 {
00303 get
00304 {
00305 return Wgl.GetCurrentDC();
00306 }
00307 }
00308
00309
00310 #endregion
00311
00312 #endregion
00313
00314 #region --- Overrides ---
00315
00318 public override string ToString()
00319 {
00320 return (this as IGraphicsContextInternal).Context.ToString();
00321 }
00322
00323 #endregion
00324
00325 #region --- IDisposable Members ---
00326
00327 public override void Dispose()
00328 {
00329 Dispose(true);
00330 GC.SuppressFinalize(this);
00331 }
00332
00333 private void Dispose(bool calledManually)
00334 {
00335 if (!IsDisposed)
00336 {
00337 if (calledManually)
00338 {
00339 DestroyContext();
00340 }
00341 else
00342 {
00343 Debug.Print("[Warning] OpenGL context {0} leaked. Did you forget to call IGraphicsContext.Dispose()?",
00344 Handle.Handle);
00345 }
00346 IsDisposed = true;
00347 }
00348 }
00349
00350 ~WinGLContext()
00351 {
00352 Dispose(false);
00353 }
00354
00355 #region private void DestroyContext()
00356
00357 private void DestroyContext()
00358 {
00359 if (Handle != ContextHandle.Zero)
00360 {
00361 try
00362 {
00363
00364 if (!Wgl.Imports.DeleteContext(Handle.Handle))
00365 Debug.Print("Failed to destroy OpenGL context {0}. Error: {1}",
00366 Handle.ToString(), Marshal.GetLastWin32Error());
00367 }
00368 catch (AccessViolationException e)
00369 {
00370 Debug.WriteLine("An access violation occured while destroying the OpenGL context. Please report at http://www.opentk.com.");
00371 Debug.Indent();
00372 Debug.Print("Marshal.GetLastWin32Error(): {0}", Marshal.GetLastWin32Error().ToString());
00373 Debug.WriteLine(e.ToString());
00374 Debug.Unindent();
00375 }
00376 Handle = ContextHandle.Zero;
00377 }
00378 }
00379
00380 #endregion
00381
00382 #endregion
00383 }
00384 }