Skip to content

Commit

Permalink
Adding Translation, Scale, Rotation, and Transform constraints.
Browse files Browse the repository at this point in the history
  • Loading branch information
luigi-rosso committed Jan 14, 2018
1 parent 89ca40d commit 2e7e871
Show file tree
Hide file tree
Showing 10 changed files with 780 additions and 8 deletions.
16 changes: 16 additions & 0 deletions Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,22 @@ private void ReadComponentsBlock(BlockReader block)
case BlockTypes.ActorDistanceConstraint:
component = ActorDistanceConstraint.Read(this, nodeBlock);
break;

case BlockTypes.ActorTranslationConstraint:
component = ActorTranslationConstraint.Read(this, nodeBlock);
break;

case BlockTypes.ActorScaleConstraint:
component = ActorScaleConstraint.Read(this, nodeBlock);
break;

case BlockTypes.ActorRotationConstraint:
component = ActorRotationConstraint.Read(this, nodeBlock);
break;

case BlockTypes.ActorTransformConstraint:
component = ActorTransformConstraint.Read(this, nodeBlock);
break;
}
}
if(component is ActorNode)
Expand Down
113 changes: 113 additions & 0 deletions ActorAxisConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System;
using System.IO;
using System.Collections.Generic;
using Nima.Math2D;

namespace Nima
{
public abstract class ActorAxisConstraint : ActorTargetedConstraint
{
protected bool m_CopyX;
protected bool m_CopyY;
protected float m_ScaleX;
protected float m_ScaleY;
protected bool m_EnableMinX;
protected bool m_EnableMinY;
protected bool m_EnableMaxX;
protected bool m_EnableMaxY;
protected float m_MaxX;
protected float m_MaxY;
protected float m_MinX;
protected float m_MinY;
protected bool m_Offset;
protected TransformSpace m_SourceSpace;
protected TransformSpace m_DestSpace;
protected TransformSpace m_MinMaxSpace;

public ActorAxisConstraint()
{
m_CopyX = false;
m_CopyY = false;
m_ScaleX = 1.0f;
m_ScaleY = 1.0f;
m_EnableMinX = false;
m_EnableMinY = false;
m_EnableMaxX = false;
m_EnableMaxY = false;
m_MinX = 0.0f;
m_MinY = 0.0f;
m_MaxX = 0.0f;
m_MaxY = 0.0f;
m_Offset = false;
m_SourceSpace = TransformSpace.World;
m_DestSpace = TransformSpace.World;
m_MinMaxSpace = TransformSpace.World;
}

public override void OnDirty(byte dirt)
{
MarkDirty();
}

public static ActorAxisConstraint Read(Actor actor, BinaryReader reader, ActorAxisConstraint component)
{
ActorTargetedConstraint.Read(actor, reader, component);

if((component.m_CopyX = reader.ReadByte() == 1))
{
component.m_ScaleX = reader.ReadSingle();
}
if((component.m_EnableMinX = reader.ReadByte() == 1))
{
component.m_MinX = reader.ReadSingle();
}
if((component.m_EnableMaxX = reader.ReadByte() == 1))
{
component.m_MaxX = reader.ReadSingle();
}

// Y Axis
if((component.m_CopyY = reader.ReadByte() == 1))
{
component.m_ScaleY = reader.ReadSingle();
}
if((component.m_EnableMinY = reader.ReadByte() == 1))
{
component.m_MinY = reader.ReadSingle();
}
if((component.m_EnableMaxY = reader.ReadByte() == 1))
{
component.m_MaxY = reader.ReadSingle();
}

component.m_Offset = reader.ReadByte() == 1;
component.m_SourceSpace = (TransformSpace)reader.ReadByte();
component.m_DestSpace = (TransformSpace)reader.ReadByte();
component.m_MinMaxSpace = (TransformSpace)reader.ReadByte();

return component;
}

public void Copy(ActorAxisConstraint node, Actor resetActor)
{
base.Copy(node, resetActor);

m_CopyX = node.m_CopyX;
m_CopyY = node.m_CopyY;
m_ScaleX = node.m_ScaleX;
m_ScaleY = node.m_ScaleY;
m_EnableMinX = node.m_EnableMinX;
m_EnableMinY = node.m_EnableMinY;
m_EnableMaxX = node.m_EnableMaxX;
m_EnableMaxY = node.m_EnableMaxY;
m_MinX = node.m_MinX;
m_MinY = node.m_MinY;
m_MaxX = node.m_MaxX;
m_MaxY = node.m_MaxY;
m_Offset = node.m_Offset;
m_SourceSpace = node.m_SourceSpace;
m_DestSpace = node.m_DestSpace;
m_MinMaxSpace = node.m_MinMaxSpace;
}
}
}
214 changes: 214 additions & 0 deletions ActorRotationConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
using System;
using System.IO;
using System.Collections.Generic;
using Nima.Math2D;

