This code can load a scene from a dotScene file and attach it to a SceneNode of a Mogre application.

For questions use this forum thread.

DotScene

DotScene is a standardized XML file format (extension .scene) and can describe a complete scene. It does'nt contain any mesh data, texture data, etc. It just contains elements that describe a scene.

There are scene exporters for modeling applications like Blender, 3D Studio, etc.

History

Originally this code is a port of the New DotScene Loader (done by BenJ in April 2007).

Later the C++ code and this C# port got different updates.

User smiley80 added camera import code to the Mogre exporter. But removed the parts which are not used by the Blender exporter at the moment.

This code was tested with Blender dotScene exporter. If there are problems with files generated by other programs, please report it. You also can try the original port.

For updates you can look to the current code of New DotScene Loader where more features are implemented.

Using example

Helper.DotSceneLoader dsl = new Helper.DotSceneLoader();
SceneNode roomNode = sceneMgr.RootSceneNode.CreateChildSceneNode(new Vector3(0, 0, 0));
dsl.ParseDotScene("room1.scene", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, sceneMgr, roomNode);


room1.scene is the name of the dotscene file

ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME is the name of the group the dotscene file and the meshes are loaded in

sceneMgr is the SceneManager

roomNode is the SceneNode the scene gets attended to

See also


Exporters

Source code

namespace Helper
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
using Mogre;

