
//////////////////////////////////////////////////////////////////////
//
//	Crytek Source code 
//	Copyright (c) Crytek 2001-2004
// 
//	File: 
//
//  Description:  
//
//	History:
//
//////////////////////////////////////////////////////////////////////

#ifndef _CRY_ANIMATION_CRY_SKIN_TYPES_HDR_
#define _CRY_ANIMATION_CRY_SKIN_TYPES_HDR_

#include "MathUtils.h"
//////////////////////////////////////////////////////////////////////////
// the packed skin vertex structure: rigid or smooth, 16 byte
// the point is the original point in the bone's CS
struct CrySkinVertexAligned
{
	Vec3 pt;

	union
	{
		unsigned nDest; // the destination vertex index to store the transformed point
		float fWeight; // the weight of the point
	};
};

// the way the packed indices/group headers are kept: short or int
#define CRY_SKIN_AUX_INT_SIZE 2

#if CRY_SKIN_AUX_INT_SIZE==2
typedef unsigned short CrySkinAuxInt;
#elif CRY_SKIN_AUX_INT_SIZE==4
typedef unsigned CrySkinAuxInt;
#if defined _CPU_AMD64
#error You will need to modify the file CrySkinAMD64.ASM to make this work!
#endif	 // _CPU_AMD64
#else
#error CRY_SKIN_AUX_INT_SIZE must be defined and be 2 or 4
#endif

//////////////////////////////////////////////////////////////////////////
// Unpacked rigid vertex structure
struct CrySkinRigidVertex
{
	Vec3 pt;
	unsigned nDest; // the destination vertex index

	CrySkinRigidVertex(){}

	// initializes the structure given the offset from the bone and the destination vertex index
	CrySkinRigidVertex (const Vec3& _ptOffset, unsigned _nDest):
		pt (_ptOffset),
		nDest (_nDest)
		{
		}

	// constructs the packed rigid vertex data from this structure
	void build (CrySkinVertexAligned& vDst)const
	{
		vDst.pt = pt;
		vDst.nDest = nDest;
	}
};

// aligned by 16-byte boundary tangent vectors
// if you don't want the padding to be used, just define it as
// typedef SPipTangents SPipTangentsA16;
struct SPipTangentsA16
{
  Vec3 m_Tangent;
	unsigned long m_Pad0;
  Vec3 m_Binormal;
	unsigned long m_Pad1;
  Vec3 m_TNormal;
	unsigned long m_Pad2;

	inline SPipTangentsA16& operator = (const SPipTangents& right)
	{
		m_Tangent  = right.m_Tangent;
		m_Binormal = right.m_Binormal;
		m_TNormal  = right.m_TNormal;
		return *this;
	}

	inline void copyTo (SPipTangents* right)
	{/*
#ifdef DO_ASM
    _asm
		{
			mov EBX, this
			mov EDX, right
			
			mov EAX, [EBX]
			mov [EDX], EAX
			mov EAX, [EBX+4]
			mov [EDX+4], EAX
			mov EAX, [EBX+8]
			mov [EDX+8], EAX

			mov EAX, [EBX+0x10]
			mov [EDX+0xC], EAX
			mov EAX, [EBX+0x14]
			mov [EDX+0x10], EAX
			mov EAX, [EBX+0x18]
			mov [EDX+0x14], EAX

			mov EAX, [EBX+0x20]
			mov [EDX+0x18], EAX
			mov EAX, [EBX+0x24]
			mov [EDX+0x1C], EAX
			mov EAX, [EBX+0x28]
			mov [EBX+0x20], EAX
		}
#else
		*/
		right->m_Tangent  = m_Tangent;
		right->m_Binormal = m_Binormal;
		right->m_TNormal  = m_TNormal;
//#endif
	}
};


// the size of the SPipTangentsA: can be either 0x30 for aligned structure or
// 0x24 for non-aligned
#define sizeofSPipTangentsA 0x24

#if sizeofSPipTangentsA == 0x24
// this is the actual structure that's to be used to store tangents
typedef SPipTangents SPipTangentsA;
#elif sizeofSPipTangentsA == 0x30
typedef SPipTangentsA16 SPipTangentsA;
#else
#error 
#endif
//////////////////////////////////////////////////////////////////////////
// Unpacked rigid basis structure
struct CrySkinRigidBaseInfo
{
	Vec3 ptTangent;
	Vec3 ptBinormal;
	unsigned nDest;

	CrySkinRigidBaseInfo (){}
	CrySkinRigidBaseInfo (const Matrix44& matInvDef, const TangData& rBasis, unsigned _nDest):
	ptTangent (matInvDef.TransformVectorOLD(rBasis.tangent)),
	ptBinormal(matInvDef.TransformVectorOLD(rBasis.binormal)),
	nDest (_nDest)
	{

	}

	// constructs the packed representation of the base: uses pDst[0] for tangent and destination
	// vertex, and pDst[1] for binormal. Does not set the additional field of the pDst[1]
	void build (CrySkinVertexAligned* pDst)const
	{
		pDst[0].pt = ptTangent;
		// we multiply to get the actual offset (to avoid multiplication in assembly)
		// and add the dummy bits that avoid denormalization assists in SSE
		pDst[0].nDest = nDest * sizeof(SPipTangentsA) + 0x40000000;
		pDst[1].pt = ptBinormal;
		pDst[1].fWeight = 0;
	}
};

//////////////////////////////////////////////////////////////////////////
// Unpacked smooth vertex structure
struct CrySkinSmoothVertex: public CrySkinRigidVertex
{
	float fWeight;// the weight of the point

	CrySkinSmoothVertex(){}

	// initializes this smooth vertex structure
	CrySkinSmoothVertex (const CryLink& rLink, unsigned _nDest):
		CrySkinRigidVertex(rLink.offset, _nDest),
		fWeight(rLink.Blending)
	{
	}

	// constructs the packed rigid vertex data from this structure
	void build (CrySkinVertexAligned& vDst)const
	{
		vDst.pt = pt;
		vDst.fWeight = fWeight;
	}
};

#endif