Пример #1
0
        public static ActorImage Read(Actor actor, BinaryReader reader, ActorImage node = null)
        {
            if (node == null)
            {
                node = new ActorImage();
            }

            ActorNode.Read(actor, reader, node);

            bool isVisible = reader.ReadByte() != 0;

            if (isVisible)
            {
                node.m_BlendMode    = (BlendModes)reader.ReadByte();
                node.m_DrawOrder    = (int)reader.ReadUInt16();
                node.m_TextureIndex = (int)reader.ReadByte();

                int numConnectedBones = (int)reader.ReadByte();
                if (numConnectedBones != 0)
                {
                    node.m_BoneConnections = new BoneConnection[numConnectedBones];

                    for (int i = 0; i < numConnectedBones; i++)
                    {
                        BoneConnection bc = new BoneConnection();
                        bc.m_BoneIdx = reader.ReadUInt16();
                        Actor.ReadFloat32Array(reader, bc.m_Bind.Values);
                        Mat2D.Invert(bc.m_InverseBind, bc.m_Bind);

                        node.m_BoneConnections[i] = bc;
                    }

                    Mat2D worldOverride = new Mat2D();
                    Actor.ReadFloat32Array(reader, worldOverride.Values);
                    node.WorldTransformOverride = worldOverride;
                }

                uint numVertices  = reader.ReadUInt32();
                int  vertexStride = numConnectedBones > 0 ? 12 : 4;
                node.m_VertexCount = (int)numVertices;
                node.m_Vertices    = new float[numVertices * vertexStride];
                Actor.ReadFloat32Array(reader, node.m_Vertices);

                uint numTris = reader.ReadUInt32();
                node.m_Triangles     = new ushort[numTris * 3];
                node.m_TriangleCount = (int)numTris;
                Actor.ReadUInt16Array(reader, node.m_Triangles);
            }

            return(node);
        }
Пример #2
0
        public bool LoadFrom(Stream stream)
        {
            BlockReader reader = new BlockReader(stream);

            byte N       = reader.ReadByte();
            byte I       = reader.ReadByte();
            byte M       = reader.ReadByte();
            byte A       = reader.ReadByte();
            uint version = reader.ReadUInt32();

            if (N != 78 || I != 73 || M != 77 || A != 65)
            {
                return(false);
            }
            if (version < 12)
            {
                return(false);
            }

            m_Version = version;

            //version == 1.0
            //Debugger.Log("NIMA confirmed. " + reader.BaseStream.Length);
            //byte[] data = new byte[reader.BaseStream.Length];

            m_MaxTextureIndex = 0;
            m_Root            = new ActorNode(this);

            BlockReader block = null;

            while ((block = reader.ReadNextBlock()) != null)
            {
                switch (block.BlockType)
                {
                case (int)BlockTypes.Components:
                    ReadComponentsBlock(block);
                    break;

                case (int)BlockTypes.Animations:
                    ReadAnimationsBlock(block);
                    break;
                }
            }

            return(true);
        }
Пример #3
0
        public virtual void ResolveComponentIndices(ActorComponent[] components)
        {
            ActorNode node = components[m_ParentIdx] as ActorNode;

            if (node != null)
            {
                if (this is ActorNode)
                {
                    node.AddChild(this as ActorNode);
                }
                else
                {
                    m_Parent = node;
                }
                m_Actor.AddDependency(this, node);
            }
        }