public class DotSceneLoader
{
#region Fields

public List<string> DynamicObjects; //String
public List<string> StaticObjects; //String

protected SceneNode mAttachNode;
protected SceneManager mSceneMgr;
protected String m_sGroupName;
protected String m_sPrependNode;

#endregion Fields

#region Constructors

public DotSceneLoader()
{
}

~DotSceneLoader()
{
}

#endregion Constructors

#region Methods

public void ParseDotScene(String SceneName, String groupName, SceneManager yourSceneMgr)
{
   ParseDotScene(SceneName, groupName, yourSceneMgr, null, "");
}

public void ParseDotScene(String SceneName, String groupName, SceneManager yourSceneMgr, SceneNode pAttachNode)
{
   ParseDotScene(SceneName, groupName, yourSceneMgr, pAttachNode, "");
}

public void ParseDotScene(String SceneName, String groupName, SceneManager yourSceneMgr, SceneNode pAttachNode, String sPrependNode)
{
   // set up shared object values
   m_sGroupName = groupName;
   mSceneMgr = yourSceneMgr;
   m_sPrependNode = sPrependNode;
   this.StaticObjects = new List<string>();
   this.DynamicObjects = new List<string>();

   XmlDocument XMLDoc = null;
   XmlElement XMLRoot;

   DataStreamPtr pStream = ResourceGroupManager.Singleton.OpenResource(SceneName, groupName);

   String data = pStream.AsString;
   // Open the .scene File
   XMLDoc = new XmlDocument();
   XMLDoc.LoadXml(data);
   pStream.Close();

   // Validate the File
   XMLRoot = XMLDoc.DocumentElement;
   if (XMLRoot.Name != "scene")
   {
      LogManager.Singleton.LogMessage("[DotSceneLoader] Error: Invalid .scene File. Missing <scene>");
      return;
   }

   // figure out where to attach any nodes we create
   mAttachNode = pAttachNode;
   if (mAttachNode == null)
      mAttachNode = mSceneMgr.RootSceneNode;

   // Process the scene
   processScene(XMLRoot);
}

protected float ParseFloat(String s)
{
   NumberFormatInfo provider = new NumberFormatInfo();
   provider.NumberDecimalSeparator = ".";
   return float.Parse(s, provider);
}

protected String getAttrib(XmlElement XMLNode, String attrib)
{
   return getAttrib(XMLNode, attrib, "");
}

protected String getAttrib(XmlElement XMLNode, String attrib, String defaultValue)
{
   if (!string.IsNullOrEmpty(XMLNode.GetAttribute(attrib)))
      return XMLNode.GetAttribute(attrib);
   else
      return defaultValue;
}

protected bool getAttribBool(XmlElement XMLNode, String parameter)
{
   return getAttribBool(XMLNode, parameter, false);
}

protected bool getAttribBool(XmlElement XMLNode, String attrib, bool defaultValue)
{
   if (string.IsNullOrEmpty(XMLNode.GetAttribute(attrib)))
      return defaultValue;

   if (XMLNode.GetAttribute(attrib) == "true")
      return true;

   return false;
}

protected float getAttribReal(XmlElement XMLNode, String parameter)
{
   return getAttribReal(XMLNode, parameter, 0.0f);
}

protected float getAttribReal(XmlElement XMLNode, String attrib, float defaultValue)
{
   if (!string.IsNullOrEmpty(XMLNode.GetAttribute(attrib)))
      return ParseFloat(XMLNode.GetAttribute(attrib));
   else
      return defaultValue;
}

protected ColourValue parseColour(XmlElement XMLNode)
{
   return new ColourValue(
      ParseFloat(XMLNode.GetAttribute("r")),
      ParseFloat(XMLNode.GetAttribute("g")),
      ParseFloat(XMLNode.GetAttribute("b")),
      string.IsNullOrEmpty(XMLNode.GetAttribute("a")) == false ? ParseFloat(XMLNode.GetAttribute("a")) : 1
     );
}

protected Quaternion parseQuaternion(XmlElement XMLNode)
{
   Quaternion orientation = new Quaternion();

   orientation.x = ParseFloat(XMLNode.GetAttribute("x"));
   orientation.y = ParseFloat(XMLNode.GetAttribute("y"));
   orientation.z = ParseFloat(XMLNode.GetAttribute("z"));
   orientation.w = ParseFloat(XMLNode.GetAttribute("w"));

   return orientation;
}

protected Quaternion parseRotation(XmlElement XMLNode)
{
   Quaternion orientation = new Quaternion();

   orientation.x = ParseFloat(XMLNode.GetAttribute("qx"));
   orientation.y = ParseFloat(XMLNode.GetAttribute("qy"));
   orientation.z = ParseFloat(XMLNode.GetAttribute("qz"));
   orientation.w = ParseFloat(XMLNode.GetAttribute("qw"));

   return orientation;
}

protected Vector3 parseVector3(XmlElement XMLNode)
{
   return new Vector3(
      ParseFloat(XMLNode.GetAttribute("x")),
      ParseFloat(XMLNode.GetAttribute("y")),
      ParseFloat(XMLNode.GetAttribute("z"))
     );
}

protected void processCamera(XmlElement XMLNode, SceneNode pParent)
{
   // Process attributes
   String name = getAttrib(XMLNode, "name");

   // Create the light
   Camera pCamera = mSceneMgr.CreateCamera(name);
   if (pParent != null)
      pParent.AttachObject(pCamera);

   float pFov = getAttribReal(XMLNode, "fov", 45);
   pCamera.FOVy = new Degree(pFov);

   String sValue = getAttrib(XMLNode, "projectionType", "perspective");
   if (sValue == "perspective")
      pCamera.ProjectionType = ProjectionType.PT_PERSPECTIVE;
   else if (sValue == "orthographic")
      pCamera.ProjectionType = ProjectionType.PT_ORTHOGRAPHIC;

   XmlElement pElement;

   // Process normal (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("clipping");
   if(pElement != null)
   {
      // Blender
      float nearDist = getAttribReal(pElement, "nearPlaneDist");
      if (nearDist == 0)
      {
         // 3ds
         nearDist = getAttribReal(pElement, "near");
      }
      pCamera.NearClipDistance = nearDist;

      // Blender
      float farDist =  getAttribReal(pElement, "farPlaneDist");
      if (farDist == 0)
      {
         // 3ds
         farDist = getAttribReal(pElement, "far");
      }
      pCamera.FarClipDistance = farDist;
   }
}

protected void processEntity(XmlElement XMLNode, SceneNode pParent)
{
   // Process attributes
   String name = getAttrib(XMLNode, "name");
   String meshFile = getAttrib(XMLNode, "meshFile");

   bool bstatic = getAttribBool(XMLNode, "static", false);
   if (bstatic)
      StaticObjects.Add(name);
   else
      DynamicObjects.Add(name);

   bool bvisible = getAttribBool(XMLNode, "visible", true);
   bool bcastshadows = getAttribBool(XMLNode, "castShadows", true);
   float brenderingDistance = getAttribReal(XMLNode, "renderingDistance", 0);

   // Create the entity
   Entity pEntity = null;
   try
   {
      MeshPtr mesh = MeshManager.Singleton.Load(meshFile, m_sGroupName);
      ushort src, dest;
      mesh.SuggestTangentVectorBuildParams(VertexElementSemantic.VES_TANGENT, out src, out dest);
      mesh.BuildTangentVectors(VertexElementSemantic.VES_TANGENT, src, dest);

      pEntity = mSceneMgr.CreateEntity(name, meshFile);
      pEntity.Visible = bvisible;
      pEntity.CastShadows = bcastshadows;
      pEntity.RenderingDistance = brenderingDistance;
      
      XmlElement pElement;
      // Process subentities (?)
      pElement = (XmlElement)XMLNode.SelectSingleNode("subentities");
      if(pElement != null)
      {
         pElement = (XmlElement)pElement.FirstChild;
         while (pElement != null)
         {
            string mat = getAttrib(pElement, "materialName");
            pEntity.SetMaterialName(mat);
            pElement = (XmlElement)pElement.NextSibling;
         }
      }
      
      pParent.AttachObject(pEntity);
   }
   catch (Exception e)
   {
      LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading an entity!" + e.Message);
   }
   

}

protected void processEnvironment(XmlElement XMLNode)
{
   XmlElement pElement;

   // Process fog (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("fog");
   if (pElement != null)
      processFog(pElement);

   // Process colourAmbient (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("colourAmbient");
   if (pElement != null)
      mSceneMgr.AmbientLight = parseColour(pElement);

   // Process colourBackground (?)
   //! @todo Set the background colour of all viewports (RenderWindow has to be provided then)
   //            pElement = (XmlElement)XMLNode.SelectSingleNode("colourBackground");
   //            if (pElement != null)
   //                ;//mSceneMgr->set(parseColour(pElement));

   //            // Process userDataReference (?)
   //            pElement = (XmlElement)XMLNode.SelectSingleNode("userData");
   //            if (pElement != null)
   //                processUserDataReference(pElement);
}

protected void processFog(XmlElement XMLNode)
{
   // Process attributes
   float linearStart = getAttribReal(XMLNode, "linearStart", 0.0f);
   float linearEnd = getAttribReal(XMLNode, "linearEnd", 1.0f);

   FogMode mode = FogMode.FOG_NONE;
   String sMode = getAttrib(XMLNode, "mode");
   // only linear atm
   if(sMode == "none")
      mode = FogMode.FOG_NONE;
   else if(sMode == "exp")
      mode = FogMode.FOG_EXP;
   else if(sMode == "exp2")
      mode = FogMode.FOG_EXP2;
   else if(sMode == "linear")
      mode = FogMode.FOG_LINEAR;

   XmlElement pElement;

   // Process colourDiffuse (?)
   ColourValue colourDiffuse = ColourValue.White;
   pElement = (XmlElement)XMLNode.SelectSingleNode("colourDiffuse");
   if(pElement != null)
      colourDiffuse = parseColour(pElement);

   // Setup the fog
   mSceneMgr.SetFog(mode, colourDiffuse, 0.001f, linearStart, linearEnd);
}

protected void processLight(XmlElement XMLNode, SceneNode pParent)
{
   // Process attributes
   String name = getAttrib(XMLNode, "name");

   // Create the light
   Light pLight = mSceneMgr.CreateLight(name);
   if (pParent != null)
      pParent.AttachObject(pLight);

   String sValue = getAttrib(XMLNode, "type");
   if (sValue == "point")
      pLight.Type = Light.LightTypes.LT_POINT;
   else if (sValue == "directional")
      pLight.Type = Light.LightTypes.LT_DIRECTIONAL;
   else if (sValue == "spotLight")
      pLight.Type = Light.LightTypes.LT_SPOTLIGHT;

   // only set if Lamp is Spotlight (Blender)
   bool castShadow = true;
   if (XMLNode.HasAttribute("castShadow"))
   {
      castShadow = getAttribBool(XMLNode, "castShadow", true);
   }
   else if (XMLNode.HasAttribute("castShadows"))
   {
      castShadow = getAttribBool(XMLNode, "castShadows", true);
   }
   
   pLight.CastShadows = castShadow;

   XmlElement pElement;

   // Process normal (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("normal");
   if (pElement != null)
      pLight.Direction = parseVector3(pElement);

   // Process colourDiffuse (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("colourDiffuse");
   if (pElement != null)
      pLight.DiffuseColour = parseColour(pElement);

   // Process colourSpecular (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("colourSpecular");
   if (pElement != null)
      pLight.SpecularColour = parseColour(pElement);

   // Process lightRange (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("lightRange");
   if (pElement != null)
      processLightRange(pElement, pLight);

   // Process lightAttenuation (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("lightAttenuation");
   if (pElement != null)
      processLightAttenuation(pElement, pLight);
}

protected void processLightAttenuation(XmlElement XMLNode, Light pLight)
{
   // Process attributes
   float range = getAttribReal(XMLNode, "range");
   float constant = getAttribReal(XMLNode, "constant");
   float linear = getAttribReal(XMLNode, "linear");
   float quadratic = getAttribReal(XMLNode, "quadratic");

   // Setup the light attenuation
   pLight.SetAttenuation(range, constant, linear, quadratic);
}

protected void processLightRange(XmlElement XMLNode, Light pLight)
{
   // Process attributes
   float inner = getAttribReal(XMLNode, "inner");
   float outer = getAttribReal(XMLNode, "outer");
   float falloff = getAttribReal(XMLNode, "falloff", 1.0f);

   // Setup the light range
   pLight.SetSpotlightRange(new Radian((Degree)inner), new Radian((Degree)outer), falloff);
}

protected void processNode(XmlElement XMLNode, SceneNode pParent)
{
   // Construct the node's name
   String name = m_sPrependNode + getAttrib(XMLNode, "name");

   // Create the scene node
   SceneNode pNode;
   if (name.Length == 0)
   {
      // Let Ogre choose the name
      if (pParent != null)
         pNode = pParent.CreateChildSceneNode();
      else
         pNode = mAttachNode.CreateChildSceneNode();
   }
   else
   {
      // Provide the name
      if (pParent != null)
         pNode = pParent.CreateChildSceneNode(name);
      else
         pNode = mAttachNode.CreateChildSceneNode(name);
   }

   // Process other attributes
   XmlElement pElement;

   // Process position (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("position");
   if (pElement != null)
   {
      pNode.Position = parseVector3(pElement);
      pNode.SetInitialState();
   }

   // Process quaternion (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("quaternion");
   if (pElement != null)
   {
      pNode.Orientation = parseQuaternion(pElement);
      pNode.SetInitialState();
   }

   // Process rotation (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("rotation");
   if (pElement != null)
   {
      pNode.Orientation = parseRotation(pElement);
      pNode.SetInitialState();
   }
   
   // Process scale (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("scale");
   if (pElement != null)
   {
      pNode.SetScale(parseVector3(pElement));
      pNode.SetInitialState();
   }

   // Process entity (*)
   pElement = (XmlElement)XMLNode.SelectSingleNode("entity");
   if (pElement != null)
   {
      processEntity(pElement, pNode);
   }

   // Process light (*)
   pElement = (XmlElement)XMLNode.SelectSingleNode("light");
   if (pElement != null)
   {
      processLight(pElement, pNode);
   }

   // Process plane (*)
   pElement = (XmlElement)XMLNode.SelectSingleNode("plane");
   while (pElement != null)
   {
      processPlane(pElement, pNode);
      pElement = (XmlElement)pElement.NextSibling;
   }


   
   // Process camera (*)
   pElement = (XmlElement)XMLNode.SelectSingleNode("camera");
   if (pElement != null)
   {
      processCamera(pElement, pNode);
   }

   // Process userDataReference (?)
   pElement = (XmlElement)XMLNode.SelectSingleNode("userData");
   if (pElement != null)
      processUserDataReference(pElement, pNode);

   // Process childnodes
   pElement = (XmlElement)XMLNode.SelectSingleNode("node");
   while (pElement != null)
   {
      processNode(pElement, pNode);
      pElement = (XmlElement)pElement.NextSibling;
   }
}

protected void processPlane(XmlElement XMLNode, SceneNode pParent)
{

   string name = getAttrib(XMLNode, "name");
   float distance  = getAttribReal(XMLNode, "distance");
   float width = getAttribReal(XMLNode, "width");
   float height = getAttribReal(XMLNode, "height");
   
   int xSegments = (int)getAttribReal(XMLNode, "xSegments");
   int ySegments = (int)getAttribReal(XMLNode, "ySegments");
   int numTexCoordSets = (int)getAttribReal(XMLNode, "numTexCoordSets");
   float uTile = getAttribReal(XMLNode, "uTile");
   float vTile = getAttribReal(XMLNode, "vTile");
   string material = getAttrib(XMLNode, "material");
   bool normals = getAttribBool(XMLNode, "normals");
   bool movablePlane = getAttribBool(XMLNode, "movablePlane");
   bool castShadows = getAttribBool(XMLNode, "castShadows");
   bool receiveShadows = getAttribBool(XMLNode, "receiveShadows");
   
   Vector3 normal= Vector3.ZERO;
   XmlElement pElement = (XmlElement)XMLNode.SelectSingleNode("normal");
   if (pElement != null)
      normal = parseVector3(pElement);
   
   Vector3 upVector = Vector3.UNIT_Y;
   pElement = (XmlElement)XMLNode.SelectSingleNode("upVector");
   if (pElement != null)
      upVector = parseVector3(pElement);
   
   Plane pPlane = new Plane(normal, upVector);
   
   Entity pEntity= null;
   try
   {
      MeshPtr ptr = MeshManager.Singleton.CreatePlane(name, m_sGroupName, pPlane, width, height, xSegments, ySegments, normals, (ushort) numTexCoordSets, uTile, vTile, upVector);
      pEntity = mSceneMgr.CreateEntity(name, name);
      pParent.AttachObject(pEntity);
   }
   catch (Exception e)
   {
      LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading an entity!" + e.Message);
   }

}

protected void processNodes(XmlElement XMLNode)
{
   XmlElement pElement;

   // Process node (*)
   pElement = (XmlElement)XMLNode.SelectSingleNode("node");
   while (pElement != null)
   {
      processNode(pElement, null);
      XmlNode nextNode = pElement.NextSibling;
      pElement = nextNode as XmlElement;
      while(pElement==null && nextNode!=null)
      {
         nextNode = nextNode.NextSibling;
         pElement = nextNode as XmlElement;
      }
   }
}

protected void processScene(XmlElement XMLRoot)
{
   // Process the scene parameters
   String version = getAttrib(XMLRoot, "formatVersion", "unknown");

   String message = "[DotSceneLoader] Parsing dotScene file with version " + version;

   LogManager.Singleton.LogMessage(message);

   XmlElement pElement;

   // Process nodes (?)
   pElement = (XmlElement)XMLRoot.SelectSingleNode("nodes");
   if (pElement != null)
      processNodes(pElement);

   // Process environment (?)
   pElement = (XmlElement)XMLRoot.SelectSingleNode("environment");
   if (pElement != null)
      processEnvironment(pElement);
   // Process externals (?)
   //         pElement = (XmlElement)XMLRoot.SelectSingleNode("externals");
   //         if (pElement != null)
   //            processExternals(pElement);
}

protected void processUserDataReference(XmlElement XMLNode, SceneNode pNode)
{
   // TODO
}

#endregion Methods
}
}

