/Graphics/Basics/Shader.cs
C# | 208 lines | 113 code | 21 blank | 74 comment | 21 complexity | 2f890bfa168e653cc0559071d7b56923 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.Collections.Generic;
- using Delta.ContentSystem.Rendering;
- using Delta.Engine.Dynamic;
- using Delta.Utilities;
- using Delta.Utilities.Graphics.ShaderFeatures;
-
- namespace Delta.Graphics.Basics
- {
- /// <summary>
- /// Shader base class, defines all the public methods we can call from the
- /// outside, mostly done from the material class or some render classes.
- /// Most importantly each platform implements all the platform dependant
- /// render code (which can be both fixed function or shader based if the
- /// hardware supports it).
- /// <para />
- /// You can use this class to extend shader functionality for all platforms.
- /// If you just change OpenTKShader, your game will not be able to use that
- /// changes on any other graphic platform.
- /// <para />
- /// Note: Please check the wiki for help and ask in the forum on how to
- /// extend the Shader class and add more uniforms and features.
- /// </summary>
- public abstract class Shader : BaseShader
- {
- #region Create (Static)
- /// <summary>
- /// Create shader from the shader content name if that is known. Note that
- /// there is also a Create overload just from the shader feature flags.
- /// </summary>
- /// <param name="shaderName">Shader content name</param>
- /// <returns>Shader</returns>
- public static Shader Create(string shaderName)
- {
- if (String.IsNullOrEmpty(shaderName))
- {
- // Use the flags Create method instead!
- return Create(ShaderFeatureFlags.Basic);
- }
-
- if (shaderCache == null)
- {
- shaderCache = new Dictionary<string, Shader>(
- StringComparer.InvariantCultureIgnoreCase);
- shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
-
- // Make sure that every shader gets reloaded with the new internal
- // graphics device handle), every time that the device is reseted.
- Graphic.DeviceReset += shaderCache.Clear;
- Graphic.DeviceReset += shaderFlagsCache.Clear;
- }
-
- // Before we try to load the new shader, we look at first if we have it
- // already in the shader cache
- if (shaderCache.ContainsKey(shaderName))
- {
- // if we already have it, then just return the shader from the cache
- return shaderCache[shaderName];
- }
-
- // Else if we haven't it loaded yet, then do it now
- Shader loadedShader = Factory.Create<Shader>(shaderName);
- if (loadedShader == null)
- {
- Log.Warning("Graphic.CreateShader: The shader '" + shaderName +
- "' couldn't be loaded, the shader type was not found.");
- return null;
- }
-
- // Add it to the (global) shader cache
- if (shaderCache.ContainsKey(shaderName) == false)
- {
- shaderCache.Add(shaderName, loadedShader);
- if (shaderCache.Count > 75)
- {
- Log.Warning("The shader cache got bigger than 75 entries! " +
- "Please dispose some unused shaders (make sure to dispose " +
- "scenes as well to get rid of content).");
- }
- }
- // And make sure it exists in the shader flags cache as well
- if (shaderFlagsCache.ContainsKey(loadedShader.Flags) == false)
- {
- shaderFlagsCache.Add(loadedShader.Flags, loadedShader);
- if (shaderFlagsCache.Count > 75)
- {
- Log.Warning("The shader flags cache got bigger than 75 entries! " +
- "Please dispose some unused shaders (make sure to dispose " +
- "scenes as well to get rid of content).");
- }
- }
-
- // And return it finally
- return loadedShader;
- }
- #endregion
-
- #region Private
-
- #region shaderCache (Private)
- /// <summary>
- /// Global shader cache, makes sure that every shader is only loaded once.
- /// </summary>
- private static Dictionary<string, Shader> shaderCache;
- #endregion
-
- #region shaderFlagsCache (Private)
- /// <summary>
- /// Global shader flags cache, makes sure that every dynamically requested
- /// shader via shader flags is only loaded once.
- /// </summary>
- private static Dictionary<ShaderFeatureFlags, Shader> shaderFlagsCache;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Creates a base shader, this constructor will grab the ShaderData and
- /// then setup the native shader objects (the graphics device needs to be
- /// up). When the device is lost or the window gets resized the matrices
- /// are updated, we reload everything and grab the shader parameters again.
- /// The Load method also checks if we are loading the same shader again
- /// and caches the results, so we never create two instances of the same
- /// shader! If we do a warning is outputted to prevent bad performance
- /// of using multiple shaders with the exact same internal data.
- /// </summary>
- /// <param name="setShaderName">Set shader name for loading the ShaderData
- /// from the content system, which is used to create the shader</param>
- protected Shader(string setShaderName)
- : base(ShaderData.Get(setShaderName))
- {
- }
-
- /// <summary>
- /// Create shader from shader flags instead of the content name.
- /// </summary>
- /// <param name="setShaderFlags">Shader flags to search for a shader
- /// content entry with this flags</param>
- protected Shader(ShaderFeatureFlags setShaderFlags)
- : base(ShaderData.Get(setShaderFlags))
- {
- }
- #endregion
-
- #region Methods (Private)
-
- #region Create
- /// <summary>
- /// Create shader dynamically from shader flags. Will just return the
- /// first shader we can find from the content system that uses those flags.
- /// For more control use the Create method with the shader content name!
- /// Note: Only allowed internally for fallback, normally in applications
- /// shaders are created by the MaterialData.ShaderName string value!
- /// </summary>
- /// <param name="shaderFlags">Shader flags combination</param>
- /// <returns>Shader we found that matches this flags</returns>
- internal static Shader Create(ShaderFeatureFlags shaderFlags)
- {
- if (shaderCache == null)
- {
- shaderCache = new Dictionary<string, Shader>(
- StringComparer.InvariantCultureIgnoreCase);
- shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
-
- // Make sure that every shader gets reloaded with the new internal
- // graphics device handle), every time that the device is reseted.
- //wrong: Graphic.DeviceReset += shaderCache.Clear;
- //wrong: Graphic.DeviceReset += shaderFlagsCache.Clear;
- }
-
- // Before we try to load the new shader, we look at first if we have it
- // already in the shader cache
- if (shaderFlagsCache.ContainsKey(shaderFlags))
- {
- // if we already have it, then just return the shader from the cache
- return shaderFlagsCache[shaderFlags];
- }
-
- // Else if we haven't it loaded yet, then do it now
- Shader loadedShader = Factory.Create<Shader>(shaderFlags);
- if (loadedShader == null)
- {
- Log.Warning("Shader.Create: The shader with the flags '" +
- shaderFlags + "' couldn't be loaded, it was not found.");
- return null;
- }
-
- // Add it the shader flags cache
- if (shaderFlagsCache.ContainsKey(shaderFlags) == false)
- {
- shaderFlagsCache.Add(shaderFlags, loadedShader);
- }
- // Add it to the global shader name cache as well
- string shaderKey = loadedShader.Name;
- if (shaderCache.ContainsKey(shaderKey) == false)
- {
- shaderCache.Add(shaderKey, loadedShader);
- }
-
- // And return it finally
- return loadedShader;
- }
- #endregion
-
- #endregion
- }
- }