From cf84f9909a9e893b1b7363b9f921791f849e2a9d Mon Sep 17 00:00:00 2001 From: parax0 Date: Sat, 30 Apr 2016 06:17:02 -0600 Subject: [PATCH] Added support for attaching assets from properties to locator bones in the World Editor --- src/Core/Core.pro | 6 +- src/Core/Resource/CAnimationParameters.cpp | 46 ++--- src/Core/Resource/CAnimationParameters.h | 14 +- src/Core/Resource/CSkeleton.cpp | 15 +- src/Core/Resource/CSkeleton.h | 6 +- src/Core/Resource/Cooker/CTemplateWriter.cpp | 15 ++ src/Core/Resource/Factory/CSkeletonLoader.cpp | 12 +- src/Core/Resource/Factory/CTemplateLoader.cpp | 28 +++ src/Core/Resource/Model/CModel.h | 3 +- src/Core/Resource/Script/CScriptObject.cpp | 15 +- src/Core/Resource/Script/CScriptObject.h | 13 +- src/Core/Resource/Script/CScriptTemplate.cpp | 95 +++------- src/Core/Resource/Script/CScriptTemplate.h | 13 +- src/Core/Scene/CScriptAttachNode.cpp | 157 +++++++++++++++ src/Core/Scene/CScriptAttachNode.h | 37 ++++ src/Core/Scene/CScriptNode.cpp | 179 ++++++++++++++---- src/Core/Scene/CScriptNode.h | 20 +- src/Core/Scene/ENodeType.h | 5 +- .../ScriptExtra/CDamageableTriggerExtra.cpp | 2 +- .../ScriptExtra/CDamageableTriggerExtra.h | 2 +- src/Core/ScriptExtra/CDoorExtra.cpp | 16 +- src/Core/ScriptExtra/CDoorExtra.h | 2 +- .../ScriptExtra/CPointOfInterestExtra.cpp | 2 +- src/Core/ScriptExtra/CPointOfInterestExtra.h | 2 +- src/Core/ScriptExtra/CRadiusSphereExtra.cpp | 2 +- src/Core/ScriptExtra/CRadiusSphereExtra.h | 2 +- src/Core/ScriptExtra/CScriptExtra.cpp | 6 +- src/Core/ScriptExtra/CScriptExtra.h | 14 +- src/Core/ScriptExtra/CSpacePirateExtra.cpp | 2 +- src/Core/ScriptExtra/CSpacePirateExtra.h | 2 +- src/Core/ScriptExtra/CSplinePathExtra.cpp | 2 +- src/Core/ScriptExtra/CSplinePathExtra.h | 2 +- src/Core/ScriptExtra/CWaypointExtra.cpp | 2 +- src/Core/ScriptExtra/CWaypointExtra.h | 2 +- src/Editor/PropertyEdit/CPropertyDelegate.cpp | 4 +- src/Editor/Widgets/WAnimParamsEditor.cpp | 2 +- templates/mp1/Script/Beetle.xml | 3 + templates/mp1/Script/ElitePirate.xml | 3 + templates/mp1/Script/OmegaPirate.xml | 4 + templates/mp1/Script/Thardus.xml | 28 +-- templates/mp2/Script/SandBoss.xml | 9 + templates/mp2/Structs/SandBossStructA.xml | 36 +--- 42 files changed, 575 insertions(+), 255 deletions(-) create mode 100644 src/Core/Scene/CScriptAttachNode.cpp create mode 100644 src/Core/Scene/CScriptAttachNode.h diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 9ae9fa02..912780a3 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -194,7 +194,8 @@ HEADERS += \ Render/CBoneTransformData.h \ Resource/CSkin.h \ Resource/Factory/CSkinLoader.h \ - Render/EDepthGroup.h + Render/EDepthGroup.h \ + Scene/CScriptAttachNode.h # Source Files SOURCES += \ @@ -279,4 +280,5 @@ SOURCES += \ Resource/CAnimation.cpp \ Resource/Factory/CAnimationLoader.cpp \ Resource/Factory/CSkinLoader.cpp \ - Resource/Model/EVertexAttribute.cpp + Resource/Model/EVertexAttribute.cpp \ + Scene/CScriptAttachNode.cpp diff --git a/src/Core/Resource/CAnimationParameters.cpp b/src/Core/Resource/CAnimationParameters.cpp index b0368095..61f82012 100644 --- a/src/Core/Resource/CAnimationParameters.cpp +++ b/src/Core/Resource/CAnimationParameters.cpp @@ -7,8 +7,8 @@ CAnimationParameters::CAnimationParameters() : mGame(ePrime) - , mNodeIndex(0) - , mUnknown1(0) + , mCharIndex(0) + , mAnimIndex(0) , mUnknown2(0) , mUnknown3(0) { @@ -16,8 +16,8 @@ CAnimationParameters::CAnimationParameters() CAnimationParameters::CAnimationParameters(EGame Game) : mGame(Game) - , mNodeIndex(0) - , mUnknown1(0) + , mCharIndex(0) + , mAnimIndex(0) , mUnknown2(0) , mUnknown3(0) { @@ -25,22 +25,22 @@ CAnimationParameters::CAnimationParameters(EGame Game) CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game) : mGame(Game) - , mNodeIndex(0) - , mUnknown1(0) + , mCharIndex(0) + , mAnimIndex(0) , mUnknown2(0) , mUnknown3(0) { if (Game <= eEchoes) { mCharacter = CResourceInfo(rSCLY.ReadLong(), "ANCS"); - mNodeIndex = rSCLY.ReadLong(); - mUnknown1 = rSCLY.ReadLong(); + mCharIndex = rSCLY.ReadLong(); + mAnimIndex = rSCLY.ReadLong(); } else if (Game <= eCorruption) { mCharacter = CResourceInfo(rSCLY.ReadLongLong(), "CHAR"); - mUnknown1 = rSCLY.ReadLong(); + mAnimIndex = rSCLY.ReadLong(); } else if (Game == eReturns) @@ -50,7 +50,7 @@ CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game) // 0x80 - CharacterAnimationSet is empty. if (Flags & 0x80) { - mUnknown1 = -1; + mAnimIndex = -1; mUnknown2 = 0; mUnknown3 = 0; return; @@ -60,9 +60,9 @@ CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game) // 0x20 - Default Anim is present if (Flags & 0x20) - mUnknown1 = rSCLY.ReadLong(); + mAnimIndex = rSCLY.ReadLong(); else - mUnknown1 = -1; + mAnimIndex = -1; // 0x40 - Two-value struct is present if (Flags & 0x40) @@ -85,8 +85,8 @@ void CAnimationParameters::Write(IOutputStream& rSCLY) if (mCharacter.IsValid()) { rSCLY.WriteLong(mCharacter.ID().ToLong()); - rSCLY.WriteLong(mNodeIndex); - rSCLY.WriteLong(mUnknown1); + rSCLY.WriteLong(mCharIndex); + rSCLY.WriteLong(mAnimIndex); } else { @@ -101,7 +101,7 @@ void CAnimationParameters::Write(IOutputStream& rSCLY) if (mCharacter.IsValid()) { rSCLY.WriteLongLong(mCharacter.ID().ToLongLong()); - rSCLY.WriteLong(mUnknown1); + rSCLY.WriteLong(mAnimIndex); } else @@ -119,14 +119,14 @@ void CAnimationParameters::Write(IOutputStream& rSCLY) else { u8 Flag = 0; - if (mUnknown1 != -1) Flag |= 0x20; + if (mAnimIndex != -1) Flag |= 0x20; if (mUnknown2 != 0 || mUnknown3 != 0) Flag |= 0x40; rSCLY.WriteByte(Flag); rSCLY.WriteLongLong(mCharacter.ID().ToLongLong()); if (Flag & 0x20) - rSCLY.WriteLong(mUnknown1); + rSCLY.WriteLong(mAnimIndex); if (Flag & 0x40) { @@ -144,7 +144,7 @@ CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/) CAnimSet *pSet = (CAnimSet*) mCharacter.Load(); if (!pSet) return nullptr; if (pSet->Type() != eAnimSet) return nullptr; - if (NodeIndex == -1) NodeIndex = mNodeIndex; + if (NodeIndex == -1) NodeIndex = mCharIndex; if (pSet->NumNodes() <= (u32) NodeIndex) return nullptr; return pSet->NodeModel(NodeIndex); @@ -157,7 +157,7 @@ TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/) CAnimSet *pSet = (CAnimSet*) mCharacter.Load(); if (!pSet) return ""; if (pSet->Type() != eAnimSet) return ""; - if (NodeIndex == -1) NodeIndex = mNodeIndex; + if (NodeIndex == -1) NodeIndex = mCharIndex; if (pSet->NumNodes() <= (u32) NodeIndex) return ""; return pSet->NodeName((u32) NodeIndex); @@ -166,9 +166,11 @@ TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/) // ************ ACCESSORS ************ u32 CAnimationParameters::Unknown(u32 Index) { + // mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot + // of UI stuff that depends on these functions atm for accessing and editing parameters. switch (Index) { - case 0: return mUnknown1; + case 0: return mAnimIndex; case 1: return mUnknown2; case 2: return mUnknown3; default: return 0; @@ -180,7 +182,7 @@ void CAnimationParameters::SetResource(CResourceInfo Res) if (Res.Type() == "ANCS" || Res.Type() == "CHAR") { mCharacter = Res; - mNodeIndex = 0; + mCharIndex = 0; } else Log::Error("Resource with invalid type passed to CAnimationParameters: " + Res.ToString()); @@ -190,7 +192,7 @@ void CAnimationParameters::SetUnknown(u32 Index, u32 Value) { switch (Index) { - case 0: mUnknown1 = Value; + case 0: mAnimIndex = Value; case 1: mUnknown2 = Value; case 2: mUnknown3 = Value; } diff --git a/src/Core/Resource/CAnimationParameters.h b/src/Core/Resource/CAnimationParameters.h index 28cb81c7..202290ce 100644 --- a/src/Core/Resource/CAnimationParameters.h +++ b/src/Core/Resource/CAnimationParameters.h @@ -12,8 +12,8 @@ class CAnimationParameters EGame mGame; CResourceInfo mCharacter; - u32 mNodeIndex; - u32 mUnknown1; + u32 mCharIndex; + u32 mAnimIndex; u32 mUnknown2; u32 mUnknown3; @@ -29,8 +29,10 @@ public: // Accessors inline EGame Version() const { return mGame; } inline CAnimSet* AnimSet() const { return (CAnimSet*) mCharacter.Load(); } - inline u32 CharacterIndex() { return mNodeIndex; } - inline void SetNodeIndex(u32 Index) { mNodeIndex = Index; } + inline u32 CharacterIndex() const { return mCharIndex; } + inline u32 AnimIndex() const { return mAnimIndex; } + inline void SetCharIndex(u32 Index) { mCharIndex = Index; } + inline void SetAnimIndex(u32 Index) { mAnimIndex = Index; } u32 Unknown(u32 Index); void SetResource(CResourceInfo Res); @@ -41,8 +43,8 @@ public: { return ( (mGame == rkOther.mGame) && (mCharacter == rkOther.mCharacter) && - (mNodeIndex == rkOther.mNodeIndex) && - (mUnknown1 == rkOther.mUnknown1) && + (mCharIndex == rkOther.mCharIndex) && + (mAnimIndex == rkOther.mAnimIndex) && (mUnknown2 == rkOther.mUnknown2) && (mUnknown3 == rkOther.mUnknown3) ); } diff --git a/src/Core/Resource/CSkeleton.cpp b/src/Core/Resource/CSkeleton.cpp index 4906047f..b76900a9 100644 --- a/src/Core/Resource/CSkeleton.cpp +++ b/src/Core/Resource/CSkeleton.cpp @@ -14,7 +14,7 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& { // Get transform data SBoneTransformInfo TransformInfo; - TransformInfo.Position = mPosition; + TransformInfo.Position = mLocalPosition; if (pAnim) pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale); @@ -41,7 +41,7 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const { - return rkData[mID] * AbsolutePosition(); + return rkData[mID] * Position(); } bool CBone::IsRoot() const @@ -77,6 +77,17 @@ CBone* CSkeleton::BoneByID(u32 BoneID) const return nullptr; } +CBone* CSkeleton::BoneByName(const TString& rkBoneName) const +{ + for (u32 iBone = 0; iBone < mBones.size(); iBone++) + { + if (mBones[iBone]->Name() == rkBoneName) + return mBones[iBone]; + } + + return nullptr; +} + u32 CSkeleton::MaxBoneID() const { u32 ID = 0; diff --git a/src/Core/Resource/CSkeleton.h b/src/Core/Resource/CSkeleton.h index 6a4cfaec..6b6e7841 100644 --- a/src/Core/Resource/CSkeleton.h +++ b/src/Core/Resource/CSkeleton.h @@ -37,6 +37,7 @@ public: ~CSkeleton(); void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot); CBone* BoneByID(u32 BoneID) const; + CBone* BoneByName(const TString& rkBoneName) const; u32 MaxBoneID() const; void Draw(FRenderOptions Options, const CBoneTransformData& rkData); @@ -55,7 +56,9 @@ class CBone std::vector mChildren; u32 mID; CVector3f mPosition; + CVector3f mLocalPosition; CQuaternion mRotation; + CQuaternion mLocalRotation; TString mName; CTransform4f mInvBind; @@ -72,8 +75,9 @@ public: inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; } inline u32 ID() const { return mID; } inline CVector3f Position() const { return mPosition; } - inline CVector3f AbsolutePosition() const { return mPosition + (mpParent ? mpParent->AbsolutePosition() : CVector3f::skZero); } + inline CVector3f LocalPosition() const { return mLocalPosition; } inline CQuaternion Rotation() const { return mRotation; } + inline CQuaternion LocalRotation() const { return mLocalRotation; } inline TString Name() const { return mName; } }; diff --git a/src/Core/Resource/Cooker/CTemplateWriter.cpp b/src/Core/Resource/Cooker/CTemplateWriter.cpp index c272ade1..ab2d00e9 100644 --- a/src/Core/Resource/Cooker/CTemplateWriter.cpp +++ b/src/Core/Resource/Cooker/CTemplateWriter.cpp @@ -311,6 +311,21 @@ void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp) pAssets->LinkEndChild(pAsset); } + // Attachments + if (!pTemp->mAttachments.empty()) + { + XMLElement *pAttachments = ScriptXML.NewElement("attachments"); + pEditor->LinkEndChild(pAttachments); + + for (auto it = pTemp->mAttachments.begin(); it != pTemp->mAttachments.end(); it++) + { + XMLElement *pAttachment = ScriptXML.NewElement("attachment"); + pAttachment->SetAttribute("propertyID", *it->AttachProperty); + pAttachment->SetAttribute("locator", *it->LocatorName); + pAttachments->LinkEndChild(pAttachment); + } + } + // Preview Scale if (pTemp->mPreviewScale != 1.f) { diff --git a/src/Core/Resource/Factory/CSkeletonLoader.cpp b/src/Core/Resource/Factory/CSkeletonLoader.cpp index 14091381..e873b589 100644 --- a/src/Core/Resource/Factory/CSkeletonLoader.cpp +++ b/src/Core/Resource/Factory/CSkeletonLoader.cpp @@ -10,7 +10,9 @@ void CSkeletonLoader::SetLocalBoneCoords(CBone *pBone) SetLocalBoneCoords(pBone->ChildByIndex(iChild)); if (pBone->mpParent) - pBone->mPosition -= pBone->mpParent->mPosition; + pBone->mLocalPosition = pBone->mPosition - pBone->mpParent->mPosition; + else + pBone->mLocalPosition = pBone->mPosition; } void CSkeletonLoader::CalculateBoneInverseBindMatrices() @@ -18,7 +20,7 @@ void CSkeletonLoader::CalculateBoneInverseBindMatrices() for (u32 iBone = 0; iBone < mpSkeleton->mBones.size(); iBone++) { CBone *pBone = mpSkeleton->mBones[iBone]; - pBone->mInvBind = CTransform4f::TranslationMatrix(-pBone->AbsolutePosition()); + pBone->mInvBind = CTransform4f::TranslationMatrix(-pBone->Position()); } } @@ -50,8 +52,8 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF) BoneInfo[iBone].ParentID = rCINF.ReadLong(); pBone->mPosition = CVector3f(rCINF); - // Version test. No version number. The next value is the linked bone count in MP1 and the first - // skin metric value in MP2. The max bone count is 100 so the linked bone count will not be higher + // Version test. No version number. The next value is the linked bone count in MP1 and the + // rotation value in MP2. The max bone count is 100 so the linked bone count will not be higher // than that. Additionally, every bone links to its parent at least and every skeleton (as far as I // know) has at least two bones so the linked bone count will never be 0. if (Game == eUnknownVersion) @@ -62,7 +64,7 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF) if (Game == eEchoes) { pBone->mRotation = CQuaternion(rCINF); - rCINF.Seek(0x10, SEEK_CUR); // Think this is another quaternion, not sure what for. + pBone->mLocalRotation = CQuaternion(rCINF); } u32 NumLinkedBones = rCINF.ReadLong(); diff --git a/src/Core/Resource/Factory/CTemplateLoader.cpp b/src/Core/Resource/Factory/CTemplateLoader.cpp index 43837feb..dcbb82c0 100644 --- a/src/Core/Resource/Factory/CTemplateLoader.cpp +++ b/src/Core/Resource/Factory/CTemplateLoader.cpp @@ -548,6 +548,34 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS } } + // Attachments + XMLElement *pAttachments = pEditor->FirstChildElement("attachments"); + + if (pAttachments) + { + XMLElement *pAttachment = pAttachments->FirstChildElement("attachment"); + u32 AttachIdx = 0; + + while (pAttachment) + { + SAttachment Attachment; + Attachment.AttachProperty = pAttachment->Attribute("propertyID"); + Attachment.LocatorName = pAttachment->Attribute("locator"); + + // Validate property + IPropertyTemplate *pProp = pScript->mpBaseStruct->PropertyByIDString(Attachment.AttachProperty); + + if (!pProp) + Log::Error(rkTemplateName + ": Invalid property for attachment " + TString::FromInt32(AttachIdx) + ": " + Attachment.AttachProperty); + else if (pProp->Type() != eCharacterProperty && (pProp->Type() != eFileProperty || !static_cast(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 + pScript->mAttachments.push_back(Attachment); + + pAttachment = pAttachment->NextSiblingElement("attachment"); + } + } + // Preview Scale XMLElement *pPreviewScale = pEditor->FirstChildElement("preview_scale"); diff --git a/src/Core/Resource/Model/CModel.h b/src/Core/Resource/Model/CModel.h index 30c2a411..42379231 100644 --- a/src/Core/Resource/Model/CModel.h +++ b/src/Core/Resource/Model/CModel.h @@ -4,6 +4,7 @@ #include "CBasicModel.h" #include "SSurface.h" #include "Core/Resource/CMaterialSet.h" +#include "Core/Resource/CSkeleton.h" #include "Core/Resource/CSkin.h" #include "Core/OpenGL/CIndexBuffer.h" #include "Core/OpenGL/GLCommon.h" @@ -40,7 +41,7 @@ public: bool HasTransparency(u32 MatSet); bool IsSurfaceTransparent(u32 Surface, u32 MatSet); - bool IsSkinned() const { return (mpSkin != nullptr); } + inline bool IsSkinned() const { return (mpSkin != nullptr); } private: CIndexBuffer* InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive); diff --git a/src/Core/Resource/Script/CScriptObject.cpp b/src/Core/Resource/Script/CScriptObject.cpp index 61744401..eeb86899 100644 --- a/src/Core/Resource/Script/CScriptObject.cpp +++ b/src/Core/Resource/Script/CScriptObject.cpp @@ -9,8 +9,6 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa , mpLayer(pLayer) , mVersion(0) , mInstanceID(InstanceID) - , mpDisplayModel(nullptr) - , mpCollision(nullptr) , mHasInGameModel(false) , mIsCheckingNearVisibleActivation(false) { @@ -37,21 +35,14 @@ CScriptObject::~CScriptObject() mpScale = mpTemplate->FindScale(mpProperties); mpActive = mpTemplate->FindActive(mpProperties); mpLightParameters = mpTemplate->FindLightParameters(mpProperties); - mHasInGameModel = mpTemplate->HasInGameModel(mpProperties); - EvaluateDisplayModel(); - EvaluateBillboard(); + EvaluateDisplayAsset(); EvaluateCollisionModel(); EvaluateVolume(); } -void CScriptObject::EvaluateDisplayModel() +void CScriptObject::EvaluateDisplayAsset() { - mpDisplayModel = mpTemplate->FindDisplayModel(mpProperties); -} - -void CScriptObject::EvaluateBillboard() -{ - mpBillboard = mpTemplate->FindBillboardTexture(mpProperties); + mpDisplayAsset = mpTemplate->FindDisplayAsset(mpProperties, mActiveCharIndex, mActiveAnimIndex, mHasInGameModel); } void CScriptObject::EvaluateCollisionModel() diff --git a/src/Core/Resource/Script/CScriptObject.h b/src/Core/Resource/Script/CScriptObject.h index 426a22c4..0c671993 100644 --- a/src/Core/Resource/Script/CScriptObject.h +++ b/src/Core/Resource/Script/CScriptObject.h @@ -38,9 +38,10 @@ class CScriptObject TVector3Property *mpScale; TBoolProperty *mpActive; CPropertyStruct *mpLightParameters; - TResPtr mpDisplayModel; - TResPtr mpBillboard; + TResPtr mpDisplayAsset; TResPtr mpCollision; + u32 mActiveCharIndex; + u32 mActiveAnimIndex; bool mHasInGameModel; EVolumeShape mVolumeShape; @@ -54,8 +55,7 @@ public: ~CScriptObject(); void EvaluateProperties(); - void EvaluateDisplayModel(); - void EvaluateBillboard(); + void EvaluateDisplayAsset(); void EvaluateCollisionModel(); void EvaluateVolume(); bool IsEditorProperty(IProperty *pProp); @@ -89,8 +89,9 @@ public: bool IsActive() const { return mpActive ? mpActive->Get() : false; } bool HasInGameModel() const { return mHasInGameModel; } CPropertyStruct* LightParameters() const { return mpLightParameters; } - CModel* DisplayModel() const { return mpDisplayModel; } - CTexture* Billboard() const { return mpBillboard; } + CResource* DisplayAsset() const { return mpDisplayAsset; } + u32 ActiveCharIndex() const { return mActiveCharIndex; } + u32 ActiveAnimIndex() const { return mActiveAnimIndex; } CCollisionMeshGroup* Collision() const { return mpCollision; } EVolumeShape VolumeShape() const { return mVolumeShape; } float VolumeScale() const { return mVolumeScale; } diff --git a/src/Core/Resource/Script/CScriptTemplate.cpp b/src/Core/Resource/Script/CScriptTemplate.cpp index 35c42931..d344410a 100644 --- a/src/Core/Resource/Script/CScriptTemplate.cpp +++ b/src/Core/Resource/Script/CScriptTemplate.cpp @@ -152,12 +152,14 @@ CPropertyStruct* CScriptTemplate::FindLightParameters(CPropertyStruct *pProperti return TFetchProperty(pProperties, mLightParametersIDString); } -// todo: merge these four functions, they have near-identical code -CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties) +CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame) { + rOutCharIndex = -1; + rOutAnimIndex = -1; + rOutIsInGame = false; + for (auto it = mAssets.begin(); it != mAssets.end(); it++) { - if ((it->AssetType != SEditorAsset::eModel) && (it->AssetType != SEditorAsset::eAnimParams)) continue; CResource *pRes = nullptr; // File @@ -172,58 +174,34 @@ CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties) { IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation); - if (pProp->Type() == eFileProperty) + if (it->AssetType == SEditorAsset::eAnimParams && pProp->Type() == eCharacterProperty) { - TFileProperty *pFile = static_cast(pProp); - pRes = pFile->Get().Load(); + TCharacterProperty *pChar = static_cast(pProp); + pRes = pChar->Get().AnimSet(); + + if (pRes) + { + rOutCharIndex = (it->ForceNodeIndex >= 0 ? it->ForceNodeIndex : pChar->Get().CharacterIndex()); + rOutAnimIndex = pChar->Get().AnimIndex(); + } } - else if (pProp->Type() == eCharacterProperty) - { - TCharacterProperty *pParams = static_cast(pProp); - pRes = pParams->Get().GetCurrentModel(it->ForceNodeIndex); - } - } - - // Verify resource exists + is correct type - if (pRes && (pRes->Type() == eModel)) - return static_cast(pRes); - } - - return nullptr; -} - -CTexture* CScriptTemplate::FindBillboardTexture(CPropertyStruct *pProperties) -{ - for (auto it = mAssets.begin(); it != mAssets.end(); it++) - { - if (it->AssetType != SEditorAsset::eBillboard) continue; - CResource *pRes = nullptr; - - // File - if (it->AssetSource == SEditorAsset::eFile) - { - TString path = "../resources/" + it->AssetLocation; - pRes = gResCache.GetResource(path); - } - - // Property - else - { - IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation); - - if (pProp->Type() == eFileProperty) + else { TFileProperty *pFile = static_cast(pProp); pRes = pFile->Get().Load(); } } - // Verify resource exists + is correct type - if (pRes && (pRes->Type() == eTexture)) - return static_cast(pRes); + // If we have a valid resource, return + if (pRes) + { + rOutIsInGame = (pRes->Type() != eTexture && it->AssetSource == SEditorAsset::eProperty); + return pRes; + } } + // None are valid - no display asset return nullptr; } @@ -261,35 +239,6 @@ CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties return nullptr; } -bool CScriptTemplate::HasInGameModel(CPropertyStruct *pProperties) -{ - for (auto it = mAssets.begin(); it != mAssets.end(); it++) - { - if ((it->AssetType != SEditorAsset::eModel) && (it->AssetType != SEditorAsset::eAnimParams)) continue; - if (it->AssetSource == SEditorAsset::eFile) continue; - CResource *pRes = nullptr; - - IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation); - - if (pProp->Type() == eFileProperty) - { - TFileProperty *pFile = static_cast(pProp); - pRes = pFile->Get().Load(); - } - - else if (pProp->Type() == eCharacterProperty) - { - TCharacterProperty *pParams = static_cast(pProp); - pRes = pParams->Get().GetCurrentModel(it->ForceNodeIndex); - } - - // Verify resource exists + is correct type - if (pRes && (pRes->Type() == eModel)) - return true; - } - - return false; -} // ************ OBJECT TRACKING ************ u32 CScriptTemplate::NumObjects() const diff --git a/src/Core/Resource/Script/CScriptTemplate.h b/src/Core/Resource/Script/CScriptTemplate.h index 91c5e791..65b52602 100644 --- a/src/Core/Resource/Script/CScriptTemplate.h +++ b/src/Core/Resource/Script/CScriptTemplate.h @@ -16,6 +16,12 @@ class CScriptObject; typedef TString TIDString; +struct SAttachment +{ + TIDString AttachProperty; // Must point to a CMDL! + TString LocatorName; +}; + /* * CScriptTemplate is a class that encases the data contained in one of the XML templates. * It essentially sets the layout of any given script object. @@ -68,6 +74,7 @@ private: TIDString mActiveIDString; TIDString mLightParametersIDString; std::vector mAssets; + std::vector mAttachments; ERotationType mRotationType; EScaleType mScaleType; @@ -99,10 +106,8 @@ public: TVector3Property* FindScale(CPropertyStruct *pProperties); TBoolProperty* FindActive(CPropertyStruct *pProperties); CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties); - CModel* FindDisplayModel(CPropertyStruct *pProperties); - CTexture* FindBillboardTexture(CPropertyStruct *pProperties); + CResource* FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame); CCollisionMeshGroup* FindCollision(CPropertyStruct *pProperties); - bool HasInGameModel(CPropertyStruct *pProperties); // Accessors inline CMasterTemplate* MasterTemplate() const { return mpMaster; } @@ -114,6 +119,8 @@ public: inline bool IsVisible() const { return mVisible; } inline TString SourceFile() const { return mSourceFile; } inline CStructTemplate* BaseStruct() const { return mpBaseStruct; } + inline u32 NumAttachments() const { return mAttachments.size(); } + const SAttachment& Attachment(u32 Index) const { return mAttachments[Index]; } inline bool HasName() const { return !mNameIDString.IsEmpty(); } inline bool HasPosition() const { return !mPositionIDString.IsEmpty(); } diff --git a/src/Core/Scene/CScriptAttachNode.cpp b/src/Core/Scene/CScriptAttachNode.cpp new file mode 100644 index 00000000..3706b97a --- /dev/null +++ b/src/Core/Scene/CScriptAttachNode.cpp @@ -0,0 +1,157 @@ +#include "CScriptAttachNode.h" +#include "CScriptNode.h" +#include "Core/Render/CRenderer.h" +#include "Core/Resource/Script/IProperty.h" +#include + +CScriptAttachNode::CScriptAttachNode(CScene *pScene, const TIDString& rkAttachProperty, const TString& rkLocator, CScriptNode *pParent) + : CSceneNode(pScene, -1, pParent) + , mpScriptNode(pParent) + , mLocatorName(rkLocator) +{ + CPropertyStruct *pBaseStruct = pParent->Instance()->Properties(); + mpAttachAssetProp = pBaseStruct->PropertyByIDString(rkAttachProperty); + if (mpAttachAssetProp) AttachPropertyModified(); + + ParentDisplayAssetChanged(mpScriptNode->DisplayAsset()); +} + +void CScriptAttachNode::AttachPropertyModified() +{ + if (mpAttachAssetProp) + { + if (mpAttachAssetProp->Type() == eFileProperty) + mpAttachAsset = TPropCast(mpAttachAssetProp)->Get().Load(); + else if (mpAttachAssetProp->Type() == eCharacterProperty) + mpAttachAsset = TPropCast(mpAttachAssetProp)->Get().AnimSet(); + + CModel *pModel = Model(); + + if (pModel && pModel->Type() == eModel) + mLocalAABox = pModel->AABox(); + else + mLocalAABox = CAABox::skInfinite; + + MarkTransformChanged(); + } +} + +void CScriptAttachNode::ParentDisplayAssetChanged(CResource *pNewDisplayAsset) +{ + if (pNewDisplayAsset->Type() == eAnimSet) + { + CSkeleton *pSkel = mpScriptNode->ActiveSkeleton(); + mpLocator = pSkel->BoneByName(mLocatorName); + } + + else + { + mpLocator = nullptr; + } + + MarkTransformChanged(); +} + +CModel* CScriptAttachNode::Model() const +{ + if (mpAttachAsset) + { + if (mpAttachAsset->Type() == eModel) + return static_cast(mpAttachAsset.RawPointer()); + + if (mpAttachAsset->Type() == eAnimSet) + { + TCharacterProperty *pProp = TPropCast(mpAttachAssetProp); + return pProp->Get().GetCurrentModel(); + } + } + + return nullptr; +} + +void CScriptAttachNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo) +{ + CModel *pModel = Model(); + if (!pModel) return; + + if (rkViewInfo.ViewFrustum.BoxInFrustum(AABox())) + { + if (pModel->HasTransparency(0)) + AddSurfacesToRenderer(pRenderer, pModel, 0, rkViewInfo); + else + pRenderer->AddMesh(this, -1, AABox(), false, eDrawMesh); + + if (mpParent->IsSelected() && !rkViewInfo.GameMode) + pRenderer->AddMesh(this, -1, AABox(), false, eDrawSelection); + } +} + +void CScriptAttachNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo) +{ + LoadModelMatrix(); + mpParent->LoadLights(rkViewInfo); + + CGraphics::SetupAmbientColor(); + CGraphics::UpdateVertexBlock(); + + CGraphics::sPixelBlock.TintColor = mpParent->TintColor(rkViewInfo); + CGraphics::sPixelBlock.TevColor = CColor::skWhite; + CGraphics::UpdatePixelBlock(); + + if (ComponentIndex < 0) + Model()->Draw(Options, 0); + else + Model()->DrawSurface(Options, ComponentIndex, 0); +} + +void CScriptAttachNode::DrawSelection() +{ + LoadModelMatrix(); + glBlendFunc(GL_ONE, GL_ZERO); + Model()->DrawWireframe(eNoRenderOptions, mpParent->WireframeColor()); +} + +void CScriptAttachNode::RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& /*rkViewInfo*/) +{ + CModel *pModel = Model(); + if (!pModel) return; + + const CRay& rkRay = rTester.Ray(); + std::pair BoxResult = AABox().IntersectsRay(rkRay); + + if (BoxResult.first) + rTester.AddNodeModel(this, pModel); +} + +SRayIntersection CScriptAttachNode::RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo) +{ + FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions(); + + SRayIntersection Out; + Out.pNode = mpParent; + Out.ComponentIndex = AssetID; + + CRay TransformedRay = rkRay.Transformed(Transform().Inverse()); + std::pair Result = Model()->GetSurface(AssetID)->IntersectsRay(TransformedRay, Options.HasFlag(eEnableBackfaceCull)); + + if (Result.first) + { + Out.Hit = true; + CVector3f HitPoint = TransformedRay.PointOnRay(Result.second); + CVector3f WorldHitPoint = Transform() * HitPoint; + Out.Distance = rkRay.Origin().Distance(WorldHitPoint); + } + + else Out.Hit = false; + + return Out; +} + +// ************ PROTECTED ************ +void CScriptAttachNode::CalculateTransform(CTransform4f& rOut) const +{ + if (mpLocator) + rOut = mpScriptNode->BoneTransform(mpLocator->ID(), false); + + CSceneNode::CalculateTransform(rOut); +} diff --git a/src/Core/Scene/CScriptAttachNode.h b/src/Core/Scene/CScriptAttachNode.h new file mode 100644 index 00000000..c4b8e15a --- /dev/null +++ b/src/Core/Scene/CScriptAttachNode.h @@ -0,0 +1,37 @@ +#ifndef CSCRIPTATTACHNODE_H +#define CSCRIPTATTACHNODE_H + +#include "CSceneNode.h" +#include "Core/Resource/Script/IProperty.h" + +class CScriptNode; + +class CScriptAttachNode : public CSceneNode +{ + CScriptNode *mpScriptNode; + TResPtr mpAttachAsset; + IProperty *mpAttachAssetProp; + + TString mLocatorName; + CBone *mpLocator; + +public: + explicit CScriptAttachNode(CScene *pScene, const TIDString& rkAttachProperty, const TString& rkLocator, CScriptNode *pParent); + void AttachPropertyModified(); + void ParentDisplayAssetChanged(CResource *pNewDisplayAsset); + CModel* Model() const; + + ENodeType NodeType() { return eScriptAttachNode; } + void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); + void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo); + void DrawSelection(); + void RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& rkViewInfo); + SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo); + + inline IProperty* AttachProperty() const { return mpAttachAssetProp; } + +protected: + void CalculateTransform(CTransform4f& rOut) const; +}; + +#endif // CSCRIPTATTACHNODE_H diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 337e3c03..232ed1e1 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -7,6 +7,7 @@ #include "Core/Resource/Script/CMasterTemplate.h" #include "Core/Resource/Script/CScriptLayer.h" #include "Core/ScriptExtra/CScriptExtra.h" +#include #include CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScriptObject *pInstance) @@ -15,10 +16,12 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip , mpVolumePreviewNode(nullptr) , mHasVolumePreview(false) , mpInstance(pInstance) - , mpBillboard(nullptr) + , mpExtra(nullptr) { + ASSERT(pInstance); + // Evaluate instance - SetActiveModel(nullptr); + SetDisplayAsset(nullptr); mpCollisionNode = new CCollisionNode(pScene, -1, this); mpCollisionNode->SetInheritance(true, true, false); @@ -36,8 +39,9 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip SetName("[" + pTemp->Name() + "] " + mpInstance->InstanceName()); // Determine display assets - SetActiveModel(mpInstance->DisplayModel()); - mpBillboard = mpInstance->Billboard(); + SetDisplayAsset(mpInstance->DisplayAsset()); + mCharIndex = mpInstance->ActiveCharIndex(); + mAnimIndex = mpInstance->ActiveAnimIndex(); mpCollisionNode->SetCollision(mpInstance->Collision()); // Create preview volume node @@ -54,6 +58,14 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip } } + // Create attachment nodes + for (u32 iAttach = 0; iAttach < pTemp->NumAttachments(); iAttach++) + { + const SAttachment& rkAttach = pTemp->Attachment(iAttach); + CScriptAttachNode *pAttach = new CScriptAttachNode(pScene, rkAttach.AttachProperty, rkAttach.LocatorName, this); + mAttachments.push_back(pAttach); + } + // Fetch LightParameters mpLightParameters = new CLightParameters(mpInstance->LightParameters(), mpInstance->MasterTemplate()->Game()); SetLightLayerIndex(mpLightParameters->LightLayerIndex()); @@ -75,10 +87,12 @@ ENodeType CScriptNode::NodeType() void CScriptNode::PostLoad() { - if (mpActiveModel) + CModel *pModel = ActiveModel(); + + if (pModel) { - mpActiveModel->BufferGL(); - mpActiveModel->GenerateMaterialShaders(); + pModel->BufferGL(); + pModel->GenerateMaterialShaders(); } } @@ -130,17 +144,22 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInf if (rkViewInfo.ShowFlags & eShowObjectGeometry || rkViewInfo.GameMode) { + for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++) + mAttachments[iAttach]->AddToRenderer(pRenderer, rkViewInfo); + if (rkViewInfo.ViewFrustum.BoxInFrustum(AABox())) { - if (!mpActiveModel) + CModel *pModel = ActiveModel(); + + if (!pModel) pRenderer->AddMesh(this, -1, AABox(), false, eDrawMesh); else { - if (!mpActiveModel->HasTransparency(0)) + if (!pModel->HasTransparency(0)) pRenderer->AddMesh(this, -1, AABox(), false, eDrawMesh); else - AddSurfacesToRenderer(pRenderer, mpActiveModel, 0, rkViewInfo); + AddSurfacesToRenderer(pRenderer, pModel, 0, rkViewInfo); } } } @@ -160,7 +179,7 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInf void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo) { - if (!mpInstance) return; + if (!mpInstance || !mpDisplayAsset) return; // Draw model if (UsesModel()) @@ -191,9 +210,11 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn LoadModelMatrix(); // Draw model if possible! - if (mpActiveModel) + CModel *pModel = ActiveModel(); + + if (pModel) { - if (mpActiveModel->IsSkinned()) CGraphics::LoadIdentityBoneTransforms(); + if (pModel->IsSkinned()) CGraphics::LoadIdentityBoneTransforms(); if (mpExtra) CGraphics::sPixelBlock.TevColor = mpExtra->TevColor(); else CGraphics::sPixelBlock.TevColor = CColor::skWhite; @@ -202,9 +223,9 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn CGraphics::UpdatePixelBlock(); if (ComponentIndex < 0) - mpActiveModel->Draw(Options, 0); + pModel->Draw(Options, 0); else - mpActiveModel->DrawSurface(Options, ComponentIndex, 0); + pModel->DrawSurface(Options, ComponentIndex, 0); } // If no model or billboard, default to drawing a purple box @@ -219,9 +240,9 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn } // Draw billboard - else if (mpBillboard) + else if (mpDisplayAsset->Type() == eTexture) { - CDrawUtil::DrawBillboard(mpBillboard, mPosition, BillboardScale(), TintColor(rkViewInfo)); + CDrawUtil::DrawBillboard(ActiveBillboard(), mPosition, BillboardScale(), TintColor(rkViewInfo)); } } @@ -233,7 +254,8 @@ void CScriptNode::DrawSelection() // Draw wireframe for models if (UsesModel()) { - CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); + CModel *pModel = ActiveModel(); + if (!pModel) pModel = CDrawUtil::GetCubeModel(); pModel->DrawWireframe(eNoRenderOptions, WireframeColor()); } @@ -309,7 +331,8 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester& rTester, const SVie if (BoxResult.first) { - if (mpActiveModel) rTester.AddNodeModel(this, mpActiveModel); + CModel *pModel = ActiveModel(); + if (pModel) rTester.AddNodeModel(this, pModel); else rTester.AddNode(this, 0, BoxResult.second); } } @@ -326,6 +349,12 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester& rTester, const SVie std::pair BoxResult = BillBox.IntersectsRay(rkRay); if (BoxResult.first) rTester.AddNode(this, 0, BoxResult.second); } + + // Run ray check on child nodes as well + mpCollisionNode->RayAABoxIntersectTest(rTester, rkViewInfo); + + for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++) + mAttachments[iAttach]->RayAABoxIntersectTest(rTester, rkViewInfo); } SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo) @@ -339,7 +368,8 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& rkRay, u32 AssetI // Model test if (UsesModel()) { - CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); + CModel *pModel = ActiveModel(); + if (!pModel) pModel = CDrawUtil::GetCubeModel(); CRay TransformedRay = rkRay.Transformed(Transform().Inverse()); std::pair Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((Options & eEnableBackfaceCull) == 0)); @@ -385,7 +415,7 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& rkRay, u32 AssetI // Step 4: look up the hit texel and check whether it's transparent or opaque CVector2f TexCoord = (LocalHitPoint + CVector2f(1.f)) * 0.5f; TexCoord.X = -TexCoord.X + 1.f; - float TexelAlpha = mpBillboard->ReadTexelAlpha(TexCoord); + float TexelAlpha = ActiveBillboard()->ReadTexelAlpha(TexCoord); if (TexelAlpha < 0.25f) Out.Hit = false; @@ -450,24 +480,24 @@ void CScriptNode::PropertyModified(IProperty *pProp) // Update resources if (pProp->Type() == eCharacterProperty) { - mpInstance->EvaluateDisplayModel(); - SetActiveModel(mpInstance->DisplayModel()); + mpInstance->EvaluateDisplayAsset(); + mCharIndex = mpInstance->ActiveCharIndex(); + mAnimIndex = mpInstance->ActiveAnimIndex(); + SetDisplayAsset(mpInstance->DisplayAsset()); } + else if (pProp->Type() == eFileProperty) { - CFileTemplate *pFile = static_cast(pProp->Template()); + CFileTemplate *pFileTemp = static_cast(pProp->Template()); - if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR")) + if (pFileTemp->AcceptsExtension("CMDL") || pFileTemp->AcceptsExtension("TXTR") || pFileTemp->AcceptsExtension("ANCS") || pFileTemp->AcceptsExtension("CHAR")) { - mpInstance->EvaluateDisplayModel(); - SetActiveModel(mpInstance->DisplayModel()); + mpInstance->EvaluateDisplayAsset(); + mCharIndex = mpInstance->ActiveCharIndex(); + mAnimIndex = mpInstance->ActiveAnimIndex(); + SetDisplayAsset(mpInstance->DisplayAsset()); } - else if (pFile->AcceptsExtension("TXTR")) - { - mpInstance->EvaluateBillboard(); - mpBillboard = mpInstance->Billboard(); - } - else if (pFile->AcceptsExtension("DCLN")) + else if (pFileTemp->AcceptsExtension("DCLN")) { mpInstance->EvaluateCollisionModel(); mpCollisionNode->SetCollision(mpInstance->Collision()); @@ -492,11 +522,19 @@ void CScriptNode::PropertyModified(IProperty *pProp) mScale = mpInstance->Scale(); MarkTransformChanged(); - SetLightLayerIndex(mpLightParameters->LightLayerIndex()); } - // Update script extra + // Notify attachments + for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++) + { + CScriptAttachNode *pAttach = mAttachments[iAttach]; + + if (pAttach->AttachProperty() == pProp) + pAttach->AttachPropertyModified(); + } + + // Notify script extra if (mpExtra) mpExtra->PropertyModified(pProp); // Update game mode visibility @@ -628,12 +666,43 @@ CScriptExtra* CScriptNode::Extra() const CModel* CScriptNode::ActiveModel() const { - return mpActiveModel; + if (mpDisplayAsset) + { + if (mpDisplayAsset->Type() == eModel) + return static_cast(mpDisplayAsset.RawPointer()); + else if (mpDisplayAsset->Type() == eAnimSet) + return static_cast(mpDisplayAsset.RawPointer())->NodeModel(mCharIndex); + } + + return nullptr; +} + +CAnimSet* CScriptNode::ActiveAnimSet() const +{ + if (mpDisplayAsset && mpDisplayAsset->Type() == eAnimSet) + return static_cast(mpDisplayAsset.RawPointer()); + else + return nullptr; +} + +CSkeleton* CScriptNode::ActiveSkeleton() const +{ + CAnimSet *pSet = ActiveAnimSet(); + if (pSet) return pSet->NodeSkeleton(mCharIndex); + else return nullptr; +} + +CTexture* CScriptNode::ActiveBillboard() const +{ + if (mpDisplayAsset && mpDisplayAsset->Type() == eTexture) + return static_cast(mpDisplayAsset.RawPointer()); + else + return nullptr; } bool CScriptNode::UsesModel() const { - return ((mpActiveModel != nullptr) || (mpBillboard == nullptr)); + return (mpDisplayAsset == nullptr || ActiveModel() != nullptr); } bool CScriptNode::HasPreviewVolume() const @@ -655,12 +724,38 @@ CVector2f CScriptNode::BillboardScale() const return Out * 0.5f * Template()->PreviewScale(); } -// ************ PROTECTED ************ -void CScriptNode::SetActiveModel(CModel *pModel) +CTransform4f CScriptNode::BoneTransform(u32 BoneID, bool Absolute) const { - mpActiveModel = pModel; - mLocalAABox = (pModel ? pModel->AABox() : CAABox::skOne); - MarkTransformChanged(); + CTransform4f Out; + CSkeleton *pSkel = ActiveSkeleton(); + + if (pSkel) + { + CBone *pBone = pSkel->BoneByID(BoneID); + Out.Translate(pBone->Position()); + } + + if (Absolute) Out = Transform() * Out; + + return Out; +} + +// ************ PROTECTED ************ +void CScriptNode::SetDisplayAsset(CResource *pRes) +{ + if (mpDisplayAsset != pRes) + { + mpDisplayAsset = 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 diff --git a/src/Core/Scene/CScriptNode.h b/src/Core/Scene/CScriptNode.h index f6648105..461c6974 100644 --- a/src/Core/Scene/CScriptNode.h +++ b/src/Core/Scene/CScriptNode.h @@ -2,6 +2,7 @@ #define CSCRIPTNODE_H #include "CSceneNode.h" +#include "CScriptAttachNode.h" #include "CModelNode.h" #include "CCollisionNode.h" #include "Core/Resource/Script/CScriptObject.h" @@ -14,9 +15,11 @@ class CScriptNode : public CSceneNode CScriptObject *mpInstance; CScriptExtra *mpExtra; - TResPtr mpActiveModel; - TResPtr mpBillboard; + TResPtr mpDisplayAsset; + u32 mCharIndex; + u32 mAnimIndex; CCollisionNode *mpCollisionNode; + std::vector mAttachments; bool mHasValidPosition; bool mHasVolumePreview; @@ -53,14 +56,21 @@ public: CScriptObject* Instance() const; CScriptTemplate* Template() const; CScriptExtra* Extra() const; - CModel* ActiveModel() const; - bool UsesModel() const; bool HasPreviewVolume() const; CAABox PreviewVolumeAABox() const; CVector2f BillboardScale() const; + CTransform4f BoneTransform(u32 BoneID, bool Absolute) const; + + CModel* ActiveModel() const; + CAnimSet* ActiveAnimSet() const; + CSkeleton* ActiveSkeleton() const; + CTexture* ActiveBillboard() const; + bool UsesModel() const; + + inline CResource* DisplayAsset() const { return mpDisplayAsset; } protected: - void SetActiveModel(CModel *pModel); + void SetDisplayAsset(CResource *pRes); void CalculateTransform(CTransform4f& rOut) const; }; diff --git a/src/Core/Scene/ENodeType.h b/src/Core/Scene/ENodeType.h index 60ea2673..1addc328 100644 --- a/src/Core/Scene/ENodeType.h +++ b/src/Core/Scene/ENodeType.h @@ -12,8 +12,9 @@ enum ENodeType eCollisionNode = 0x8, eScriptNode = 0x10, eScriptExtraNode = 0x20, - eLightNode = 0x40, - eAllNodeTypes = 0x7F + eScriptAttachNode = 0x40, + eLightNode = 0x80, + eAllNodeTypes = 0xFFFFFFFF }; DECLARE_FLAGS(ENodeType, FNodeFlags) diff --git a/src/Core/ScriptExtra/CDamageableTriggerExtra.cpp b/src/Core/ScriptExtra/CDamageableTriggerExtra.cpp index 47410686..4f61ff73 100644 --- a/src/Core/ScriptExtra/CDamageableTriggerExtra.cpp +++ b/src/Core/ScriptExtra/CDamageableTriggerExtra.cpp @@ -2,7 +2,7 @@ #include "Core/Render/CDrawUtil.h" #include "Core/Render/CRenderer.h" -CDamageableTriggerExtra::CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CDamageableTriggerExtra::CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) , mpRenderSideProp(nullptr) , mpMat(nullptr) diff --git a/src/Core/ScriptExtra/CDamageableTriggerExtra.h b/src/Core/ScriptExtra/CDamageableTriggerExtra.h index 26d47c7e..37d2a5ee 100644 --- a/src/Core/ScriptExtra/CDamageableTriggerExtra.h +++ b/src/Core/ScriptExtra/CDamageableTriggerExtra.h @@ -31,7 +31,7 @@ class CDamageableTriggerExtra : public CScriptExtra float mCachedRayDistance; public: - explicit CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); ~CDamageableTriggerExtra(); void CreateMaterial(); void UpdatePlaneTransform(); diff --git a/src/Core/ScriptExtra/CDoorExtra.cpp b/src/Core/ScriptExtra/CDoorExtra.cpp index 9c1ec83d..c78c4b00 100644 --- a/src/Core/ScriptExtra/CDoorExtra.cpp +++ b/src/Core/ScriptExtra/CDoorExtra.cpp @@ -1,7 +1,7 @@ #include "CDoorExtra.h" #include "Core/Render/CRenderer.h" -CDoorExtra::CDoorExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CDoorExtra::CDoorExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) , mpShieldModelProp(nullptr) , mpShieldColorProp(nullptr) @@ -117,22 +117,22 @@ SRayIntersection CDoorExtra::RayNodeIntersectTest(const CRay& rkRay, u32 AssetID { FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions(); - SRayIntersection out; - out.pNode = mpParent; - out.ComponentIndex = AssetID; + SRayIntersection Out; + Out.pNode = mpParent; + Out.ComponentIndex = AssetID; CRay TransformedRay = rkRay.Transformed(Transform().Inverse()); std::pair Result = mpShieldModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((Options & eEnableBackfaceCull) == 0)); if (Result.first) { - out.Hit = true; + Out.Hit = true; CVector3f HitPoint = TransformedRay.PointOnRay(Result.second); CVector3f WorldHitPoint = Transform() * HitPoint; - out.Distance = rkRay.Origin().Distance(WorldHitPoint); + Out.Distance = rkRay.Origin().Distance(WorldHitPoint); } - else out.Hit = false; + else Out.Hit = false; - return out; + return Out; } diff --git a/src/Core/ScriptExtra/CDoorExtra.h b/src/Core/ScriptExtra/CDoorExtra.h index 2a528df9..b9d8b4f8 100644 --- a/src/Core/ScriptExtra/CDoorExtra.h +++ b/src/Core/ScriptExtra/CDoorExtra.h @@ -13,7 +13,7 @@ class CDoorExtra : public CScriptExtra CColor mShieldColor; public: - explicit CDoorExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CDoorExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); void PropertyModified(IProperty *pProperty); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo); diff --git a/src/Core/ScriptExtra/CPointOfInterestExtra.cpp b/src/Core/ScriptExtra/CPointOfInterestExtra.cpp index 7d77d2c0..60ecddae 100644 --- a/src/Core/ScriptExtra/CPointOfInterestExtra.cpp +++ b/src/Core/ScriptExtra/CPointOfInterestExtra.cpp @@ -3,7 +3,7 @@ const CColor CPointOfInterestExtra::skRegularColor = CColor::Integral(0xFF,0x70,0x00); const CColor CPointOfInterestExtra::skImportantColor = CColor::Integral(0xFF,0x00,0x00); -CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) , mpScanProperty(nullptr) , mpScanData(nullptr) diff --git a/src/Core/ScriptExtra/CPointOfInterestExtra.h b/src/Core/ScriptExtra/CPointOfInterestExtra.h index d516f1cc..123b3676 100644 --- a/src/Core/ScriptExtra/CPointOfInterestExtra.h +++ b/src/Core/ScriptExtra/CPointOfInterestExtra.h @@ -12,7 +12,7 @@ class CPointOfInterestExtra : public CScriptExtra TResPtr mpScanData; public: - explicit CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); void PropertyModified(IProperty* pProperty); void ModifyTintColor(CColor& Color); CScan* GetScan() const { return mpScanData; } diff --git a/src/Core/ScriptExtra/CRadiusSphereExtra.cpp b/src/Core/ScriptExtra/CRadiusSphereExtra.cpp index 2d7c0955..73440848 100644 --- a/src/Core/ScriptExtra/CRadiusSphereExtra.cpp +++ b/src/Core/ScriptExtra/CRadiusSphereExtra.cpp @@ -2,7 +2,7 @@ #include "Core/Render/CDrawUtil.h" #include "Core/Render/CRenderer.h" -CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) , mpRadius(nullptr) { diff --git a/src/Core/ScriptExtra/CRadiusSphereExtra.h b/src/Core/ScriptExtra/CRadiusSphereExtra.h index 4c5e25cb..9b0a9217 100644 --- a/src/Core/ScriptExtra/CRadiusSphereExtra.h +++ b/src/Core/ScriptExtra/CRadiusSphereExtra.h @@ -10,7 +10,7 @@ class CRadiusSphereExtra : public CScriptExtra TFloatProperty *mpRadius; public: - explicit CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo); CColor Color() const; diff --git a/src/Core/ScriptExtra/CScriptExtra.cpp b/src/Core/ScriptExtra/CScriptExtra.cpp index e3a3880a..72c98ce7 100644 --- a/src/Core/ScriptExtra/CScriptExtra.cpp +++ b/src/Core/ScriptExtra/CScriptExtra.cpp @@ -52,9 +52,9 @@ CScriptExtra* CScriptExtra::CreateExtra(CScriptNode *pNode) pExtra = new CRadiusSphereExtra(pObj, pNode->Scene(), pNode); break; - case 0x53505041: // SplinePath (DKCR) - case 0x5043544C: // PathControl (DKCR) - case 0x434C5043: // ClingPathControl (DKCR) + case 0x53505041: // "SPPA" SplinePath (DKCR) + case 0x5043544C: // "PCTL" PathControl (DKCR) + case 0x434C5043: // "CLPC" ClingPathControl (DKCR) pExtra = new CSplinePathExtra(pObj, pNode->Scene(), pNode); break; } diff --git a/src/Core/ScriptExtra/CScriptExtra.h b/src/Core/ScriptExtra/CScriptExtra.h index ffd6c84a..3608503e 100644 --- a/src/Core/ScriptExtra/CScriptExtra.h +++ b/src/Core/ScriptExtra/CScriptExtra.h @@ -3,6 +3,7 @@ #include "Core/Scene/CSceneNode.h" #include "Core/Scene/CScriptNode.h" +#include /* CScriptExtra is a class that allows for additional coded behavior on any given * script object type. Subclass IScriptExtra, add the new class to CScriptExtra.cpp, @@ -15,18 +16,20 @@ class CScriptExtra : public CSceneNode { protected: + CScriptNode *mpScriptNode; CScriptObject *mpInstance; EGame mGame; public: - explicit CScriptExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0) - : CSceneNode(pScene, -1, pParent), - mpInstance(pInstance), - mGame(pInstance->Template()->Game()) + explicit CScriptExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0) + : CSceneNode(pScene, -1, pParent) + , mpScriptNode(pParent) + , mpInstance(pInstance) + , mGame(pInstance->Template()->Game()) { } - virtual ~CScriptExtra() {} + virtual ~CScriptExtra() {} inline CScriptObject* Instance() const { return mpInstance; } inline EGame Game() const { return mGame; } @@ -43,6 +46,7 @@ public: // Virtual CScriptExtra functions virtual void InstanceTransformed() {} virtual void PropertyModified(IProperty* /*pProperty*/) {} + virtual void DisplayAssetChanged(CResource* /*pNewDisplayAsset*/) {} virtual void LinksModified() {} virtual bool ShouldDrawNormalAssets() { return true; } virtual bool ShouldDrawVolume() { return true; } diff --git a/src/Core/ScriptExtra/CSpacePirateExtra.cpp b/src/Core/ScriptExtra/CSpacePirateExtra.cpp index 8958ac27..cb3e135a 100644 --- a/src/Core/ScriptExtra/CSpacePirateExtra.cpp +++ b/src/Core/ScriptExtra/CSpacePirateExtra.cpp @@ -1,6 +1,6 @@ #include "CSpacePirateExtra.h" -CSpacePirateExtra::CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CSpacePirateExtra::CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene ,pParent) , mpPowerVuln(nullptr) , mpWaveVuln(nullptr) diff --git a/src/Core/ScriptExtra/CSpacePirateExtra.h b/src/Core/ScriptExtra/CSpacePirateExtra.h index 333a51c2..e7dd1d2e 100644 --- a/src/Core/ScriptExtra/CSpacePirateExtra.h +++ b/src/Core/ScriptExtra/CSpacePirateExtra.h @@ -13,7 +13,7 @@ class CSpacePirateExtra : public CScriptExtra TEnumProperty *mpPlasmaVuln; public: - explicit CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); CColor TevColor(); }; diff --git a/src/Core/ScriptExtra/CSplinePathExtra.cpp b/src/Core/ScriptExtra/CSplinePathExtra.cpp index 3f1fc74f..93721729 100644 --- a/src/Core/ScriptExtra/CSplinePathExtra.cpp +++ b/src/Core/ScriptExtra/CSplinePathExtra.cpp @@ -3,7 +3,7 @@ #include "Core/Resource/Script/CLink.h" #include "Core/Scene/CScene.h" -CSplinePathExtra::CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CSplinePathExtra::CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) { mpPathColor = TPropCast(pInstance->Properties()->PropertyByID(0x00DD86E2)); diff --git a/src/Core/ScriptExtra/CSplinePathExtra.h b/src/Core/ScriptExtra/CSplinePathExtra.h index 42cbae62..b4915260 100644 --- a/src/Core/ScriptExtra/CSplinePathExtra.h +++ b/src/Core/ScriptExtra/CSplinePathExtra.h @@ -15,7 +15,7 @@ class CSplinePathExtra : public CScriptExtra std::list mWaypoints; public: - explicit CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); ~CSplinePathExtra() { ClearWaypoints(); } inline CColor PathColor() const { return (mpPathColor ? mpPathColor->Get() : CColor::skBlack); } diff --git a/src/Core/ScriptExtra/CWaypointExtra.cpp b/src/Core/ScriptExtra/CWaypointExtra.cpp index 8bbe45df..96125008 100644 --- a/src/Core/ScriptExtra/CWaypointExtra.cpp +++ b/src/Core/ScriptExtra/CWaypointExtra.cpp @@ -4,7 +4,7 @@ #include "Core/Render/CRenderer.h" #include "Core/Scene/CScene.h" -CWaypointExtra::CWaypointExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent) +CWaypointExtra::CWaypointExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent) : CScriptExtra(pInstance, pScene, pParent) , mColor(CColor::skBlack) , mLinksBuilt(false) diff --git a/src/Core/ScriptExtra/CWaypointExtra.h b/src/Core/ScriptExtra/CWaypointExtra.h index 620fe6a0..b29dbd32 100644 --- a/src/Core/ScriptExtra/CWaypointExtra.h +++ b/src/Core/ScriptExtra/CWaypointExtra.h @@ -20,7 +20,7 @@ class CWaypointExtra : public CScriptExtra std::vector mLinks; public: - explicit CWaypointExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0); + explicit CWaypointExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); ~CWaypointExtra(); void CheckColor(); void AddToSplinePath(CSplinePathExtra *pPath); diff --git a/src/Editor/PropertyEdit/CPropertyDelegate.cpp b/src/Editor/PropertyEdit/CPropertyDelegate.cpp index 6a14b448..29aca05b 100644 --- a/src/Editor/PropertyEdit/CPropertyDelegate.cpp +++ b/src/Editor/PropertyEdit/CPropertyDelegate.cpp @@ -655,14 +655,14 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde { Params.SetResource( static_cast(pEditor)->GetResourceInfo() ); // Reset all other parameters to 0 - Params.SetNodeIndex(0); + Params.SetCharIndex(0); for (u32 iUnk = 0; iUnk < 3; iUnk++) Params.SetUnknown(iUnk, 0); } else if (Type == eEnumProperty) { - Params.SetNodeIndex( static_cast(pEditor)->currentIndex() ); + Params.SetCharIndex( static_cast(pEditor)->currentIndex() ); } else if (Type == eLongProperty) diff --git a/src/Editor/Widgets/WAnimParamsEditor.cpp b/src/Editor/Widgets/WAnimParamsEditor.cpp index ec540773..8be63f16 100644 --- a/src/Editor/Widgets/WAnimParamsEditor.cpp +++ b/src/Editor/Widgets/WAnimParamsEditor.cpp @@ -76,7 +76,7 @@ void WAnimParamsEditor::OnResourceChanged(QString Path) void WAnimParamsEditor::OnCharacterChanged(int Index) { - mParams.SetNodeIndex(Index); + mParams.SetCharIndex(Index); emit ParametersChanged(mParams); } diff --git a/templates/mp1/Script/Beetle.xml b/templates/mp1/Script/Beetle.xml index 395af9d8..001613bf 100644 --- a/templates/mp1/Script/Beetle.xml +++ b/templates/mp1/Script/Beetle.xml @@ -38,6 +38,9 @@ 0x06:0x04 0x0C + + + enabled enabled diff --git a/templates/mp1/Script/ElitePirate.xml b/templates/mp1/Script/ElitePirate.xml index 385fd2c7..7037f1c4 100644 --- a/templates/mp1/Script/ElitePirate.xml +++ b/templates/mp1/Script/ElitePirate.xml @@ -61,6 +61,9 @@ 0x11 0x14 + + + enabled enabled diff --git a/templates/mp1/Script/OmegaPirate.xml b/templates/mp1/Script/OmegaPirate.xml index 3f85bf37..698796cf 100644 --- a/templates/mp1/Script/OmegaPirate.xml +++ b/templates/mp1/Script/OmegaPirate.xml @@ -65,6 +65,10 @@ 0x14 0x2A + + + + enabled enabled diff --git a/templates/mp1/Script/Thardus.xml b/templates/mp1/Script/Thardus.xml index cc545633..2da940b9 100644 --- a/templates/mp1/Script/Thardus.xml +++ b/templates/mp1/Script/Thardus.xml @@ -10,20 +10,20 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/templates/mp2/Script/SandBoss.xml b/templates/mp2/Script/SandBoss.xml index 9126f512..794b3d58 100644 --- a/templates/mp2/Script/SandBoss.xml +++ b/templates/mp2/Script/SandBoss.xml @@ -243,6 +243,15 @@ 0x91E88D81:0x0CF8C54C:0x37E99C23 0x91E88D81:0xBBD84681 + + + + + + + + + enabled enabled diff --git a/templates/mp2/Structs/SandBossStructA.xml b/templates/mp2/Structs/SandBossStructA.xml index 337e980b..d43b696e 100644 --- a/templates/mp2/Structs/SandBossStructA.xml +++ b/templates/mp2/Structs/SandBossStructA.xml @@ -1,32 +1,14 @@ - - -1 - - - -1 - - - -1 - - - -1 - - - -1 - - - -1 - - - -1 - - - -1 - - - -1 - + + + + + + + + +