Пример #4
0
        public override void Constrain(ActorNode node)
        {
            ActorNode target = m_Target as ActorNode;

            if (target == null)
            {
                return;
            }

            Vec2D targetTranslation = target.GetWorldTranslation(new Vec2D());
            Vec2D ourTranslation    = m_Parent.GetWorldTranslation(new Vec2D());

            Vec2D toTarget        = Vec2D.Subtract(new Vec2D(), ourTranslation, targetTranslation);
            float currentDistance = Vec2D.Length(toTarget);

            switch (m_Mode)
            {
            case Mode.Closer:
                if (currentDistance < m_Distance)
                {
                    return;
                }
                break;

            case Mode.Further:
                if (currentDistance > m_Distance)
                {
                    return;
                }
                break;
            }
            if (currentDistance < 0.001)
            {
                return;
            }

            Vec2D.Scale(toTarget, toTarget, 1.0f / currentDistance);
            Vec2D.Scale(toTarget, toTarget, m_Distance);

            Mat2D world    = m_Parent.WorldTransform;
            Vec2D position = Vec2D.Lerp(new Vec2D(), ourTranslation, Vec2D.Add(new Vec2D(), targetTranslation, toTarget), m_Strength);

            world[4] = position[0];
            world[5] = position[1];
        }
Пример #5
0
        public static ActorNode Read(Actor actor, BinaryReader reader, ActorNode node = null)
        {
            if (node == null)
            {
                node = new ActorNode();
            }
            ActorComponent.Read(actor, reader, node);
            Actor.ReadFloat32Array(reader, node.m_Translation.Values);
            node.m_Rotation = reader.ReadSingle();
            Actor.ReadFloat32Array(reader, node.m_Scale.Values);
            node.m_Opacity = reader.ReadSingle();

            if (actor.Version >= 13)
            {
                node.m_IsCollapsedVisibility = reader.ReadByte() == 1;
            }

            return(node);
        }
Пример #6
0
        public void Copy(Actor actor)
        {
            m_Animations      = actor.m_Animations;
            m_Flags           = actor.m_Flags;
            m_MaxTextureIndex = actor.m_MaxTextureIndex;
            m_ImageNodeCount  = actor.m_ImageNodeCount;
            m_NodeCount       = actor.m_NodeCount;

            if (actor.ComponentCount != 0)
            {
                m_Components = new ActorComponent[actor.ComponentCount];
            }
            if (m_NodeCount != 0)            // This will always be at least 1.
            {
                m_Nodes = new ActorNode[m_NodeCount];
            }
            if (m_ImageNodeCount != 0)
            {
                m_ImageNodes = new ActorImage[m_ImageNodeCount];
            }

            if (actor.ComponentCount != 0)
            {
                int idx    = 0;
                int imgIdx = 0;
                int ndIdx  = 0;

                foreach (ActorComponent component in actor.Components)
                {
                    if (component == null)
                    {
                        m_Components[idx++] = null;
                        continue;
                    }
                    ActorComponent instanceComponent = component.MakeInstance(this);
                    m_Components[idx++] = instanceComponent;
                    ActorNode nodeInstance = instanceComponent as ActorNode;
                    if (nodeInstance != null)
                    {
                        m_Nodes[ndIdx++] = nodeInstance;
                    }

                    ActorImage imageInstance = instanceComponent as ActorImage;
                    if (imageInstance != null)
                    {
                        m_ImageNodes[imgIdx++] = imageInstance;
                    }
                }
            }

            m_Root = m_Components[0] as ActorNode;

            foreach (ActorComponent component in m_Components)
            {
                if (m_Root == component || component == null)
                {
                    continue;
                }
                component.ResolveComponentIndices(m_Components);
            }

            foreach (ActorComponent component in m_Components)
            {
                if (m_Root == component || component == null)
                {
                    continue;
                }
                component.CompleteResolve();
            }

            SortDependencies();
        }