Source code more comprehensive

#region Using

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
using Mogre;

#endregion

namespace RMOgre
{
  /// <summary>
  /// Classe permettant le chargement d'un scene Ogre
  /// </summary>
  public class DotSceneLoader
  {
    #region Membres

    private readonly List<LookTarget> lookTargets = new List<LookTarget>();
    private readonly List<TrackTarget> trackTargets = new List<TrackTarget>();

    /// <summary>
    /// SceneNode attachée
    /// </summary>
    protected SceneNode sceneNodeAttach;

    /// <summary>
    /// SceneManager
    /// </summary>
    protected SceneManager sceneManager;

    /// <summary>
    /// nom groupe
    /// </summary>
    protected string sGroupName;

    /// <summary>
    /// node
    /// </summary>
    protected string sPrependNode;

    private Camera camera;

    #endregion

    #region Structures

    /// <summary>
    /// Structure permettant de stocker les noeuds Look pour affectation a posteriori
    /// </summary>
    private struct LookTarget
    {
      private readonly SceneNode sourceNode;
      private readonly Camera sourceCamera;
      private string nodeName;
      private Node.TransformSpace relativeTo;
      private bool isPositionSet;
      private Vector3 position;
      private Vector3 localDirection;

      public Camera SourceCamera
      {
        get { return sourceCamera; }
      }

      public string NodeName
      {
        get { return nodeName; }
        set { nodeName = value; }
      }

      public Node.TransformSpace RelativeTo
      {
        get { return relativeTo; }
        set { relativeTo = value; }
      }

      public bool IsPositionSet
      {
        get { return isPositionSet; }
        set { isPositionSet = value; }
      }

      public Vector3 Position
      {
        get { return position; }
        set { position = value; }
      }

      public Vector3 LocalDirection
      {
        get { return localDirection; }
        set { localDirection = value; }
      }

      public SceneNode SourceNode
      {
        get { return sourceNode; }
      }

      /// <summary>
      ///  * Initializes the LookTarget for a scene node or camera.
      ///      * Either sourceNode or sourceCamera must be non-null
      /// </summary>
      /// <param name="_sourceNode">Noeud</param>
      /// <param name="_sourceCamera">Camera</param>
      public LookTarget(SceneNode _sourceNode, Camera _sourceCamera)
      {
        sourceNode = _sourceNode;
        sourceCamera = _sourceCamera;
        relativeTo = Node.TransformSpace.TS_LOCAL;
        isPositionSet = false;
        position = Vector3.ZERO;
        localDirection = Vector3.NEGATIVE_UNIT_Z;
        nodeName = null;
      }
    }

    /// <summary>
    /// Structure permettant de stocker les noeuds target pour affectation a posteriori
    /// </summary>
    private struct TrackTarget
    {
      private readonly SceneNode sourceNode;
      private readonly Camera sourceCamera;
      private string nodeName;
      private Vector3 offset;
      private Vector3 localDirection;

      public Camera SourceCamera
      {
        get { return sourceCamera; }
      }

      public SceneNode SourceNode
      {
        get { return sourceNode; }
      }

      public string NodeName
      {
        get { return nodeName; }
        set { nodeName = value; }
      }

      public Vector3 LocalDirection
      {
        get { return localDirection; }
        set { localDirection = value; }
      }

      public Vector3 Offset
      {
        get { return offset; }
        set { offset = value; }
      }

      /// <summary>
      /// Constructeur
      /// </summary>
      /// <param name="_sourceNode">Noeud</param>
      /// <param name="_sourceCamera">Camera</param>
      public TrackTarget(SceneNode _sourceNode, Camera _sourceCamera)
      {
        sourceNode = _sourceNode;
        sourceCamera = _sourceCamera;
        offset = Vector3.ZERO;
        localDirection = Vector3.NEGATIVE_UNIT_Z;
        nodeName = null;
      }
    };

    #endregion

    #region Accesseurs

    /// <summary>
    /// Fenêtre de rendu
    /// </summary>
    protected RenderWindow RenderWindow { get; set; }

    #endregion

    /// <summary>
    /// Declaration d'une scene
    /// </summary>
    /// <param name="_sSceneName">Fichier à charger dans les ressources</param>
    /// <param name="_sGroupName">Groupe de ressources associées</param>
    /// <param name="_sceneManager">Scene manager associé</param>
    public void ParseDotScene(string _sSceneName, string _sGroupName, SceneManager _sceneManager)
    {
      ParseDotScene(_sSceneName, _sGroupName, _sceneManager, null, "");
    }

    /// <summary>
    /// Declaration d'une scene
    /// </summary>
    /// <param name="_sSceneName">Fichier à charger dans les ressources</param>
    /// <param name="_sGroupName">Groupe de ressources associées</param>
    /// <param name="_sceneManager">Scene manager associé</param>
    /// <param name="_sceneNode">Noeud à laquelle la scene est rattachée</param>
    public void ParseDotScene(string _sSceneName, string _sGroupName, SceneManager _sceneManager, SceneNode _sceneNode)
    {
      ParseDotScene(_sSceneName, _sGroupName, _sceneManager, _sceneNode, "");
    }

    /// <summary>
    /// Declaration d'une scene
    /// </summary>
    /// <param name="_sSceneName">Fichier à charger dans les ressources</param>
    /// <param name="_sGroupName">Groupe de ressources associées</param>
    /// <param name="_sceneManager">Scene manager associé</param>
    /// <param name="_sceneNode">Noeud à laquelle la scene est rattachée</param>
    /// <param name="_sPrependNode">Préfixe du noeud</param>
    public void ParseDotScene(string _sSceneName, string _sGroupName, SceneManager _sceneManager, SceneNode _sceneNode, string _sPrependNode)
    {
      ParseDotScene(_sSceneName, _sGroupName, _sceneManager, _sceneNode, _sPrependNode, null);
    }

    /// <summary>
    /// Declaration d'une scene
    /// </summary>
    /// <param name="_sSceneName">Fichier à charger dans les ressources</param>
    /// <param name="_sGroupName">Groupe de ressources associées</param>
    /// <param name="_sceneManager">Scene manager associé</param>
    /// <param name="_sceneNodeAttach">Noeud à laquelle la scene est rattachée</param>
    /// <param name="_sPrependNode">Préfixe du noeud</param>
    /// <param name="_renderWindow">Objet de rendu</param>
    public void ParseDotScene(string _sSceneName, string _sGroupName, SceneManager _sceneManager, SceneNode _sceneNodeAttach, string _sPrependNode, RenderWindow _renderWindow)
    {
      RenderWindow = _renderWindow;

      // set up shared object values
      sGroupName = _sGroupName;
      sceneManager = _sceneManager;
      sPrependNode = _sPrependNode;
      //this.StaticObjects = new List<string>();
      //this.DynamicObjects = new List<string>();

      DataStreamPtr pStream = ResourceGroupManager.Singleton.OpenResource(_sSceneName, _sGroupName);

      string data = pStream.AsString;
      // Open the .scene File
      XmlDocument xmlDoc = new XmlDocument();
      xmlDoc.LoadXml(data);
      pStream.Close();

      // Validate the File
      XmlElement xmlRoot = xmlDoc.DocumentElement;
      if (xmlRoot != null && xmlRoot.Name != "scene")
      {
        LogManager.Singleton.LogMessage("[DotSceneLoader] Error: Invalid .scene File. Missing <scene>");
        return;
      }

      // figure out where to attach any nodes we create
      sceneNodeAttach = _sceneNodeAttach ?? sceneManager.RootSceneNode;

      // Process the scene
      ProcessScene(xmlRoot);
    }

    /// <summary>
    /// Lecture d'un nombre a virgule
    /// </summary>
    /// <param name="_s">nombre format texte</param>
    /// <returns>float</returns>
    protected float ParseFloat(string _s)
    {
      NumberFormatInfo provider = new NumberFormatInfo
                                    {
                                      NumberDecimalSeparator = "."
                                    };
      return float.Parse(_s, provider);
    }

    /// <summary>
    /// récupération chaine
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <returns>string</returns>
    protected string GetAttrib(XmlElement _xmlElement, string _sAttrib)
    {
      return GetAttrib(_xmlElement, _sAttrib, "");
    }

    /// <summary>
    /// récupération chaine
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_sDefaultValue">valeur par défaut</param>
    /// <returns>string</returns>
    protected string GetAttrib(XmlElement _xmlElement, string _sAttrib, string _sDefaultValue)
    {
      if (!string.IsNullOrEmpty(_xmlElement.GetAttribute(_sAttrib))) return _xmlElement.GetAttribute(_sAttrib);
      return _sDefaultValue;
    }

    /// <summary>
    /// récupération bolléen
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sParameter">attribut</param>
    /// <returns>bool</returns>
    protected bool GetAttribBool(XmlElement _xmlElement, string _sParameter)
    {
      return GetAttribBool(_xmlElement, _sParameter, false);
    }

