PageRenderTime 252ms CodeModel.GetById 100ms app.highlight 7ms RepoModel.GetById 101ms app.codeStats 0ms

/Graphics/Basics/Shader.cs

#
C# | 208 lines | 113 code | 21 blank | 74 comment | 21 complexity | 2f890bfa168e653cc0559071d7b56923 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using Delta.ContentSystem.Rendering;
  4using Delta.Engine.Dynamic;
  5using Delta.Utilities;
  6using Delta.Utilities.Graphics.ShaderFeatures;
  7
  8namespace Delta.Graphics.Basics
  9{
 10	/// <summary>
 11	/// Shader base class, defines all the public methods we can call from the
 12	/// outside, mostly done from the material class or some render classes.
 13	/// Most importantly each platform implements all the platform dependant
 14	/// render code (which can be both fixed function or shader based if the
 15	/// hardware supports it).
 16	/// <para />
 17	/// You can use this class to extend shader functionality for all platforms.
 18	/// If you just change OpenTKShader, your game will not be able to use that
 19	/// changes on any other graphic platform.
 20	/// <para />
 21	/// Note: Please check the wiki for help and ask in the forum on how to
 22	/// extend the Shader class and add more uniforms and features.
 23	/// </summary>
 24	public abstract class Shader : BaseShader
 25	{
 26		#region Create (Static)
 27		/// <summary>
 28		/// Create shader from the shader content name if that is known. Note that
 29		/// there is also a Create overload just from the shader feature flags.
 30		/// </summary>
 31		/// <param name="shaderName">Shader content name</param>
 32		/// <returns>Shader</returns>
 33		public static Shader Create(string shaderName)
 34		{
 35			if (String.IsNullOrEmpty(shaderName))
 36			{
 37				// Use the flags Create method instead!
 38				return Create(ShaderFeatureFlags.Basic);
 39			}
 40
 41			if (shaderCache == null)
 42			{
 43				shaderCache = new Dictionary<string, Shader>(
 44					StringComparer.InvariantCultureIgnoreCase);
 45				shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
 46
 47				// Make sure that every shader gets reloaded with the new internal
 48				// graphics device handle), every time that the device is reseted.
 49				Graphic.DeviceReset += shaderCache.Clear;
 50				Graphic.DeviceReset += shaderFlagsCache.Clear;
 51			}
 52
 53			// Before we try to load the new shader, we look at first if we have it
 54			// already in the shader cache
 55			if (shaderCache.ContainsKey(shaderName))
 56			{
 57				// if we already have it, then just return the shader from the cache
 58				return shaderCache[shaderName];
 59			}
 60
 61			// Else if we haven't it loaded yet, then do it now
 62			Shader loadedShader = Factory.Create<Shader>(shaderName);
 63			if (loadedShader == null)
 64			{
 65				Log.Warning("Graphic.CreateShader: The shader '" + shaderName +
 66				            "' couldn't be loaded, the shader type was not found.");
 67				return null;
 68			}
 69
 70			// Add it to the (global) shader cache
 71			if (shaderCache.ContainsKey(shaderName) == false)
 72			{
 73				shaderCache.Add(shaderName, loadedShader);
 74				if (shaderCache.Count > 75)
 75				{
 76					Log.Warning("The shader cache got bigger than 75 entries! " +
 77					            "Please dispose some unused shaders (make sure to dispose " +
 78					            "scenes as well to get rid of content).");
 79				}
 80			}
 81			// And make sure it exists in the shader flags cache as well
 82			if (shaderFlagsCache.ContainsKey(loadedShader.Flags) == false)
 83			{
 84				shaderFlagsCache.Add(loadedShader.Flags, loadedShader);
 85				if (shaderFlagsCache.Count > 75)
 86				{
 87					Log.Warning("The shader flags cache got bigger than 75 entries! " +
 88					            "Please dispose some unused shaders (make sure to dispose " +
 89					            "scenes as well to get rid of content).");
 90				}
 91			}
 92
 93			// And return it finally
 94			return loadedShader;
 95		}
 96		#endregion
 97
 98		#region Private
 99
100		#region shaderCache (Private)
101		/// <summary>
102		/// Global shader cache, makes sure that every shader is only loaded once.
103		/// </summary>
104		private static Dictionary<string, Shader> shaderCache;
105		#endregion
106
107		#region shaderFlagsCache (Private)
108		/// <summary>
109		/// Global shader flags cache, makes sure that every dynamically requested
110		/// shader via shader flags is only loaded once.
111		/// </summary>
112		private static Dictionary<ShaderFeatureFlags, Shader> shaderFlagsCache;
113		#endregion
114
115		#endregion
116
117		#region Constructors
118		/// <summary>
119		/// Creates a base shader, this constructor will grab the ShaderData and
120		/// then setup the native shader objects (the graphics device needs to be
121		/// up). When the device is lost or the window gets resized the matrices
122		/// are updated, we reload everything and grab the shader parameters again.
123		/// The Load method also checks if we are loading the same shader again
124		/// and caches the results, so we never create two instances of the same
125		/// shader! If we do a warning is outputted to prevent bad performance
126		/// of using multiple shaders with the exact same internal data.
127		/// </summary>
128		/// <param name="setShaderName">Set shader name for loading the ShaderData
129		/// from the content system, which is used to create the shader</param>
130		protected Shader(string setShaderName)
131			: base(ShaderData.Get(setShaderName))
132		{
133		}
134
135		/// <summary>
136		/// Create shader from shader flags instead of the content name.
137		/// </summary>
138		/// <param name="setShaderFlags">Shader flags to search for a shader
139		/// content entry with this flags</param>
140		protected Shader(ShaderFeatureFlags setShaderFlags)
141			: base(ShaderData.Get(setShaderFlags))
142		{
143		}
144		#endregion
145
146		#region Methods (Private)
147
148		#region Create
149		/// <summary>
150		/// Create shader dynamically from shader flags. Will just return the
151		/// first shader we can find from the content system that uses those flags.
152		/// For more control use the Create method with the shader content name!
153		/// Note: Only allowed internally for fallback, normally in applications
154		/// shaders are created by the MaterialData.ShaderName string value!
155		/// </summary>
156		/// <param name="shaderFlags">Shader flags combination</param>
157		/// <returns>Shader we found that matches this flags</returns>
158		internal static Shader Create(ShaderFeatureFlags shaderFlags)
159		{
160			if (shaderCache == null)
161			{
162				shaderCache = new Dictionary<string, Shader>(
163					StringComparer.InvariantCultureIgnoreCase);
164				shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
165
166				// Make sure that every shader gets reloaded with the new internal
167				// graphics device handle), every time that the device is reseted.
168				//wrong: Graphic.DeviceReset += shaderCache.Clear;
169				//wrong: Graphic.DeviceReset += shaderFlagsCache.Clear;
170			}
171
172			// Before we try to load the new shader, we look at first if we have it
173			// already in the shader cache
174			if (shaderFlagsCache.ContainsKey(shaderFlags))
175			{
176				// if we already have it, then just return the shader from the cache
177				return shaderFlagsCache[shaderFlags];
178			}
179
180			// Else if we haven't it loaded yet, then do it now
181			Shader loadedShader = Factory.Create<Shader>(shaderFlags);
182			if (loadedShader == null)
183			{
184				Log.Warning("Shader.Create: The shader with the flags '" +
185				            shaderFlags + "' couldn't be loaded, it was not found.");
186				return null;
187			}
188
189			// Add it the shader flags cache
190			if (shaderFlagsCache.ContainsKey(shaderFlags) == false)
191			{
192				shaderFlagsCache.Add(shaderFlags, loadedShader);
193			}
194			// Add it to the global shader name cache as well
195			string shaderKey = loadedShader.Name;
196			if (shaderCache.ContainsKey(shaderKey) == false)
197			{
198				shaderCache.Add(shaderKey, loadedShader);
199			}
200
201			// And return it finally
202			return loadedShader;
203		}
204		#endregion
205
206		#endregion
207	}
208}