/Graphics/OpenTK/OpenTKGraphic.cs
C# | 358 lines | 252 code | 29 blank | 77 comment | 43 complexity | 2117d77d09e87c5324a276b6b3d541c9 MD5 | raw file
Possible License(s): Apache-2.0
1using System; 2using Delta.Engine; 3using Delta.Graphics.BaseOpenGL; 4using Delta.Utilities; 5using Delta.Utilities.Graphics; 6using OpenTK; 7using OpenTK.Graphics; 8using OpenTK.Graphics.OpenGL; 9 10namespace Delta.Graphics.OpenTK 11{ 12 /// <summary> 13 /// OpenTKGraphic implementation using Delta.OpenTK (for Windows). 14 /// Note: OpenTK spams a little info into the debug console. 15 /// </summary> 16 internal class OpenTKGraphic : BaseOpenGLGraphic 17 { 18 #region Private 19 20 #region sourceBlendMode (Private) 21 /// <summary> 22 /// Source blend mode 23 /// </summary> 24 private BlendingFactorSrc sourceBlendMode = BlendingFactorSrc.Zero; 25 #endregion 26 27 #region destinationBlendMode (Private) 28 /// <summary> 29 /// Destination blend mode 30 /// </summary> 31 private BlendingFactorDest destinationBlendMode = BlendingFactorDest.Zero; 32 #endregion 33 34 #region blendFunc (Private) 35 /// <summary> 36 /// Blend function 37 /// </summary> 38 private BlendEquationMode blendFunc = BlendEquationMode.FuncAdd; 39 #endregion 40 41 #endregion 42 43 #region Constructors 44 /// <summary> 45 /// Create graphic with parent 46 /// </summary> 47 protected OpenTKGraphic() 48 : base("OpenTKGraphics") 49 { 50 // Register at the "device reseted" event to know when we have to renew 51 // our (global) resources with the new graphic device handle 52 //Core.Graphic.DeviceReset += new DeviceResetDelegate(RecreateResources); 53 if (Settings.Extra.IsFullscreen) 54 { 55 DisplayResolution res = DisplayDevice.Default.SelectResolution( 56 (int)Settings.Resolution.Width, (int)Settings.Resolution.Height, 57 // Should be 32 bit and we do not care about the refresh rate! 58 32, 0); 59 DisplayDevice.Default.ChangeResolution(res); 60 if (res.Width != (int)Settings.Resolution.Width || 61 res.Height != (int)Settings.Resolution.Height) 62 { 63 Log.Info( 64 "Sorry, resolution request failed! Could not find resolution: " + 65 Settings.Resolution + ". Using this resolution instead " + 66 "(probably the current one): " + res); 67 } 68 } 69 70 try 71 { 72 glWindowInfo = WindowInfoHelper.Create( 73 Application.Window.ViewportHandle); 74 75 // Set wanted mode. Note: If given values are not valid, a default 76 // mode (32bit) will be chosen, which is suboptimal. 77 GraphicsMode mode = new GraphicsMode(new ColorFormat(8, 8, 8, 8), 78 Settings.Extra.DepthBufferSize, 0, 79 Settings.Extra.AntiAliasingSamples); 80 81 graphicsDevice = new GraphicsContext(mode, glWindowInfo, 2, 0, 82 GraphicsContextFlags.Default); 83 84 graphicsDevice.MakeCurrent(glWindowInfo); 85 graphicsDevice.LoadAll(); 86 87 // Set the graphic context in the Graphics namespace to make sure 88 // resources can be created from now on. 89 GraphicsContext = graphicsDevice; 90 91 // Retrieve major and minor gl version number 92 string[] version = GL.GetString(StringName.Version).Split('.'); 93 if (version.Length < 2 || 94 int.TryParse(version[0], out majorGLVersion) == false || 95 int.TryParse(version[1], out minorGLVersion) == false) 96 { 97 Log.Warning( 98 "Failed to retrieve GL version from string: " + 99 GL.GetString(StringName.Version) + ". Setting OpenGL version " + 100 "to at least 2.0"); 101 if (majorGLVersion < 2) 102 { 103 majorGLVersion = 2; 104 minorGLVersion = 0; 105 } 106 } 107 108 GL.Viewport(0, 0, Application.Window.ViewportPixelWidth, 109 Application.Window.ViewportPixelHeight); 110 // Disable VSync to see the performance (we are over 60 fps anyway) 111 graphicsDevice.VSync = false; 112 if (Settings.Extra.UseDepthBuffer) 113 { 114 // Note: We don't need to create DepthBuffer as create above. 115 GL.Enable(EnableCap.DepthTest); 116 GL.DepthFunc(DepthFunction.Lequal); 117 GL.DepthMask(true); 118 // Note: Make sure to use the double version of ClearDepth here, 119 // otherwise we are calling the OpenGL 4.1 version of ClearDepth 120 // and that obviously only works on platforms that support it! 121 GL.ClearDepth(1.0); 122 } 123 else 124 { 125 GL.Disable(EnableCap.DepthTest); 126 GL.DepthMask(false); 127 } 128 129 if (Settings.Extra.UseAntiAliasing) 130 { 131 GL.Enable(EnableCap.PointSmooth); 132 GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest); 133 GL.Enable(EnableCap.LineSmooth); 134 GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest); 135 GL.Enable(EnableCap.Multisample); 136 } 137 138 // OpenGL greater than 2.0 does always support GLSL shaders 139 if (majorGLVersion >= 2 || 140 (SupportsExtension("GL_ARB_shading_language_100") && 141 SupportsExtension("GL_ARB_shader_objects") && 142 SupportsExtension("GL_ARB_fragment_shader") && 143 SupportsExtension("GL_ARB_vertex_program"))) 144 { 145 hasGpuShaderSupport = true; 146 } 147 else 148 { 149 hasGpuShaderSupport = false; 150 } 151 152 // Disable lighting 153 GL.Disable(EnableCap.Lighting); 154 155 // Finally call the "Device Reset" to make sure that all our 156 // "render states" will set to the graphics device too 157 // -> Note: This will "raise" the "DeviceReseted" event. 158 ResetDevice(); 159 } 160 #region AccessViolationException 161 // Note: We cannot catch AccessViolationException directly anymore in 162 // CLR 4.0, so this is handled in Factory.cs:600 too! 163 // http://stackoverflow.com/questions/1626368/difference-between-clr-2-0-and-clr-4-0 164 catch (AccessViolationException ex) 165 { 166 IsValid = false; 167 /*Note by Ben@exdream 2010-08-29: If this crashes with an AccessViolationException like this, make sure you have good Nvidia drivers, also see: http://www.opentk.com/node/946 and http://www.opentk.com/node/885 and http://www.opentk.com/node/1305 (last one is to make sure all project configurations are the same, x86 in our case) 16801:27.777 Warning: Fatal Error: Unhandled exception occurred (Application is terminated, we cannot recover!): System.Exception: Failed to create instance of Delta.Graphics.OpenTK.OpenTKGraphic ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 169C:\code\Delta\Graphics\OpenTK\Platform\Windows\Bindings\Wgl.cs(551,1): at OpenTK.Platform.Windows.Wgl.Arb.CreateContextAttribs(IntPtr hDC, IntPtr hShareContext, Int32[] attribList) 170C:\code\Delta\Graphics\OpenTK\Platform\Windows\WinGLContext.cs(113,1): at OpenTK.Platform.Windows.WinGLContext..ctor(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext, Int32 major, Int32 minor, GraphicsContextFlags flags) 171C:\code\Delta\Graphics\OpenTK\Platform\Windows\WinFactory.cs(53,1): at OpenTK.Platform.Windows.WinFactory.CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, Boolean directRendering, Int32 major, Int32 minor, GraphicsContextFlags flags) 172 */ 173 Application.Error( 174 "Fatal crash while trying to create the OpenTK graphics context. " + 175 "Make sure you have good Nvidia drivers, see OpenTK Bindings " + 176 "Wgl.cs:557 for details: ", ex); 177 } 178 #endregion 179 180 catch (Exception ex) 181 { 182 IsValid = false; 183 Application.Error("Unable to create a graphics context: ", ex); 184 } 185 } 186 #endregion 187 188 #region Methods (Private) 189 190 #region SwitchBlendMode 191 /// <summary> 192 /// Switches to the given blend mode (if it isn't active yet). 193 /// </summary> 194 protected override BlendMode SwitchBlendMode(BlendMode wishedBlendMode) 195 { 196 switch (wishedBlendMode) 197 { 198 case BlendMode.Opaque: 199 case BlendMode.AlphaTest: 200 sourceBlendMode = BlendingFactorSrc.Zero; 201 destinationBlendMode = BlendingFactorDest.Zero; 202 blendFunc = (BlendEquationMode)0; 203 204 //We do no non-shader rendering, so this is not required: 205 //GL.Enable(EnableCap.AlphaTest); 206 //Log.Warning("AlphaTest must always be implemented via shader"); 207 //okay, works fine in shader, but use Opaque too: break; 208 if (blendingEnabled) 209 { 210 blendingEnabled = false; 211 GL.Disable(EnableCap.Blend); 212 } 213 break; 214 215 case BlendMode.Subtractive: 216 if (blendingEnabled == false) 217 { 218 blendingEnabled = true; 219 GL.Enable(EnableCap.Blend); 220 } 221 // Pretty much the same as Additive, just subtracting 222 if (sourceBlendMode != BlendingFactorSrc.SrcAlpha || 223 destinationBlendMode != BlendingFactorDest.One) 224 { 225 sourceBlendMode = BlendingFactorSrc.SrcAlpha; 226 destinationBlendMode = BlendingFactorDest.One; 227 GL.BlendFunc(sourceBlendMode, destinationBlendMode); 228 } 229 if (blendFunc != BlendEquationMode.FuncReverseSubtract) 230 { 231 blendFunc = BlendEquationMode.FuncReverseSubtract; 232 GL.BlendEquation(blendFunc); 233 } 234 break; 235 236 case BlendMode.Additive: 237 if (blendingEnabled == false) 238 { 239 blendingEnabled = true; 240 GL.Enable(EnableCap.Blend); 241 } 242 if (sourceBlendMode != BlendingFactorSrc.SrcAlpha || 243 destinationBlendMode != BlendingFactorDest.One) 244 { 245 sourceBlendMode = BlendingFactorSrc.SrcAlpha; 246 destinationBlendMode = BlendingFactorDest.One; 247 GL.BlendFunc(sourceBlendMode, destinationBlendMode); 248 } 249 if (blendFunc != BlendEquationMode.FuncAdd) 250 { 251 blendFunc = BlendEquationMode.FuncAdd; 252 GL.BlendEquation(blendFunc); 253 } 254 break; 255 256 case BlendMode.Translucency: 257 if (blendingEnabled == false) 258 { 259 blendingEnabled = true; 260 GL.Enable(EnableCap.Blend); 261 } 262 if (sourceBlendMode != BlendingFactorSrc.SrcAlpha || 263 destinationBlendMode != BlendingFactorDest.OneMinusSrcAlpha) 264 { 265 sourceBlendMode = BlendingFactorSrc.SrcAlpha; 266 destinationBlendMode = BlendingFactorDest.OneMinusSrcAlpha; 267 GL.BlendFunc(sourceBlendMode, destinationBlendMode); 268 } 269 if (blendFunc != BlendEquationMode.FuncAdd) 270 { 271 blendFunc = BlendEquationMode.FuncAdd; 272 GL.BlendEquation(blendFunc); 273 } 274 break; 275 276 case BlendMode.LightEffect: 277 if (blendingEnabled == false) 278 { 279 blendingEnabled = true; 280 GL.Enable(EnableCap.Blend); 281 } 282 if (sourceBlendMode != BlendingFactorSrc.DstColor || 283 destinationBlendMode != BlendingFactorDest.One) 284 { 285 sourceBlendMode = BlendingFactorSrc.DstColor; 286 destinationBlendMode = BlendingFactorDest.One; 287 GL.BlendFunc(sourceBlendMode, destinationBlendMode); 288 } 289 if (blendFunc != BlendEquationMode.FuncAdd) 290 { 291 blendFunc = BlendEquationMode.FuncAdd; 292 GL.BlendEquation(blendFunc); 293 } 294 break; 295 } 296 297 return wishedBlendMode; 298 } 299 #endregion 300 301 #region SwitchBackFaceCulling 302 /// <summary> 303 /// Sets the back face culling on (do not render back faces) or off (no 304 /// culling, all faces are rendered, e.g. for debugging or wire-frames). 305 /// </summary> 306 protected override void SwitchBackFaceCulling(bool switchToOn) 307 { 308 if (switchToOn) 309 { 310 // Enable culling 311 GL.Enable(EnableCap.CullFace); 312 // In OpenGL Counter-clockwise is the default for front faces, like us 313 GL.CullFace(CullFaceMode.Back); 314 } 315 else 316 { 317 // Disable culling. 318 GL.Disable(EnableCap.CullFace); 319 // Show both front and back, no need to set cull face. 320 } 321 } 322 #endregion 323 324 #region SwitchDitheringAndNicestHints 325 /// <summary> 326 /// By default, OpenGL enables dither that could improve quality 327 /// but reduces performance. We want more performance by default. 328 /// Usually only has an effect in 565 RGB frame buffers on OpenGL ES 329 /// done here is to set the perspective correction hint to fastest 330 /// to tell the drive we want more performance, not a better look ^^ 331 /// </summary> 332 /// <param name="useDithering">True to turn on dithering (false on PC, 333 /// true on some mobile platforms).</param> 334 /// <param name="usePerspectiveCorrection"> 335 /// Use perspective correction? Usually always on (cost some performance). 336 /// </param> 337 /// <param name="otherHints"> 338 /// Nice look settings (usually the default values anyway) and false to 339 /// disable dithering and use fastest hints (usually false for slow 340 /// platforms). 341 /// </param> 342 protected override void SwitchDitheringAndNicestHints( 343 bool useDithering, bool usePerspectiveCorrection, bool otherHints) 344 { 345 if (useDithering) 346 { 347 GL.Enable(EnableCap.Dither); 348 } 349 else 350 { 351 GL.Disable(EnableCap.Dither); 352 } 353 } 354 #endregion 355 356 #endregion 357 } 358}