#region File Description
//-----------------------------------------------------------------------------
// A scene node that can be linked to an external source and copy its transformations.
//
// Author: Ronen Ness.
// Since: 2017.
//-----------------------------------------------------------------------------
#endregion
using Microsoft.Xna.Framework;
using System.Collections.Generic;
namespace GeonBit.Core.Graphics
{
///
/// An external transformations source we can attach to a LinkedNode to update its transformations.
/// This is used to connect a node to a physical body, like a Bullet3d rigid body etc.
///
public interface ITransformationsSource
{
///
/// Return if transformations are dirty and need update.
///
bool IsDirty { get; }
///
/// Get body transformations.
///
Matrix WorldTransform { get; }
///
/// Invoked after the node took the transformations from the source.
///
void NodeAcceptedTransform();
}
///
/// A scene node designed to be integrated into GeonBit scene and receive updates from external source,
/// like physical body. This is the default node we use everywhere in the engine.
///
public class LinkedNode : CullingNode
{
///
/// Option to bind external transformations for this node, like a physical body etc.
///
public ITransformationsSource TransformsBind = null;
///
/// If true, will not copy scale transformations from source
///
public bool KeepScale = true;
///
/// Clone this scene node.
///
/// Node copy.
public override Node Clone()
{
LinkedNode ret = new LinkedNode();
ret._transformations = _transformations.Clone();
ret.Visible = Visible;
return ret;
}
///
/// Calc final transformations for current frame.
/// This uses an indicator to know if an update is needed, so no harm is done if you call it multiple times.
///
protected override void UpdateTransformations()
{
// if got no transformations bind, call base update
if (TransformsBind == null)
{
base.UpdateTransformations();
return;
}
// if got here it means we need to get transformations from external source.
// check if dirty
if (TransformsBind.IsDirty)
{
// update world transform from bind
if (KeepScale)
{
Vector3 prevScale = _parent.WorldScale * _transformations.Scale;
_worldTransform = Matrix.CreateScale(prevScale) * TransformsBind.WorldTransform;
}
else
{
_worldTransform = TransformsBind.WorldTransform;
}
// notify parent that we accepted transformation and send world matrix change event
TransformsBind.NodeAcceptedTransform();
OnWorldMatrixChange();
}
// no longer dirty
_isDirty = false;
}
}
}