Added support for attaching assets from properties to locator bones in the World Editor

This commit is contained in:
parax0
2016-04-30 06:17:02 -06:00
parent 2655f9d3fd
commit cf84f9909a
42 changed files with 575 additions and 255 deletions

View File

@@ -0,0 +1,157 @@
#include "CScriptAttachNode.h"
#include "CScriptNode.h"
#include "Core/Render/CRenderer.h"
#include "Core/Resource/Script/IProperty.h"
#include <Common/Assert.h>
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<TFileProperty>(mpAttachAssetProp)->Get().Load();
else if (mpAttachAssetProp->Type() == eCharacterProperty)
mpAttachAsset = TPropCast<TCharacterProperty>(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<CModel*>(mpAttachAsset.RawPointer());
if (mpAttachAsset->Type() == eAnimSet)
{
TCharacterProperty *pProp = TPropCast<TCharacterProperty>(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<bool,float> 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<bool,float> 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);
}

View File

@@ -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<CResource> 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

View File

@@ -7,6 +7,7 @@
#include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/ScriptExtra/CScriptExtra.h"
#include <Common/Assert.h>
#include <Math/MathUtil.h>
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<bool,float> 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<bool,float> 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<CFileTemplate*>(pProp->Template());
CFileTemplate *pFileTemp = static_cast<CFileTemplate*>(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<CModel*>(mpDisplayAsset.RawPointer());
else if (mpDisplayAsset->Type() == eAnimSet)
return static_cast<CAnimSet*>(mpDisplayAsset.RawPointer())->NodeModel(mCharIndex);
}
return nullptr;
}
CAnimSet* CScriptNode::ActiveAnimSet() const
{
if (mpDisplayAsset && mpDisplayAsset->Type() == eAnimSet)
return static_cast<CAnimSet*>(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<CTexture*>(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

View File

@@ -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<CModel> mpActiveModel;
TResPtr<CTexture> mpBillboard;
TResPtr<CResource> mpDisplayAsset;
u32 mCharIndex;
u32 mAnimIndex;
CCollisionNode *mpCollisionNode;
std::vector<CScriptAttachNode*> 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;
};

View File

@@ -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)