PageRenderTime 287ms CodeModel.GetById 120ms app.highlight 42ms RepoModel.GetById 119ms app.codeStats 1ms

/Rendering/SceneGraph/SceneGraphNode.cs

#
C# | 821 lines | 517 code | 68 blank | 236 comment | 21 complexity | 17b7892abd3061a6f055953ce7175358 MD5 | raw file
  1#region License
  2/* Copyright : Santtu Syrjälä
  3 * License : New BSD
  4 * 
  5 * SceneGraphNode for Delta Engine 
  6 * 
  7 * General purpose scene graph for 2D and 3D that is compatible with Delta Engines vertex constructs, cameras and rendering pipeline.
  8 * 
  9 * 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
 10 * in here if YOU WISH.
 11 * 
 12 * 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
 13 * this. It is NOT REQUIRED, though it would serve as a little thanks that would warm this programmer's heart.
 14 * 
 15 * Changes :
 16 * 10.09.2011 : Release of the preview 0.1.0.0
 17 */
 18#endregion
 19
 20using System;
 21using System.Collections.Generic;
 22using Delta.Utilities.Datatypes;
 23
 24namespace Delta.Rendering.SceneGraph
 25{
 26	/// <summary>
 27	/// Represents Node that can be part of global Scene hierarchy.
 28	/// Note that every SceneNode can have more than one children.
 29	/// </summary>
 30	public class SceneGraphNode
 31	{
 32		#region Constants
 33		/// <summary>
 34		/// Sync object to be locked during RenderAll
 35		/// </summary>
 36		private static readonly object lockObject = new object();
 37		#endregion
 38
 39		#region RenderOrder (Public)
 40		/// <summary>
 41		/// This property sets the child node render order. If ChildrenFirst then
 42		/// child nodes are processed first and then the current node, ChildrenLast
 43		/// is the opposite.
 44		/// </summary>
 45		public ChildrenRenderOrder RenderOrder
 46		{
 47			get;
 48			set;
 49		}
 50		#endregion
 51
 52		#region Parent (Public)
 53		/// <summary>
 54		/// Gets the parent of this node.
 55		/// </summary>
 56		public SceneGraphNode Parent
 57		{
 58			get;
 59			private set;
 60		}
 61		#endregion
 62
 63		#region Root (Public)
 64		/// <summary>
 65		/// Property to get the root node.
 66		/// </summary>
 67		public SceneGraphNode Root
 68		{
 69			get;
 70			private set;
 71		}
 72		#endregion
 73
 74		#region Depth (Public)
 75		/// <summary>
 76		/// Gets the depth of the tree beginning from this node.
 77		/// </summary>
 78		public int Depth
 79		{
 80			get;
 81			private set;
 82		}
 83		#endregion
 84
 85		#region ChildrenCount (Public)
 86		/// <summary>
 87		/// Gets the children count.
 88		/// </summary>
 89		public int ChildrenCount
 90		{
 91			get
 92			{
 93				return children.Count;
 94			}
 95		}
 96		#endregion
 97
 98		#region Children (Public)
 99		/// <summary>
100		/// Gets enumerator of all children of this node.
101		/// </summary>
102		public IEnumerable<SceneGraphNode> Children
103		{
104			get
105			{
106				return children;
107			}
108		}
109		#endregion
110
111		#region LocalPosition (Public)
112		/// <summary>
113		/// Gets or Sets the local position. 
114		/// Use method <see cref="GetLocalPosition"/> for performance.
115		/// </summary>
116		public Vector LocalPosition
117		{
118			get
119			{
120				return localPosition;
121			}
122			set
123			{
124				SetLocalPosition(ref value);
125			}
126		}
127		#endregion
128
129		#region LocalRotation (Public)
130		/// <summary>
131		/// Property to get the local rotation. 
132		/// Use method <see cref="GetLocalRotation"/> for performance.
133		/// </summary>
134		public Vector LocalRotation
135		{
136			get
137			{
138				UpdateTransformation();
139				return localRotation;
140			}
141			set
142			{
143				SetLocalRotation(ref value);
144			}
145		}
146		#endregion
147
148		#region LocalScale (Public)
149		/// <summary>
150		/// Get or Sets the local scale. 
151		/// Use method <see cref="GetLocalScale"/> for performance.
152		/// </summary>
153		public Vector LocalScale
154		{
155			get
156			{
157				return localScale;
158			}
159			set
160			{
161				SetLocalScale(ref value);
162			}
163		}
164		#endregion
165
166		#region WorldPosition (Public)
167		/// <summary>
168		/// Gets the world position. 
169		/// Use method <see cref="GetWorldPosition"/> for performance.
170		/// </summary>
171		public Vector WorldPosition
172		{
173			get
174			{
175				Vector toReturn = Vector.Zero;
176				GetWorldPosition(ref toReturn);
177				return toReturn;
178			}
179		}
180		#endregion
181
182		#region WorldRotation (Public)
183		/// <summary>
184		/// Property to get the world rotation. 
185		/// Use method <see cref="GetWorldRotation"/> for performance.
186		/// </summary>
187		public Vector WorldRotation
188		{
189			get
190			{
191				Vector toReturn = Vector.Zero;
192				GetWorldRotation(ref toReturn);
193				return toReturn;
194			}
195		}
196		#endregion
197
198		#region WorldScale (Public)
199		/// <summary>
200		/// Gets the world scale. 
201		/// Use method <see cref="GetWorldScale"/> for performance.
202		/// </summary>
203		public Vector WorldScale
204		{
205			get
206			{
207				Vector toReturn = Vector.Zero;
208				GetWorldScale(ref toReturn);
209				return toReturn;
210			}
211		}
212		#endregion
213
214		#region LocalTransformation (Public)
215		/// <summary>
216		/// Local transformation matrix, copy value type. 
217		/// Use method <see cref="GetLocalTransformation"/> for performance.
218		/// </summary>
219		public Matrix LocalTransformation
220		{
221			get
222			{
223				UpdateTransformation();
224				return localTransformation;
225			}
226		}
227		#endregion
228
229		#region WorldTransformation (Public)
230		/// <summary>
231		/// World transformation matrix, copy value type. 
232		/// Use method <see cref="GetWorldTransformation"/> for performance.
233		/// </summary>
234		public Matrix WorldTransformation
235		{
236			get
237			{
238				UpdateTransformation();
239				return worldTransformation;
240			}
241		}
242		#endregion
243
244		#region Protected
245
246		#region worldTransformation (Protected)
247		/// <summary>
248		/// Matrix combined with Parent local transformation.
249		/// </summary>
250		protected Matrix worldTransformation;
251		#endregion
252
253		#region Recalculate (Protected)
254		/// <summary>
255		/// If recalculate is true, UpdateTransformation recalculates world matrix.
256		/// </summary>
257		protected bool Recalculate
258		{
259			get
260			{
261				return recalculate;
262			}
263			private set
264			{
265				recalculate = value;
266				foreach (SceneGraphNode node in children)
267				{
268					node.Recalculate = true;
269				}
270			}
271		}
272		#endregion
273
274		#endregion
275
276		#region Private
277
278		#region localPosition (Private)
279		/// <summary>
280		/// Local position of this node.
281		/// </summary>
282		private Vector localPosition;
283		#endregion
284
285		#region localRotation (Private)
286		/// <summary>
287		/// Local rotation of this node.
288		/// </summary>
289		private Vector localRotation;
290		#endregion
291
292		#region localScale (Private)
293		/// <summary>
294		/// Local scale of this node.
295		/// </summary>
296		private Vector localScale;
297		#endregion
298
299		#region localTransformation (Private)
300		/// <summary>
301		/// Local transformation of this node.
302		/// </summary>
303		private Matrix localTransformation;
304		#endregion
305
306		#region recalculate (Private)
307		/// <summary>
308		/// Value that indicates whether to calculate the full transformation.
309		/// </summary>
310		private bool recalculate;
311		#endregion
312
313		#region children (Private)
314		/// <summary>
315		/// List containing all children of this node.
316		/// </summary>
317		private readonly List<SceneGraphNode> children = new List<SceneGraphNode>();
318		#endregion
319
320		#endregion
321
322		#region Constructors
323		/// <summary>
324		/// Creates a new instance of <see cref="SceneGraphNode"/>
325		/// </summary>
326		public SceneGraphNode()
327		{
328			ResetLocal();
329			Root = this;
330			RenderOrder = ChildrenRenderOrder.ChildrenFirst;
331		}
332		#endregion
333
334		#region ResetLocal (Public)
335		/// <summary>
336		/// Resets the node to original values.
337		/// </summary>
338		public void ResetLocal()
339		{
340			localPosition = Vector.Zero;
341			localRotation = Vector.Zero;
342			localScale = Vector.One;
343			Recalculate = true;
344		}
345		#endregion
346
347		#region Add (Public)
348		/// <summary>
349		/// Add a new node to the end of the child node list.
350		/// </summary>
351		/// <param name="toAdd">Node to add.</param>
352		public void Add(SceneGraphNode toAdd)
353		{
354			// Check if node was already added.
355			if (children.Contains(toAdd))
356			{
357				return;
358			}
359
360			children.Add(toAdd);
361			toAdd.Root = Root;
362			toAdd.Parent = this;
363			toAdd.Recalculate = true;
364			CheckDepth(toAdd);
365		}
366
367		/// <summary>
368		/// Adds an enumerable list of SceneGraphNode to this node.
369		/// </summary>
370		/// <param name="toAdd">Nodes to add.</param>
371		public void Add(IEnumerable<SceneGraphNode> toAdd)
372		{
373			foreach (SceneGraphNode iterNode in toAdd)
374			{
375				Add(iterNode);
376			}
377		}
378		#endregion
379
380		#region Insert (Public)
381		/// <summary>
382		/// Inserts node at specific position.
383		/// </summary>
384		/// <param name="index">Index where to insert.</param>
385		/// <param name="toAdd">Node to add.</param>
386		public void Insert(int index, SceneGraphNode toAdd)
387		{
388			children.Insert(index, toAdd);
389			toAdd.Parent = this;
390			toAdd.Root = Root;
391			toAdd.Recalculate = true;
392			CheckDepth(toAdd);
393		}
394
395		/// <summary>
396		/// Inserts enumerable list of nodes at specific location.
397		/// </summary>
398		/// <param name="index">Index where to insert.</param>
399		/// <param name="toAdd">Nodes to add.</param>
400		public void Insert(int index, IEnumerable<SceneGraphNode> toAdd)
401		{
402			children.InsertRange(index, toAdd);
403			foreach (SceneGraphNode node in toAdd)
404			{
405				node.Parent = this;
406				node.Root = Root;
407				node.Recalculate = true;
408				CheckDepth(node);
409			}
410		}
411		#endregion
412
413		#region Remove (Public)
414		/// <summary>
415		/// Removes child node.
416		/// </summary>
417		/// <param name="toRemove">Node to remove.</param>
418		/// <returns>True if remove succeeded.</returns>
419		public bool Remove(SceneGraphNode toRemove)
420		{
421			// Check if children exists.
422			if (children.Contains(toRemove) == false)
423			{
424				return false;
425			}
426
427			bool toReturn = children.Remove(toRemove);
428			if (toReturn)
429			{
430				toRemove.Root = null;
431				toRemove.Parent = null;
432				toRemove.CheckDepth(null);
433			}
434			CheckDepth(null);
435			return toReturn;
436		}
437		#endregion
438
439		#region RemoveAt (Public)
440		/// <summary>
441		/// Removes child node at index.
442		/// </summary>
443		/// <param name="index">Index where to remove.</param>
444		public void RemoveAt(int index)
445		{
446			if (index > children.Count - 1)
447			{
448				throw new ArgumentOutOfRangeException("index");
449			}
450
451			SceneGraphNode toRemove = children[index];
452			toRemove.Root = null;
453			children.RemoveAt(index);
454			toRemove.Parent = null;
455			toRemove.CheckDepth(null);
456
457			CheckDepth(null);
458		}
459		#endregion
460
461		#region RemoveFromParent (Public)
462		/// <summary>
463		/// Removes this node from parent.
464		/// </summary>
465		public void RemoveFromParent()
466		{
467			if (Parent != null)
468			{
469				Parent.Remove(this);
470			}
471		}
472		#endregion
473
474		#region Clear (Public)
475		/// <summary>
476		/// Removes all child nodes.
477		/// </summary>
478		public void Clear()
479		{
480			children.Clear();
481			CheckDepth(null);
482		}
483		#endregion
484
485		#region GetLocalPosition (Public)
486		/// <summary>
487		/// Method to get the local position.
488		/// </summary>
489		/// <param name="whereToSet">Where to store the position.</param>
490		public void GetLocalPosition(ref Vector whereToSet)
491		{
492			UpdateTransformation();
493			whereToSet = localPosition;
494		}
495		#endregion
496
497		#region SetLocalPosition (Public)
498		/// <summary>
499		/// Set the local position.
500		/// </summary>
501		/// <param name="toSet">What to set.</param>
502		public virtual void SetLocalPosition(ref Vector toSet)
503		{
504			localPosition = toSet;
505			Recalculate = true;
506		}
507
508		/// <summary>
509		/// Set local position.
510		/// </summary>
511		/// <param name="x">X coordinate.</param>
512		/// <param name="y">Y coordinate.</param>
513		/// <param name="z">Z coordinate.</param>
514		public virtual void SetLocalPosition(float x, float y, float z)
515		{
516			localPosition.X = x;
517			localPosition.Y = y;
518			localPosition.Z = z;
519			Recalculate = true;
520		}
521		#endregion
522
523		#region OffsetLocalPosition (Public)
524		/// <summary>
525		/// Offset the local position with given value.
526		/// </summary>
527		/// <param name="toSet">What to offset.</param>
528		/// <param name="toOffset">Offset</param>
529		public virtual void OffsetLocalPosition(ref Vector toOffset)
530		{
531			localPosition.X += toOffset.X;
532			localPosition.Y += toOffset.Y;
533			localPosition.Z += toOffset.Z;
534			Recalculate = true;
535		}
536
537		/// <summary>
538		/// Method to offset local position.
539		/// </summary>
540		/// <param name="x">X coordinate.</param>
541		/// <param name="y">Y coordinate.</param>
542		/// <param name="z">Z coordinate.</param>
543		public virtual void OffsetLocalPosition(float x, float y, float z)
544		{
545			localPosition.X += x;
546			localPosition.Y += y;
547			localPosition.Z += z;
548			Recalculate = true;
549		}
550		#endregion
551
552		#region GetLocalRotation (Public)
553		/// <summary>
554		/// Method to get the local rotation.
555		/// </summary>
556		/// <param name="whereToSet">Where to store the rotation.</param>
557		public void GetLocalRotation(ref Vector whereToSet)
558		{
559			UpdateTransformation();
560			whereToSet = localRotation;
561		}
562		#endregion
563
564		#region SetLocalRotation (Public)
565		/// <summary>
566		/// Method to set the local rotation.
567		/// </summary>
568		/// <param name="toSet">What to set.</param>
569		public virtual void SetLocalRotation(ref Vector toSet)
570		{
571			localRotation = toSet;
572			Recalculate = true;
573		}
574
575		/// <summary>
576		/// Method to set local rotation.
577		/// </summary>
578		/// <param name="x">X coordinate.</param>
579		/// <param name="y">Y coordinate.</param>
580		/// <param name="z">Z coordinate.</param>
581		public virtual void SetLocalRotation(float x, float y, float z)
582		{
583			localRotation.X = x;
584			localRotation.Y = y;
585			localRotation.Z = z;
586			Recalculate = true;
587		}
588		#endregion
589
590		#region GetLocalScale (Public)
591		/// <summary>
592		/// Method to get the local scale.
593		/// </summary>
594		/// <param name="whereToSet">Where to store the scale.</param>
595		public void GetLocalScale(ref Vector whereToSet)
596		{
597			UpdateTransformation();
598			whereToSet = localScale;
599		}
600		#endregion
601
602		#region SetLocalScale (Public)
603		/// <summary>
604		/// Method for setting the local scale.
605		/// </summary>
606		/// <param name="toSet">What to set.</param>
607		public virtual void SetLocalScale(ref Vector toSet)
608		{
609			localScale = toSet;
610			Recalculate = true;
611		}
612
613		/// <summary>
614		/// Method for setting local scale.
615		/// </summary>
616		/// <param name="x">X coordinate.</param>
617		/// <param name="y">Y coordinate.</param>
618		/// <param name="z">Z coordinate.</param>
619		public virtual void SetLocalScale(float x, float y, float z)
620		{
621			localScale.X = x;
622			localScale.Y = y;
623			localScale.Z = z;
624			Recalculate = true;
625		}
626		#endregion
627
628		#region GetLocalTransformation (Public)
629		/// <summary>
630		/// Method to get the local transformation matrix.
631		/// </summary>
632		/// <param name="whereToGet">Where the local matrix is stored.</param>
633		public void GetLocalTransformation(ref Matrix whereToGet)
634		{
635			UpdateTransformation();
636			whereToGet = localTransformation;
637		}
638		#endregion
639
640		#region GetWorldTransformation (Public)
641		/// <summary>
642		/// Method to get the world transformation matrix.
643		/// </summary>
644		/// <param name="whereToGet">Where the world matrix is stored.</param>
645		public void GetWorldTransformation(ref Matrix whereToGet)
646		{
647			UpdateTransformation();
648			whereToGet = worldTransformation;
649		}
650		#endregion
651
652		#region GetWorldPosition (Public)
653		/// <summary>
654		/// Method to get the world position of the node.
655		/// </summary>
656		/// <param name="whereToSet">Where to store the position.</param>
657		public void GetWorldPosition(ref Vector whereToSet)
658		{
659			UpdateTransformation();
660			whereToSet = worldTransformation.Translation;
661		}
662		#endregion
663
664		#region GetWorldRotation (Public)
665		/// <summary>
666		/// Method to getting the world rotation.
667		/// </summary>
668		/// <param name="whereToSet">Where to store the rotation.</param>
669		public void GetWorldRotation(ref Vector whereToSet)
670		{
671			UpdateTransformation();
672			// There could be easier way to do this...
673			SceneGraphNode current = this;
674			whereToSet.X = 0;
675			whereToSet.Y = 0;
676			whereToSet.Z = 0;
677			while (current != null)
678			{
679				Vector.Add(ref whereToSet, ref current.localRotation, out whereToSet);
680				current = current.Parent;
681			}
682			whereToSet.X = whereToSet.X % 360.0f;
683			whereToSet.Y = whereToSet.Y % 360.0f;
684			whereToSet.Z = whereToSet.Z % 360.0f;
685		}
686		#endregion
687
688		#region GetWorldScale (Public)
689		/// <summary>
690		///Get the world scale.
691		/// </summary>
692		/// <param name="whereToSet">Where to store the scale.</param>
693		public void GetWorldScale(ref Vector whereToSet)
694		{
695			UpdateTransformation();
696			whereToSet = worldTransformation.Scaling;
697		}
698		#endregion
699
700		#region Render (Public)
701		/// <summary>
702		/// Render method to be called when this node is to be rendered. 
703		/// Override if you need to render this node.
704		/// </summary>
705		public virtual void Render()
706		{
707		}
708		#endregion
709
710		#region RenderAll (Public)
711		/// <summary>
712		/// Renders all child nodes and this node.
713		/// </summary>
714		public void RenderAll()
715		{
716			lock (lockObject)
717			{
718				UpdateTransformation();
719				int i;
720				switch (RenderOrder)
721				{
722					case ChildrenRenderOrder.ChildrenFirst:
723						for (i = 0; i < children.Count; i++)
724						{
725							children[i].RenderAll();
726						}
727
728						// Render this node for last.
729						Render();
730						break;
731					default:
732						// Render this node for first.
733						Render();
734						for (i = 0; i < children.Count; i++)
735						{
736							children[i].RenderAll();
737						}
738						break;
739				}
740			}
741		}
742		#endregion
743
744		#region Methods (Private)
745
746		#region UpdateTransformation
747		/// <summary>
748		/// Updates local and world transformation if needed, so if Recalculate is 
749		/// true then it is recalculated.
750		/// </summary>
751		/// <returns>
752		/// True if the matrices were recalculated.
753		/// </returns>
754		protected virtual bool UpdateTransformation()
755		{
756			bool toReturn = false;
757			lock (this)
758			{
759				if (Recalculate)
760				{
761					// Order is: Scale - Rotation - Translation
762					toReturn = true;
763					localTransformation = Matrix.CreateScale(localScale);
764					Matrix tempMatrix = Matrix.CreateRotationZYX(localRotation.X,
765						localRotation.Y, localRotation.Z);
766
767					Matrix.Multiply(ref localTransformation, ref tempMatrix,
768						ref localTransformation);
769
770					tempMatrix = Matrix.CreateTranslation(localPosition);
771					Matrix.Multiply(ref localTransformation, ref tempMatrix,
772						ref localTransformation);
773
774					// Combine with parent, if any.
775					if (Parent != null)
776					{
777						Parent.UpdateTransformation();
778						Matrix.Multiply(ref localTransformation,
779							ref Parent.worldTransformation, ref worldTransformation);
780					}
781					else
782					{
783						worldTransformation = localTransformation;
784					}
785					Recalculate = false;
786				}
787			}
788			return toReturn;
789		}
790		#endregion
791
792		#region CheckDepth
793		/// <summary>
794		/// Checks the node depth.
795		/// </summary>
796		/// <param name="toCheck">Graph node to check.</param>
797		private void CheckDepth(SceneGraphNode toCheck)
798		{
799			int oldDepth = Depth;
800			if (toCheck == null)
801			{
802				Depth = 0;
803				foreach (SceneGraphNode node in children)
804				{
805					Depth = Math.Max(1 + node.Depth, Depth);
806				}
807			}
808			else
809			{
810				Depth = Math.Max(1 + toCheck.Depth, Depth);
811			}
812			if (oldDepth != Depth && Parent != null)
813			{
814				Parent.CheckDepth(null);
815			}
816		}
817		#endregion
818
819		#endregion
820	}
821}