topical media & game development

talk show tell print

game-xna-intro-XnaGraphicEngineChapter6-Shaders-ShaderEffect.cs / cs



  // Project: XnaGraphicEngine, File: ShaderEffect.cs
  // Namespace: XnaGraphicEngine.Shaders, Class: ShaderEffect
  // Path: C:\code\XnaGraphicEngine\Shaders, Author: Abi
  // Code lines: 904, Size of file: 24,94 KB
  // Creation date: 07.09.2006 05:56
  // Last modified: 05.11.2006 00:32
  // Generated with Commenter by abi.exDream.com
  
  #region Using directives
  if DEBUG
  //using NUnit.Framework;
  endif
  using Microsoft.Xna.Framework;
  using Microsoft.Xna.Framework.Graphics;
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Text;
  using XnaGraphicEngine.Graphics;
  using XnaGraphicEngine.Helpers;
  using Texture = XnaGraphicEngine.Graphics.Texture;
  using XnaTexture = Microsoft.Xna.Framework.Graphics.Texture;
  using XnaGraphicEngine.Game;
  #endregion
  
  namespace XnaGraphicEngine.Shaders
  {
  
<summary> Shader effect class. You can either directly use this class by providing a fx filename in the constructor or derive from this class for special shader functionality (see post screen shaders for a more complex example). </summary> public class ShaderEffect : IGraphicContent { #region Some shaders <summary> Line rendering shader </summary> public static ShaderEffect lineRendering = new ShaderEffect("LineRendering.fx"); #endregion

                  #region Variables
  
<summary> Content name for this shader </summary> private string shaderContentName = "";

  
<summary> Effect </summary> protected Effect effect = null; <summary> Effect handles for shaders. </summary> protected EffectParameter worldViewProj; #endregion

                  #region Properties
  
<summary> Is this shader valid to render? If not we can't perform any rendering. </summary> <returns>Bool</returns> public bool Valid { get { return effect != null; } // get } // Valid

  
<summary> Effect </summary> <returns>Effect</returns> public Effect Effect { get { return effect; } // get } // Effect

  
<summary> Number of techniques </summary> <returns>Int</returns> public int NumberOfTechniques { get { return effect.Techniques.Count; } // get } // NumberOfTechniques

  
<summary> Get technique </summary> <param name="techniqueName">Technique name</param> <returns>Effect technique</returns> public EffectTechnique GetTechnique(string techniqueName) { return effect.Techniques[techniqueName]; } // GetTechnique(techniqueName)

  
<summary> Set value helper to set an effect parameter. </summary> <param name="param">Param</param> <param name="setMatrix">Set matrix</param> private void SetValue(EffectParameter param, ref Matrix lastUsedMatrix, Matrix newMatrix) { /*obs, always update, matrices change every frame anyway! matrix compare takes too long, it eats up almost 50% of this method. if (param != null && lastUsedMatrix != newMatrix)

  
                          {
                                  lastUsedMatrix = newMatrix;
                                  param.SetValue(newMatrix);
                          } // if (param)
                  } // SetValue(param, setMatrix)
  
  
<summary> Set value helper to set an effect parameter. </summary> <param name="param">Param</param> <param name="lastUsedVector">Last used vector</param> <param name="newVector">New vector</param> private void SetValue(EffectParameter param, ref Vector3 lastUsedVector, Vector3 newVector) { if (param != null && lastUsedVector != newVector) { lastUsedVector = newVector; param.SetValue(newVector); } // if (param) } // SetValue(param, lastUsedVector, newVector)

  
<summary> Set value helper to set an effect parameter. </summary> <param name="param">Param</param> <param name="lastUsedColor">Last used color</param> <param name="newColor">New color</param> private void SetValue(EffectParameter param, ref Color lastUsedColor, Color newColor) { // Note: This check eats few % of the performance, but the color // often stays the change (around 50%). if (param != null && //slower: lastUsedColor != newColor) lastUsedColor.PackedValue != newColor.PackedValue) { lastUsedColor = newColor; //obs: param.SetValue(ColorHelper.ConvertColorToVector4(newColor)); param.SetValue(newColor.ToVector4()); } // if (param) } // SetValue(param, lastUsedColor, newColor)

  
<summary> Set value helper to set an effect parameter. </summary> <param name="param">Param</param> <param name="lastUsedValue">Last used value</param> <param name="newValue">New value</param> private void SetValue(EffectParameter param, ref float lastUsedValue, float newValue) { if (param != null && lastUsedValue != newValue) { lastUsedValue = newValue; param.SetValue(newValue); } // if (param) } // SetValue(param, lastUsedValue, newValue)

  
<summary> Set value helper to set an effect parameter. </summary> <param name="param">Param</param> <param name="lastUsedValue">Last used value</param> <param name="newValue">New value</param> private void SetValue(EffectParameter param, ref XnaTexture lastUsedValue, XnaTexture newValue) { if (param != null && lastUsedValue != newValue) { lastUsedValue = newValue; param.SetValue(newValue); } // if (param) } // SetValue(param, lastUsedValue, newValue)

                  protected Matrix lastUsedWorldViewProjMatrix = Matrix.Identity;
  
<summary> Set world view proj matrix </summary> protected Matrix WorldViewProjMatrix { set { SetValue(worldViewProj, ref lastUsedWorldViewProjMatrix, value); } // set } // WorldViewProjMatrix #endregion

                  #region Constructor
                  public ShaderEffect(string shaderName)
                  {
                          if (BaseGame.Device == null)
                                  throw new NullReferenceException(
                                          "XNA device is not initialized, can't create ShaderEffect.");
  
                          shaderContentName = StringHelper.ExtractFilename(shaderName, true);
  
                          Load();
  
                          BaseGame.RegisterGraphicContentObject(this);
                  } // SimpleShader()
                  #endregion
  
                  #region Dispose
  
<summary> Dispose </summary> public virtual void Dispose() { // Dispose shader effect if (effect != null) effect.Dispose(); } // Dispose() #endregion

                  #region Reload effect
  
<summary> Reload effect (can be useful if we change the fx file dynamically). </summary> public void Load() { /*obs // Dispose old shader if (effect != null) Dispose();

  
  
                          // Load shader
                          try
                          {
                                  // We have to try, there is no "Exists" method.
                                  // We could try to check the xnb filename, but why bother? ^^
                                  effect = BaseGame.Content.Load<Effect>(
                                          Path.Combine(Directories.ContentDirectory, shaderContentName));
                          } // try
  if XBOX360
                          catch (Exception ex)
                          {
                                  Log.Write("Failed to load shader "+shaderContentName+". " +
                                          "Error: " + ex.ToString());
                                  // Rethrow error, app can't continue!
                                  throw ex;
                          }
  else
                          catch
                          {
                                  // Try again by loading by filename (only allowed for windows!)
                                  // Content file was most likely removed for easier testing :)
                                  try
                                  {
                                          CompiledEffect compiledEffect = Effect.CompileEffectFromFile(
                                                  Path.Combine("Shaders", shaderContentName + ".fx"),
                                                  null, null, CompilerOptions.None,
                                                  TargetPlatform.Windows);
  
                                          effect = new Effect(BaseGame.Device,
                                                  compiledEffect.GetEffectCode(), CompilerOptions.None, null);
                                  } // try
                                  catch (Exception ex)
                                  {
                                          Log.Write("Failed to load shader "+shaderContentName+". " +
                                                  "Error: " + ex.ToString());
                                          // Rethrow error, app can't continue!
                                          throw ex;
                                  } // catch
                          } // catch
  endif
  
                          GetParameters();
                  } // Reload()
                  #endregion
  
                  #region Get parameters
  
<summary> Get parameters, override to support more </summary> protected virtual void GetParameters() { worldViewProj = effect.Parameters["worldViewProj"]; } // GetParameters() #endregion

                  #region SetParameters
  
<summary> Set parameters, override to set more </summary> public virtual void SetParameters() { if (worldViewProj != null) worldViewProj.SetValue(BaseGame.WorldViewProjectionMatrix); } // SetParameters() #endregion

                  #region Update
  
<summary> Update </summary> public void Update() { effect.CommitChanges(); } // Update() #endregion

                  #region Render
  
<summary> Render </summary> <param name="techniqueName">Technique name</param> <param name="renderDelegate">Render delegate</param> public void Render(string techniqueName, BaseGame.RenderDelegate renderDelegate) { SetParameters();

                          /*will become important later in the book.
                          // Can we do the requested technique?
                          // For graphic cards not supporting ps2.0, fall back to ps1.1
                          if (BaseGame.CanUsePS20 == false &&
                                  techniqueName.EndsWith("20"))
                                  // Use same technique without the 20 ending!
                                  techniqueName = techniqueName.Substring(0, techniqueName.Length - 2);
  			 */
  
                          // Start shader
                          effect.CurrentTechnique = effect.Techniques[techniqueName];
                          effect.Begin(SaveStateMode.None);
  
                          // Render all passes (usually just one)
                          //foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                          for (int num = 0; num < effect.CurrentTechnique.Passes.Count; num++)
                          {
                                  EffectPass pass = effect.CurrentTechnique.Passes[num];
  
                                  pass.Begin();
                                  renderDelegate();
                                  pass.End();
                          } // foreach (pass)
  
                          // End shader
                          effect.End();
                  } // Render(passName, renderDelegate)
                  #endregion
  
                  #region Render single pass shader
  
<summary> Render single pass shader, little faster and simpler than Render and it just uses the current technique and renderes only the first pass (most shaders have only 1 pass anyway). Used for MeshRenderManager! </summary> <param name="renderDelegate">Render delegate</param> public void RenderSinglePassShader( BaseGame.RenderDelegate renderDelegate) { // Start effect (current technique should be set) effect.Begin(SaveStateMode.None); // Start first pass effect.CurrentTechnique.Passes[0].Begin();

                          // Render
                          renderDelegate();
  
                          // End pass and shader
                          effect.CurrentTechnique.Passes[0].End();
                          effect.End();
                  } // RenderSinglePassShader(renderDelegate)
                  #endregion
          } // class ShaderEffect
  } // namespace XnaGraphicEngine.Shaders
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.