    /// <summary>
    /// récupération bolléen
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_bDefaultValue">valeur par défaut</param>
    /// <returns>bool</returns>
    protected bool GetAttribBool(XmlElement _xmlElement, string _sAttrib, bool _bDefaultValue)
    {
      if (string.IsNullOrEmpty(_xmlElement.GetAttribute(_sAttrib)))
        return _bDefaultValue;

      if (_xmlElement.GetAttribute(_sAttrib) == "true")
        return true;

      return false;
    }

    /// <summary>
    /// Récupération SceneNode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sParameter">paramètres</param>
    /// <returns>SceneNode</returns>
    protected SceneNode GetAttribSceneNode(XmlElement _xmlElement, string _sParameter)
    {
      return GetAttribSceneNode(_xmlElement, _sParameter, null);
    }

    /// <summary>
    /// Récupération SceneNode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attributs</param>
    /// <param name="_snDefaultValue">SceneNode par défaut</param>
    /// <returns>SceneNode</returns>
    protected SceneNode GetAttribSceneNode(XmlElement _xmlElement, string _sAttrib, SceneNode _snDefaultValue)
    {
      string sNodeName = _xmlElement.GetAttribute(_sAttrib);
      if (string.IsNullOrEmpty(sNodeName)) return _snDefaultValue;

      if (!sceneManager.HasSceneNode(sNodeName)) return _snDefaultValue;
      return sceneManager.GetSceneNode(sNodeName);
    }

    /// <summary>
    /// Lecture attribut nombre a virgule
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sParameter">attribut</param>
    /// <returns>float</returns>
    protected float GetAttribReal(XmlElement _xmlElement, string _sParameter)
    {
      return GetAttribReal(_xmlElement, _sParameter, 0.0f);
    }

    /// <summary>
    /// Lecture attribut nombre a virgule
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_fDefaultValue">valeur par défaut</param>
    /// <returns>float</returns>
    protected float GetAttribReal(XmlElement _xmlElement, string _sAttrib, float _fDefaultValue)
    {
      if (!string.IsNullOrEmpty(_xmlElement.GetAttribute(_sAttrib))) return ParseFloat(_xmlElement.GetAttribute(_sAttrib));
      return _fDefaultValue;
    }



    /// <summary>
    /// Lecture uint
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sParameter">attribut</param>
    /// <returns>uint</returns>
    protected uint GetAttribUInt(XmlElement _xmlElement, string _sParameter)
    {
      return GetAttribUInt(_xmlElement, _sParameter, 0);
    }

    /// <summary>
    /// Lecture uint
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_uiDefaultValue">valeur par défaut</param>
    /// <returns>uint</returns>
    protected uint GetAttribUInt(XmlElement _xmlElement, string _sAttrib, uint _uiDefaultValue)
    {
      if (!string.IsNullOrEmpty(_xmlElement.GetAttribute(_sAttrib))) return uint.Parse(_xmlElement.GetAttribute(_sAttrib));
      return _uiDefaultValue;
    }

    /// <summary>
    /// Récupération InterpolationMode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <returns>InterpolationMode</returns>
    protected Animation.InterpolationMode GetAttribAnimationInterpolationMode(XmlElement _xmlElement, string _sAttrib)
    {
      return GetAttribAnimationInterpolationMode(_xmlElement, _sAttrib, Animation.InterpolationMode.IM_LINEAR);
    }

    /// <summary>
    ///  Récupération InterpolationMode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_interpolationModeDefaultValue">InterpolationMode par défaut</param>
    /// <returns>InterpolationMode</returns>
    protected Animation.InterpolationMode GetAttribAnimationInterpolationMode(XmlElement _xmlElement, string _sAttrib, Animation.InterpolationMode _interpolationModeDefaultValue)
    {
      string sInterpolationModeText = GetAttrib(_xmlElement, _sAttrib);
      if (!string.IsNullOrEmpty(sInterpolationModeText))
      {
        sInterpolationModeText = sInterpolationModeText.ToLower();
        if (sInterpolationModeText == "linear")
          return Animation.InterpolationMode.IM_LINEAR;
        if (sInterpolationModeText == "spline")
          return Animation.InterpolationMode.IM_SPLINE;

        LogManager.Singleton.LogMessage("Invalid animation interpolation mode specified: " + sInterpolationModeText);
      }
      return _interpolationModeDefaultValue;
    }

    /// <summary>
    ///  Récupération RotationInterpolationMode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <returns>RotationInterpolationMode</returns>
    protected Animation.RotationInterpolationMode GetAttribAnimationRotationInterpolationMode(XmlElement _xmlElement, string _sAttrib)
    {
      return GetAttribAnimationRotationInterpolationMode(_xmlElement, _sAttrib, Animation.RotationInterpolationMode.RIM_LINEAR);
    }

    /// <summary>
    ///  Récupération RotationInterpolationMode
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sAttrib">attribut</param>
    /// <param name="_rotationInterpolationModeModeDefaultValue">RotationInterpolationMode par défaut</param>
    /// <returns>RotationInterpolationMode</returns>
    protected Animation.RotationInterpolationMode GetAttribAnimationRotationInterpolationMode(XmlElement _xmlElement, string _sAttrib, Animation.RotationInterpolationMode _rotationInterpolationModeModeDefaultValue)
    {
      string sRotationInterpolationMode = GetAttrib(_xmlElement, _sAttrib);
      if (!string.IsNullOrEmpty(sRotationInterpolationMode))
      {
        sRotationInterpolationMode = sRotationInterpolationMode.ToLower();
        if (sRotationInterpolationMode == "linear")
          return Animation.RotationInterpolationMode.RIM_LINEAR;
        if (sRotationInterpolationMode == "spherical")
          return Animation.RotationInterpolationMode.RIM_SPHERICAL;

        LogManager.Singleton.LogMessage("Invalid animation rotation interpolation mode specified: " + sRotationInterpolationMode);
      }
      return _rotationInterpolationModeModeDefaultValue;
    }

    /// <summary>
    /// Lecture couleur
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <returns>ColourValue</returns>
    protected ColourValue ParseColour(XmlElement _xmlElement)
    {
      return new ColourValue(
        ParseFloat(_xmlElement.GetAttribute("r")),
        ParseFloat(_xmlElement.GetAttribute("g")),
        ParseFloat(_xmlElement.GetAttribute("b")),
        string.IsNullOrEmpty(_xmlElement.GetAttribute("a")) == false ? ParseFloat(_xmlElement.GetAttribute("a")) : 1
        );
    }

    /// <summary>
    /// Lecture quaternion
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <returns>Quaternion</returns>
    protected Quaternion ParseQuaternion(XmlElement _xmlElement)
    {
      Quaternion orientation = new Quaternion
                                 {
                                   x = ParseFloat(_xmlElement.GetAttribute("x")),
                                   y = ParseFloat(_xmlElement.GetAttribute("y")),
                                   z = ParseFloat(_xmlElement.GetAttribute("z")),
                                   w = ParseFloat(_xmlElement.GetAttribute("w"))
                                 };

      return orientation;
    }

    /// <summary>
    /// Lecture quaternion de rotation
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <returns>Quaternion</returns>
    protected Quaternion ParseRotation(XmlElement _xmlElement)
    {
      Quaternion orientation = new Quaternion
                                 {
                                   x = ParseFloat(_xmlElement.GetAttribute("qx")),
                                   y = ParseFloat(_xmlElement.GetAttribute("qy")),
                                   z = ParseFloat(_xmlElement.GetAttribute("qz")),
                                   w = ParseFloat(_xmlElement.GetAttribute("qw"))
                                 };

      return orientation;
    }

    /// <summary>
    /// Lecture d'un Vector3
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <returns>Vector3</returns>
    protected Vector3 ParseVector3(XmlElement _xmlElement)
    {
      return new Vector3(
        ParseFloat(_xmlElement.GetAttribute("x")),
        ParseFloat(_xmlElement.GetAttribute("y")),
        ParseFloat(_xmlElement.GetAttribute("z"))
        );
    }

    /// <summary>
    /// Chargement caméra
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessCamera(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      #region Defaut

      // Process attributes
      string name = GetAttrib(_xmlElement, "name");

      // Create the camera
      camera = sceneManager.CreateCamera(name);

      if (_sceneNodeParent != null)
        _sceneNodeParent.AttachObject(camera);

      //camera.AspectRatio = GetAttribReal(_xmlElement, "aspectRatio", 4 / 3f);


      float pFov = GetAttribReal(_xmlElement, "fov", Mogre.Math.PI / 4);
      camera.FOVy = new Radian(pFov);

      string sValue = GetAttrib(_xmlElement, "projectionType", "perspective");
      if (sValue == "perspective") camera.ProjectionType = ProjectionType.PT_PERSPECTIVE;
      else if (sValue == "orthographic") camera.ProjectionType = ProjectionType.PT_ORTHOGRAPHIC;

      #endregion

      foreach (XmlElement xmlElementChild in _xmlElement.ChildNodes)
      {
        switch (xmlElementChild.Name)
        {
          case "rotation":
            camera.Rotate(ParseRotation(xmlElementChild));
            break;
          case "clipping":
            float fNearDist = GetAttribReal(xmlElementChild, "nearPlaneDist");
            // ReSharper disable CompareOfFloatsByEqualityOperator
            if (fNearDist == 0)
            {
              // 3ds
              fNearDist = GetAttribReal(xmlElementChild, "near");
            }
            camera.NearClipDistance = fNearDist;
            // Blender
            float fFarDist = GetAttribReal(xmlElementChild, "farPlaneDist");
            if (fFarDist == 0)
            {
              // 3ds
              fFarDist = GetAttribReal(xmlElementChild, "far");
            }
            // ReSharper restore CompareOfFloatsByEqualityOperator
            camera.FarClipDistance = fFarDist;
            break;
          case "lookTarget":
            LoadLookTarget(xmlElementChild, null, camera);
            break;
          case "trackTarget":
            LoadTrackTarget(xmlElementChild, null, camera);
            break;
        }
      }

      //xmlElement = (XmlElement)_xmlElement.SelectSingleNode("target");
      //if (xmlElement != null)
      //{
      //  bool bEnable = GetAttribBool(xmlElement, "enabled", true);
      //  Vector3 v3Offset = new Vector3(GetAttribReal(xmlElement, "offset_x", 0), GetAttribReal(xmlElement, "offset_y", 0), GetAttribReal(xmlElement, "offset_z", 0));
      //  SceneNode pNode = GetAttribSceneNode(xmlElement, "node_name", null);
      //  if (pNode != null) camera.SetAutoTracking(bEnable, pNode, v3Offset);
      //}

      //xmlElement = (XmlElement)_xmlElement.SelectSingleNode("lookat");
      //if (xmlElement != null)
      //{
      //  Vector3 v3Offset = new Vector3(GetAttribReal(xmlElement, "x", 0), GetAttribReal(xmlElement, "y", 0), GetAttribReal(xmlElement, "z", 0));
      //  camera.LookAt(v3Offset);
      //}
    }

