Technique.cs :  » Game » RealmForge » Axiom » Graphics » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Game » RealmForge 
RealmForge » Axiom » Graphics » Technique.cs
#region LGPL License
/*
Axiom Game Engine Library
Copyright (C) 2003  Axiom Project Team

The overall design, and a majority of the core engine and rendering code 
contained within this library is a derivative of the open source Object Oriented 
Graphics Engine OGRE, which can be found at http://ogre.sourceforge.net.  
Many thanks to the OGRE team for maintaining such a high quality project.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#endregion

using System;
using System.Collections;
using System.Diagnostics;
using Axiom.Core;

namespace Axiom.Graphics{
  /// <summary>
  ///   Class representing an approach to rendering a particular Material. 
  /// </summary>
  /// <remarks>
  ///    The engine will attempt to use the best technique supported by the active hardware, 
  ///    unless you specifically request a lower detail technique (say for distant rendering)
  /// </remarks>
  public class Technique {
    #region Fields

    /// <summary>
    ///    The material that owns this technique.
    /// </summary>
    protected Material parent;
    /// <summary>
    ///    The list of passes (fixed function or programmable) contained in this technique.
    /// </summary>
    protected PassList passes = new PassList();
    /// <summary>
    ///    List of derived passes, categorized (and ordered) into illumination stages.
    /// </summary>
    protected ArrayList illuminationPasses = new ArrayList();
    /// <summary>
    ///    Flag that states whether or not this technique is supported on the current hardware.
    /// </summary>
    protected bool isSupported;
    /// <summary>
    ///    Name of this technique.
    /// </summary>
    protected string name;
    /// <summary>
    ///    Level of detail index for this technique.
    /// </summary>
    protected int lodIndex;
    
    #endregion
    
    #region Constructors
    
    public Technique(Material parent) {
      this.parent = parent;
    }
    
    #endregion
    
    #region Methods

    /// <summary>
    ///    Internal method for clearing the illumination pass list.
    /// </summary>
    protected void ClearIlluminationPasses() {
      for(int i = 0; i < illuminationPasses.Count; i++) {
        IlluminationPass iPass = (IlluminationPass)illuminationPasses[i];

        if(iPass.DestroyOnShutdown) {
          iPass.Pass.QueueForDeletion();
        }
      }

      illuminationPasses.Clear();
    }

    /// <summary>
    ///    Clones this Technique.
    /// </summary>
    /// <param name="parent">Material that will own this technique.</param>
    /// <returns></returns>
    public Technique Clone(Material parent) {
      Technique newTechnique = new Technique(parent);

      CopyTo(newTechnique);

      return newTechnique;
    }

    /// <summary>
    ///    Copy the details of this Technique to another.
    /// </summary>
    /// <param name="target"></param>
    public void CopyTo(Technique target) {
      target.isSupported = isSupported;
      target.lodIndex = lodIndex;

      target.RemoveAllPasses();

      // clone each pass and add that to the new technique
      for(int i = 0; i < passes.Count; i++) {
        Pass pass = (Pass)passes[i];
        Pass newPass = pass.Clone(target, pass.Index);
        target.passes.Add(newPass);
      }

      // recompile illumination passes
      target.CompileIlluminationPasses();
    }

    /// <summary>
    ///    Compilation method for Techniques.  See <see cref="Axiom.Core.Material"/>
    /// </summary>
    /// <param name="autoManageTextureUnits">
    ///    Determines whether or not the engine should split up extra texture unit requests
    ///    into extra passes if the hardware does not have enough available units.
    /// </param>
    internal void Compile(bool autoManageTextureUnits) {
      // assume not supported unles it proves otherwise
      isSupported = false;    
                
      // grab a ref to the current hardware caps
      HardwareCaps caps = Root.Instance.RenderSystem.Caps;
      int numAvailTexUnits = caps.TextureUnitCount;

      // check requirements for each pass
      for(int i = 0; i < passes.Count; i++) {
        Pass pass = (Pass)passes[i];

        int numTexUnitsRequested = pass.NumTextureUnitStages;

        if(pass.HasFragmentProgram) {
          // check texture units
          if(numTexUnitsRequested > numAvailTexUnits) {
            // can't do this, since programmable passes cannot be split automatically
            return;
          }

          // check fragment program version
          if(!pass.FragmentProgram.IsSupported) {
            // can't do this one
            return;
          }
        }
        else {
          // check support for a few fixed function options while we are here
          for(int j = 0; j < pass.NumTextureUnitStages; j++) {
            TextureUnitState texUnit = pass.GetTextureUnitState(j);

            // check to make sure we have some cube mapping support
            if(texUnit.Is3D && !caps.CheckCap(Capabilities.CubeMapping)) {
              return;
            }

            // if this is a Dot3 blending layer, make sure we can support it
            if(texUnit.ColorBlendMode.operation == LayerBlendOperationEx.DotProduct && !caps.CheckCap(Capabilities.Dot3)) {
              return;
            }
          }

          // keep splitting until the texture units required for this pass are available
          while(numTexUnitsRequested > numAvailTexUnits) {
            // split this pass up into more passes
            pass = pass.Split(numAvailTexUnits);
            numTexUnitsRequested = pass.NumTextureUnitStages;
          }
        }

        // if this has a vertex program, check the syntax code to be sure the hardware supports it
        if(pass.HasVertexProgram) {
          // check vertex program version
          if(!pass.VertexProgram.IsSupported) {
            // can't do this one
            return;
          }
        }
      } // for

      // if we made it this far, we are good to go!
      isSupported = true;

      // Now compile for categorised illumination, in case we need it later
      CompileIlluminationPasses();
    }

    /// <summary>
    ///    Internal method for splitting the passes into illumination passes.
    /// </summary>
    public void CompileIlluminationPasses() {
      ClearIlluminationPasses();

      // don't need to split transparent passes since they are rendered seperately
      if(this.IsTransparent) {
        return;
      }

      // start off with ambient passes
      IlluminationStage stage = IlluminationStage.Ambient;

      bool hasAmbient = false;

      for(int i = 0; i < passes.Count; /* increment in logic */) {
        Pass pass = (Pass)passes[i];
        IlluminationPass iPass;

        switch(stage) {
          case IlluminationStage.Ambient:
            // keep looking for ambient only
            if(pass.IsAmbientOnly) {
              iPass = new IlluminationPass();
              iPass.OriginalPass = pass;
              iPass.Pass = pass;
              iPass.Stage = stage;
              illuminationPasses.Add(iPass);
              hasAmbient = true;

              // progress to the next pass
              i++;
            }
            else {
              // split off any ambient part
              if(pass.Ambient.CompareTo(ColorEx.Black) != 0 || 
                pass.Emissive.CompareTo(ColorEx.Black) != 0) {

                Pass newPass = new Pass(this, pass.Index);
                pass.CopyTo(newPass);

                // remove any texture units
                newPass.RemoveAllTextureUnitStates();

                // also remove any fragment program
                if(newPass.HasFragmentProgram) {
                  newPass.SetFragmentProgram("");
                }

                // We have to leave vertex program alone (if any) and
                // just trust that the author is using light bindings, which 
                // we will ensure there are none in the ambient pass
                newPass.Diffuse = ColorEx.Black;
                newPass.Specular = ColorEx.Black;

                // if ambient and emissive are zero, then color write isn't needed
                if(newPass.Ambient.CompareTo(ColorEx.Black) == 0 &&
                  newPass.Emissive.CompareTo(ColorEx.Black) == 0) {

                  newPass.ColorWrite = false;
                }

                iPass = new IlluminationPass();
                iPass.DestroyOnShutdown = true;
                iPass.OriginalPass = pass;
                iPass.Pass = newPass;
                iPass.Stage = stage;

                illuminationPasses.Add(iPass);
                hasAmbient = true;
              }

              if(!hasAmbient) {
                // make up a new basic pass
                Pass newPass = new Pass(this, pass.Index);
                pass.CopyTo(newPass);

                newPass.Ambient = ColorEx.Black;
                newPass.Diffuse = ColorEx.Black;

                iPass = new IlluminationPass();
                iPass.DestroyOnShutdown = true;
                iPass.OriginalPass = pass;
                iPass.Pass = newPass;
                iPass.Stage = stage;
                illuminationPasses.Add(iPass);
                hasAmbient = true;
              }

              // this means we are done with ambients, progress to per-light
              stage = IlluminationStage.PerLight;
            }

            break;

          case IlluminationStage.PerLight:
            if(pass.RunOncePerLight) {
              // if this is per-light already, use it directly
              iPass = new IlluminationPass();
              iPass.DestroyOnShutdown = false;
              iPass.OriginalPass = pass;
              iPass.Pass = pass;
              iPass.Stage = stage;
              illuminationPasses.Add(iPass);

              // progress to the next pass
              i++;
            }
            else {
              // split off per-light details (can only be done for one)
              if(pass.LightingEnabled &&
                (pass.Diffuse.CompareTo(ColorEx.Black) != 0 ||
                pass.Specular.CompareTo(ColorEx.Black) != 0)) {

                // copy existing pass
                Pass newPass = new Pass(this, pass.Index);
                pass.CopyTo(newPass);

                newPass.RemoveAllTextureUnitStates();

                // also remove any fragment program
                if(newPass.HasFragmentProgram) {
                  newPass.SetFragmentProgram("");
                }

                // Cannot remove vertex program, have to assume that
                // it will process diffuse lights, ambient will be turned off
                newPass.Ambient = ColorEx.Black;
                newPass.Emissive = ColorEx.Black;

                // must be additive
                newPass.SetSceneBlending(SceneBlendFactor.One, SceneBlendFactor.One);

                iPass = new IlluminationPass();
                iPass.DestroyOnShutdown = true;
                iPass.OriginalPass = pass;
                iPass.Pass = newPass;
                iPass.Stage = stage;

                illuminationPasses.Add(iPass);
              }

              // This means the end of per-light passes
              stage = IlluminationStage.Decal;
            }

            break;

          case IlluminationStage.Decal:
            // We just want a 'lighting off' pass to finish off
            // and only if there are texture units
            if(pass.NumTextureUnitStages > 0) {
              if(!pass.LightingEnabled) {
                // we assume this pass already combines as required with the scene
                iPass = new IlluminationPass();
                iPass.DestroyOnShutdown = false;
                iPass.OriginalPass = pass;
                iPass.Pass = pass;
                iPass.Stage = stage;
                illuminationPasses.Add(iPass);
              }
              else {
                // Copy the pass and tweak away the lighting parts
                Pass newPass = new Pass(this, pass.Index);
                pass.CopyTo(newPass);
                newPass.Ambient = ColorEx.Black;
                newPass.Diffuse = ColorEx.Black;
                newPass.Specular = ColorEx.Black;
                newPass.Emissive = ColorEx.Black;
                newPass.LightingEnabled = false;
                // modulate
                newPass.SetSceneBlending(SceneBlendFactor.DestColor, SceneBlendFactor.Zero);

                // there is nothing we can do about vertex & fragment
                // programs here, so people will just have to make their
                // programs friendly-like if they want to use this technique
                iPass = new IlluminationPass();
                iPass.DestroyOnShutdown = true;
                iPass.OriginalPass = pass;
                iPass.Pass = newPass;
                iPass.Stage = stage;
                illuminationPasses.Add(iPass);
              }
            }

            // always increment on decal, since nothing more to do with this pass
            i++;

            break;
        }
      }
    }

    /// <summary>
    ///    Creates a new Pass for this technique.
    /// </summary>
    /// <remarks>
    ///    A Pass is a single rendering pass, ie a single draw of the given material.
    ///    Note that if you create a non-programmable pass, during compilation of the
    ///    material the pass may be split into multiple passes if the graphics card cannot
    ///    handle the number of texture units requested. For programmable passes, however, 
    ///    the number of passes you create will never be altered, so you have to make sure 
    ///    that you create an alternative fallback Technique for if a card does not have 
    ///    enough facilities for what you're asking for.
    /// </remarks>
    /// <param name="programmable">
    ///    True if programmable via vertex or fragment programs, false if fixed function.
    /// </param>
    /// <returns>A new Pass object reference.</returns>
    public Pass CreatePass() {
      Pass pass = new Pass(this, passes.Count);
      passes.Add(pass);
      return pass;
    }

    /// <summary>
    ///    Retreives the Pass at the specified index.
    /// </summary>
    /// <param name="index">Index of the Pass to retreive.</param>
    public Pass GetPass(int index) {
      Debug.Assert(index < passes.Count, "index < passes.Count");

      return (Pass)passes[index];
    }

    /// <summary>
    ///    Retreives the IlluminationPass at the specified index.
    /// </summary>
    /// <param name="index">Index of the IlluminationPass to retreive.</param>
    public IlluminationPass GetIlluminationPass(int index) {
      Debug.Assert(index < illuminationPasses.Count, "index < illuminationPasses.Count");

      return (IlluminationPass)illuminationPasses[index];
    }

    /// <summary>
    ///    Loads resources required by this Technique.
    /// </summary>
    public void Load() {
      Debug.Assert(isSupported, "This technique is not supported.");

      // load each pass
      for(int i = 0; i < passes.Count; i++) {
        ((Pass)passes[i]).Load();
      }
    }

    /// <summary>
    ///    Forces this Technique to recompile.
    /// </summary>
    /// <remarks>
    ///    The parent Material is asked to recompile to accomplish this.
    /// </remarks>
    internal void NotifyNeedsRecompile() {
      parent.NotifyNeedsRecompile();
    }

    /// <summary>
    ///    Removes the specified Pass from this Technique.
    /// </summary>
    /// <param name="pass">A reference to the Pass to be removed.</param>
    public void RemovePass(Pass pass) {
      Debug.Assert(pass != null, "pass != null");

      pass.QueueForDeletion();

      passes.Remove(pass);
    }

    /// <summary>
    ///    Removes all passes from this technique and queues them for deletion.
    /// </summary>
    public void RemoveAllPasses() {
      // load each pass
      for(int i = 0; i < passes.Count; i++) {
        Pass pass = (Pass)passes[i];
        pass.QueueForDeletion();
      }

      passes.Clear();
    }

    public void SetSceneBlending(SceneBlendType blendType) {
      // load each pass
      for(int i = 0; i < passes.Count; i++) {
        ((Pass)passes[i]).SetSceneBlending(blendType);
      }
    }

    public void SetSceneBlending(SceneBlendFactor src, SceneBlendFactor dest) {
      // load each pass
      for(int i = 0; i < passes.Count; i++) {
        ((Pass)passes[i]).SetSceneBlending(src, dest);
      }
    }

    /// <summary>
    ///    Unloads resources used by this Technique.
    /// </summary>
    public void Unload() {
      // load each pass
      for(int i = 0; i < passes.Count; i++) {
        ((Pass)passes[i]).Unload();
      }
    }
    
    #endregion
    
    #region Properties

    public ColorEx Ambient {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).Ambient = value;
        }
      }
    }

    public CullingMode CullingMode {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).CullMode = value;
        }
      }
    }

    public bool DepthCheck {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).DepthCheck = value;
        }
      }
      get {
        if (passes.Count == 0) {
          return false;
        }
        else {
          // Base decision on the depth settings of the first pass
          return ((Pass)passes[0]).DepthCheck;
        }
      }
    }

    public bool DepthWrite {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).DepthWrite = value;
        }
      }
      get {
        if (passes.Count == 0) {
          return false;
        }
        else {
          // Base decision on the depth settings of the first pass
          return ((Pass)passes[0]).DepthWrite;
        }
      }
    }

    public ColorEx Diffuse {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).Diffuse = value;
        }
      }
    }

    /// <summary>
    ///    Returns true if this Technique has already been loaded.
    /// </summary>
    public bool IsLoaded {
      get {
        return parent.IsLoaded;
      }
    }

    /// <summary>
    ///    Flag that states whether or not this technique is supported on the current hardware.
    /// </summary>
    /// <remarks>
    ///    This will only be correct after the Technique has been compiled, which is
    ///    usually triggered in Material.Compile.
    /// </remarks>
    public bool IsSupported {
      get {
        return isSupported;
      }
    }

    /// <summary>
    ///    Returns true if this Technique involves transparency.
    /// </summary>
    /// <remarks>
    ///    This basically boils down to whether the first pass
    ///    has a scene blending factor. Even if the other passes 
    ///    do not, the base color, including parts of the original 
    ///    scene, may be used for blending, therefore we have to treat
    ///    the whole Technique as transparent.
    /// </remarks>
    public bool IsTransparent {
      get {
        if(passes.Count == 0) {
          return false;
        }
        else {
          // based on the transparency of the first pass
          return ((Pass)passes[0]).IsTransparent;
        }
      }
    }

    /// <summary>
    /// 
    /// </summary>
    public bool Lighting {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).LightingEnabled = value;
        }
      }
    }

    /// <summary>
    ///    Assigns a level-of-detail (LOD) index to this Technique.
    /// </summary>
    /// <remarks>
    ///    As noted previously, as well as providing fallback support for various
    ///    graphics cards, multiple Technique objects can also be used to implement
    ///    material LOD, where the detail of the material diminishes with distance to 
    ///    save rendering power.
    ///    <p/>
    ///    By default, all Techniques have a LOD index of 0, which means they are the highest
    ///    level of detail. Increasing LOD indexes are lower levels of detail. You can 
    ///    assign more than one Technique to the same LOD index, meaning that the best 
    ///    Technique that is supported at that LOD index is used. 
    ///    <p/>
    ///    You should not leave gaps in the LOD sequence; the engine will allow you to do this
    ///    and will continue to function as if the LODs were sequential, but it will 
    ///    confuse matters.
    /// </remarks>
    public int LodIndex {
      get {
        return lodIndex;
      }
      set {
        lodIndex = value;
        NotifyNeedsRecompile();
      }
    }

    public ManualCullingMode ManualCullMode {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).ManualCullMode = value;
        }
      }
    }

    /// <summary>
    ///    Gets/Sets the name of this technique.
    /// </summary>
    public string Name {
      get {
        return name;
      }
      set {
        name = value;
      }
    }

    /// <summary>
    ///    Gets the number of passes within this Technique.
    /// </summary>
    public int NumPasses {
      get {
        return passes.Count;
      }
    }

    /// <summary>
    ///    Gets the number of illumination passes compiled from this technique.
    /// </summary>
    public int IlluminationPassCount {
      get {
        return illuminationPasses.Count;
      }
    }

    /// <summary>
    ///    Gets a reference to the Material that owns this Technique.
    /// </summary>
    public Material Parent {
      get {
        return parent;
      }
    }

    public TextureFiltering TextureFiltering {
      set {
        for(int i = 0; i < passes.Count; i++) {
          ((Pass)passes[i]).TextureFiltering = value;
        }
      }
    }

    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.