using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aiwaz.Contracts; using Aiwaz.Resources.Attributes; namespace Aiwaz.Resources { public class TransformationBindings : ICreationParams { public string WorldMatrixSemanticName; public string LocalMatrixSemanticName; public string WorldPositionSemanticName; public string LocalPositionSemanticName; public string WorldDirectionSemanticName; public string LocalDirectionSemanticName; public string WorldUpDirectionSemanticName; public string LocalUpDirectionSemanticName; public string WorldRightDirectionSemanticName; public string LocalRightDirectionSemanticName; } [CreationParameters("Default transformation")] public class DefaultTransformationBindings : TransformationBindings { public DefaultTransformationBindings() { WorldMatrixSemanticName = "WorldMatrix"; LocalMatrixSemanticName = "LocalMatrix"; WorldPositionSemanticName = "WorldPosition"; LocalPositionSemanticName = "LocalPosition"; WorldDirectionSemanticName = "WorldDirection"; LocalDirectionSemanticName = "LocalDirection"; WorldUpDirectionSemanticName = "WorldUpDirection"; LocalUpDirectionSemanticName = "LocalUpDirection"; WorldRightDirectionSemanticName = "WorldUpDirection"; LocalRightDirectionSemanticName = "LocalUpDirection"; } } [CreationParameters("Camera transformation")] public class CameraTransformationBindings : TransformationBindings { public CameraTransformationBindings() { WorldPositionSemanticName = "CamPos"; WorldDirectionSemanticName = "CamDir"; } } [AiwazResource("Transformation", "Common transformations for a shader and geometry buffers like position, scale and rotation.")] public class Transformation : ShaderParameterSet, IUpdatable { #region ITransformation Members Reference worldMatrixRef = new Reference(new SlimDX.Matrix()); Reference worldPositionRef = new Reference(new SlimDX.Vector3()); Reference worldDirectionRef = new Reference(new SlimDX.Vector3()); Reference worldUpDirectionRef = new Reference(new SlimDX.Vector3()); Reference worldRightDirectionRef = new Reference(new SlimDX.Vector3()); Reference localMatrixRef = new Reference(new SlimDX.Matrix()); Reference localPositionRef = new Reference(new SlimDX.Vector3()); Reference localDirectionRef = new Reference(new SlimDX.Vector3()); Reference localUpDirectionRef = new Reference(new SlimDX.Vector3()); Reference localRightDirectionRef = new Reference(new SlimDX.Vector3()); private TransformationBindings transformationBindings; private SlimDX.Vector3 lastKnownYawPitchRoll; private SlimDX.Quaternion localRotation; private SlimDX.Vector3 localScale; private Transformation transformationParent; private List transformations = new List(); private Transformation() : base(5) { } private Transformation(TransformationBindings transformationBindings) : this() { this.WorldScale = this.LocalScale = new SlimDX.Vector3(1.0f, 1.0f, 1.0f); this.LocalDirection = this.WorldDirection = new SlimDX.Vector3(0.0f, 0.0f, 1.0f); this.LocalUpDirection = this.WorldUpDirection = new SlimDX.Vector3(0.0f, 1.0f, 0.0f); this.LocalRightDirection = this.WorldRightDirection = new SlimDX.Vector3(1.0f, 0.0f, 0.0f); this.TransformationBindings = transformationBindings; } public Transformation(DefaultTransformationBindings transformationBindings) : this((TransformationBindings)transformationBindings) { } public Transformation(CameraTransformationBindings transformationBindings) : this((TransformationBindings)transformationBindings) { } public TransformationBindings TransformationBindings { get { return transformationBindings; } set { transformationBindings = value; baseShaderParameterSet.RemoveAllShaderParameters(); this.RecreateAllShaderParameters(); } } public SlimDX.Vector3 LocalPosition { get { return (SlimDX.Vector3)localPositionRef.RawValue; } set { localPositionRef.RawValue = value; WantsUpdate = true; } } public SlimDX.Vector3 WorldPosition { get { return (SlimDX.Vector3)worldPositionRef.RawValue; } protected set { worldPositionRef.RawValue = value; } } public SlimDX.Vector3 LocalRotationYPR { get { return lastKnownYawPitchRoll; } set { lastKnownYawPitchRoll = value; LocalRotation = SlimDX.Quaternion.RotationYawPitchRoll(value.X, value.Y, value.Z); WantsUpdate = true; } } public SlimDX.Quaternion LocalRotation { get { return localRotation; } set { localRotation = value; WantsUpdate = true; } } public SlimDX.Quaternion WorldRotation { get; protected set; } public SlimDX.Vector3 LocalDirection { get { return (SlimDX.Vector3)localDirectionRef.RawValue; } protected set { localDirectionRef.RawValue = value; } } public SlimDX.Vector3 WorldDirection { get { return (SlimDX.Vector3)worldDirectionRef.RawValue; } protected set { worldDirectionRef.RawValue = value; } } public SlimDX.Vector3 LocalUpDirection { get { return (SlimDX.Vector3)localUpDirectionRef.RawValue; } protected set { localUpDirectionRef.RawValue = value; } } public SlimDX.Vector3 WorldUpDirection { get { return (SlimDX.Vector3)worldUpDirectionRef.RawValue; } protected set { worldUpDirectionRef.RawValue = value; } } public SlimDX.Vector3 LocalRightDirection { get { return (SlimDX.Vector3)localRightDirectionRef.RawValue; } protected set { localRightDirectionRef.RawValue = value; } } public SlimDX.Vector3 WorldRightDirection { get { return (SlimDX.Vector3)worldRightDirectionRef.RawValue; } protected set { worldRightDirectionRef.RawValue = value; } } public SlimDX.Vector3 LocalScale { get { return localScale; } set { localScale = value; WantsUpdate = true; } } public SlimDX.Vector3 WorldScale { get; protected set; } public SlimDX.Matrix WorldMatrix { get { return (SlimDX.Matrix)worldMatrixRef.RawValue; } protected set { worldMatrixRef.RawValue = value; } } public SlimDX.Matrix LocalMatrix { get { return (SlimDX.Matrix)localMatrixRef.RawValue; } protected set { localMatrixRef.RawValue = value; } } public Transformation TransformationParent { get { return transformationParent; } set { var oldTransformationParent = transformationParent; transformationParent = value; WantsUpdate = true; if (oldTransformationParent != null) oldTransformationParent.RemoveTransformation(this); } } public IEnumerable Transformations { get { return transformations; } } public void AddTransformation(Transformation transformation) { if (!transformations.Contains(transformation)) { transformation.TransformationParent = this; transformations.Add(transformation); WantsUpdate = true; } } public void RemoveTransformation(Transformation transformation) { if (transformations.Remove(transformation)) transformation.TransformationParent = null; } protected virtual void RecreateAllShaderParameters() { if (transformationBindings == null) return; if (!string.IsNullOrEmpty(transformationBindings.WorldMatrixSemanticName)) this.SetParameter(transformationBindings.WorldMatrixSemanticName, worldMatrixRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.LocalMatrixSemanticName)) this.SetParameter(transformationBindings.LocalMatrixSemanticName, localMatrixRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.WorldPositionSemanticName)) this.SetParameter(transformationBindings.WorldPositionSemanticName, worldPositionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.LocalPositionSemanticName)) this.SetParameter(transformationBindings.LocalPositionSemanticName, localPositionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.WorldDirectionSemanticName)) this.SetParameter(transformationBindings.WorldDirectionSemanticName, worldDirectionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.LocalDirectionSemanticName)) this.SetParameter(transformationBindings.LocalDirectionSemanticName, localDirectionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.WorldUpDirectionSemanticName)) this.SetParameter(transformationBindings.WorldUpDirectionSemanticName, worldUpDirectionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.LocalUpDirectionSemanticName)) this.SetParameter(transformationBindings.LocalUpDirectionSemanticName, localUpDirectionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.WorldRightDirectionSemanticName)) this.SetParameter(transformationBindings.WorldRightDirectionSemanticName, worldRightDirectionRef, ParameterBindType.BindBySemantic); if (!string.IsNullOrEmpty(transformationBindings.LocalRightDirectionSemanticName)) this.SetParameter(transformationBindings.LocalRightDirectionSemanticName, localRightDirectionRef, ParameterBindType.BindBySemantic); } #endregion #region IUpdatable Members public virtual void Update(bool forceUpdate) { if (!WantsUpdate && !forceUpdate) return; WantsUpdate = false; var localMatrix = SlimDX.Matrix.Transformation(SlimDX.Vector3.Zero, SlimDX.Quaternion.Identity, localScale, SlimDX.Vector3.Zero, localRotation, this.LocalPosition); var direction = new SlimDX.Vector3(0.0f, 0.0f, 1.0f); var upDirection = new SlimDX.Vector3(0.0f, 1.0f, 0.0f); var rightDirection = new SlimDX.Vector3(1.0f, 0.0f, 0.0f); { var rotMat = SlimDX.Matrix.RotationQuaternion(localRotation); LocalDirection = SlimDX.Vector3.TransformNormal(direction, rotMat); LocalUpDirection = SlimDX.Vector3.TransformNormal(upDirection, rotMat); LocalRightDirection = SlimDX.Vector3.TransformNormal(rightDirection, rotMat); } WorldMatrix = localMatrix; // stack parent matrix if (transformationParent != null) WorldMatrix = localMatrix * transformationParent.WorldMatrix; // extract world related data SlimDX.Vector3 tmpScale; SlimDX.Vector3 tmpPos; SlimDX.Quaternion tmpRot; WorldMatrix.Decompose(out tmpScale, out tmpRot, out tmpPos); WorldPosition = tmpPos; WorldRotation = tmpRot; WorldScale = tmpScale; { var rotMat = SlimDX.Matrix.RotationQuaternion(WorldRotation); WorldDirection = SlimDX.Vector3.TransformNormal(direction, rotMat); WorldUpDirection = SlimDX.Vector3.TransformNormal(upDirection, rotMat); WorldRightDirection = SlimDX.Vector3.TransformNormal(rightDirection, rotMat); } // update following transformations foreach (var transformation in transformations) if (transformation is IUpdatable) { var updatable = transformation as IUpdatable; if (updatable != null && (updatable.WantsUpdate || forceUpdate)) updatable.Update(forceUpdate); } } public bool WantsUpdate { get; protected set; } #endregion } }