    /// <summary>
    /// Chargement d'une entity
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessEntity(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      Entity entity = GetEntity(_xmlElement);
      if (entity != null) _sceneNodeParent.AttachObject(entity);
    }

    /// <summary>
    /// Retourne l'entity défini dans le xmlElement
    /// </summary>
    /// <param name="_xmlElement"></param>
    /// <returns></returns>
    private Entity GetEntity(XmlElement _xmlElement)
    {
      Entity entity=null;
      // Process attributes
      string name = GetAttrib(_xmlElement, "name");
      string meshFile = GetAttrib(_xmlElement, "meshFile");

      bool bvisible = GetAttribBool(_xmlElement, "visible", true);
      bool bcastshadows = GetAttribBool(_xmlElement, "castShadows", true);
      float brenderingDistance = GetAttribReal(_xmlElement, "renderingDistance", 0);
      //bool bReceiveShadows = GetAttribBool(_xmlElement, "receiveShadows", true);

      // Create the entity
      try
      {
        MeshPtr mesh = MeshManager.Singleton.Load(meshFile, sGroupName);
        try
        {
          ushort src, dest;
          mesh.SuggestTangentVectorBuildParams(VertexElementSemantic.VES_TANGENT, out src, out dest);
          mesh.BuildTangentVectors(VertexElementSemantic.VES_TANGENT, src, dest);
        }
        catch
        {
        }

        entity = sceneManager.CreateEntity(name, meshFile);
        entity.Visible = bvisible;
        entity.CastShadows = bcastshadows;
        //entity.ReceivesShadows = bReceiveShadows; //No setter
        entity.RenderingDistance = brenderingDistance;

        // Process subentities (?)
        ProcessSubEntities(_xmlElement, entity);
        ProcessBoneAttachments(_xmlElement, entity);
      }
      catch (Exception e)
      {
        LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading an entity!" + e.Message);
      }
      return entity;
    }

    /// <summary>
    /// Gère les subEntities
    /// </summary>
    /// <param name="_xmlElement"></param>
    /// <param name="_entity"></param>
    private void ProcessSubEntities(XmlElement _xmlElement, Entity _entity)
    {
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("subentities");
      if (xmlElement != null)
      {
        xmlElement = (XmlElement)xmlElement.FirstChild;
        while (xmlElement != null)
        {
          string mat = GetAttrib(xmlElement, "materialName");
          _entity.GetSubEntity(GetAttribUInt(xmlElement, "index")).SetMaterialName(mat);
          xmlElement = (XmlElement)xmlElement.NextSibling;
        }
      }
    }

    /// <summary>
    /// Créer les attachements
    /// </summary>
    /// <param name="_xmlElement"></param>
    /// <param name="_entity">Entity auquel sont associés les elts à rattacher</param>
    private void ProcessBoneAttachments(XmlElement _xmlElement, Entity _entity)
    {
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("boneAttachments");
      if (xmlElement != null)
      {
        XmlElement xmlElementAttach = (XmlElement)xmlElement.FirstChild;
        while (xmlElementAttach != null)
        {
          string sBone = GetAttrib(xmlElementAttach, "bone");
          TagPoint tagPoint = _entity.AttachObjectToBone(sBone, GetEntity((XmlElement)xmlElementAttach.SelectSingleNode("entity")));
          //Parse child elements
          foreach (XmlElement xmlElementChild in xmlElementAttach.ChildNodes)
          {
            switch (xmlElementChild.Name)
            {
              case "position":
                tagPoint.Position= ParseVector3(xmlElementChild);
                break;
              case "rotation":
                tagPoint.Orientation = ParseRotation(xmlElementChild);
                break;
              case "scale":
                tagPoint.SetScale(ParseVector3(xmlElementChild));
                break;
            }
          }
          xmlElementAttach = (XmlElement)xmlElementAttach.NextSibling;
        }
      }
    }

    /// <summary>
    /// Chargement des animations
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessNodeAnimations(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      foreach (XmlElement xmlElementChild in _xmlElement.ChildNodes)
      {
        if (xmlElementChild.Name == "animation")
          ProcessNodeAnimation(xmlElementChild, _sceneNodeParent);
      }
    }

    /// <summary>
    /// Chargement d'une animation
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessNodeAnimation(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      //Get enabled and looping states
      bool bEnable = GetAttribBool(_xmlElement, "enable", false);
      bool bLooping = GetAttribBool(_xmlElement, "loop", false);

      //Animation name
      string sName = GetAttrib(_xmlElement, "name");

      //Get existing animation or create new one
      Animation animation;
      if (sceneManager.HasAnimation(sName))
        animation = sceneManager.GetAnimation(sName);
      else
      {
        //Length
        float fLength = GetAttribReal(_xmlElement, "length", 0);

        //Interpolation mode
        Animation.InterpolationMode interpolationMode = GetAttribAnimationInterpolationMode(_xmlElement, "interpolationMode");

        //Rotation interpolation mode
        Animation.RotationInterpolationMode rotationInterpolationMode = GetAttribAnimationRotationInterpolationMode(_xmlElement, "rotationInterpolationMode");

        //Notify the callback
        //if (this->callback != 0)
        //    this->callback->LoadingNodeAnimation(this, params);

        //Create animation
        animation = sceneManager.CreateAnimation(sName, fLength);
        animation.SetInterpolationMode(interpolationMode);
        animation.SetRotationInterpolationMode(rotationInterpolationMode);

        //Notify the callback
        //if (this->callback != 0)
        //    this->callback->CreatedNodeAnimation(this, node, animation);
      }

      //Create animation track for node
      NodeAnimationTrack animationTrack = animation.CreateNodeTrack((ushort)(animation.NumNodeTracks + 1), _sceneNodeParent);

      //Load animation keyframes
      foreach (XmlElement xmlElementChild in _xmlElement.ChildNodes)
      {
        if (xmlElementChild.Name == "keyframe")
          ProcessNodeAnimationKeyFrame(xmlElementChild, animationTrack);
      }

      //Notify callback
      //if (this->callback != 0)
      //    this->callback->CreatedNodeAnimationTrack(this, node, animationTrack, params.enable, params.looping);

      //if ((this->loadOptions & NO_ANIMATION_STATES) == 0)
      //{
      //Create a new animation state to track the animation
      if (!sceneManager.HasAnimationState(sName))
      {
        //No animation state has been created for the animation yet
        AnimationState animationState = sceneManager.CreateAnimationState(sName);
        animationState.Enabled = bEnable;
        animationState.Loop = bLooping;

        //Notify callback
        //if (this->callback != 0)
        //    this->callback->CreatedNodeAnimationState(this, node, animationState);
      }
      //else if (this->callback != 0)
      //        this->callback->ReferencedNodeAnimationState(this, node, animationState);
      //}
    }

    /// <summary>
    /// Chargement KeyFrame d'une animation 
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_nodeAnimationTrack">NodeAnimationTrack</param>
    protected void ProcessNodeAnimationKeyFrame(XmlElement _xmlElement, NodeAnimationTrack _nodeAnimationTrack)
    {
      //Key time
      float fKeyTime = GetAttribReal(_xmlElement, "time", 0);

      //Create the key frame
      TransformKeyFrame keyFrame = _nodeAnimationTrack.CreateNodeKeyFrame(fKeyTime);

      //Parse child elements
      foreach (XmlElement xmlElementChild in _xmlElement.ChildNodes)
      {
        switch (xmlElementChild.Name)
        {
          case "translation":
            keyFrame.Translate = ParseVector3(xmlElementChild);
            break;
          case "rotation":
            keyFrame.Rotation = ParseRotation(xmlElementChild);
            break;
          case "scale":
            keyFrame.Scale = ParseVector3(xmlElementChild);
            break;
        }
      }
    }

    /// <summary>
    /// Chargement de l'environement
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessEnvironment(XmlElement _xmlElement)
    {
      // Process fog (?)
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("fog");
      if (xmlElement != null) ProcessFog(xmlElement);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("skyBox");
      if (xmlElement != null) ProcessSkyBox(xmlElement);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("skyDome");
      if (xmlElement != null) ProcessSkyDome(xmlElement);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("skyPlane");
      if (xmlElement != null) ProcessSkyPlane(xmlElement);

      // Process colourAmbient (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourAmbient");
      if (xmlElement != null) sceneManager.AmbientLight = ParseColour(xmlElement);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("shadows");
      if (xmlElement != null) ProcessShadows(xmlElement);


      if (RenderWindow != null)
      {
        Viewport viewport = RenderWindow.NumViewports == 0 ? RenderWindow.AddViewport(camera) : RenderWindow.GetViewport(0);
        viewport.Camera = camera;
        camera.AspectRatio = (float)viewport.ActualWidth / viewport.ActualHeight;
        xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourBackground");
        if (xmlElement != null) viewport.BackgroundColour = ParseColour(xmlElement);
      }
    }

