PageRenderTime 37ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

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