Пример #7
0
        private void ReadComponentsBlock(BlockReader block)
        {
            int componentCount = block.ReadUInt16();

            m_Components    = new ActorComponent[componentCount + 1];
            m_Components[0] = m_Root;

            // Guaranteed from the exporter to be in index order.
            BlockReader nodeBlock = null;

            int componentIndex = 1;

            m_NodeCount = 1;
            while ((nodeBlock = block.ReadNextBlock()) != null)
            {
                ActorComponent component = null;
                if (Enum.IsDefined(typeof(BlockTypes), nodeBlock.BlockType))
                {
                    BlockTypes type = (BlockTypes)nodeBlock.BlockType;
                    switch (type)
                    {
                    case BlockTypes.ActorNode:
                        component = ActorNode.Read(this, nodeBlock);
                        break;

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

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

                    case BlockTypes.ActorImage:
                        m_ImageNodeCount++;
                        component = ActorImage.Read(this, nodeBlock, makeImageNode());
                        if ((component as ActorImage).TextureIndex > m_MaxTextureIndex)
                        {
                            m_MaxTextureIndex = (component as ActorImage).TextureIndex;
                        }
                        break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    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)
                {
                    m_NodeCount++;
                }

                m_Components[componentIndex] = component;
                if (component != null)
                {
                    component.Idx = (ushort)(componentIndex);
                }
                componentIndex++;
            }

            m_ImageNodes = new ActorImage[m_ImageNodeCount];
            m_Nodes      = new ActorNode[m_NodeCount];
            m_Nodes[0]   = m_Root;

            // Resolve nodes.
            int imgIdx = 0;
            int anIdx  = 0;

            ActorComponent[] components = m_Components;
            for (int i = 1; i <= componentCount; i++)
            {
                ActorComponent c = components[i];
                // Nodes can be null if we read from a file version that contained nodes that we don't interpret in this runtime.
                if (c != null)
                {
                    c.ResolveComponentIndices(components);
                }

                ActorImage ain = c as ActorImage;
                if (ain != null)
                {
                    m_ImageNodes[imgIdx++] = ain;
                }

                ActorNode an = c as ActorNode;
                if (an != null)
                {
                    m_Nodes[anIdx++] = an;
                }
            }

            for (int i = 1; i <= componentCount; i++)
            {
                ActorComponent c = components[i];
                if (c != null)
                {
                    c.CompleteResolve();
                }
            }

            SortDependencies();
        }
Пример #8
0
    public void Start()
    {
        m_Actor = gameObject.GetComponent <Nima.Unity.ActorBaseComponent>();
        if (m_Actor != null)
        {
            // Get a game object from the actor, use this to mount items or query for other components.
            // GameObject headColliderGameObject = m_Actor.GetActorGameObject("HeadCollider");
            // if(headColliderGameObject != null)
            // {
            //  Collider2D collider = headColliderGameObject.GetComponent<Collider2D>();
            //  if(collider != null)
            //  {
            //      // Set it to a trigger, or do something else with it...
            //      // collider.isTrigger = true;
            //  }
            // }
            if (m_Actor.ActorInstance != null)
            {
                m_Idle       = m_Actor.ActorInstance.GetAnimation("Idle");
                m_Aim        = m_Actor.ActorInstance.GetAnimation("Aim2");
                m_Walk       = m_Actor.ActorInstance.GetAnimationInstance("Walk");
                m_Run        = m_Actor.ActorInstance.GetAnimation("Run");
                m_WalkToIdle = m_Actor.ActorInstance.GetAnimation("WalkToIdle");

                // We made walk an animation instance so it has it's own sense of time which lets it do things like track events.
                m_Walk.AnimationEvent += delegate(object animationInstance, Nima.Animation.AnimationEventArgs args)
                {
                    // Event triggered from animation.
                };
                Nima.ActorNode characterNode = m_Actor.ActorInstance.GetNode("Character");
                if (characterNode != null)
                {
                    m_GroundSpeedProperty = characterNode.GetCustomFloatProperty("GroundSpeed");
                    m_IsRunningProperty   = characterNode.GetCustomBooleanProperty("IsRunning");
                }
                // Calculate aim slices.
                if (m_Aim != null)
                {
                    Nima.ActorNode muzzle = m_Actor.ActorInstance.GetNode("Muzzle");
                    if (muzzle != null)
                    {
                        for (int i = 0; i < AimSliceCount; i++)
                        {
                            float position = i / (float)(AimSliceCount - 1) * m_Aim.Duration;
                            m_Aim.Apply(position, m_Actor.ActorInstance, 1.0f);
                            m_Actor.ActorInstance.Advance(0.0f);
                            Nima.Math2D.Mat2D worldTransform = muzzle.WorldTransform;

                            AimSlice slice = m_AimLookup[i];

                            // Extract forward vector and position.
                            slice.dir = new Nima.Math2D.Vec2D();
                            Nima.Math2D.Vec2D.Normalize(slice.dir, new Nima.Math2D.Vec2D(worldTransform[0], worldTransform[1]));
                            slice.point = new Nima.Math2D.Vec2D(worldTransform[4] * Nima.Unity.ActorAsset.NimaToUnityScale,
                                                                worldTransform[5] * Nima.Unity.ActorAsset.NimaToUnityScale);
                            m_AimLookup[i] = slice;
                        }
                    }
                    if (m_Walk != null)
                    {
                        m_Walk.Time = 0.0f;
                        m_Walk.Apply(1.0f);

                        for (int i = 0; i < AimSliceCount; i++)
                        {
                            float position = i / (float)(AimSliceCount - 1) * m_Aim.Duration;
                            m_Aim.Apply(position, m_Actor.ActorInstance, 1.0f);
                            m_Actor.ActorInstance.Advance(0.0f);
                            Nima.Math2D.Mat2D worldTransform = muzzle.WorldTransform;

                            AimSlice slice = m_AimWalkingLookup[i];

                            // Extract forward vector and position.
                            slice.dir = new Nima.Math2D.Vec2D();
                            Nima.Math2D.Vec2D.Normalize(slice.dir, new Nima.Math2D.Vec2D(worldTransform[0], worldTransform[1]));
                            slice.point = new Nima.Math2D.Vec2D(worldTransform[4] * Nima.Unity.ActorAsset.NimaToUnityScale,
                                                                worldTransform[5] * Nima.Unity.ActorAsset.NimaToUnityScale);
                            m_AimWalkingLookup[i] = slice;
                        }
                    }
                }
            }
        }
        m_IdleTime = 0.0f;
    }
Пример #9
0
        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);
        }
