diff --git a/PrimeWorldEditor.pro b/PrimeWorldEditor.pro index 889a3c68..aafb21bc 100644 --- a/PrimeWorldEditor.pro +++ b/PrimeWorldEditor.pro @@ -152,7 +152,11 @@ SOURCES += \ UI/WAnimParamsEditor.cpp \ Resource/CCollisionMeshGroup.cpp \ Core/CFrustumPlanes.cpp \ - Core/CLightParameters.cpp + Core/CLightParameters.cpp \ + Scene/script/CPointOfInterestExtra.cpp \ + Scene/script/CScriptExtra.cpp \ + Scene/script/CSpacePirateExtra.cpp \ + Scene/script/CWaypointExtra.cpp HEADERS += \ Common/AnimUtil.h \ @@ -320,7 +324,11 @@ HEADERS += \ Resource/CCollisionMeshGroup.h \ Core/CFrustumPlanes.h \ Core/CLightParameters.h \ - Core/SViewInfo.h + Core/SViewInfo.h \ + Scene/script/CScriptExtra.h \ + Scene/script/CPointOfInterestExtra.h \ + Scene/script/CSpacePirateExtra.h \ + Scene/script/CWaypointExtra.h FORMS += \ UI/CStartWindow.ui \ diff --git a/Resource/script/CScriptTemplate.cpp b/Resource/script/CScriptTemplate.cpp index af3c3011..74271cc5 100644 --- a/Resource/script/CScriptTemplate.cpp +++ b/Resource/script/CScriptTemplate.cpp @@ -25,6 +25,11 @@ CMasterTemplate* CScriptTemplate::MasterTemplate() return mpMaster; } +EGame CScriptTemplate::Game() +{ + return mpMaster->GetGame(); +} + TString CScriptTemplate::TemplateName(s32 propCount) const { // Return original name if there is only one property set diff --git a/Resource/script/CScriptTemplate.h b/Resource/script/CScriptTemplate.h index 78247d07..8ab65dc6 100644 --- a/Resource/script/CScriptTemplate.h +++ b/Resource/script/CScriptTemplate.h @@ -93,6 +93,7 @@ public: ~CScriptTemplate(); CMasterTemplate* MasterTemplate(); + EGame Game(); TString TemplateName(s32 propCount = -1) const; TString PropertySetNameByCount(s32 propCount) const; TString PropertySetNameByIndex(u32 index) const; diff --git a/Scene/CRootNode.h b/Scene/CRootNode.h index cad84961..6080a62f 100644 --- a/Scene/CRootNode.h +++ b/Scene/CRootNode.h @@ -15,9 +15,6 @@ public: return eRootNode; } - inline void AddToRenderer(CRenderer *, const SViewInfo&) {} - inline void Draw(ERenderOptions, const SViewInfo&) {} - inline void DrawAsset(ERenderOptions, u32, const SViewInfo&) {} inline void RayAABoxIntersectTest(CRayCollisionTester &) {} inline SRayIntersection RayNodeIntersectTest(const CRay &, u32, const SViewInfo&) { diff --git a/Scene/CSceneNode.cpp b/Scene/CSceneNode.cpp index 27f5b2a1..e3bbcbb4 100644 --- a/Scene/CSceneNode.cpp +++ b/Scene/CSceneNode.cpp @@ -71,6 +71,11 @@ bool CSceneNode::IsVisible() const return mVisible; } +CColor CSceneNode::TintColor(const SViewInfo& ViewInfo) const +{ + return (IsSelected() && !ViewInfo.GameMode ? skSelectionTint : CColor::skWhite); +} + CColor CSceneNode::WireframeColor() const { return CColor::skWhite; @@ -307,12 +312,6 @@ CSceneManager* CSceneNode::Scene() return mpScene; } -CColor CSceneNode::TintColor(const SViewInfo& ViewInfo) const -{ - // convenience; this is/will be a fairly common operation - return (IsSelected() && !ViewInfo.GameMode ? skSelectionTint : CColor::skWhite); -} - CVector3f CSceneNode::LocalPosition() const { return mPosition; diff --git a/Scene/CSceneNode.h b/Scene/CSceneNode.h index 75b8e6b9..8a86e830 100644 --- a/Scene/CSceneNode.h +++ b/Scene/CSceneNode.h @@ -54,10 +54,12 @@ public: virtual ~CSceneNode(); virtual ENodeType NodeType() = 0; virtual TString PrefixedName() const; + virtual void AddToRenderer(CRenderer* /*pRenderer*/, const SViewInfo& /*ViewInfo*/) {} virtual void DrawSelection(); virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester); virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo) = 0; virtual bool IsVisible() const; + virtual CColor TintColor(const SViewInfo& ViewInfo) const; virtual CColor WireframeColor() const; void Unparent(); @@ -82,7 +84,6 @@ public: TString Name() const; CSceneNode* Parent() const; CSceneManager* Scene(); - CColor TintColor(const SViewInfo& ViewInfo) const; CVector3f LocalPosition() const; CVector3f AbsolutePosition() const; CQuaternion LocalRotation() const; diff --git a/Scene/CScriptNode.cpp b/Scene/CScriptNode.cpp index a9212470..c9568c57 100644 --- a/Scene/CScriptNode.cpp +++ b/Scene/CScriptNode.cpp @@ -1,5 +1,6 @@ #include "CScriptNode.h" -#include +#include "script/CScriptExtra.h" + #include #include #include @@ -89,6 +90,8 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje mLocalAABox = mpActiveModel->AABox(); else mLocalAABox = CAABox::skOne; + + mpExtra = CScriptExtra::CreateExtra(this); } ENodeType CScriptNode::NodeType() @@ -105,6 +108,9 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) { if (!mpInstance) return; + // Add script extra to renderer first + if (mpExtra) mpExtra->AddToRenderer(pRenderer, ViewInfo); + // If we're in game mode, then override other visibility settings. if (ViewInfo.GameMode) { @@ -112,44 +118,50 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) return; } - // Otherwise, we proceed as normal - ERenderOptions options = pRenderer->RenderOptions(); + // Check whether the script extra wants us to render before we render. + bool ShouldDraw = (!mpExtra || mpExtra->ShouldDrawNormalAssets()); - if ((options & eDrawObjectCollision) && (!ViewInfo.GameMode)) - mpCollisionNode->AddToRenderer(pRenderer, ViewInfo); - - if (options & eDrawObjects || ViewInfo.GameMode) + if (ShouldDraw) { - if (ViewInfo.ViewFrustum.BoxInFrustum(AABox())) + // Otherwise, we proceed as normal + ERenderOptions options = pRenderer->RenderOptions(); + + if ((options & eDrawObjectCollision) && (!ViewInfo.GameMode)) + mpCollisionNode->AddToRenderer(pRenderer, ViewInfo); + + if (options & eDrawObjects || ViewInfo.GameMode) { - if (!mpActiveModel) - pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); - - else + if (ViewInfo.ViewFrustum.BoxInFrustum(AABox())) { - if (!mpActiveModel->IsBuffered()) - mpActiveModel->BufferGL(); - - if (!mpActiveModel->HasTransparency(0)) + if (!mpActiveModel) pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); else { - u32 SubmeshCount = mpActiveModel->GetSurfaceCount(); + if (!mpActiveModel->IsBuffered()) + mpActiveModel->BufferGL(); - for (u32 s = 0; s < SubmeshCount; s++) + if (!mpActiveModel->HasTransparency(0)) + pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); + + else { - if (ViewInfo.ViewFrustum.BoxInFrustum(mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()))) + u32 SubmeshCount = mpActiveModel->GetSurfaceCount(); + + for (u32 s = 0; s < SubmeshCount; s++) { - if (!mpActiveModel->IsSurfaceTransparent(s, 0)) - pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); - else - pRenderer->AddTransparentMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + if (ViewInfo.ViewFrustum.BoxInFrustum(mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()))) + { + if (!mpActiveModel->IsSurfaceTransparent(s, 0)) + pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + else + pRenderer->AddTransparentMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + } } } } - } + } } } @@ -157,9 +169,10 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) { // Script nodes always draw their selections regardless of frustum planes // in order to ensure that script connection lines don't get improperly culled. - pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection); + if (ShouldDraw) + pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection); - if (mHasVolumePreview) + if (mHasVolumePreview && (!mpExtra || mpExtra->ShouldDrawVolume())) mpVolumePreviewNode->AddToRenderer(pRenderer, ViewInfo); } } @@ -173,6 +186,10 @@ void CScriptNode::Draw(ERenderOptions Options, const SViewInfo& ViewInfo) { LoadModelMatrix(); LoadLights(ViewInfo); + + if (mpExtra) CGraphics::sPixelBlock.TevColor = mpExtra->TevColor().ToVector4f(); + else CGraphics::sPixelBlock.TevColor = CColor::skWhite.ToVector4f(); + CGraphics::sPixelBlock.TintColor = TintColor(ViewInfo).ToVector4f(); mpActiveModel->Draw(Options, 0); } @@ -208,10 +225,14 @@ void CScriptNode::DrawAsset(ERenderOptions Options, u32 Asset, const SViewInfo& else CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f(); - CGraphics::sPixelBlock.TintColor = TintColor(ViewInfo).ToVector4f(); LoadModelMatrix(); LoadLights(ViewInfo); + if (mpExtra) CGraphics::sPixelBlock.TevColor = mpExtra->TevColor().ToVector4f(); + else CGraphics::sPixelBlock.TevColor = CColor::skWhite.ToVector4f(); + + CGraphics::sPixelBlock.TintColor = TintColor(ViewInfo).ToVector4f(); + mpActiveModel->DrawSurface(Options, Asset, 0); } @@ -234,9 +255,10 @@ void CScriptNode::DrawSelection() for (u32 iIn = 0; iIn < mpInstance->NumInLinks(); iIn++) { + // Don't draw in links if the other object is selected. const SLink& con = mpInstance->InLink(iIn); CScriptNode *pLinkNode = mpScene->ScriptNodeByID(con.ObjectID); - if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed); + if (pLinkNode && !pLinkNode->IsSelected()) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed); } for (u32 iOut = 0; iOut < mpInstance->NumOutLinks(); iOut++) @@ -253,6 +275,16 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester &Tester) if (!mpInstance) return; + // Let script extra do ray check first + if (mpExtra) + { + mpExtra->RayAABoxIntersectTest(Tester); + + // If the extra doesn't want us rendering, then don't do the ray test either + if (!mpExtra->ShouldDrawNormalAssets()) return; + } + + // Otherwise, proceed with the ray test as normal... const CRay& Ray = Tester.Ray(); if (mpActiveModel || !mpBillboard) @@ -390,6 +422,13 @@ bool CScriptNode::IsVisible() const return (mVisible && mpInstance->Layer()->IsVisible() && mpInstance->Template()->IsVisible()); } +CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const +{ + CColor BaseColor = CSceneNode::TintColor(ViewInfo); + if (mpExtra) mpExtra->ModifyTintColor(BaseColor); + return BaseColor; +} + CColor CScriptNode::WireframeColor() const { return CColor((u8) 12, 135, 194, 255); diff --git a/Scene/CScriptNode.h b/Scene/CScriptNode.h index 4aaa520a..3c2bbd3d 100644 --- a/Scene/CScriptNode.h +++ b/Scene/CScriptNode.h @@ -10,6 +10,8 @@ class CScriptNode : public CSceneNode { CScriptObject *mpInstance; + class CScriptExtra *mpExtra; + CModel *mpActiveModel; CTexture *mpBillboard; CToken mModelToken; @@ -33,6 +35,7 @@ public: void RayAABoxIntersectTest(CRayCollisionTester &Tester); SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo); bool IsVisible() const; + CColor TintColor(const SViewInfo &ViewInfo) const; CColor WireframeColor() const; CScriptObject* Object(); diff --git a/Scene/ENodeType.h b/Scene/ENodeType.h index 6a2677f7..c808cba0 100644 --- a/Scene/ENodeType.h +++ b/Scene/ENodeType.h @@ -8,6 +8,7 @@ enum ENodeType eStaticNode, eCollisionNode, eScriptNode, + eScriptExtraNode, eLightNode }; diff --git a/Scene/script/CPointOfInterestExtra.cpp b/Scene/script/CPointOfInterestExtra.cpp new file mode 100644 index 00000000..54b45914 --- /dev/null +++ b/Scene/script/CPointOfInterestExtra.cpp @@ -0,0 +1,66 @@ +#include "CPointOfInterestExtra.h" + +const CColor CPointOfInterestExtra::skRegularColor((u32) 0xFF7000FF); +const CColor CPointOfInterestExtra::skImportantColor((u32) 0xFF0000FF); + +CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent) + : CScriptExtra(pInstance, pScene, pParent) + , mpScanProperty(nullptr) + , mpScanData(nullptr) +{ + // Fetch scan data property + CPropertyStruct *pBaseProp = pInstance->Properties(); + + switch (mGame) + { + case ePrimeDemo: + case ePrime: + mpScanProperty = (CFileProperty*) pBaseProp->PropertyByIDString("0x04:0x00"); + break; + + case eEchoesDemo: + case eEchoes: + case eCorruptionProto: + case eCorruption: + mpScanProperty = (CFileProperty*) pBaseProp->PropertyByIDString("0xBDBEC295:0xB94E9BE7"); + break; + + default: + mpScanProperty = nullptr; + break; + } + + if (mpScanProperty) + { + if (mpScanProperty->Type() == eFileProperty) + PropertyModified(mpScanProperty); + else + mpScanProperty = nullptr; + } +} + +void CPointOfInterestExtra::PropertyModified(CPropertyBase* pProperty) +{ + if (mpScanProperty == pProperty) + { + mpScanData = (CScan*) mpScanProperty->Get(); + + if (mpScanData && mpScanData->Type() == eScan) + mScanToken = CToken(mpScanData); + + else + { + mpScanData = nullptr; + mScanToken.Unlock(); + } + } +} + +void CPointOfInterestExtra::ModifyTintColor(CColor& Color) +{ + if (mpScanData) + { + if (mpScanData->IsImportant()) Color *= skImportantColor; + else Color *= skRegularColor; + } +} diff --git a/Scene/script/CPointOfInterestExtra.h b/Scene/script/CPointOfInterestExtra.h new file mode 100644 index 00000000..d519a70e --- /dev/null +++ b/Scene/script/CPointOfInterestExtra.h @@ -0,0 +1,24 @@ +#ifndef CPOINTOFINTERESTEXTRA_H +#define CPOINTOFINTERESTEXTRA_H + +#include "CScriptExtra.h" +#include +#include + +class CPointOfInterestExtra : public CScriptExtra +{ + // Tint POI billboard orange/red depending on scan importance + CFileProperty *mpScanProperty; + CScan *mpScanData; + CToken mScanToken; + +public: + explicit CPointOfInterestExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent = 0); + void PropertyModified(CPropertyBase* pProperty); + void ModifyTintColor(CColor& Color); + + static const CColor skRegularColor; + static const CColor skImportantColor; +}; + +#endif // CPOINTOFINTERESTEXTRA_H diff --git a/Scene/script/CScriptExtra.cpp b/Scene/script/CScriptExtra.cpp new file mode 100644 index 00000000..bba781da --- /dev/null +++ b/Scene/script/CScriptExtra.cpp @@ -0,0 +1,39 @@ +#include "CScriptExtra.h" + +#include "CWaypointExtra.h" +#include "CSpacePirateExtra.h" +#include "CPointOfInterestExtra.h" + +CScriptExtra* CScriptExtra::CreateExtra(CScriptNode *pNode) +{ + CScriptExtra *pExtra = nullptr; + CScriptObject *pObj = pNode->Object(); + + if (pObj) + { + switch (pObj->ObjectTypeID()) + { + case 0x02: // Waypoint (MP1) + case 0x0D: // CameraWaypoint (MP1) + case 0x2C: // SpiderBallWaypoint (MP1) + case 0x32: // DebugCameraWaypoint(MP1) + case 0x41495750: // "AIWP" AIWaypoint (MP2/MP3/DKCR) + case 0x42414C57: // "BALW" SpiderBallWaypoint (MP2/MP3) + case 0x43414D57: // "CAMW" CameraWaypoint (MP2) + case 0x57415950: // "WAYP" Waypoint (MP2/MP3/DKCR) + pExtra = new CWaypointExtra(pObj, pNode->Scene(), pNode); + break; + + case 0x24: // SpacePirate (MP1) + pExtra = new CSpacePirateExtra(pObj, pNode->Scene(), pNode); + break; + + case 0x42: // PointOfInterest (MP1) + case 0x504F494E: // "POIN" PointOfInterest (MP2/MP3) + pExtra = new CPointOfInterestExtra(pObj, pNode->Scene(), pNode); + break; + } + } + + return pExtra; +} diff --git a/Scene/script/CScriptExtra.h b/Scene/script/CScriptExtra.h new file mode 100644 index 00000000..b4469bc8 --- /dev/null +++ b/Scene/script/CScriptExtra.h @@ -0,0 +1,53 @@ +#ifndef CSCRIPTEXTRA_H +#define CSCRIPTEXTRA_H + +#include "../CSceneNode.h" +#include "../CScriptNode.h" + +/* 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, + * and reimplement whatever functions are needed to create the desired behavior. Note + * that in addition to the functions here you can also reimplement IRenderable functions + * (to render additional geometry) and CSceneNode functions (primarily for raycast + * intersections). + */ + +class CScriptExtra : public CSceneNode +{ +protected: + CScriptObject *mpInstance; + EGame mGame; + +public: + explicit CScriptExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent = 0) + : CSceneNode(pScene, pParent), + mpInstance(pInstance), + mGame(pInstance->Template()->Game()) + { + } + + virtual ~CScriptExtra() {} + + // Default implementations for CSceneNode + virtual ENodeType NodeType() { return eScriptExtraNode; } + virtual SRayIntersection RayNodeIntersectTest(const CRay& /*Ray*/, u32 /*AssetID*/, const SViewInfo& /*ViewInfo*/) + { + SRayIntersection out; + out.Hit = false; + return out; + } + + // Virtual CScriptExtra functions + virtual void InstanceTransformed() {} + virtual void PropertyModified(CPropertyBase* /*pProperty*/) {} + virtual void LinksModified() {} + virtual bool ShouldDrawNormalAssets() { return true; } + virtual bool ShouldDrawVolume() { return true; } + virtual CColor TevColor() { return CColor::skWhite; } + virtual void ModifyTintColor(CColor& /*Color*/) {} + + // Create Script Extra + static CScriptExtra* CreateExtra(CScriptNode *pNode); +}; + +#endif // CSCRIPTEXTRA_H diff --git a/Scene/script/CSpacePirateExtra.cpp b/Scene/script/CSpacePirateExtra.cpp new file mode 100644 index 00000000..dd776ee4 --- /dev/null +++ b/Scene/script/CSpacePirateExtra.cpp @@ -0,0 +1,49 @@ +#include "CSpacePirateExtra.h" + +CSpacePirateExtra::CSpacePirateExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent) + : CScriptExtra(pInstance, pScene ,pParent) + , mpPowerVuln(nullptr) + , mpWaveVuln(nullptr) + , mpIceVuln(nullptr) + , mpPlasmaVuln(nullptr) +{ + CPropertyStruct *pBaseStruct = pInstance->Properties(); + CPropertyStruct *pVulns = (CPropertyStruct*) pBaseStruct->PropertyByIDString("0x04:0x10"); + + if (pVulns && pVulns->Type() == eStructProperty) + { + mpPowerVuln = (CLongProperty*) pVulns->PropertyByID(0x0); + if (mpPowerVuln && mpPowerVuln->Type() != eLongProperty && mpPowerVuln->Type() != eEnumProperty) + mpPowerVuln = nullptr; + + mpWaveVuln = (CLongProperty*) pVulns->PropertyByID(0x2); + if (mpWaveVuln && mpWaveVuln->Type() != eLongProperty && mpWaveVuln->Type() != eEnumProperty) + mpWaveVuln = nullptr; + + mpIceVuln = (CLongProperty*) pVulns->PropertyByID(0x1); + if (mpIceVuln && mpIceVuln->Type() != eLongProperty && mpIceVuln->Type() != eEnumProperty) + mpIceVuln = nullptr; + + mpPlasmaVuln = (CLongProperty*) pVulns->PropertyByID(0x3); + if (mpPlasmaVuln && mpPlasmaVuln->Type() != eLongProperty && mpPlasmaVuln->Type() != eEnumProperty) + mpPlasmaVuln = nullptr; + } +} + +CColor CSpacePirateExtra::TevColor() +{ + // Priority: Plasma -> Ice -> Power -> Wave + if (mpPlasmaVuln && mpPlasmaVuln->Get() == 1) + return CColor::skRed; + + if (mpIceVuln && mpIceVuln->Get() == 1) + return CColor::skWhite; + + if (mpPowerVuln && mpPowerVuln->Get() == 1) + return CColor::skYellow; + + if (mpWaveVuln && mpWaveVuln->Get() == 1) + return CColor::skPurple; + + return CColor::skWhite; +} diff --git a/Scene/script/CSpacePirateExtra.h b/Scene/script/CSpacePirateExtra.h new file mode 100644 index 00000000..6c11090f --- /dev/null +++ b/Scene/script/CSpacePirateExtra.h @@ -0,0 +1,20 @@ +#ifndef CSPACEPIRATEEXTRA_H +#define CSPACEPIRATEEXTRA_H + +#include "CScriptExtra.h" +#include + +class CSpacePirateExtra : public CScriptExtra +{ + // Render beam troopers with the correct color + CLongProperty *mpPowerVuln; + CLongProperty *mpWaveVuln; + CLongProperty *mpIceVuln; + CLongProperty *mpPlasmaVuln; + +public: + explicit CSpacePirateExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent = 0); + CColor TevColor(); +}; + +#endif // CSPACEPIRATEEXTRA_H diff --git a/Scene/script/CWaypointExtra.cpp b/Scene/script/CWaypointExtra.cpp new file mode 100644 index 00000000..c8a9f967 --- /dev/null +++ b/Scene/script/CWaypointExtra.cpp @@ -0,0 +1,106 @@ +#include "CWaypointExtra.h" +#include +#include +#include + +CWaypointExtra::CWaypointExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent) + : CScriptExtra(pInstance, pScene, pParent) + , mColor(CColor::skBlack) + , mLinksBuilt(false) +{ + // Fetch color from parent node's model + CScriptNode *pScript = static_cast(pParent); + CModel *pModel = pScript->ActiveModel(); + + if ((pModel->GetMatSetCount() > 0) && (pModel->GetMatCount() > 0)) + { + CMaterial *pMat = pModel->GetMaterialByIndex(0, 0); + mColor = pMat->Konst(0); + mColor.a = 0; + } +} + +void CWaypointExtra::BuildLinks() +{ + mLinks.clear(); + + for (u32 iLink = 0; iLink < mpInstance->NumOutLinks(); iLink++) + { + const SLink& rkLink = mpInstance->OutLink(iLink); + + if (IsPathLink(rkLink)) + { + CScriptNode *pNode = mpScene->ScriptNodeByID(rkLink.ObjectID); + + SWaypointLink Link; + Link.pWaypoint = pNode; + Link.LineAABB.ExpandBounds(AbsolutePosition()); + Link.LineAABB.ExpandBounds(pNode->AbsolutePosition()); + mLinks.push_back(Link); + } + } + + mLinksBuilt = true; +} + +bool CWaypointExtra::IsPathLink(const SLink& rkLink) +{ + bool Valid = false; + + if (rkLink.State < 0xFF) + { + if (rkLink.State == 0x1 && rkLink.Message == 0x8) Valid = true; // Arrived / Next (MP1) + } + + else + { + CFourCC State(rkLink.State); + CFourCC Message(rkLink.Message); + if (State == "ARRV" && Message == "NEXT") Valid = true; // Arrived / Next (MP2) + if (State == "NEXT" && Message == "ATCH") Valid = true; // Next / Attach (MP3/DKCR) + } + + if (Valid) + { + CScriptNode *pNode = mpScene->ScriptNodeByID(rkLink.ObjectID); + + if (pNode) + return pNode->Object()->ObjectTypeID() == mpInstance->ObjectTypeID(); + } + + return false; +} + +void CWaypointExtra::LinksModified() +{ + BuildLinks(); +} + +void CWaypointExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) +{ + // This call is necessary because if we try to build links in the constructor, it'll + // fail because we haven't finished loading the scene yet. + if (!mLinksBuilt) BuildLinks(); + + if (!ViewInfo.GameMode && mpParent->IsVisible() && !mpParent->IsSelected()) + { + for (u32 iLink = 0; iLink < mLinks.size(); iLink++) + { + CScriptNode *pNode = mLinks[iLink].pWaypoint; + + if (pNode->IsVisible() && !pNode->IsSelected() && ViewInfo.ViewFrustum.BoxInFrustum(mLinks[iLink].LineAABB)) + pRenderer->AddOpaqueMesh(this, iLink, mLinks[iLink].LineAABB, eDrawAsset); + } + } +} + +void CWaypointExtra::DrawAsset(ERenderOptions /*Options*/, u32 AssetID, const SViewInfo& /*ViewInfo*/) +{ + glBlendFunc(GL_ONE, GL_ZERO); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_TRUE); + + CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity; + CGraphics::UpdateMVPBlock(); + CDrawUtil::DrawLine(mpParent->AABox().Center(), mLinks[AssetID].pWaypoint->AABox().Center(), mColor); +} diff --git a/Scene/script/CWaypointExtra.h b/Scene/script/CWaypointExtra.h new file mode 100644 index 00000000..be11a1d0 --- /dev/null +++ b/Scene/script/CWaypointExtra.h @@ -0,0 +1,30 @@ +#ifndef CWAYPOINTEXTRA_H +#define CWAYPOINTEXTRA_H + +#include "CScriptExtra.h" +#include + +class CWaypointExtra : public CScriptExtra +{ + // Draw waypoint paths formed by script connections + CColor mColor; + bool mLinksBuilt; + + struct SWaypointLink + { + CScriptNode *pWaypoint; + CAABox LineAABB; + }; + std::vector mLinks; + +public: + explicit CWaypointExtra(CScriptObject *pInstance, CSceneManager *pScene, CSceneNode *pParent = 0); + void BuildLinks(); + bool IsPathLink(const SLink& rkLink); + + void LinksModified(); + void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); + void DrawAsset(ERenderOptions Options, u32 AssetID, const SViewInfo& ViewInfo); +}; + +#endif // CWAYPOINTEXTRA_H