namespace Nima
{
public class ActorRotationConstraint : ActorTargetedConstraint
{
const float PI2 = (float)(Math.PI*2.0);

protected bool m_Copy;
protected float m_Scale;
protected bool m_EnableMin;
protected bool m_EnableMax;
protected float m_Max;
protected float m_Min;
protected bool m_Offset;
protected TransformSpace m_SourceSpace;
protected TransformSpace m_DestSpace;
protected TransformSpace m_MinMaxSpace;
TransformComponents m_ComponentsA;
TransformComponents m_ComponentsB;

public ActorRotationConstraint()
{
m_Copy = false;
m_Scale = 1.0f;
m_EnableMin = false;
m_EnableMax = false;
m_Min = 0.0f;
m_Max = 0.0f;
m_Offset = false;
m_SourceSpace = TransformSpace.World;
m_DestSpace = TransformSpace.World;
m_MinMaxSpace = TransformSpace.World;
m_ComponentsA = new TransformComponents();
m_ComponentsB = new TransformComponents();
}

public override void OnDirty(byte dirt)
{
MarkDirty();
}

public static ActorRotationConstraint Read(Actor actor, BinaryReader reader, ActorRotationConstraint component = null)
{
if(component == null)
{
component = new ActorRotationConstraint();
}
ActorTargetedConstraint.Read(actor, reader, component);

if((component.m_Copy = reader.ReadByte() == 1))
{
component.m_Scale = reader.ReadSingle();
}
if((component.m_EnableMin = reader.ReadByte() == 1))
{
component.m_Min = reader.ReadSingle();
}
if((component.m_EnableMax = reader.ReadByte() == 1))
{
component.m_Max = reader.ReadSingle();
}

component.m_Offset = reader.ReadByte() == 1;
component.m_SourceSpace = (TransformSpace)reader.ReadByte();
component.m_DestSpace = (TransformSpace)reader.ReadByte();
component.m_MinMaxSpace = (TransformSpace)reader.ReadByte();

return component;
}

public void Copy(ActorRotationConstraint node, Actor resetActor)
{
base.Copy(node, resetActor);

m_Copy = node.m_Copy;
m_Scale = node.m_Scale;
m_EnableMin = node.m_EnableMin;
m_EnableMax = node.m_EnableMax;
m_Min = node.m_Min;
m_Max = node.m_Max;

m_Offset = node.m_Offset;
m_SourceSpace = node.m_SourceSpace;
m_DestSpace = node.m_DestSpace;
m_MinMaxSpace = node.m_MinMaxSpace;
}

public override void Constrain(ActorNode node)
{
ActorNode target = m_Target as ActorNode;
ActorNode grandParent = m_Parent.Parent;

Mat2D transformA = m_Parent.WorldTransform;
Mat2D transformB = new Mat2D();
Mat2D.Decompose(transformA, m_ComponentsA);
if(target == null)
{
Mat2D.Copy(transformB, transformA);
m_ComponentsB[0] = m_ComponentsA[0];
m_ComponentsB[1] = m_ComponentsA[1];
m_ComponentsB[2] = m_ComponentsA[2];
m_ComponentsB[3] = m_ComponentsA[3];
m_ComponentsB[4] = m_ComponentsA[4];
m_ComponentsB[5] = m_ComponentsA[5];
}
else
{
Mat2D.Copy(transformB, target.WorldTransform);
if(m_SourceSpace == TransformSpace.Local)
{
ActorNode sourceGrandParent = target.Parent;
if(sourceGrandParent != null)
{
Mat2D inverse = new Mat2D();
if(!Mat2D.Invert(inverse, sourceGrandParent.WorldTransform))
{
return;
}
Mat2D.Multiply(transformB, inverse, transformB);
}
}
Mat2D.Decompose(transformB, m_ComponentsB);

if(!m_Copy)
{
m_ComponentsB.Rotation = m_DestSpace == TransformSpace.Local ? 1.0f : m_ComponentsA.Rotation;
}
else
{
m_ComponentsB.Rotation *= m_Scale;
if(m_Offset)
{
m_ComponentsB.Rotation += m_Parent.Rotation;
}
}

if(m_DestSpace == TransformSpace.Local)
{
// Destination space is in parent transform coordinates.
// Recompose the parent local transform and get it in world, then decompose the world for interpolation.
if(grandParent != null)
{
Mat2D.Compose(transformB, m_ComponentsB);
Mat2D.Multiply(transformB, grandParent.WorldTransform, transformB);
Mat2D.Decompose(transformB, m_ComponentsB);
}
}
}

bool clampLocal = m_MinMaxSpace == TransformSpace.Local && grandParent != null;
if(clampLocal)
{
// Apply min max in local space, so transform to local coordinates first.
Mat2D.Compose(transformB, m_ComponentsB);
Mat2D inverse = new Mat2D();
if(!Mat2D.Invert(inverse, grandParent.WorldTransform))
{
return;
}
Mat2D.Multiply(transformB, inverse, transformB);
Mat2D.Decompose(transformB, m_ComponentsB);
}
if(m_EnableMax && m_ComponentsB.Rotation > m_Max)
{
m_ComponentsB.Rotation = m_Max;
}
if(m_EnableMin && m_ComponentsB.Rotation < m_Min)
{
m_ComponentsB.Rotation = m_Min;
}
if(clampLocal)
{
// Transform back to world.
Mat2D.Compose(transformB, m_ComponentsB);
Mat2D.Multiply(transformB, grandParent.WorldTransform, transformB);
Mat2D.Decompose(transformB, m_ComponentsB);
}

float angleA = m_ComponentsA.Rotation%PI2;
float angleB = m_ComponentsB.Rotation%PI2;
float diff = angleB - angleA;

if(diff > Math.PI)
{
diff -= PI2;
}
else if(diff < -Math.PI)
{
diff += PI2;
}
float ti = 1.0f-m_Strength;

m_ComponentsB.Rotation = m_ComponentsA.Rotation + diff * m_Strength;
m_ComponentsB.X = m_ComponentsA.X;
m_ComponentsB.Y = m_ComponentsA.Y;
m_ComponentsB.ScaleX = m_ComponentsA.ScaleX;
m_ComponentsB.ScaleY = m_ComponentsA.ScaleY;
m_ComponentsB.Skew = m_ComponentsA.Skew;

Mat2D.Compose(m_Parent.WorldTransform, m_ComponentsB);
}

public override ActorComponent MakeInstance(Actor resetActor)
{
ActorRotationConstraint instance = new ActorRotationConstraint();
instance.Copy(this, resetActor);
return instance;
}
}
}
Loading

0 comments on commit 2e7e871

Please sign in to comment.