Пример #10
0
 public static ActorCollider Read(Actor actor, BinaryReader reader, ActorCollider property)
 {
     ActorNode.Read(actor, reader, property);
     property.IsCollisionEnabled = reader.ReadByte() == 1;
     return(property);
 }
Пример #11
0
 public abstract void Constrain(ActorNode node);
Пример #12
0
        public override void Constrain(ActorNode node)
        {
            ActorNode target = m_Target as ActorNode;

            if (target == null)
            {
                return;
            }
            Vec2D worldTargetTranslation = new Vec2D();

            target.GetWorldTranslation(worldTargetTranslation);

            if (m_InfluencedBones.Length == 0)
            {
                return;
            }

            // Decompose the chain.
            foreach (BoneChain item in m_FKChain)
            {
                ActorBone bone        = item.m_Bone;
                Mat2D     parentWorld = bone.Parent.WorldTransform;
                Mat2D.Invert(item.m_ParentWorldInverse, parentWorld);
                Mat2D.Multiply(bone.Transform, item.m_ParentWorldInverse, bone.WorldTransform);
                Mat2D.Decompose(bone.Transform, item.m_TransformComponents);
            }

            int count = m_BoneData.Count;

            if (count == 1)
            {
                Solve1(m_BoneData[0], worldTargetTranslation);
            }
            else if (count == 2)
            {
                Solve2(m_BoneData[0], m_BoneData[1], worldTargetTranslation);
            }
            else
            {
                BoneChain tip = m_BoneData[count - 1];
                for (int i = 0; i < count - 1; i++)
                {
                    BoneChain item = m_BoneData[i];
                    Solve2(item, tip, worldTargetTranslation);
                    for (int j = item.m_Index + 1; j < m_FKChain.Length - 1; j++)
                    {
                        BoneChain fk = m_FKChain[j];
                        Mat2D.Invert(fk.m_ParentWorldInverse, fk.m_Bone.Parent.WorldTransform);
                    }
                }
            }

            // At the end, mix the FK angle with the IK angle by strength
            if (m_Strength != 1.0)
            {
                foreach (BoneChain fk in m_FKChain)
                {
                    if (!fk.m_Included)
                    {
                        ActorBone bone = fk.m_Bone;
                        Mat2D.Multiply(bone.WorldTransform, bone.Parent.WorldTransform, bone.Transform);
                        continue;
                    }
                    float fromAngle = fk.m_TransformComponents.Rotation % PI2;
                    float toAngle   = fk.m_Angle % PI2;
                    float diff      = toAngle - fromAngle;
                    if (diff > PI)
                    {
                        diff -= PI2;
                    }
                    else if (diff < -PI)
                    {
                        diff += PI2;
                    }
                    float angle = fromAngle + diff * m_Strength;
                    ConstrainRotation(fk, angle);
                }
            }
        }