    /// <summary>
    /// Chargement des ombres
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessShadows(XmlElement _xmlElement)
    {
      string sTechnique = GetAttrib(_xmlElement, "technique", "none");
      switch (sTechnique)
      {
        case "stencilAdditive":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_STENCIL_ADDITIVE;
          break;
        case "stencilModulative":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_STENCIL_MODULATIVE;
          break;
        case "textureAdditive":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE;
          break;
        case "textureAdditiveIntegrated":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED;
          break;
        case "textureModulative":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE;
          break;
        case "textureModulativeIntegrated":
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED;
          break;
        default:
          sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_NONE;
          break;
      }
      sceneManager.ShadowFarDistance = GetAttribReal(_xmlElement, "farDistance", 0);
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourShadow");
      if (xmlElement != null) sceneManager.ShadowColour = ParseColour(xmlElement);
      //      <shadows technique="stencilModulative" farDistance="0">
      //    <colourShadow r="0" g="0" b="0" />
      //</shadows>
    }

    /// <summary>
    /// Chargement ciel en "boite"
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessSkyBox(XmlElement _xmlElement)
    {
      // Process attributes
      string material = GetAttrib(_xmlElement, "material");
      float distance = GetAttribReal(_xmlElement, "distance", 5000);
      bool drawFirst = GetAttribBool(_xmlElement, "drawFirst", true);

      // Process rotation (?)
      Quaternion rotation = Quaternion.IDENTITY;
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("rotation");
      if (xmlElement != null)
        rotation = ParseQuaternion(xmlElement);

      // Setup the sky box
      sceneManager.SetSkyBox(true, material, distance, drawFirst, rotation, sGroupName);
    }

    /// <summary>
    /// Chargement ciel en "dome"
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessSkyDome(XmlElement _xmlElement)
    {
      // Process attributes
      string material = GetAttrib(_xmlElement, "material");
      float curvature = GetAttribReal(_xmlElement, "curvature", 10);
      float tiling = GetAttribReal(_xmlElement, "tiling", 8);
      float distance = GetAttribReal(_xmlElement, "distance", 4000);
      bool drawFirst = GetAttribBool(_xmlElement, "drawFirst", true);

      // Process rotation (?)
      Quaternion rotation = Quaternion.IDENTITY;
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("rotation");
      if (xmlElement != null)
        rotation = ParseQuaternion(xmlElement);

      // Setup the sky dome
      sceneManager.SetSkyDome(true, material, curvature, tiling, distance, drawFirst, rotation, 16, 16, -1, sGroupName);
    }

    /// <summary>
    /// Chargement plan de ciel
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessSkyPlane(XmlElement _xmlElement)
    {
      // Process attributes
      string material = GetAttrib(_xmlElement, "material");
      float planeX = GetAttribReal(_xmlElement, "planeX", 0);
      float planeY = GetAttribReal(_xmlElement, "planeY", -1);
      float planeZ = GetAttribReal(_xmlElement, "planeZ", 0);
      float planeD = GetAttribReal(_xmlElement, "planeD", 5000);
      float scale = GetAttribReal(_xmlElement, "scale", 1000);
      float bow = GetAttribReal(_xmlElement, "bow", 0);
      float tiling = GetAttribReal(_xmlElement, "tiling", 10);
      bool drawFirst = GetAttribBool(_xmlElement, "drawFirst", true);

      // Setup the sky plane
      Plane plane;
      plane.normal = new Vector3(planeX, planeY, planeZ);
      plane.d = planeD;
      sceneManager.SetSkyPlane(true, plane, material, scale, tiling, drawFirst, bow, 1, 1, sGroupName);
    }

    /// <summary>
    /// Chargement brouillard
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessFog(XmlElement _xmlElement)
    {
      // Process attributes
      float linearStart = GetAttribReal(_xmlElement, "linearStart", 0.0f);
      float linearEnd = GetAttribReal(_xmlElement, "linearEnd", 1.0f);

      FogMode mode = FogMode.FOG_NONE;
      string sMode = GetAttrib(_xmlElement, "mode");
      // only linear atm
      if (sMode == "none")
        mode = FogMode.FOG_NONE;
      else if (sMode == "exp")
        mode = FogMode.FOG_EXP;
      else if (sMode == "exp2")
        mode = FogMode.FOG_EXP2;
      else if (sMode == "linear")
        mode = FogMode.FOG_LINEAR;

      // Process colourDiffuse (?)
      ColourValue colourDiffuse = ColourValue.White;
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourDiffuse");
      if (xmlElement != null)
        colourDiffuse = ParseColour(xmlElement);

      // Setup the fog
      sceneManager.SetFog(mode, colourDiffuse, 0.001f, linearStart, linearEnd);
    }

    /// <summary>
    /// Chargement d'une lumière
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessLight(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      // Process attributes
      string name = GetAttrib(_xmlElement, "name");

      // Create the light
      Light light = sceneManager.CreateLight(name);
      if (_sceneNodeParent != null)
        _sceneNodeParent.AttachObject(light);

      string sValue = GetAttrib(_xmlElement, "type");
      if (sValue == "point")
        light.Type = Light.LightTypes.LT_POINT;
      else if (sValue == "directional")
        light.Type = Light.LightTypes.LT_DIRECTIONAL;
      else if (sValue == "spot")
        light.Type = Light.LightTypes.LT_SPOTLIGHT;

      // only set if Lamp is Spotlight (Blender)
      bool castShadow = true;
      if (_xmlElement.HasAttribute("castShadow"))
      {
        castShadow = GetAttribBool(_xmlElement, "castShadow", true);
      }
      else if (_xmlElement.HasAttribute("castShadows"))
      {
        castShadow = GetAttribBool(_xmlElement, "castShadows", true);
      }

      light.CastShadows = castShadow;

      // Process normal (?)
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("normal");
      if (xmlElement != null)
        light.Direction = ParseVector3(xmlElement);      // Process normal (?)

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("position");
      if (xmlElement != null)
        light.Position = ParseVector3(xmlElement);

      // Process colourDiffuse (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourDiffuse");
      if (xmlElement != null)
        light.DiffuseColour = ParseColour(xmlElement);

      // Process colourSpecular (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourSpecular");
      if (xmlElement != null)
        light.SpecularColour = ParseColour(xmlElement);

      // Process lightRange (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("lightRange");
      if (xmlElement != null)
        ProcessLightRange(xmlElement, light);

      // Process lightAttenuation (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("lightAttenuation");
      if (xmlElement != null)
        ProcessLightAttenuation(xmlElement, light);
    }

    /// <summary>
    /// Chargement aténuation d'une lumière
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_light">Light</param>
    protected void ProcessLightAttenuation(XmlElement _xmlElement, Light _light)
    {
      // Process attributes
      float range = GetAttribReal(_xmlElement, "range");
      float constant = GetAttribReal(_xmlElement, "constant");
      float linear = GetAttribReal(_xmlElement, "linear");
      float quadratic = GetAttribReal(_xmlElement, "quadratic");

      // Setup the light attenuation
      _light.SetAttenuation(range, constant, linear, quadratic);
    }

    /// <summary>
    /// Chargement portée d'une lumière
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_light">Light</param>
    protected void ProcessLightRange(XmlElement _xmlElement, Light _light)
    {
      // Process attributes
      float inner = GetAttribReal(_xmlElement, "inner");
      float outer = GetAttribReal(_xmlElement, "outer");
      float falloff = GetAttribReal(_xmlElement, "falloff", 1.0f);

      // Setup the light range
      _light.SetSpotlightRange(new Radian((Degree)inner), new Radian((Degree)outer), falloff);
    }

    /// <summary>
    /// Chargement d'une node
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessNode(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      // Construct the node's name
      string name = sPrependNode + GetAttrib(_xmlElement, "name");

      bool bIsInitialStateSet = false;

      // Create the scene node
      SceneNode sceneNode;
      if (name.Length == 0)
      {
        // Let Ogre choose the name
        sceneNode = _sceneNodeParent != null ? _sceneNodeParent.CreateChildSceneNode() : sceneNodeAttach.CreateChildSceneNode();
      }
      else
      {
        // Provide the name
        sceneNode = _sceneNodeParent != null ? _sceneNodeParent.CreateChildSceneNode(name) : sceneNodeAttach.CreateChildSceneNode(name);
      }

      // Process other attributes

      // Process position (?)
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("position");
      if (xmlElement != null)
      {
        sceneNode.Position = ParseVector3(xmlElement);
        sceneNode.SetInitialState();
      }

      // Process quaternion (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("quaternion");
      if (xmlElement != null)
      {
        sceneNode.Orientation = ParseQuaternion(xmlElement);
        sceneNode.SetInitialState();
      }

      // Process rotation (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("rotation");
      if (xmlElement != null)
      {
        sceneNode.Orientation = ParseRotation(xmlElement);
        sceneNode.SetInitialState();
      }

      // Process scale (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("scale");
      if (xmlElement != null)
      {
        sceneNode.SetScale(ParseVector3(xmlElement));
        sceneNode.SetInitialState();
      }

      // Process entity (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("entity");
      if (xmlElement != null) ProcessEntity(xmlElement, sceneNode);


      // Process light (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("light");
      if (xmlElement != null) ProcessLight(xmlElement, sceneNode);

      // Process plane (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("plane");
      if (xmlElement != null)
      {
        ProcessPlane(xmlElement, sceneNode);
        //xmlElement = (XmlElement)xmlElement.NextSibling;
      }

      // Process plane (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("billboardset");
      if (xmlElement != null)
      {
        ProcessBillboardSet(xmlElement, sceneNode);
        //xmlElement = (XmlElement)xmlElement.NextSibling;
      }
      // Process camera (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("camera");
      if (xmlElement != null) ProcessCamera(xmlElement, sceneNode);

      // Process particleSystem (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("particleSystem");
      if (xmlElement != null) ProcessParticleSystem(xmlElement, sceneNode);

      // Process terrain (*)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("terrain");
      if (xmlElement != null) ProcessTerrain(xmlElement, sceneNode);

      // Process userDataReference (?)
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("userData");
      if (xmlElement != null) ProcessUserDataReference(xmlElement, sceneNode);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("lookTarget");
      if (xmlElement != null) LoadLookTarget(xmlElement, sceneNode, null);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("trackTarget");
      if (xmlElement != null) LoadTrackTarget(xmlElement, sceneNode, null);

      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("animations");
      if (xmlElement != null)
      {
        ProcessNodeAnimations(xmlElement, sceneNode);
        SetIdentityInitialState(sceneNode);
        bIsInitialStateSet = true;
      }

      // Process childnodes
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("node");
      while (xmlElement != null)
      {
        ProcessNode(xmlElement, sceneNode);
        xmlElement = (XmlElement)xmlElement.NextSibling;
      }

      //Set the initial state if it hasn't already been set
      if (!bIsInitialStateSet)
        sceneNode.SetInitialState();
    }

