void Causality::BuildJointMirrorRelation(IArmature& armature)
{
	Joint* root = armature.root();
	ArmatureFrameConstView frame = armature.bind_frame();

	float epsilon = 1.00f;
	auto _children = root->descendants_breadth_first();
	std::vector<std::reference_wrapper<Joint>> children(_children.begin(), _children.end());
	std::vector<Joint*> &joints = reinterpret_cast<std::vector<Joint*> &>(children);

	for (int i = 0; i < children.size(); i++)
	{
		auto& bonei = frame[joints[i]->ID];
		auto& ti = bonei.GblTranslation;
		auto ji = joints[i];

		for (int j = i + 1; j < children.size(); j++)
		{
			auto& bonej = frame[joints[j]->ID];
			auto& tj = bonej.GblTranslation;

			auto jj = joints[j];
			
			auto pi = joints[i]->parent();
			auto pj = joints[j]->parent();

			if (((pi == pj && pi->MirrorJoint == nullptr) || pi->MirrorJoint == pj || pj->MirrorJoint == pi) && is_similar(ji, jj))
			{
				if (pi != pj && child_index(ji) != child_index(jj))
					continue;

				ji->MirrorJoint = jj;
				jj->MirrorJoint = ji;
			}
		}
	}

#ifdef _DEBUG
	for (int i = 0; i < children.size(); i++)
	{
		std::cout << joints[i]->Name;
		if (joints[i]->MirrorJoint)
			std::cout << " <==> " <<  joints[i]->MirrorJoint->Name;
		std::cout << std::endl;
	}
#endif
}
void Causality::RemoveFrameRootTransform(ArmatureFrameView frame, const IArmature & armature)
{
	auto& rotBone = frame[armature.root()->ID];
	rotBone.GblRotation = rotBone.LclRotation = Math::Quaternion::Identity;
	rotBone.GblTranslation = rotBone.LclTranslation = Math::Vector3::Zero;
	rotBone.GblScaling = rotBone.LclScaling = Math::Vector3::One;
	FrameRebuildGlobal(armature, frame);
}
void StaticArmature::clone_from(const IArmature & rhs)
{
	for (auto& j : rhs.joints())
		m_order.push_back(j.ID);

	this->m_joints.resize(m_order.size());
	this->m_rootIdx = rhs.root()->ID;
	this->m_defaultFrame = rhs.bind_frame();

	// Copy Joint meta-data
	for (auto& j : rhs.joints())
		m_joints[j.ID] = j;

	// rebuild structure
	for (int i : this->m_order)
	{
		if (m_joints[i].ParentID >= 0 && m_joints[i].ParentID != i)
		{
			m_joints[m_joints[i].ParentID].append_children_back(&m_joints[i]);
		}
	}
}
	void FrameLerp(ArmatureFrameView out, ArmatureFrameConstView lhs, ArmatureFrameConstView rhs, float t, const IArmature& armature, bool rebuild)
	{
		//assert((Armature == lhs.pArmature) && (lhs.pArmature == rhs.pArmature));
		XMVECTOR vt = XMVectorReplicate(t);
		for (size_t i = 0; i < armature.size(); i++)
		{
			XMStoreA(out[i].LclRotation, DirectX::XMQuaternionSlerpV(XMLoadA(lhs[i].LclRotation), XMLoadA(rhs[i].LclRotation), vt));
			XMStoreA(out[i].LclScaling, DirectX::XMVectorLerpV(XMLoadA(lhs[i].LclScaling), XMLoadA(rhs[i].LclScaling), vt));
			XMStoreA(out[i].LclTranslation, DirectX::XMVectorLerpV(XMLoadA(lhs[i].LclTranslation), XMLoadA(rhs[i].LclTranslation), vt));
		}
		if (rebuild)
			FrameRebuildGlobal(armature, out);
	}
	void FrameRebuildLocal(const IArmature& armature, ArmatureFrameView frame)
	{
		for (auto& joint : armature.joints())
		{
			auto& bone = frame[joint.ID];
			if (joint.is_root())
			{
				bone.LclRotation = bone.GblRotation;
				bone.LclScaling = bone.GblScaling;
				bone.LclTranslation = bone.GblTranslation;
				bone.LclLength = bone.GblLength = 1.0f; // Length of root doesnot have any meaning
			}
			else
			{
				bone.UpdateLocalData(frame[joint.ParentID]);
			}
		}
	}
ArmatureFrame::ArmatureFrame(const IArmature & armature)
{
	assert(this->size() == armature.size());
	auto df = armature.bind_frame();
	BaseType::assign(df.begin(), df.end());
}