Applied various fixes to the attachment system, made skeleton rendering more flexible, added the ability for attachments to specify an attach type

This commit is contained in:
parax0
2016-05-01 17:32:55 -06:00
parent 07609cfa14
commit ce688fcb8e
29 changed files with 332 additions and 151 deletions

View File

@@ -195,7 +195,8 @@ HEADERS += \
Resource/CSkin.h \
Resource/Factory/CSkinLoader.h \
Render/EDepthGroup.h \
Scene/CScriptAttachNode.h
Scene/CScriptAttachNode.h \
ScriptExtra/CSandwormExtra.h
# Source Files
SOURCES += \
@@ -281,4 +282,5 @@ SOURCES += \
Resource/Factory/CAnimationLoader.cpp \
Resource/Factory/CSkinLoader.cpp \
Resource/Model/EVertexAttribute.cpp \
Scene/CScriptAttachNode.cpp
Scene/CScriptAttachNode.cpp \
ScriptExtra/CSandwormExtra.cpp

View File

@@ -18,6 +18,7 @@ public:
inline const CTransform4f& BoneMatrix(u32 BoneID) const { return mBoneMatrices[BoneID]; }
inline const void* Data() const { return mBoneMatrices.data(); }
inline u32 DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); }
inline u32 NumTrackedBones() const { return mBoneMatrices.size(); }
inline CTransform4f& operator[](u32 BoneIndex) { return BoneMatrix(BoneIndex); }
inline const CTransform4f& operator[](u32 BoneIndex) const { return BoneMatrix(BoneIndex); }
};

View File

@@ -2,6 +2,7 @@
#include "Core/Render/CBoneTransformData.h"
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CGraphics.h"
#include <Common/Assert.h>
#include <Math/MathUtil.h>
// ************ CBone ************
@@ -44,6 +45,11 @@ CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
return rkData[mID] * Position();
}
CQuaternion CBone::TransformedRotation(const CBoneTransformData &rkData) const
{
return rkData[mID] * Rotation();
}
bool CBone::IsRoot() const
{
// In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the
@@ -103,33 +109,41 @@ u32 CSkeleton::MaxBoneID() const
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
{
ASSERT(rData.NumTrackedBones() >= MaxBoneID());
mpRootBone->UpdateTransform(rData, SBoneTransformInfo(), pAnim, Time, AnchorRoot);
}
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData& rkData)
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkData)
{
// Draw all child links first to minimize model matrix swaps.
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pBone->TransformedPosition(rkData);
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw child links
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
{
CBone *pChild = pBone->ChildByIndex(iChild);
CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
CDrawUtil::DrawLine(BonePos, ChildPos);
}
}
// Draw bone spheres
CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix;
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw bone
CTransform4f Transform;
Transform.Scale(skSphereRadius);
Transform.Translate(BonePos);
CGraphics::sMVPBlock.ModelMatrix = Transform;
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawSphere(CColor::skWhite);
// Draw child links
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::UpdateMVPBlock();
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
{
CVector3f ChildPos = pBone->ChildByIndex(iChild)->TransformedPosition(rkData);
CDrawUtil::DrawLine(BonePos, ChildPos);
}
}
}

View File

@@ -40,7 +40,7 @@ public:
CBone* BoneByName(const TString& rkBoneName) const;
u32 MaxBoneID() const;
void Draw(FRenderOptions Options, const CBoneTransformData& rkData);
void Draw(FRenderOptions Options, const CBoneTransformData *pkData);
std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
inline u32 NumBones() const { return mBones.size(); }
@@ -66,6 +66,7 @@ public:
CBone(CSkeleton *pSkel);
void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
CQuaternion TransformedRotation(const CBoneTransformData& rkData) const;
bool IsRoot() const;
// Accessors

View File

@@ -323,6 +323,14 @@ void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp)
pAttachment->SetAttribute("propertyID", *it->AttachProperty);
pAttachment->SetAttribute("locator", *it->LocatorName);
pAttachments->LinkEndChild(pAttachment);
// Sub-properties
if (it->AttachType != eAttach)
{
XMLElement *pAttachType = ScriptXML.NewElement("attach_type");
pAttachType->SetText("follow");
pAttachment->LinkEndChild(pAttachType);
}
}
}

View File