    /// <summary>
    /// Chargement terrain
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessTerrain(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      float fWorldSize = GetAttribReal(_xmlElement, "worldSize");
      ushort usMapSize = ushort.Parse(_xmlElement.GetAttribute("mapSize"));
      //bool colourmapEnabled = GetAttribBool(_xmlElement, "colourmapEnabled");
      //int colourMapTextureSize = int.Parse(_xmlElement.GetAttribute("colourMapTextureSize"));
      //int compositeMapDistance = int.Parse(_xmlElement.GetAttribute("tuningCompositeMapDistance"));
      //int maxPixelError = int.Parse(_xmlElement.GetAttribute("tuningMaxPixelError"));

      //Vector3 lightdir = new Vector3(0f, -0.3f, 0.75f);
      //lightdir.Normalise();
      //Light l = mSceneMgr.CreateLight("tstLight");
      //l.Type = Light.LightTypes.LT_DIRECTIONAL;
      //l.Direction = lightdir;
      //l.DiffuseColour = new ColourValue(1.0f, 1.0f, 1.0f);
      //l.SpecularColour = new ColourValue(0.4f, 0.4f, 0.4f);
      //if (mSceneMgr.AmbientLight == null) mSceneMgr.AmbientLight=new ColourValue(0.6f, 0.6f, 0.6f);

      //TerrainGlobalOptions mTerrainGlobalOptions = new TerrainGlobalOptions
      //                                               {
      //                                                 MaxPixelError = maxPixelError,
      //                                                 CompositeMapDistance = compositeMapDistance,
      //                                                 LightMapDirection = lightdir,
      //                                                 CompositeMapAmbient = mSceneMgr.AmbientLight,
      //                                                 CompositeMapDiffuse = l.DiffuseColour
      //                                               };

      TerrainGroup mTerrainGroup = new TerrainGroup(sceneManager, Terrain.Alignment.ALIGN_X_Z, usMapSize, fWorldSize)
                                     {
                                       Origin = Vector3.ZERO,
                                       ResourceGroup = sGroupName
                                     };


      // Process terrain pages (*)
      XmlElement pElement = (XmlElement)_xmlElement.SelectSingleNode("terrainPages");
      if (pElement != null)
      {
        // ReSharper disable PossibleNullReferenceException
        foreach (XmlElement xmlElement in pElement.SelectNodes("terrainPage"))
        // ReSharper restore PossibleNullReferenceException
        {
          ProcessTerrainPage(xmlElement, _sceneNodeParent, mTerrainGroup);
        }
      }
      mTerrainGroup.LoadAllTerrains(true);
      mTerrainGroup.FreeTemporaryResources();
      //mTerrain->setPosition(mTerrainPosition);
    }

    /// <summary>
    /// Chargement terrain
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    /// <param name="_mTerrainGroup">TerrainGroup</param>
    protected void ProcessTerrainPage(XmlElement _xmlElement, SceneNode _sceneNodeParent, TerrainGroup _mTerrainGroup)
    {
      string sName = GetAttrib(_xmlElement, "name");
      int iPageX = int.Parse(_xmlElement.GetAttribute("pageX"));
      int iPageY = int.Parse(_xmlElement.GetAttribute("pageY"));

      if (ResourceGroupManager.Singleton.ResourceExists(_mTerrainGroup.ResourceGroup, sName))
      {
        _mTerrainGroup.DefineTerrain(iPageX, iPageY, sName);
      }
    }

    /// <summary>
    /// Chargement d'un plan
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNodeParent">SceneNode parent</param>
    protected void ProcessPlane(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      string sName = GetAttrib(_xmlElement, "name");
      //float distance = GetAttribReal(_xmlElement, "distance");
      float fWidth = GetAttribReal(_xmlElement, "width");
      float fHeight = GetAttribReal(_xmlElement, "height");

      int ixSegments = (int)GetAttribReal(_xmlElement, "xSegments");
      int iySegments = (int)GetAttribReal(_xmlElement, "ySegments");
      int iNumTexCoordSets = (int)GetAttribReal(_xmlElement, "numTexCoordSets");
      float fuTile = GetAttribReal(_xmlElement, "uTile");
      float fvTile = GetAttribReal(_xmlElement, "vTile");
      string sMaterial = GetAttrib(_xmlElement, "material");
      bool bNormals = GetAttribBool(_xmlElement, "normals");
      //bool movablePlane = GetAttribBool(_xmlElement, "movablePlane");
      bool bCastShadows = GetAttribBool(_xmlElement, "castShadows");
      //bool receiveShadows = GetAttribBool(_xmlElement, "receiveShadows");

      Vector3 v3Normal = Vector3.ZERO;
      XmlElement pElement = (XmlElement)_xmlElement.SelectSingleNode("normal");
      if (pElement != null)
        v3Normal = ParseVector3(pElement);

      Vector3 v3UpVector = Vector3.UNIT_Y;
      pElement = (XmlElement)_xmlElement.SelectSingleNode("upVector");
      if (pElement != null)
        v3UpVector = ParseVector3(pElement);

      Plane plane = new Plane(v3Normal, v3UpVector);

      try
      {
        MeshManager.Singleton.CreatePlane(sName, sGroupName, plane, fWidth, fHeight, ixSegments, iySegments, bNormals, (ushort)iNumTexCoordSets, fuTile, fvTile, v3UpVector);

        Entity entity = sceneManager.CreateEntity(sName, sName);
        entity.CastShadows = bCastShadows;

        if (!string.IsNullOrWhiteSpace(sMaterial)) entity.SetMaterialName(sMaterial);
        _sceneNodeParent.AttachObject(entity);
      }
      catch (Exception e)
      {
        LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading a plane!" + e.Message);
      }
    }

    /// <summary>
    /// Chargement d'une node 
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    protected void ProcessNodes(XmlElement _xmlElement)
    {
      // Process node (*)
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("node");
      while (xmlElement != null)
      {
        ProcessNode(xmlElement, null);
        XmlNode nextNode = xmlElement.NextSibling;
        xmlElement = nextNode as XmlElement;
        while (xmlElement == null && nextNode != null)
        {
          nextNode = nextNode.NextSibling;
          xmlElement = nextNode as XmlElement;
        }
      }
    }

    //    <!ELEMENT billboardSet (billboard*)>
    //<!ATTLIST billboardSet
    //    name        CDATA    #REQUIRED   
    //    material    CDATA    #REQUIRED
    //    id            ID        #IMPLIED
    //    width        CDATA    #DEFAULT    "10"
    //    height        CDATA    #DEFAULT    "10"
    //    type        (orientedCommon | orientedSelf | point) "point"
    //    origin        (bottomLeft | bottomCenter | bottomRight | left | center | right | topLeft | topCenter | topRight) "center"
    //>

