PageRenderTime 42ms CodeModel.GetById 32ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/Graphics/OpenTK/OpenTKGraphic.cs

#
C# | 358 lines | 252 code | 29 blank | 77 comment | 43 complexity | 2117d77d09e87c5324a276b6b3d541c9 MD5 | raw file
  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}