/Rendering/SceneGraph/SceneGraphNode.cs
C# | 821 lines | 517 code | 68 blank | 236 comment | 21 complexity | 17b7892abd3061a6f055953ce7175358 MD5 | raw file
Possible License(s): Apache-2.0
- #region License
- /* Copyright : Santtu Syrjälä
- * License : New BSD
- *
- * SceneGraphNode for Delta Engine
- *
- * General purpose scene graph for 2D and 3D that is compatible with Delta Engines vertex constructs, cameras and rendering pipeline.
- *
- * If You find a bug, find a way to make it work faster or other additions to make it more useful please share them! You can find me in Delta Engine forums. You will get Your name
- * in here if YOU WISH.
- *
- * Addition : I don't wa...(of course I want) NEED money for this thing. I though would like You to include me in the credits portion of Your application if You like/use
- * this. It is NOT REQUIRED, though it would serve as a little thanks that would warm this programmer's heart.
- *
- * Changes :
- * 10.09.2011 : Release of the preview 0.1.0.0
- */
- #endregion
-
- using System;
- using System.Collections.Generic;
- using Delta.Utilities.Datatypes;
-
- namespace Delta.Rendering.SceneGraph
- {
- /// <summary>
- /// Represents Node that can be part of global Scene hierarchy.
- /// Note that every SceneNode can have more than one children.
- /// </summary>
- public class SceneGraphNode
- {
- #region Constants
- /// <summary>
- /// Sync object to be locked during RenderAll
- /// </summary>
- private static readonly object lockObject = new object();
- #endregion
-
- #region RenderOrder (Public)
- /// <summary>
- /// This property sets the child node render order. If ChildrenFirst then
- /// child nodes are processed first and then the current node, ChildrenLast
- /// is the opposite.
- /// </summary>
- public ChildrenRenderOrder RenderOrder
- {
- get;
- set;
- }
- #endregion
-
- #region Parent (Public)
- /// <summary>
- /// Gets the parent of this node.
- /// </summary>
- public SceneGraphNode Parent
- {
- get;
- private set;
- }
- #endregion
-
- #region Root (Public)
- /// <summary>
- /// Property to get the root node.
- /// </summary>
- public SceneGraphNode Root
- {
- get;
- private set;
- }
- #endregion
-
- #region Depth (Public)
- /// <summary>
- /// Gets the depth of the tree beginning from this node.
- /// </summary>
- public int Depth
- {
- get;
- private set;
- }
- #endregion
-
- #region ChildrenCount (Public)
- /// <summary>
- /// Gets the children count.
- /// </summary>
- public int ChildrenCount
- {
- get
- {
- return children.Count;
- }
- }
- #endregion
-
- #region Children (Public)
- /// <summary>
- /// Gets enumerator of all children of this node.
- /// </summary>
- public IEnumerable<SceneGraphNode> Children
- {
- get
- {
- return children;
- }
- }
- #endregion
-
- #region LocalPosition (Public)
- /// <summary>
- /// Gets or Sets the local position.
- /// Use method <see cref="GetLocalPosition"/> for performance.
- /// </summary>
- public Vector LocalPosition
- {
- get
- {
- return localPosition;
- }
- set
- {
- SetLocalPosition(ref value);
- }
- }
- #endregion
-
- #region LocalRotation (Public)
- /// <summary>
- /// Property to get the local rotation.
- /// Use method <see cref="GetLocalRotation"/> for performance.
- /// </summary>
- public Vector LocalRotation
- {
- get
- {
- UpdateTransformation();
- return localRotation;
- }
- set
- {
- SetLocalRotation(ref value);
- }
- }
- #endregion
-
- #region LocalScale (Public)
- /// <summary>
- /// Get or Sets the local scale.
- /// Use method <see cref="GetLocalScale"/> for performance.
- /// </summary>
- public Vector LocalScale
- {
- get
- {
- return localScale;
- }
- set
- {
- SetLocalScale(ref value);
- }
- }
- #endregion
-
- #region WorldPosition (Public)
- /// <summary>
- /// Gets the world position.
- /// Use method <see cref="GetWorldPosition"/> for performance.
- /// </summary>
- public Vector WorldPosition
- {
- get
- {
- Vector toReturn = Vector.Zero;
- GetWorldPosition(ref toReturn);
- return toReturn;
- }
- }
- #endregion
-
- #region WorldRotation (Public)
- /// <summary>
- /// Property to get the world rotation.
- /// Use method <see cref="GetWorldRotation"/> for performance.
- /// </summary>
- public Vector WorldRotation
- {
- get
- {
- Vector toReturn = Vector.Zero;
- GetWorldRotation(ref toReturn);
- return toReturn;
- }
- }
- #endregion
-
- #region WorldScale (Public)
- /// <summary>
- /// Gets the world scale.
- /// Use method <see cref="GetWorldScale"/> for performance.
- /// </summary>
- public Vector WorldScale
- {
- get
- {
- Vector toReturn = Vector.Zero;
- GetWorldScale(ref toReturn);
- return toReturn;
- }
- }
- #endregion
-
- #region LocalTransformation (Public)
- /// <summary>
- /// Local transformation matrix, copy value type.
- /// Use method <see cref="GetLocalTransformation"/> for performance.
- /// </summary>
- public Matrix LocalTransformation
- {
- get
- {
- UpdateTransformation();
- return localTransformation;
- }
- }
- #endregion
-
- #region WorldTransformation (Public)
- /// <summary>
- /// World transformation matrix, copy value type.
- /// Use method <see cref="GetWorldTransformation"/> for performance.
- /// </summary>
- public Matrix WorldTransformation
- {
- get
- {
- UpdateTransformation();
- return worldTransformation;
- }
- }
- #endregion
-
- #region Protected
-
- #region worldTransformation (Protected)
- /// <summary>
- /// Matrix combined with Parent local transformation.
- /// </summary>
- protected Matrix worldTransformation;
- #endregion
-
- #region Recalculate (Protected)
- /// <summary>
- /// If recalculate is true, UpdateTransformation recalculates world matrix.
- /// </summary>
- protected bool Recalculate
- {
- get
- {
- return recalculate;
- }
- private set
- {
- recalculate = value;
- foreach (SceneGraphNode node in children)
- {
- node.Recalculate = true;
- }
- }
- }
- #endregion
-
- #endregion
-
- #region Private
-
- #region localPosition (Private)
- /// <summary>
- /// Local position of this node.
- /// </summary>
- private Vector localPosition;
- #endregion
-
- #region localRotation (Private)
- /// <summary>
- /// Local rotation of this node.
- /// </summary>
- private Vector localRotation;
- #endregion
-
- #region localScale (Private)
- /// <summary>
- /// Local scale of this node.
- /// </summary>
- private Vector localScale;
- #endregion
-
- #region localTransformation (Private)
- /// <summary>
- /// Local transformation of this node.
- /// </summary>
- private Matrix localTransformation;
- #endregion
-
- #region recalculate (Private)
- /// <summary>
- /// Value that indicates whether to calculate the full transformation.
- /// </summary>
- private bool recalculate;
- #endregion
-
- #region children (Private)
- /// <summary>
- /// List containing all children of this node.
- /// </summary>
- private readonly List<SceneGraphNode> children = new List<SceneGraphNode>();
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Creates a new instance of <see cref="SceneGraphNode"/>
- /// </summary>
- public SceneGraphNode()
- {
- ResetLocal();
- Root = this;
- RenderOrder = ChildrenRenderOrder.ChildrenFirst;
- }
- #endregion
-
- #region ResetLocal (Public)
- /// <summary>
- /// Resets the node to original values.
- /// </summary>
- public void ResetLocal()
- {
- localPosition = Vector.Zero;
- localRotation = Vector.Zero;
- localScale = Vector.One;
- Recalculate = true;
- }
- #endregion
-
- #region Add (Public)
- /// <summary>
- /// Add a new node to the end of the child node list.
- /// </summary>
- /// <param name="toAdd">Node to add.</param>
- public void Add(SceneGraphNode toAdd)
- {
- // Check if node was already added.
- if (children.Contains(toAdd))
- {
- return;
- }
-
- children.Add(toAdd);
- toAdd.Root = Root;
- toAdd.Parent = this;
- toAdd.Recalculate = true;
- CheckDepth(toAdd);
- }
-
- /// <summary>
- /// Adds an enumerable list of SceneGraphNode to this node.
- /// </summary>
- /// <param name="toAdd">Nodes to add.</param>
- public void Add(IEnumerable<SceneGraphNode> toAdd)
- {
- foreach (SceneGraphNode iterNode in toAdd)
- {
- Add(iterNode);
- }
- }
- #endregion
-
- #region Insert (Public)
- /// <summary>
- /// Inserts node at specific position.
- /// </summary>
- /// <param name="index">Index where to insert.</param>
- /// <param name="toAdd">Node to add.</param>
- public void Insert(int index, SceneGraphNode toAdd)
- {
- children.Insert(index, toAdd);
- toAdd.Parent = this;
- toAdd.Root = Root;
- toAdd.Recalculate = true;
- CheckDepth(toAdd);
- }
-
- /// <summary>
- /// Inserts enumerable list of nodes at specific location.
- /// </summary>
- /// <param name="index">Index where to insert.</param>
- /// <param name="toAdd">Nodes to add.</param>
- public void Insert(int index, IEnumerable<SceneGraphNode> toAdd)
- {
- children.InsertRange(index, toAdd);
- foreach (SceneGraphNode node in toAdd)
- {
- node.Parent = this;
- node.Root = Root;
- node.Recalculate = true;
- CheckDepth(node);
- }
- }
- #endregion
-
- #region Remove (Public)
- /// <summary>
- /// Removes child node.
- /// </summary>
- /// <param name="toRemove">Node to remove.</param>
- /// <returns>True if remove succeeded.</returns>
- public bool Remove(SceneGraphNode toRemove)
- {
- // Check if children exists.
- if (children.Contains(toRemove) == false)
- {
- return false;
- }
-
- bool toReturn = children.Remove(toRemove);
- if (toReturn)
- {
- toRemove.Root = null;
- toRemove.Parent = null;
- toRemove.CheckDepth(null);
- }
- CheckDepth(null);
- return toReturn;
- }
- #endregion
-
- #region RemoveAt (Public)
- /// <summary>
- /// Removes child node at index.
- /// </summary>
- /// <param name="index">Index where to remove.</param>
- public void RemoveAt(int index)
- {
- if (index > children.Count - 1)
- {
- throw new ArgumentOutOfRangeException("index");
- }
-
- SceneGraphNode toRemove = children[index];
- toRemove.Root = null;
- children.RemoveAt(index);
- toRemove.Parent = null;
- toRemove.CheckDepth(null);
-
- CheckDepth(null);
- }
- #endregion
-
- #region RemoveFromParent (Public)
- /// <summary>
- /// Removes this node from parent.
- /// </summary>
- public void RemoveFromParent()
- {
- if (Parent != null)
- {
- Parent.Remove(this);
- }
- }
- #endregion
-
- #region Clear (Public)
- /// <summary>
- /// Removes all child nodes.
- /// </summary>
- public void Clear()
- {
- children.Clear();
- CheckDepth(null);
- }
- #endregion
-
- #region GetLocalPosition (Public)
- /// <summary>
- /// Method to get the local position.
- /// </summary>
- /// <param name="whereToSet">Where to store the position.</param>
- public void GetLocalPosition(ref Vector whereToSet)
- {
- UpdateTransformation();
- whereToSet = localPosition;
- }
- #endregion
-
- #region SetLocalPosition (Public)
- /// <summary>
- /// Set the local position.
- /// </summary>
- /// <param name="toSet">What to set.</param>
- public virtual void SetLocalPosition(ref Vector toSet)
- {
- localPosition = toSet;
- Recalculate = true;
- }
-
- /// <summary>
- /// Set local position.
- /// </summary>
- /// <param name="x">X coordinate.</param>
- /// <param name="y">Y coordinate.</param>
- /// <param name="z">Z coordinate.</param>
- public virtual void SetLocalPosition(float x, float y, float z)
- {
- localPosition.X = x;
- localPosition.Y = y;
- localPosition.Z = z;
- Recalculate = true;
- }
- #endregion
-
- #region OffsetLocalPosition (Public)
- /// <summary>
- /// Offset the local position with given value.
- /// </summary>
- /// <param name="toSet">What to offset.</param>
- /// <param name="toOffset">Offset</param>
- public virtual void OffsetLocalPosition(ref Vector toOffset)
- {
- localPosition.X += toOffset.X;
- localPosition.Y += toOffset.Y;
- localPosition.Z += toOffset.Z;
- Recalculate = true;
- }
-
- /// <summary>
- /// Method to offset local position.
- /// </summary>
- /// <param name="x">X coordinate.</param>
- /// <param name="y">Y coordinate.</param>
- /// <param name="z">Z coordinate.</param>
- public virtual void OffsetLocalPosition(float x, float y, float z)
- {
- localPosition.X += x;
- localPosition.Y += y;
- localPosition.Z += z;
- Recalculate = true;
- }
- #endregion
-
- #region GetLocalRotation (Public)
- /// <summary>
- /// Method to get the local rotation.
- /// </summary>
- /// <param name="whereToSet">Where to store the rotation.</param>
- public void GetLocalRotation(ref Vector whereToSet)
- {
- UpdateTransformation();
- whereToSet = localRotation;
- }
- #endregion
-
- #region SetLocalRotation (Public)
- /// <summary>
- /// Method to set the local rotation.
- /// </summary>
- /// <param name="toSet">What to set.</param>
- public virtual void SetLocalRotation(ref Vector toSet)
- {
- localRotation = toSet;
- Recalculate = true;
- }
-
- /// <summary>
- /// Method to set local rotation.
- /// </summary>
- /// <param name="x">X coordinate.</param>
- /// <param name="y">Y coordinate.</param>
- /// <param name="z">Z coordinate.</param>
- public virtual void SetLocalRotation(float x, float y, float z)
- {
- localRotation.X = x;
- localRotation.Y = y;
- localRotation.Z = z;
- Recalculate = true;
- }
- #endregion
-
- #region GetLocalScale (Public)
- /// <summary>
- /// Method to get the local scale.
- /// </summary>
- /// <param name="whereToSet">Where to store the scale.</param>
- public void GetLocalScale(ref Vector whereToSet)
- {
- UpdateTransformation();
- whereToSet = localScale;
- }
- #endregion
-
- #region SetLocalScale (Public)
- /// <summary>
- /// Method for setting the local scale.
- /// </summary>
- /// <param name="toSet">What to set.</param>
- public virtual void SetLocalScale(ref Vector toSet)
- {
- localScale = toSet;
- Recalculate = true;
- }
-
- /// <summary>
- /// Method for setting local scale.
- /// </summary>
- /// <param name="x">X coordinate.</param>
- /// <param name="y">Y coordinate.</param>
- /// <param name="z">Z coordinate.</param>
- public virtual void SetLocalScale(float x, float y, float z)
- {
- localScale.X = x;
- localScale.Y = y;
- localScale.Z = z;
- Recalculate = true;
- }
- #endregion
-
- #region GetLocalTransformation (Public)
- /// <summary>
- /// Method to get the local transformation matrix.
- /// </summary>
- /// <param name="whereToGet">Where the local matrix is stored.</param>
- public void GetLocalTransformation(ref Matrix whereToGet)
- {
- UpdateTransformation();
- whereToGet = localTransformation;
- }
- #endregion
-
- #region GetWorldTransformation (Public)
- /// <summary>
- /// Method to get the world transformation matrix.
- /// </summary>
- /// <param name="whereToGet">Where the world matrix is stored.</param>
- public void GetWorldTransformation(ref Matrix whereToGet)
- {
- UpdateTransformation();
- whereToGet = worldTransformation;
- }
- #endregion
-
- #region GetWorldPosition (Public)
- /// <summary>
- /// Method to get the world position of the node.
- /// </summary>
- /// <param name="whereToSet">Where to store the position.</param>
- public void GetWorldPosition(ref Vector whereToSet)
- {
- UpdateTransformation();
- whereToSet = worldTransformation.Translation;
- }
- #endregion
-
- #region GetWorldRotation (Public)
- /// <summary>
- /// Method to getting the world rotation.
- /// </summary>
- /// <param name="whereToSet">Where to store the rotation.</param>
- public void GetWorldRotation(ref Vector whereToSet)
- {
- UpdateTransformation();
- // There could be easier way to do this...
- SceneGraphNode current = this;
- whereToSet.X = 0;
- whereToSet.Y = 0;
- whereToSet.Z = 0;
- while (current != null)
- {
- Vector.Add(ref whereToSet, ref current.localRotation, out whereToSet);
- current = current.Parent;
- }
- whereToSet.X = whereToSet.X % 360.0f;
- whereToSet.Y = whereToSet.Y % 360.0f;
- whereToSet.Z = whereToSet.Z % 360.0f;
- }
- #endregion
-
- #region GetWorldScale (Public)
- /// <summary>
- ///Get the world scale.
- /// </summary>
- /// <param name="whereToSet">Where to store the scale.</param>
- public void GetWorldScale(ref Vector whereToSet)
- {
- UpdateTransformation();
- whereToSet = worldTransformation.Scaling;
- }
- #endregion
-
- #region Render (Public)
- /// <summary>
- /// Render method to be called when this node is to be rendered.
- /// Override if you need to render this node.
- /// </summary>
- public virtual void Render()
- {
- }
- #endregion
-
- #region RenderAll (Public)
- /// <summary>
- /// Renders all child nodes and this node.
- /// </summary>
- public void RenderAll()
- {
- lock (lockObject)
- {
- UpdateTransformation();
- int i;
- switch (RenderOrder)
- {
- case ChildrenRenderOrder.ChildrenFirst:
- for (i = 0; i < children.Count; i++)
- {
- children[i].RenderAll();
- }
-
- // Render this node for last.
- Render();
- break;
- default:
- // Render this node for first.
- Render();
- for (i = 0; i < children.Count; i++)
- {
- children[i].RenderAll();
- }
- break;
- }
- }
- }
- #endregion
-
- #region Methods (Private)
-
- #region UpdateTransformation
- /// <summary>
- /// Updates local and world transformation if needed, so if Recalculate is
- /// true then it is recalculated.
- /// </summary>
- /// <returns>
- /// True if the matrices were recalculated.
- /// </returns>
- protected virtual bool UpdateTransformation()
- {
- bool toReturn = false;
- lock (this)
- {
- if (Recalculate)
- {
- // Order is: Scale - Rotation - Translation
- toReturn = true;
- localTransformation = Matrix.CreateScale(localScale);
- Matrix tempMatrix = Matrix.CreateRotationZYX(localRotation.X,
- localRotation.Y, localRotation.Z);
-
- Matrix.Multiply(ref localTransformation, ref tempMatrix,
- ref localTransformation);
-
- tempMatrix = Matrix.CreateTranslation(localPosition);
- Matrix.Multiply(ref localTransformation, ref tempMatrix,
- ref localTransformation);
-
- // Combine with parent, if any.
- if (Parent != null)
- {
- Parent.UpdateTransformation();
- Matrix.Multiply(ref localTransformation,
- ref Parent.worldTransformation, ref worldTransformation);
- }
- else
- {
- worldTransformation = localTransformation;
- }
- Recalculate = false;
- }
- }
- return toReturn;
- }
- #endregion
-
- #region CheckDepth
- /// <summary>
- /// Checks the node depth.
- /// </summary>
- /// <param name="toCheck">Graph node to check.</param>
- private void CheckDepth(SceneGraphNode toCheck)
- {
- int oldDepth = Depth;
- if (toCheck == null)
- {
- Depth = 0;
- foreach (SceneGraphNode node in children)
- {
- Depth = Math.Max(1 + node.Depth, Depth);
- }
- }
- else
- {
- Depth = Math.Max(1 + toCheck.Depth, Depth);
- }
- if (oldDepth != Depth && Parent != null)
- {
- Parent.CheckDepth(null);
- }
- }
- #endregion
-
- #endregion
- }
- }