    /// <summary>
    /// Chargement d'un billboardset
    /// </summary>
    /// <param name="_xmlElement">xml</param>
    /// <param name="_sceneNodeParent">node auquel le billboardset est rattaché</param>
    protected void ProcessBillboardSet(XmlElement _xmlElement, SceneNode _sceneNodeParent)
    {
      string sName = GetAttrib(_xmlElement, "name");
      string sMaterial = GetAttrib(_xmlElement, "material");

      BillboardSet billboardSet = sceneManager.CreateBillboardSet(sName);
      billboardSet.DefaultHeight = GetAttribReal(_xmlElement, "height", 10);
      billboardSet.DefaultWidth = GetAttribReal(_xmlElement, "width", 10);

      switch (GetAttrib(_xmlElement, "type", "point"))
      {
        case "orientedCommon":
          billboardSet.BillboardType = BillboardType.BBT_ORIENTED_COMMON;
          break;
        case "orientedSelf":
          billboardSet.BillboardType = BillboardType.BBT_ORIENTED_SELF;
          break;
        case "point":
          billboardSet.BillboardType = BillboardType.BBT_POINT;
          break;
        case "perpendicularCommon":
          billboardSet.BillboardType = BillboardType.BBT_PERPENDICULAR_COMMON;
          break;
        case "perpendicularSelf":
          billboardSet.BillboardType = BillboardType.BBT_PERPENDICULAR_SELF;
          break;

        default:
          billboardSet.BillboardType = BillboardType.BBT_ORIENTED_COMMON;
          LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading a billboardSet! Unknown type");
          break;
      }


      billboardSet.SetMaterialName(sMaterial);
      switch (GetAttrib(_xmlElement, "origin", "center"))
      {
        case "bottomLeft":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_BOTTOM_LEFT;
          break;
        case "bottomCenter":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_BOTTOM_CENTER;
          break;
        case "bottomRight":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_BOTTOM_RIGHT;
          break;
        case "left":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_CENTER_LEFT;
          break;
        case "center":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_TOP_CENTER;
          break;
        case "right":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_CENTER_RIGHT;
          break;
        case "topLeft":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_TOP_LEFT;
          break;
        case "topCenter":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_TOP_CENTER;
          break;
        case "topRight":
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_TOP_RIGHT;
          break;
        default:
          billboardSet.BillboardOrigin = BillboardOrigin.BBO_BOTTOM_CENTER;
          LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading a billboardSet! Unknown origin");
          break;
      }

      _sceneNodeParent.AttachObject(billboardSet);

      // Process childnodes
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("billboard");
      while (xmlElement != null)
      {
        ProcessBillboard(xmlElement, billboardSet);
        xmlElement = (XmlElement)xmlElement.NextSibling;
      }

    }

    /// <summary>
    /// Création d'un billboard
    /// </summary>
    /// <param name="_xmlElement">xml</param>
    /// <param name="_billboardSet">billboardset auquel le billboard est rattaché</param>
    protected void ProcessBillboard(XmlElement _xmlElement, BillboardSet _billboardSet)
    {
      Vector3 v3Position = new Vector3();
      XmlElement xmlElement = (XmlElement)_xmlElement.SelectSingleNode("position");
      if (xmlElement != null)
      {
        v3Position = ParseVector3(xmlElement);
      }
      Billboard billboard = _billboardSet.CreateBillboard(v3Position);
      float fRotation = 0;
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("rotation");
      if (xmlElement != null)
      {
        fRotation = GetAttribReal(_xmlElement, "angle", 0);
      }
      billboard.Rotation = fRotation;

      ColourValue colourValue = ColourValue.White;
      xmlElement = (XmlElement)_xmlElement.SelectSingleNode("colourDiffuse");
      if (xmlElement != null)
      {
        colourValue = ParseColour(xmlElement);
      }
      billboard.Colour = colourValue;
      if (_xmlElement.HasAttribute("width") && _xmlElement.HasAttribute("height")) billboard.SetDimensions(GetAttribReal(_xmlElement, "width"), GetAttribReal(_xmlElement, "height"));
    }


    /// <summary>
    /// Chargement scène
    /// </summary>
    /// <param name="_xmlRoot">XmlElement</param>
    protected void ProcessScene(XmlElement _xmlRoot)
    {
      // Process the scene parameters
      string version = GetAttrib(_xmlRoot, "formatVersion", "unknown");

      string message = "[DotSceneLoader] Parsing dotScene file with version " + version;

      LogManager.Singleton.LogMessage(message);

      // Process nodes (?)
      XmlElement xmlElement = (XmlElement)_xmlRoot.SelectSingleNode("nodes");
      if (xmlElement != null)
        ProcessNodes(xmlElement);

      FinishLoadingLookAndTrackTargets();

      // Process environment (?)
      xmlElement = (XmlElement)_xmlRoot.SelectSingleNode("environment");
      if (xmlElement != null) ProcessEnvironment(xmlElement);
      // Process externals (?)
      //         pElement = (XmlElement)XMLRoot.SelectSingleNode("externals");
      //         if (pElement != null)
      //            ProcessExternals(pElement);
    }

    /// <summary>
    /// Chargement référence de donnée utilisateur
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNode">SceneNode</param>
    protected void ProcessUserDataReference(XmlElement _xmlElement, SceneNode _sceneNode)
    {
      // TODO
    }

    /// <summary>
    /// Chargement système de particule
    /// </summary>
    /// <param name="_xmlElement">XmlElement</param>
    /// <param name="_sceneNode">SceneNode</param>
    protected void ProcessParticleSystem(XmlElement _xmlElement, SceneNode _sceneNode)
    {
      // Process attributes
      string sName = GetAttrib(_xmlElement, "name");
      string sFile = GetAttrib(_xmlElement, "file");

      // Create the particle system
      try
      {
        ParticleSystem particleSystem = sceneManager.CreateParticleSystem(sName, sFile);
        _sceneNode.AttachObject(particleSystem);
      }
      catch (Exception e)
      {
        LogManager.Singleton.LogMessage("[DotSceneLoader] Error loading an Particle system!" + e.Message);
      }
    }

    private void LoadLookTarget(XmlElement _xmlElement, SceneNode _sceneNode, Camera _camera)
    {
      LookTarget lookTarget = new LookTarget(_sceneNode, _camera)
                                {
                                  NodeName = GetAttrib(_xmlElement, "nodeName")
                                };

      string relativeTo = GetAttrib(_xmlElement, "relativeTo");
      if (!string.IsNullOrEmpty(relativeTo))
        lookTarget.RelativeTo = (Node.TransformSpace)Enum.Parse(typeof(Node.TransformSpace), relativeTo);


      foreach (XmlElement childElement in _xmlElement.ChildNodes)
      {
        switch (childElement.Name)
        {
          case "position":
            lookTarget.Position = ParseVector3(childElement);
            lookTarget.IsPositionSet = true;
            break;
          case "localDirection":
            lookTarget.LocalDirection = ParseVector3(childElement);
            break;
        }
      }

      lookTargets.Add(lookTarget);
    }

    private void LoadTrackTarget(XmlElement _xmlElement, SceneNode _sceneNode, Camera _camera)
    {
      TrackTarget trackTarget = new TrackTarget(_sceneNode, _camera)
                                  {
                                    NodeName = GetAttrib(_xmlElement, "nodeName")
                                  };

      foreach (XmlElement xmlElement in _xmlElement.ChildNodes)
      {
        switch (xmlElement.Name)
        {
          case "offset":
            trackTarget.Offset = ParseVector3(xmlElement);
            break;
          case "localDirection":
            trackTarget.LocalDirection = ParseVector3(xmlElement);
            break;
        }
      }

      trackTargets.Add(trackTarget);
    }


    private void FinishLoadingLookAndTrackTargets()
    {
      // ReSharper disable ForCanBeConvertedToForeach
      for (int i = 0; i < lookTargets.Count; i++)
      // ReSharper restore ForCanBeConvertedToForeach
      {
        LookTarget lookTarget = lookTargets[i];
        SceneNode lookTargetNode = string.IsNullOrEmpty(lookTarget.NodeName) ? null : sceneManager.GetSceneNode(lookTarget.NodeName);
        Vector3 position = new Vector3();
        if (lookTarget.IsPositionSet) position = lookTarget.Position;
        else
        {
          lookTarget.RelativeTo = Node.TransformSpace.TS_WORLD;
          if (lookTargetNode != null) position = lookTargetNode._getDerivedPosition();
        }
        if (lookTarget.SourceNode != null)
          lookTarget.SourceNode.LookAt(position, lookTarget.RelativeTo, lookTarget.LocalDirection);
        else if (lookTarget.SourceCamera != null)
          lookTarget.SourceCamera.LookAt(position);
      }
      lookTargets.Clear();

      foreach (TrackTarget trackTarget in trackTargets)
      {
        SceneNode trackTargetNode = sceneManager.GetSceneNode(trackTarget.NodeName);
        if (trackTarget.SourceNode != null)
          trackTarget.SourceNode.SetAutoTracking(true, trackTargetNode, trackTarget.LocalDirection, trackTarget.Offset);
        else
        {
          if (trackTarget.SourceCamera != null) trackTarget.SourceCamera.SetAutoTracking(true, trackTargetNode, trackTarget.Offset);
        }
      }
      trackTargets.Clear();
    }

    private void SetIdentityInitialState(SceneNode _node)
    {
      //Get the current state
      Vector3 position = _node.Position;
      Quaternion orientation = _node.Orientation;
      Vector3 scale = _node.GetScale();

      //Set the initial state to be at identity
      _node.SetPosition(Vector3.ZERO.x, Vector3.ZERO.y, Vector3.ZERO.z);
      _node.SetOrientation(Quaternion.IDENTITY.w, Quaternion.IDENTITY.x, Quaternion.IDENTITY.y, Quaternion.IDENTITY.z);
      _node.SetScale(Vector3.UNIT_SCALE);
      _node.SetInitialState();

      //Set the current state so the node is in the correct position if the node has
      //animations that are initially disabled
      _node.SetPosition(position.x, position.y, position.z);
      _node.SetOrientation(orientation.w, orientation.x, orientation.y, orientation.z);
      _node.SetScale(scale);
    }
  }
}

<HR>
Creative Commons Copyright -- Some rights reserved.


THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.

1. Definitions

  • "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
  • "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
  • "Licensor" means the individual or entity that offers the Work under the terms of this License.
  • "Original Author" means the individual or entity who created the Work.
  • "Work" means the copyrightable work of authorship offered under the terms of this License.
  • "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
  • "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.

2. Fair Use Rights

Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.

3. License Grant

Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:

  • to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
  • to create and reproduce Derivative Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
  • For the avoidance of doubt, where the work is a musical composition:
    • Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
    • Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
    • Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).


The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.

4. Restrictions

The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:

  • You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
  • You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
  • If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability.

EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. Termination

  • This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
  • Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.

8. Miscellaneous

  • Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
  • Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
  • If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
  • No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
  • This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.