Пример #13
0
        public override void Constrain(ActorNode node)
        {
            ActorNode target      = m_Target as ActorNode;
            ActorNode grandParent = m_Parent.Parent;

            Mat2D transformA   = m_Parent.WorldTransform;
            Vec2D translationA = new Vec2D(transformA[4], transformA[5]);
            Vec2D translationB = new Vec2D();

            if (target == null)
            {
                Vec2D.Copy(translationB, translationA);
            }
            else
            {
                Mat2D transformB = new Mat2D(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);
                    }
                }
                translationB[0] = transformB[4];
                translationB[1] = transformB[5];

                if (!m_CopyX)
                {
                    translationB[0] = m_DestSpace == TransformSpace.Local ? 0.0f : translationA[0];
                }
                else
                {
                    translationB[0] *= m_ScaleX;
                    if (m_Offset)
                    {
                        translationB[0] += m_Parent.X;
                    }
                }

                if (!m_CopyY)
                {
                    translationB[1] = m_DestSpace == TransformSpace.Local ? 0.0f : translationA[1];
                }
                else
                {
                    translationB[1] *= m_ScaleY;

                    if (m_Offset)
                    {
                        translationB[1] += m_Parent.Y;
                    }
                }

                if (m_DestSpace == TransformSpace.Local)
                {
                    // Destination space is in parent transform coordinates.
                    if (grandParent != null)
                    {
                        Vec2D.TransformMat2D(translationB, translationB, grandParent.WorldTransform);
                    }
                }
            }

            bool clampLocal = m_MinMaxSpace == TransformSpace.Local && grandParent != null;

            if (clampLocal)
            {
                // Apply min max in local space, so transform to local coordinates first.
                Mat2D invert = new Mat2D();
                if (!Mat2D.Invert(invert, grandParent.WorldTransform))
                {
                    return;
                }
                // Get our target world coordinates in parent local.
                Vec2D.TransformMat2D(translationB, translationB, invert);
            }
            if (m_EnableMaxX && translationB[0] > m_MaxX)
            {
                translationB[0] = m_MaxX;
            }
            if (m_EnableMinX && translationB[0] < m_MinX)
            {
                translationB[0] = m_MinX;
            }
            if (m_EnableMaxY && translationB[1] > m_MaxY)
            {
                translationB[1] = m_MaxY;
            }
            if (m_EnableMinY && translationB[1] < m_MinY)
            {
                translationB[1] = m_MinY;
            }
            if (clampLocal)
            {
                // Transform back to world.
                Vec2D.TransformMat2D(translationB, translationB, grandParent.WorldTransform);
            }

            float ti = 1.0f - m_Strength;

            // Just interpolate world translation
            transformA[4] = translationA[0] * ti + translationB[0] * m_Strength;
            transformA[5] = translationA[1] * ti + translationB[1] * m_Strength;
        }