@@ -561,6 +561,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
SAttachment Attachment;
Attachment.AttachProperty = pAttachment->Attribute("propertyID");
Attachment.LocatorName = pAttachment->Attribute("locator");
Attachment.AttachType = eAttach;
// Validate property
IPropertyTemplate *pProp = pScript->mpBaseStruct->PropertyByIDString(Attachment.AttachProperty);
@@ -569,8 +570,28 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
Log::Error(rkTemplateName + ": Invalid property for attachment " + TString::FromInt32(AttachIdx) + ": " + Attachment.AttachProperty);
else if (pProp->Type() != eCharacterProperty && (pProp->Type() != eFileProperty || !static_cast<CFileTemplate*>(pProp)->AcceptsExtension("CMDL")))
Log::Error(rkTemplateName + ": Property referred to by attachment " + TString::FromInt32(AttachIdx) + " is not an attachable asset! Must be a file property that accepts CMDLs, or a character property.");
else
{
// Check sub-elements
XMLElement *pParams = pAttachment->FirstChildElement();
while (pParams)
{
TString ParamName = pParams->Name();
if (ParamName == "attach_type")
{
TString Type = TString(pParams->GetText()).ToLower();
if (Type == "follow") Attachment.AttachType = eFollow;
else if (Type != "attach") Log::Error(rkTemplateName + ": Attachment " + TString::FromInt32(AttachIdx) + " has invalid attach type specified: " + Type);
}
pParams = pParams->NextSiblingElement();
}
pScript->mAttachments.push_back(Attachment);
}
pAttachment = pAttachment->NextSiblingElement("attachment");
}

View File

