/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
- using System;
- using Delta.Engine;
- using Delta.Graphics.BaseOpenGL;
- using Delta.Utilities;
- using Delta.Utilities.Graphics;
- using OpenTK;
- using OpenTK.Graphics;
- using OpenTK.Graphics.OpenGL;
-
- namespace Delta.Graphics.OpenTK
- {
- /// <summary>
- /// OpenTKGraphic implementation using Delta.OpenTK (for Windows).
- /// Note: OpenTK spams a little info into the debug console.
- /// </summary>
- internal class OpenTKGraphic : BaseOpenGLGraphic
- {
- #region Private
-
- #region sourceBlendMode (Private)
- /// <summary>
- /// Source blend mode
- /// </summary>
- private BlendingFactorSrc sourceBlendMode = BlendingFactorSrc.Zero;
- #endregion
-
- #region destinationBlendMode (Private)
- /// <summary>
- /// Destination blend mode
- /// </summary>
- private BlendingFactorDest destinationBlendMode = BlendingFactorDest.Zero;
- #endregion
-
- #region blendFunc (Private)
- /// <summary>
- /// Blend function
- /// </summary>
- private BlendEquationMode blendFunc = BlendEquationMode.FuncAdd;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create graphic with parent
- /// </summary>
- protected OpenTKGraphic()
- : base("OpenTKGraphics")
- {
- // Register at the "device reseted" event to know when we have to renew
- // our (global) resources with the new graphic device handle
- //Core.Graphic.DeviceReset += new DeviceResetDelegate(RecreateResources);
- if (Settings.Extra.IsFullscreen)
- {
- DisplayResolution res = DisplayDevice.Default.SelectResolution(
- (int)Settings.Resolution.Width, (int)Settings.Resolution.Height,
- // Should be 32 bit and we do not care about the refresh rate!
- 32, 0);
- DisplayDevice.Default.ChangeResolution(res);
- if (res.Width != (int)Settings.Resolution.Width ||
- res.Height != (int)Settings.Resolution.Height)
- {
- Log.Info(
- "Sorry, resolution request failed! Could not find resolution: " +
- Settings.Resolution + ". Using this resolution instead " +
- "(probably the current one): " + res);
- }
- }
-
- try
- {
- glWindowInfo = WindowInfoHelper.Create(
- Application.Window.ViewportHandle);
-
- // Set wanted mode. Note: If given values are not valid, a default
- // mode (32bit) will be chosen, which is suboptimal.
- GraphicsMode mode = new GraphicsMode(new ColorFormat(8, 8, 8, 8),
- Settings.Extra.DepthBufferSize, 0,
- Settings.Extra.AntiAliasingSamples);
-
- graphicsDevice = new GraphicsContext(mode, glWindowInfo, 2, 0,
- GraphicsContextFlags.Default);
-
- graphicsDevice.MakeCurrent(glWindowInfo);
- graphicsDevice.LoadAll();
-
- // Set the graphic context in the Graphics namespace to make sure
- // resources can be created from now on.
- GraphicsContext = graphicsDevice;
-
- // Retrieve major and minor gl version number
- string[] version = GL.GetString(StringName.Version).Split('.');
- if (version.Length < 2 ||
- int.TryParse(version[0], out majorGLVersion) == false ||
- int.TryParse(version[1], out minorGLVersion) == false)
- {
- Log.Warning(
- "Failed to retrieve GL version from string: " +
- GL.GetString(StringName.Version) + ". Setting OpenGL version " +
- "to at least 2.0");
- if (majorGLVersion < 2)
- {
- majorGLVersion = 2;
- minorGLVersion = 0;
- }
- }
-
- GL.Viewport(0, 0, Application.Window.ViewportPixelWidth,
- Application.Window.ViewportPixelHeight);
- // Disable VSync to see the performance (we are over 60 fps anyway)
- graphicsDevice.VSync = false;
- if (Settings.Extra.UseDepthBuffer)
- {
- // Note: We don't need to create DepthBuffer as create above.
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Lequal);
- GL.DepthMask(true);
- // Note: Make sure to use the double version of ClearDepth here,
- // otherwise we are calling the OpenGL 4.1 version of ClearDepth
- // and that obviously only works on platforms that support it!
- GL.ClearDepth(1.0);
- }
- else
- {
- GL.Disable(EnableCap.DepthTest);
- GL.DepthMask(false);
- }
-
- if (Settings.Extra.UseAntiAliasing)
- {
- GL.Enable(EnableCap.PointSmooth);
- GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
- GL.Enable(EnableCap.LineSmooth);
- GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
- GL.Enable(EnableCap.Multisample);
- }
-
- // OpenGL greater than 2.0 does always support GLSL shaders
- if (majorGLVersion >= 2 ||
- (SupportsExtension("GL_ARB_shading_language_100") &&
- SupportsExtension("GL_ARB_shader_objects") &&
- SupportsExtension("GL_ARB_fragment_shader") &&
- SupportsExtension("GL_ARB_vertex_program")))
- {
- hasGpuShaderSupport = true;
- }
- else
- {
- hasGpuShaderSupport = false;
- }
-
- // Disable lighting
- GL.Disable(EnableCap.Lighting);
-
- // Finally call the "Device Reset" to make sure that all our
- // "render states" will set to the graphics device too
- // -> Note: This will "raise" the "DeviceReseted" event.
- ResetDevice();
- }
- #region AccessViolationException
- // Note: We cannot catch AccessViolationException directly anymore in
- // CLR 4.0, so this is handled in Factory.cs:600 too!
- // http://stackoverflow.com/questions/1626368/difference-between-clr-2-0-and-clr-4-0
- catch (AccessViolationException ex)
- {
- IsValid = false;
- /*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)
- 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.
- 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)
- 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)
- 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)
- */
- Application.Error(
- "Fatal crash while trying to create the OpenTK graphics context. " +
- "Make sure you have good Nvidia drivers, see OpenTK Bindings " +
- "Wgl.cs:557 for details: ", ex);
- }
- #endregion
-
- catch (Exception ex)
- {
- IsValid = false;
- Application.Error("Unable to create a graphics context: ", ex);
- }
- }
- #endregion
-
- #region Methods (Private)
-
- #region SwitchBlendMode
- /// <summary>
- /// Switches to the given blend mode (if it isn't active yet).
- /// </summary>
- protected override BlendMode SwitchBlendMode(BlendMode wishedBlendMode)
- {
- switch (wishedBlendMode)
- {
- case BlendMode.Opaque:
- case BlendMode.AlphaTest:
- sourceBlendMode = BlendingFactorSrc.Zero;
- destinationBlendMode = BlendingFactorDest.Zero;
- blendFunc = (BlendEquationMode)0;
-
- //We do no non-shader rendering, so this is not required:
- //GL.Enable(EnableCap.AlphaTest);
- //Log.Warning("AlphaTest must always be implemented via shader");
- //okay, works fine in shader, but use Opaque too: break;
- if (blendingEnabled)
- {
- blendingEnabled = false;
- GL.Disable(EnableCap.Blend);
- }
- break;
-
- case BlendMode.Subtractive:
- if (blendingEnabled == false)
- {
- blendingEnabled = true;
- GL.Enable(EnableCap.Blend);
- }
- // Pretty much the same as Additive, just subtracting
- if (sourceBlendMode != BlendingFactorSrc.SrcAlpha ||
- destinationBlendMode != BlendingFactorDest.One)
- {
- sourceBlendMode = BlendingFactorSrc.SrcAlpha;
- destinationBlendMode = BlendingFactorDest.One;
- GL.BlendFunc(sourceBlendMode, destinationBlendMode);
- }
- if (blendFunc != BlendEquationMode.FuncReverseSubtract)
- {
- blendFunc = BlendEquationMode.FuncReverseSubtract;
- GL.BlendEquation(blendFunc);
- }
- break;
-
- case BlendMode.Additive:
- if (blendingEnabled == false)
- {
- blendingEnabled = true;
- GL.Enable(EnableCap.Blend);
- }
- if (sourceBlendMode != BlendingFactorSrc.SrcAlpha ||
- destinationBlendMode != BlendingFactorDest.One)
- {
- sourceBlendMode = BlendingFactorSrc.SrcAlpha;
- destinationBlendMode = BlendingFactorDest.One;
- GL.BlendFunc(sourceBlendMode, destinationBlendMode);
- }
- if (blendFunc != BlendEquationMode.FuncAdd)
- {
- blendFunc = BlendEquationMode.FuncAdd;
- GL.BlendEquation(blendFunc);
- }
- break;
-
- case BlendMode.Translucency:
- if (blendingEnabled == false)
- {
- blendingEnabled = true;
- GL.Enable(EnableCap.Blend);
- }
- if (sourceBlendMode != BlendingFactorSrc.SrcAlpha ||
- destinationBlendMode != BlendingFactorDest.OneMinusSrcAlpha)
- {
- sourceBlendMode = BlendingFactorSrc.SrcAlpha;
- destinationBlendMode = BlendingFactorDest.OneMinusSrcAlpha;
- GL.BlendFunc(sourceBlendMode, destinationBlendMode);
- }
- if (blendFunc != BlendEquationMode.FuncAdd)
- {
- blendFunc = BlendEquationMode.FuncAdd;
- GL.BlendEquation(blendFunc);
- }
- break;
-
- case BlendMode.LightEffect:
- if (blendingEnabled == false)
- {
- blendingEnabled = true;
- GL.Enable(EnableCap.Blend);
- }
- if (sourceBlendMode != BlendingFactorSrc.DstColor ||
- destinationBlendMode != BlendingFactorDest.One)
- {
- sourceBlendMode = BlendingFactorSrc.DstColor;
- destinationBlendMode = BlendingFactorDest.One;
- GL.BlendFunc(sourceBlendMode, destinationBlendMode);
- }
- if (blendFunc != BlendEquationMode.FuncAdd)
- {
- blendFunc = BlendEquationMode.FuncAdd;
- GL.BlendEquation(blendFunc);
- }
- break;
- }
-
- return wishedBlendMode;
- }
- #endregion
-
- #region SwitchBackFaceCulling
- /// <summary>
- /// Sets the back face culling on (do not render back faces) or off (no
- /// culling, all faces are rendered, e.g. for debugging or wire-frames).
- /// </summary>
- protected override void SwitchBackFaceCulling(bool switchToOn)
- {
- if (switchToOn)
- {
- // Enable culling
- GL.Enable(EnableCap.CullFace);
- // In OpenGL Counter-clockwise is the default for front faces, like us
- GL.CullFace(CullFaceMode.Back);
- }
- else
- {
- // Disable culling.
- GL.Disable(EnableCap.CullFace);
- // Show both front and back, no need to set cull face.
- }
- }
- #endregion
-
- #region SwitchDitheringAndNicestHints
- /// <summary>
- /// By default, OpenGL enables dither that could improve quality
- /// but reduces performance. We want more performance by default.
- /// Usually only has an effect in 565 RGB frame buffers on OpenGL ES
- /// done here is to set the perspective correction hint to fastest
- /// to tell the drive we want more performance, not a better look ^^
- /// </summary>
- /// <param name="useDithering">True to turn on dithering (false on PC,
- /// true on some mobile platforms).</param>
- /// <param name="usePerspectiveCorrection">
- /// Use perspective correction? Usually always on (cost some performance).
- /// </param>
- /// <param name="otherHints">
- /// Nice look settings (usually the default values anyway) and false to
- /// disable dithering and use fastest hints (usually false for slow
- /// platforms).
- /// </param>
- protected override void SwitchDitheringAndNicestHints(
- bool useDithering, bool usePerspectiveCorrection, bool otherHints)
- {
- if (useDithering)
- {
- GL.Enable(EnableCap.Dither);
- }
- else
- {
- GL.Disable(EnableCap.Dither);
- }
- }
- #endregion
-
- #endregion
- }
- }