@@ -163,7 +163,8 @@ void CModel::DrawWireframe(FRenderOptions Options, CColor WireColor /*= CColor::
void CModel::SetSkin(CSkin *pSkin)
{
ASSERT(!mpSkin || !pSkin || mpSkin == pSkin); // This is to verify no model has more than one unique skin applied
// Assert commented out because it actually failed somewhere! Needs to be addressed.
//ASSERT(!mpSkin || !pSkin || mpSkin == pSkin); // This is to verify no model has more than one unique skin applied
if (mpSkin != pSkin)
{

View File

@@ -13,13 +13,19 @@
#include <vector>
class CScriptObject;
typedef TString TIDString;
enum EAttachType
{
eAttach,
eFollow
};
struct SAttachment
{
TIDString AttachProperty; // Must point to a CMDL!
TString LocatorName;
EAttachType AttachType;
};
/*

View File

@@ -57,7 +57,7 @@ void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, const SVie
// Draw skeleton
if (ComponentIndex == -2)
{
pSkel->Draw(Options, mTransformData);
pSkel->Draw(Options, &mTransformData);
}
// Draw mesh

View File

@@ -4,13 +4,14 @@
#include "Core/Resource/Script/IProperty.h"
#include <Common/Assert.h>
CScriptAttachNode::CScriptAttachNode(CScene *pScene, const TIDString& rkAttachProperty, const TString& rkLocator, CScriptNode *pParent)
CScriptAttachNode::CScriptAttachNode(CScene *pScene, const SAttachment& rkAttachment, CScriptNode *pParent)
: CSceneNode(pScene, -1, pParent)
, mpScriptNode(pParent)
, mLocatorName(rkLocator)
, mAttachType(rkAttachment.AttachType)
, mLocatorName(rkAttachment.LocatorName)
{
CPropertyStruct *pBaseStruct = pParent->Instance()->Properties();
mpAttachAssetProp = pBaseStruct->PropertyByIDString(rkAttachProperty);
mpAttachAssetProp = pBaseStruct->PropertyByIDString(rkAttachment.AttachProperty);
if (mpAttachAssetProp) AttachPropertyModified();
ParentDisplayAssetChanged(mpScriptNode->DisplayAsset());
@@ -150,8 +151,16 @@ SRayIntersection CScriptAttachNode::RayNodeIntersectTest(const CRay& rkRay, u32
// ************ PROTECTED ************
void CScriptAttachNode::CalculateTransform(CTransform4f& rOut) const
{
if (mpLocator)
rOut = mpScriptNode->BoneTransform(mpLocator->ID(), false);
// Apply our local transform
rOut.Scale(LocalScale());
rOut.Rotate(LocalRotation());
rOut.Translate(LocalPosition());
CSceneNode::CalculateTransform(rOut);
// Apply bone transform
if (mpLocator)
rOut = mpScriptNode->BoneTransform(mpLocator->ID(), mAttachType, false) * rOut;
// Apply parent transform
if (mpParent)
rOut = mpParent->Transform() * rOut;
}

View File

@@ -3,6 +3,7 @@
#include "CSceneNode.h"
#include "Core/Resource/Script/IProperty.h"
#include "Core/Resource/Script/CScriptTemplate.h"
class CScriptNode;
@@ -12,11 +13,12 @@ class CScriptAttachNode : public CSceneNode
TResPtr<CResource> mpAttachAsset;
IProperty *mpAttachAssetProp;
EAttachType mAttachType;
TString mLocatorName;
CBone *mpLocator;
public:
explicit CScriptAttachNode(CScene *pScene, const TIDString& rkAttachProperty, const TString& rkLocator, CScriptNode *pParent);
explicit CScriptAttachNode(CScene *pScene, const SAttachment& rkAttachment, CScriptNode *pParent);
void AttachPropertyModified();
void ParentDisplayAssetChanged(CResource *pNewDisplayAsset);
CModel* Model() const;
@@ -29,6 +31,7 @@ public:
SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo);
inline IProperty* AttachProperty() const { return mpAttachAssetProp; }
inline TString LocatorName() const { return mLocatorName; }
protected:
void CalculateTransform(CTransform4f& rOut) const;

View File

@@ -40,8 +40,6 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip
// Determine display assets
SetDisplayAsset(mpInstance->DisplayAsset());
mCharIndex = mpInstance->ActiveCharIndex();
mAnimIndex = mpInstance->ActiveAnimIndex();
mpCollisionNode->SetCollision(mpInstance->Collision());
// Create preview volume node
@@ -62,7 +60,7 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip
for (u32 iAttach = 0; iAttach < pTemp->NumAttachments(); iAttach++)
{
const SAttachment& rkAttach = pTemp->Attachment(iAttach);
CScriptAttachNode *pAttach = new CScriptAttachNode(pScene, rkAttach.AttachProperty, rkAttach.LocatorName, this);
CScriptAttachNode *pAttach = new CScriptAttachNode(pScene, rkAttach, this);
mAttachments.push_back(pAttach);
}
@@ -481,8 +479,6 @@ void CScriptNode::PropertyModified(IProperty *pProp)
if (pProp->Type() == eCharacterProperty)
{
mpInstance->EvaluateDisplayAsset();
mCharIndex = mpInstance->ActiveCharIndex();
mAnimIndex = mpInstance->ActiveAnimIndex();
SetDisplayAsset(mpInstance->DisplayAsset());
}
@@ -493,8 +489,6 @@ void CScriptNode::PropertyModified(IProperty *pProp)
if (pFileTemp->AcceptsExtension("CMDL") || pFileTemp->AcceptsExtension("TXTR") || pFileTemp->AcceptsExtension("ANCS") || pFileTemp->AcceptsExtension("CHAR"))
{
mpInstance->EvaluateDisplayAsset();
mCharIndex = mpInstance->ActiveCharIndex();
mAnimIndex = mpInstance->ActiveAnimIndex();
SetDisplayAsset(mpInstance->DisplayAsset());
}
else if (pFileTemp->AcceptsExtension("DCLN"))
@@ -692,6 +686,13 @@ CSkeleton* CScriptNode::ActiveSkeleton() const
else return nullptr;
}
CAnimation* CScriptNode::ActiveAnimation() const
{
CAnimSet *pSet = ActiveAnimSet();
if (pSet) return pSet->Animation(mAnimIndex);
else return nullptr;
}
CTexture* CScriptNode::ActiveBillboard() const
{
if (mpDisplayAsset && mpDisplayAsset->Type() == eTexture)
@@ -724,7 +725,7 @@ CVector2f CScriptNode::BillboardScale() const
return Out * 0.5f * Template()->PreviewScale();
}
CTransform4f CScriptNode::BoneTransform(u32 BoneID, bool Absolute) const
CTransform4f CScriptNode::BoneTransform(u32 BoneID, EAttachType AttachType, bool Absolute) const
{
CTransform4f Out;
CSkeleton *pSkel = ActiveSkeleton();
@@ -732,6 +733,9 @@ CTransform4f CScriptNode::BoneTransform(u32 BoneID, bool Absolute) const
if (pSkel)
{
CBone *pBone = pSkel->BoneByID(BoneID);
ASSERT(pBone);
if (AttachType == eAttach) Out.Rotate(pBone->Rotation());
Out.Translate(pBone->Position());
}
@@ -743,19 +747,21 @@ CTransform4f CScriptNode::BoneTransform(u32 BoneID, bool Absolute) const
// ************ PROTECTED ************
void CScriptNode::SetDisplayAsset(CResource *pRes)
{
if (mpDisplayAsset != pRes)
{
mpDisplayAsset = pRes;
CModel *pModel = ActiveModel();
mLocalAABox = (pModel ? pModel->AABox() : CAABox::skOne);
MarkTransformChanged();
mpDisplayAsset = pRes;
for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++)
mAttachments[iAttach]->ParentDisplayAssetChanged(pRes);
bool IsAnimSet = (pRes && pRes->Type() == eAnimSet);
mCharIndex = (IsAnimSet ? mpInstance->ActiveCharIndex() : -1);
mAnimIndex = (IsAnimSet ? mpInstance->ActiveAnimIndex() : -1);
if (mpExtra)
mpExtra->DisplayAssetChanged(pRes);
}
CModel *pModel = ActiveModel();
mLocalAABox = (pModel ? pModel->AABox() : CAABox::skOne);
MarkTransformChanged();
for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++)
mAttachments[iAttach]->ParentDisplayAssetChanged(pRes);
if (mpExtra)
mpExtra->DisplayAssetChanged(pRes);
}
void CScriptNode::CalculateTransform(CTransform4f& rOut) const

View File

@@ -59,15 +59,18 @@ public:
bool HasPreviewVolume() const;
CAABox PreviewVolumeAABox() const;
CVector2f BillboardScale() const;
CTransform4f BoneTransform(u32 BoneID, bool Absolute) const;
CTransform4f BoneTransform(u32 BoneID, EAttachType AttachType, bool Absolute) const;
CModel* ActiveModel() const;
CAnimSet* ActiveAnimSet() const;
CSkeleton* ActiveSkeleton() const;
CAnimation* ActiveAnimation() const;
CTexture* ActiveBillboard() const;
bool UsesModel() const;
inline CResource* DisplayAsset() const { return mpDisplayAsset; }
inline u32 NumAttachments() const { return mAttachments.size(); }
inline CScriptAttachNode* Attachment(u32 Index) const { return mAttachments[Index]; }
inline CResource* DisplayAsset() const { return mpDisplayAsset; }
protected:
void SetDisplayAsset(CResource *pRes);

View File

@@ -0,0 +1,30 @@
#include "CSandwormExtra.h"
CSandwormExtra::CSandwormExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
: CScriptExtra(pInstance, pScene, pParent)
{
// The back pincers need to be flipped 180 degrees
for (u32 iAttach = 0; iAttach < pParent->NumAttachments(); iAttach++)
{
CScriptAttachNode *pAttach = pParent->Attachment(iAttach);
if (pAttach->LocatorName() == "L_back_claw" || pAttach->LocatorName() == "R_back_claw")
pAttach->SetRotation(CVector3f(0,0,180));
}
// Get pincers scale
mpPincersScaleProperty = TPropCast<TFloatProperty>(pInstance->PropertyByIDString("0x3DB583AE"));
if (mpPincersScaleProperty) PropertyModified(mpPincersScaleProperty);
}
void CSandwormExtra::PropertyModified(IProperty *pProp)
{
if (pProp == mpPincersScaleProperty)
{
for (u32 iAttach = 0; iAttach < mpScriptNode->NumAttachments(); iAttach++)
{
CScriptAttachNode *pAttach = mpScriptNode->Attachment(iAttach);
pAttach->SetScale(CVector3f(mpPincersScaleProperty->Get()));
}
}
}

View File

@@ -0,0 +1,16 @@
#ifndef CSANDWORMEXTRA_H
#define CSANDWORMEXTRA_H
#include "CScriptExtra.h"
class CSandwormExtra : public CScriptExtra
{
// Transform adjustments to Sandworm attachments.
TFloatProperty *mpPincersScaleProperty;
public:
explicit CSandwormExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent);
void PropertyModified(IProperty *pProp);
};
#endif // CSANDWORMEXTRA_H

View File

@@ -7,6 +7,7 @@
#include "CDoorExtra.h"
#include "CRadiusSphereExtra.h"
#include "CSplinePathExtra.h"
#include "CSandwormExtra.h"
CScriptExtra* CScriptExtra::CreateExtra(CScriptNode *pNode)
{
@@ -57,6 +58,10 @@ CScriptExtra* CScriptExtra::CreateExtra(CScriptNode *pNode)
case 0x434C5043: // "CLPC" ClingPathControl (DKCR)
pExtra = new CSplinePathExtra(pObj, pNode->Scene(), pNode);
break;
case 0x574F524D: // "WORM" Sandworm (MP2)
pExtra = new CSandwormExtra(pObj, pNode->Scene(), pNode);
break;
}
}

View File

@@ -1,4 +1,5 @@
#include "CMatrix4f.h"
#include "CQuaternion.h"
#include "CVector3f.h"
#include "CVector4f.h"
#include "CTransform4f.h"
@@ -184,6 +185,12 @@ CVector4f CMatrix4f::operator*(const CVector4f& rkVec) const
return out;
}
CQuaternion CMatrix4f::operator*(const CQuaternion& rkQuat) const
{
// todo: there's probably a faster way to do this. (mirrored in CTransform4f and CQuaternion)
return CQuaternion::FromRotationMatrix(Inverse().Transpose()) * rkQuat;
}
CMatrix4f CMatrix4f::operator*(const CTransform4f& rkMtx) const
{
// CTransform4f is a 3x4 matrix with an implicit fourth row of {0, 0, 0, 1}

View File

@@ -3,6 +3,7 @@
#include <glm.hpp>
class CQuaternion;
class CVector3f;
class CVector4f;
class CTransform4f;
@@ -40,6 +41,7 @@ public:
inline const float* operator[](long Index) const;
CVector3f operator*(const CVector3f& rkVec) const;
CVector4f operator*(const CVector4f& rkVec) const;
CQuaternion operator*(const CQuaternion& rkQuat) const;
CMatrix4f operator*(const CTransform4f& rkMtx) const;
CMatrix4f operator*(const CMatrix4f& rkMtx) const;

View File

@@ -144,6 +144,17 @@ void CQuaternion::operator *= (const CQuaternion& rkOther)
*this = *this * rkOther;
}
CQuaternion CQuaternion::operator*(const CMatrix4f& rkMtx) const
{
// todo: there's probably a faster way to do this. (mirrored in CMatrix4f and CTransform4f)
return *this * CQuaternion::FromRotationMatrix(rkMtx.Inverse().Transpose());
}
void CQuaternion::operator *= (const CMatrix4f& rkMtx)
{
*this = *this * rkMtx;
}
// ************ STATIC ************
CQuaternion CQuaternion::FromEuler(CVector3f Euler)
{

View File

@@ -25,6 +25,8 @@ public:
CVector3f operator*(const CVector3f& rkVec) const;
CQuaternion operator*(const CQuaternion& rkOther) const;
void operator *= (const CQuaternion& rkOther);
CQuaternion operator*(const CMatrix4f& rkMtx) const;
void operator *= (const CMatrix4f& rkMtx);
// Static
static CQuaternion FromEuler(CVector3f Euler);

View File

@@ -221,6 +221,12 @@ CVector4f CTransform4f::operator*(const CVector4f& rkVec) const
return Out;
}
CQuaternion CTransform4f::operator*(const CQuaternion& rkQuat) const
{
// todo: there's probably a faster way to do this. (mirrored in CMatrix4f and CQuaternion)
return CQuaternion::FromRotationMatrix(Inverse().Transpose()) * rkQuat;
}
CTransform4f CTransform4f::operator*(const CTransform4f& rkMtx) const
{
CTransform4f Out;

View File

@@ -52,6 +52,7 @@ public:
const float* operator[](long Index) const;
CVector3f operator*(const CVector3f& rkVec) const;
CVector4f operator*(const CVector4f& rkVec) const;
CQuaternion operator*(const CQuaternion& rkQuat) const;
CTransform4f operator*(const CTransform4f& rkMtx) const;
void operator*=(const CTransform4f& rkMtx);
bool operator==(const CTransform4f& rkMtx) const;