mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-18 01:15:26 +00:00
Initial commit of current work on Prime World Editor
This commit is contained in:
12
Scene/CBoundingBoxNode.cpp
Normal file
12
Scene/CBoundingBoxNode.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "CBoundingBoxNode.h"
|
||||
|
||||
CBoundingBoxNode::CBoundingBoxNode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CBoundingBoxNode::~CBoundingBoxNode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
16
Scene/CBoundingBoxNode.h
Normal file
16
Scene/CBoundingBoxNode.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef CBOUNDINGBOXNODE_H
|
||||
#define CBOUNDINGBOXNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
|
||||
class CBoundingBoxNode
|
||||
{
|
||||
CColor mColor;
|
||||
|
||||
public:
|
||||
CBoundingBoxNode();
|
||||
~CBoundingBoxNode();
|
||||
|
||||
};
|
||||
|
||||
#endif // CBOUNDINGBOXNODE_H
|
||||
58
Scene/CCollisionNode.cpp
Normal file
58
Scene/CCollisionNode.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "CCollisionNode.h"
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CRenderer.h>
|
||||
|
||||
CCollisionNode::CCollisionNode(CSceneManager *pScene, CSceneNode *pParent, CCollisionMesh *pMesh)
|
||||
: CSceneNode(pScene, pParent)
|
||||
{
|
||||
mpMesh = pMesh;
|
||||
mMeshToken = CToken(pMesh);
|
||||
SetName("Collision");
|
||||
}
|
||||
|
||||
ENodeType CCollisionNode::NodeType()
|
||||
{
|
||||
return eCollisionNode;
|
||||
}
|
||||
|
||||
void CCollisionNode::AddToRenderer(CRenderer *pRenderer)
|
||||
{
|
||||
if (!mpMesh) return;
|
||||
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
if (mSelected)
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
}
|
||||
|
||||
void CCollisionNode::Draw(ERenderOptions)
|
||||
{
|
||||
// Not using parameter 1 (ERenderOptions - Options)
|
||||
if (!mpMesh) return;
|
||||
|
||||
LoadModelMatrix();
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
CDrawUtil::UseCollisionShader();
|
||||
mpMesh->Draw();
|
||||
CDrawUtil::UseColorShader(CColor::skTransparentBlack);
|
||||
mpMesh->DrawLines();
|
||||
}
|
||||
|
||||
void CCollisionNode::DrawAsset(ERenderOptions, u32)
|
||||
{
|
||||
// Not using parameter 1 (ERenderOptions - Options)
|
||||
// Not using parameter 2 (u32 - asset)
|
||||
}
|
||||
|
||||
SRayIntersection CCollisionNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
||||
{
|
||||
// todo
|
||||
SRayIntersection Result;
|
||||
Result.Hit = false;
|
||||
return Result;
|
||||
}
|
||||
21
Scene/CCollisionNode.h
Normal file
21
Scene/CCollisionNode.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CCOLLISIONNODE_H
|
||||
#define CCOLLISIONNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include <Resource/CCollisionMesh.h>
|
||||
|
||||
class CCollisionNode : public CSceneNode
|
||||
{
|
||||
CCollisionMesh *mpMesh;
|
||||
CToken mMeshToken;
|
||||
|
||||
public:
|
||||
CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMesh *pMesh = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID);
|
||||
};
|
||||
|
||||
#endif // CCOLLISIONNODE_H
|
||||
78
Scene/CLightNode.cpp
Normal file
78
Scene/CLightNode.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "CLightNode.h"
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CRenderer.h>
|
||||
|
||||
CLightNode::CLightNode(CSceneManager *pScene, CSceneNode *pParent, CLight *Light)
|
||||
: CSceneNode(pScene, pParent)
|
||||
{
|
||||
mpLight = Light;
|
||||
mLocalAABox = CAABox::skOne;
|
||||
mPosition = Light->GetPosition();
|
||||
|
||||
switch (Light->GetType())
|
||||
{
|
||||
case eLocalAmbient: SetName("Ambient Light"); break;
|
||||
case eDirectional: SetName("Directional Light"); break;
|
||||
case eSpot: SetName("Spot Light"); break;
|
||||
case eCustom: SetName("Custom Light"); break;
|
||||
}
|
||||
}
|
||||
|
||||
ENodeType CLightNode::NodeType()
|
||||
{
|
||||
return eLightNode;
|
||||
}
|
||||
|
||||
void CLightNode::AddToRenderer(CRenderer *pRenderer)
|
||||
{
|
||||
pRenderer->AddOpaqueMesh(this, 0, CAABox(mPosition + 0.5f, mPosition - 0.5f), eDrawMesh);
|
||||
|
||||
if (IsSelected())
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
}
|
||||
|
||||
void CLightNode::Draw(ERenderOptions)
|
||||
{
|
||||
// Not using parameter 1 (ERenderOptions - Options)
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glDepthMask(GL_TRUE);
|
||||
LoadModelMatrix();
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(1.f);
|
||||
CGraphics::sVertexBlock.COLOR0_Mat = CVector4f(1.f);
|
||||
CGraphics::UpdateVertexBlock();
|
||||
CDrawUtil::DrawShadedCube(mpLight->GetColor());
|
||||
|
||||
// Below commented-out code is for light radius visualization as a bounding box
|
||||
/*float r = mLight->GetRadius();
|
||||
CAABox AABB(Position + r, Position - r);
|
||||
pRenderer->DrawBoundingBox(mLight->GetColor(), AABB);*/
|
||||
}
|
||||
|
||||
void CLightNode::DrawAsset(ERenderOptions, u32)
|
||||
{
|
||||
// Not using parameter 1 (ERenderOptions - Options)
|
||||
// Not using parameter 2 (u32 - asset)
|
||||
}
|
||||
|
||||
SRayIntersection CLightNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
||||
{
|
||||
// Needs redo if I ever make these look like something other than boxes
|
||||
if (AABox().IsPointInBox(Ray.Origin()))
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (BoxResult.first)
|
||||
return SRayIntersection(true, BoxResult.second, this, 0);
|
||||
|
||||
else
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
}
|
||||
|
||||
CLight* CLightNode::Light()
|
||||
{
|
||||
return mpLight;
|
||||
}
|
||||
20
Scene/CLightNode.h
Normal file
20
Scene/CLightNode.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef CLIGHTNODE_H
|
||||
#define CLIGHTNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include <Resource/CLight.h>
|
||||
|
||||
class CLightNode : public CSceneNode
|
||||
{
|
||||
CLight *mpLight;
|
||||
public:
|
||||
CLightNode(CSceneManager *pScene, CSceneNode *pParent = 0, CLight *Light = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID);
|
||||
CLight* Light();
|
||||
};
|
||||
|
||||
#endif // CLIGHTNODE_H
|
||||
148
Scene/CModelNode.cpp
Normal file
148
Scene/CModelNode.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "CModelNode.h"
|
||||
#include <Common/Math.h>
|
||||
#include <Core/CRenderer.h>
|
||||
#include <Core/CGraphics.h>
|
||||
|
||||
CModelNode::CModelNode(CSceneManager *pScene, CSceneNode *pParent, CModel *pModel) : CSceneNode(pScene, pParent)
|
||||
{
|
||||
SetModel(pModel);
|
||||
mScale = CVector3f(1.f);
|
||||
mLightingEnabled = true;
|
||||
mForceAlphaOn = false;
|
||||
}
|
||||
|
||||
ENodeType CModelNode::NodeType()
|
||||
{
|
||||
return eModelNode;
|
||||
}
|
||||
|
||||
void CModelNode::AddToRenderer(CRenderer *pRenderer)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
|
||||
if (!mpModel->HasTransparency(mActiveMatSet))
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
else
|
||||
{
|
||||
u32 SurfaceCount = mpModel->GetSurfaceCount();
|
||||
|
||||
for (u32 iSurf = 0; iSurf < SurfaceCount; iSurf++)
|
||||
{
|
||||
if (!mpModel->IsSurfaceTransparent(iSurf, mActiveMatSet))
|
||||
pRenderer->AddOpaqueMesh(this, iSurf, mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()), eDrawAsset);
|
||||
else
|
||||
pRenderer->AddTransparentMesh(this, iSurf, mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()), eDrawAsset);
|
||||
}
|
||||
}
|
||||
|
||||
if (mSelected)
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
}
|
||||
|
||||
void CModelNode::Draw(ERenderOptions Options)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
if (mForceAlphaOn) Options = (ERenderOptions) (Options & ~eNoAlpha);
|
||||
|
||||
if (mLightingEnabled)
|
||||
{
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
}
|
||||
else
|
||||
{
|
||||
CGraphics::sNumLights = 0;
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skBlack.ToVector4f();
|
||||
}
|
||||
|
||||
CGraphics::sPixelBlock.TevColor = CVector4f(1,1,1,1);
|
||||
LoadModelMatrix();
|
||||
|
||||
mpModel->Draw(Options, mActiveMatSet);
|
||||
}
|
||||
|
||||
void CModelNode::DrawAsset(ERenderOptions Options, u32 Asset)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
if (mForceAlphaOn) Options = (ERenderOptions) (Options & ~eNoAlpha);
|
||||
|
||||
if (mLightingEnabled)
|
||||
{
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
}
|
||||
else
|
||||
{
|
||||
CGraphics::sNumLights = 0;
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skBlack.ToVector4f();
|
||||
}
|
||||
|
||||
CGraphics::sPixelBlock.TevColor = CVector4f(1,1,1,1);
|
||||
LoadModelMatrix();
|
||||
|
||||
mpModel->DrawSurface(Options, Asset, mActiveMatSet);
|
||||
}
|
||||
|
||||
void CModelNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
|
||||
const CRay& Ray = Tester.Ray();
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (BoxResult.first)
|
||||
{
|
||||
for (u32 iSurf = 0; iSurf < mpModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
std::pair<bool,float> SurfResult = mpModel->GetSurfaceAABox(iSurf).IntersectsRay(Ray);
|
||||
|
||||
if (SurfResult.first)
|
||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
||||
{
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
out.Hit = true;
|
||||
|
||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void CModelNode::SetModel(CModel *pModel)
|
||||
{
|
||||
mpModel = pModel;
|
||||
mModelToken = CToken(pModel);
|
||||
mActiveMatSet = 0;
|
||||
|
||||
if (pModel)
|
||||
{
|
||||
SetName(pModel->Source());
|
||||
mLocalAABox = mpModel->AABox();
|
||||
}
|
||||
}
|
||||
|
||||
void CModelNode::ForceAlphaEnabled(bool Enable)
|
||||
{
|
||||
mForceAlphaOn = Enable;
|
||||
}
|
||||
61
Scene/CModelNode.h
Normal file
61
Scene/CModelNode.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef CMODELNODE_H
|
||||
#define CMODELNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include <Resource/model/CModel.h>
|
||||
|
||||
class CModelNode : public CSceneNode
|
||||
{
|
||||
CModel *mpModel;
|
||||
CToken mModelToken;
|
||||
u32 mActiveMatSet;
|
||||
bool mLightingEnabled;
|
||||
bool mForceAlphaOn;
|
||||
|
||||
public:
|
||||
explicit CModelNode(CSceneManager *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
|
||||
|
||||
virtual ENodeType NodeType();
|
||||
virtual void AddToRenderer(CRenderer *pRenderer);
|
||||
virtual void Draw(ERenderOptions Options);
|
||||
virtual void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
virtual void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID);
|
||||
|
||||
void SetModel(CModel *pModel);
|
||||
void SetMatSet(u32 MatSet);
|
||||
void SetDynamicLighting(bool Enable);
|
||||
void ForceAlphaEnabled(bool Enable);
|
||||
CModel* Model();
|
||||
u32 MatSet();
|
||||
bool IsDynamicLightingEnabled();
|
||||
};
|
||||
|
||||
|
||||
// ************ INLINE FUNCTIONS ************
|
||||
inline void CModelNode::SetMatSet(u32 MatSet)
|
||||
{
|
||||
mActiveMatSet = MatSet;
|
||||
}
|
||||
|
||||
inline void CModelNode::SetDynamicLighting(bool Enable)
|
||||
{
|
||||
mLightingEnabled = Enable;
|
||||
}
|
||||
|
||||
inline CModel* CModelNode::Model()
|
||||
{
|
||||
return mpModel;
|
||||
}
|
||||
|
||||
inline u32 CModelNode::MatSet()
|
||||
{
|
||||
return mActiveMatSet;
|
||||
}
|
||||
|
||||
inline bool CModelNode::IsDynamicLightingEnabled()
|
||||
{
|
||||
return mLightingEnabled;
|
||||
}
|
||||
|
||||
#endif // CMODELNODE_H
|
||||
30
Scene/CRootNode.h
Normal file
30
Scene/CRootNode.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef CROOTNODE_H
|
||||
#define CROOTNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include <iostream>
|
||||
|
||||
// CRootNode's main purpose is to manage groups of other nodes as its children.
|
||||
class CRootNode : public CSceneNode
|
||||
{
|
||||
public:
|
||||
explicit CRootNode(CSceneManager *pScene, CSceneNode *pParent = 0) : CSceneNode(pScene, pParent) {}
|
||||
~CRootNode() {}
|
||||
|
||||
inline ENodeType NodeType() {
|
||||
return eRootNode;
|
||||
}
|
||||
|
||||
inline void AddToRenderer(CRenderer *) {}
|
||||
inline void Draw(ERenderOptions) {}
|
||||
inline void DrawAsset(ERenderOptions, u32) {}
|
||||
inline void RayAABoxIntersectTest(CRayCollisionTester &) {}
|
||||
|
||||
inline SRayIntersection RayNodeIntersectTest(const CRay &, u32) {
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
}
|
||||
|
||||
inline void DrawSelection() {}
|
||||
};
|
||||
|
||||
#endif // CROOTNODE_H
|
||||
372
Scene/CSceneNode.cpp
Normal file
372
Scene/CSceneNode.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
#include "CSceneNode.h"
|
||||
#include <Core/CRenderer.h>
|
||||
#include <gtc/quaternion.hpp>
|
||||
#include <gtx/transform.hpp>
|
||||
#include <Common/AnimUtil.h>
|
||||
#include <Common/CTransform4f.h>
|
||||
#include <Resource/CGameArea.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <algorithm>
|
||||
|
||||
u32 CSceneNode::smNumNodes = 0;
|
||||
|
||||
CSceneNode::CSceneNode(CSceneManager *pScene, CSceneNode *pParent)
|
||||
{
|
||||
smNumNodes++;
|
||||
mpScene = pScene;
|
||||
mpParent = pParent;
|
||||
|
||||
mPosition = CVector3f::skZero;
|
||||
mRotation = CQuaternion::skIdentity;
|
||||
mScale = CVector3f::skOne;
|
||||
_mTransformOutdated = true;
|
||||
|
||||
_mInheritsPosition = true;
|
||||
_mInheritsRotation = true;
|
||||
_mInheritsScale = true;
|
||||
|
||||
mMouseHovering = false;
|
||||
mSelected = false;
|
||||
mVisible = true;
|
||||
|
||||
if (mpParent)
|
||||
mpParent->mChildren.push_back(this);
|
||||
}
|
||||
|
||||
CSceneNode::~CSceneNode()
|
||||
{
|
||||
smNumNodes--;
|
||||
for (auto it = mChildren.begin(); it != mChildren.end(); it++)
|
||||
delete (*it);
|
||||
}
|
||||
|
||||
// ************ VIRTUAL ************
|
||||
std::string CSceneNode::PrefixedName() const
|
||||
{
|
||||
return Name();
|
||||
}
|
||||
|
||||
void CSceneNode::DrawSelection()
|
||||
{
|
||||
// Default implementation for virtual function
|
||||
CDrawUtil::DrawWireCube(AABox(), CColor::skWhite);
|
||||
}
|
||||
|
||||
void CSceneNode::RayAABoxIntersectTest(CRayCollisionTester& Tester)
|
||||
{
|
||||
// Default implementation for virtual function
|
||||
std::pair<bool,float> result = AABox().IntersectsRay(Tester.Ray());
|
||||
|
||||
if (result.first)
|
||||
Tester.AddNode(this, -1, result.second);
|
||||
}
|
||||
|
||||
bool CSceneNode::IsVisible() const
|
||||
{
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
// ************ MAIN FUNCTIONALITY ************
|
||||
void CSceneNode::Unparent()
|
||||
{
|
||||
// May eventually want to reset XForm so global position = local position
|
||||
// Seems like a waste performance wise for the time being though
|
||||
if (mpParent)
|
||||
mpParent->RemoveChild(this);
|
||||
|
||||
mpParent = nullptr;
|
||||
}
|
||||
|
||||
void CSceneNode::RemoveChild(CSceneNode *pChild)
|
||||
{
|
||||
for (auto it = mChildren.begin(); it != mChildren.end(); it++)
|
||||
{
|
||||
if (*it == pChild)
|
||||
{
|
||||
mChildren.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSceneNode::DeleteChildren()
|
||||
{
|
||||
for (auto it = mChildren.begin(); it != mChildren.end(); it++)
|
||||
delete *it;
|
||||
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
void CSceneNode::SetInheritance(bool InheritPos, bool InheritRot, bool InheritScale)
|
||||
{
|
||||
_mInheritsPosition = InheritPos;
|
||||
_mInheritsRotation = InheritRot;
|
||||
_mInheritsScale = InheritScale;
|
||||
MarkTransformChanged();
|
||||
}
|
||||
|
||||
void CSceneNode::LoadModelMatrix()
|
||||
{
|
||||
CGraphics::sMVPBlock.ModelMatrix = Transform().ToMatrix4f();
|
||||
CGraphics::UpdateMVPBlock();
|
||||
}
|
||||
|
||||
void CSceneNode::BuildLightList(CGameArea *pArea)
|
||||
{
|
||||
mLightCount = 0;
|
||||
|
||||
u32 LayerCount = pArea->GetLightLayerCount();
|
||||
|
||||
struct SLightEntry {
|
||||
CLight *pLight;
|
||||
float Distance;
|
||||
|
||||
SLightEntry(CLight *_pLight, float _Distance)
|
||||
: pLight(_pLight), Distance(_Distance) {}
|
||||
|
||||
bool operator<(const SLightEntry& other) {
|
||||
return (Distance < other.Distance);
|
||||
}
|
||||
};
|
||||
std::vector<SLightEntry> LightEntries;
|
||||
|
||||
for (u32 iLayer = 0; iLayer < LayerCount; iLayer++)
|
||||
{
|
||||
u32 LightCount = pArea->GetLightCount(iLayer);
|
||||
|
||||
for (u32 iLight = 0; iLight < LightCount; iLight++)
|
||||
{
|
||||
CLight* pLight = pArea->GetLight(iLayer, iLight);
|
||||
|
||||
// Directional/Spot lights take priority over custom lights.
|
||||
if ((pLight->GetType() == eDirectional) || (pLight->GetType() == eSpot))
|
||||
LightEntries.push_back(SLightEntry(pLight, 0));
|
||||
|
||||
// Custom lights will be used depending which are closest to the node
|
||||
else if (pLight->GetType() == eCustom)
|
||||
{
|
||||
bool IsInRange = AABox().IntersectsSphere(pLight->GetPosition(), pLight->GetRadius());
|
||||
|
||||
if (IsInRange)
|
||||
{
|
||||
float Dist = mPosition.Distance(pLight->GetPosition());
|
||||
LightEntries.push_back(SLightEntry(pLight, Dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which lights are closest
|
||||
std::sort(LightEntries.begin(), LightEntries.end());
|
||||
mLightCount = (LightEntries.size() > 8) ? 8 : LightEntries.size();
|
||||
|
||||
for (u32 i = 0; i < mLightCount; i++)
|
||||
mLights[i] = LightEntries[i].pLight;
|
||||
}
|
||||
|
||||
void CSceneNode::LoadLights()
|
||||
{
|
||||
CGraphics::sNumLights = 0;
|
||||
|
||||
if (CGraphics::sLightMode == CGraphics::BasicLighting)
|
||||
CGraphics::SetDefaultLighting();
|
||||
|
||||
else if (CGraphics::sLightMode == CGraphics::WorldLighting)
|
||||
for (u32 iLight = 0; iLight < mLightCount; iLight++)
|
||||
mLights[iLight]->Load();
|
||||
|
||||
CGraphics::UpdateLightBlock();
|
||||
}
|
||||
|
||||
void CSceneNode::DrawBoundingBox()
|
||||
{
|
||||
CDrawUtil::DrawWireCube(AABox(), CColor::skWhite);
|
||||
}
|
||||
|
||||
// ************ TRANSFORM ************
|
||||
void CSceneNode::Translate(const CVector3f& Translation)
|
||||
{
|
||||
mPosition += Translation;
|
||||
MarkTransformChanged();
|
||||
}
|
||||
|
||||
void CSceneNode::Scale(const CVector3f& Scale)
|
||||
{
|
||||
mScale *= Scale;
|
||||
MarkTransformChanged();
|
||||
}
|
||||
|
||||
void CSceneNode::UpdateTransform()
|
||||
{
|
||||
if (_mTransformOutdated)
|
||||
{
|
||||
ForceRecalculateTransform();
|
||||
_mTransformOutdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CSceneNode::ForceRecalculateTransform()
|
||||
{
|
||||
_mCachedTransform = CTransform4f::skIdentity;
|
||||
_mCachedTransform.Scale(GetAbsoluteScale());
|
||||
_mCachedTransform.Rotate(GetAbsoluteRotation());
|
||||
_mCachedTransform.Translate(GetAbsolutePosition());
|
||||
_mCachedAABox = mLocalAABox.Transformed(_mCachedTransform);
|
||||
|
||||
// Sync with children - only needed if caller hasn't marked transform changed already
|
||||
// If so, the children will already be marked
|
||||
if (!_mTransformOutdated)
|
||||
{
|
||||
for (auto it = mChildren.begin(); it != mChildren.end(); it++)
|
||||
(*it)->MarkTransformChanged();
|
||||
}
|
||||
_mTransformOutdated = false;
|
||||
}
|
||||
|
||||
void CSceneNode::MarkTransformChanged()
|
||||
{
|
||||
if (!_mTransformOutdated)
|
||||
{
|
||||
for (auto it = mChildren.begin(); it != mChildren.end(); it++)
|
||||
(*it)->MarkTransformChanged();
|
||||
}
|
||||
|
||||
_mTransformOutdated = true;
|
||||
}
|
||||
|
||||
const CTransform4f& CSceneNode::Transform()
|
||||
{
|
||||
if (_mTransformOutdated)
|
||||
ForceRecalculateTransform();
|
||||
|
||||
return _mCachedTransform;
|
||||
}
|
||||
|
||||
// ************ GETTERS ************
|
||||
std::string CSceneNode::Name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
CSceneNode* CSceneNode::Parent() const
|
||||
{
|
||||
return mpParent;
|
||||
}
|
||||
|
||||
CSceneManager* CSceneNode::Scene()
|
||||
{
|
||||
return mpScene;
|
||||
}
|
||||
|
||||
CVector3f CSceneNode::GetPosition() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
CVector3f CSceneNode::GetAbsolutePosition() const
|
||||
{
|
||||
CVector3f ret = mPosition;
|
||||
|
||||
if ((mpParent) && (InheritsPosition()))
|
||||
ret += mpParent->GetAbsolutePosition();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CQuaternion CSceneNode::GetRotation() const
|
||||
{
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
CQuaternion CSceneNode::GetAbsoluteRotation() const
|
||||
{
|
||||
CQuaternion ret = mRotation;
|
||||
|
||||
if ((mpParent) && (InheritsRotation()))
|
||||
ret *= mpParent->GetAbsoluteRotation();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CVector3f CSceneNode::GetScale() const
|
||||
{
|
||||
return mScale;
|
||||
}
|
||||
|
||||
CVector3f CSceneNode::GetAbsoluteScale() const
|
||||
{
|
||||
CVector3f ret = mScale;
|
||||
|
||||
if ((mpParent) && (InheritsScale()))
|
||||
ret *= mpParent->GetAbsoluteScale();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CAABox CSceneNode::AABox()
|
||||
{
|
||||
if (_mTransformOutdated)
|
||||
ForceRecalculateTransform();
|
||||
|
||||
return _mCachedAABox;
|
||||
}
|
||||
|
||||
CVector3f CSceneNode::CenterPoint()
|
||||
{
|
||||
return AABox().Center();
|
||||
}
|
||||
|
||||
bool CSceneNode::MarkedVisible() const
|
||||
{
|
||||
// The reason I have this function is because the instance view needs to know whether a node is marked
|
||||
// visible independently from other factors that may affect node visibility (as returned by IsVisible()).
|
||||
// It's a little confusing, so maybe there's a better way to set this up.
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
bool CSceneNode::IsMouseHovering() const
|
||||
{
|
||||
return mMouseHovering;
|
||||
}
|
||||
|
||||
bool CSceneNode::IsSelected() const
|
||||
{
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
bool CSceneNode::InheritsPosition() const
|
||||
{
|
||||
return _mInheritsPosition;
|
||||
}
|
||||
|
||||
bool CSceneNode::InheritsRotation() const
|
||||
{
|
||||
return _mInheritsRotation;
|
||||
}
|
||||
|
||||
bool CSceneNode::InheritsScale() const
|
||||
{
|
||||
return _mInheritsScale;
|
||||
}
|
||||
|
||||
// ************ SETTERS ************
|
||||
void CSceneNode::SetName(const std::string& Name)
|
||||
{
|
||||
mName = Name;
|
||||
}
|
||||
|
||||
void CSceneNode::SetMouseHovering(bool Hovering)
|
||||
{
|
||||
mMouseHovering = Hovering;
|
||||
}
|
||||
|
||||
void CSceneNode::SetSelected(bool Selected)
|
||||
{
|
||||
mSelected = Selected;
|
||||
}
|
||||
|
||||
void CSceneNode::SetVisible(bool Visible)
|
||||
{
|
||||
mVisible = Visible;
|
||||
}
|
||||
113
Scene/CSceneNode.h
Normal file
113
Scene/CSceneNode.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef CSCENENODE_H
|
||||
#define CSCENENODE_H
|
||||
|
||||
#include "ENodeType.h"
|
||||
#include <Common/CVector3f.h>
|
||||
#include <Common/CQuaternion.h>
|
||||
#include <Common/CAABox.h>
|
||||
#include <Common/CRay.h>
|
||||
#include <Common/CRayCollisionTester.h>
|
||||
#include <Common/types.h>
|
||||
#include <Common/CTransform4f.h>
|
||||
#include <Core/ERenderOptions.h>
|
||||
#include <Resource/CLight.h>
|
||||
#include <Resource/CGameArea.h>
|
||||
|
||||
class CRenderer;
|
||||
class CSceneManager;
|
||||
|
||||
class CSceneNode
|
||||
{
|
||||
private:
|
||||
CTransform4f _mCachedTransform;
|
||||
CAABox _mCachedAABox;
|
||||
bool _mTransformOutdated;
|
||||
|
||||
bool _mInheritsPosition;
|
||||
bool _mInheritsRotation;
|
||||
bool _mInheritsScale;
|
||||
|
||||
protected:
|
||||
static u32 smNumNodes;
|
||||
std::string mName;
|
||||
CSceneNode *mpParent;
|
||||
CSceneManager *mpScene;
|
||||
|
||||
CVector3f mPosition;
|
||||
CQuaternion mRotation;
|
||||
CVector3f mScale;
|
||||
CAABox mLocalAABox;
|
||||
bool mMouseHovering;
|
||||
bool mSelected;
|
||||
bool mVisible;
|
||||
std::list<CSceneNode*> mChildren;
|
||||
|
||||
u32 mLightCount;
|
||||
CLight* mLights[8];
|
||||
|
||||
public:
|
||||
explicit CSceneNode(CSceneManager *pScene, CSceneNode *pParent = 0);
|
||||
virtual ~CSceneNode();
|
||||
virtual ENodeType NodeType() = 0;
|
||||
virtual std::string PrefixedName() const;
|
||||
virtual void AddToRenderer(CRenderer *pRenderer) = 0;
|
||||
virtual void Draw(ERenderOptions Options) = 0;
|
||||
virtual void DrawAsset(ERenderOptions Options, u32 Asset) = 0;
|
||||
virtual void DrawSelection();
|
||||
virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID) = 0;
|
||||
virtual bool IsVisible() const;
|
||||
|
||||
void Unparent();
|
||||
void RemoveChild(CSceneNode *pChild);
|
||||
void DeleteChildren();
|
||||
void SetInheritance(bool InheritPos, bool InheritRot, bool InheritScale);
|
||||
void LoadModelMatrix();
|
||||
void BuildLightList(CGameArea *pArea);
|
||||
void LoadLights();
|
||||
void DrawBoundingBox();
|
||||
|
||||
// Transform
|
||||
void Translate(const CVector3f& Translation);
|
||||
void Scale(const CVector3f& Scale);
|
||||
void UpdateTransform();
|
||||
void ForceRecalculateTransform();
|
||||
void MarkTransformChanged();
|
||||
const CTransform4f& Transform();
|
||||
|
||||
// Getters
|
||||
std::string Name() const;
|
||||
CSceneNode* Parent() const;
|
||||
CSceneManager* Scene();
|
||||
CVector3f GetPosition() const;
|
||||
CVector3f GetAbsolutePosition() const;
|
||||
CQuaternion GetRotation() const;
|
||||
CQuaternion GetAbsoluteRotation() const;
|
||||
CVector3f GetScale() const;
|
||||
CVector3f GetAbsoluteScale() const;
|
||||
CAABox AABox();
|
||||
CVector3f CenterPoint();
|
||||
bool MarkedVisible() const;
|
||||
bool IsMouseHovering() const;
|
||||
bool IsSelected() const;
|
||||
bool InheritsPosition() const;
|
||||
bool InheritsRotation() const;
|
||||
bool InheritsScale() const;
|
||||
|
||||
// Setters
|
||||
void SetName(const std::string& Name);
|
||||
void SetMouseHovering(bool Hovering);
|
||||
void SetSelected(bool Selected);
|
||||
void SetVisible(bool Visible);
|
||||
|
||||
// Static
|
||||
static int NumNodes();
|
||||
};
|
||||
|
||||
// ************ INLINE FUNCTIONS ************
|
||||
inline int CSceneNode::NumNodes()
|
||||
{
|
||||
return smNumNodes;
|
||||
}
|
||||
|
||||
#endif // CSCENENODE_H
|
||||
320
Scene/CScriptNode.cpp
Normal file
320
Scene/CScriptNode.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "CScriptNode.h"
|
||||
#include <gtx/quaternion.hpp>
|
||||
#include <Common/AnimUtil.h>
|
||||
#include <Common/Math.h>
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CRenderer.h>
|
||||
#include <Core/CResCache.h>
|
||||
#include <Core/CSceneManager.h>
|
||||
|
||||
CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObject *pObject)
|
||||
: CSceneNode(pScene, pParent)
|
||||
{
|
||||
mpVolumePreviewNode = nullptr;
|
||||
|
||||
// Evaluate instance
|
||||
mpInstance = pObject;
|
||||
mpActiveModel = nullptr;
|
||||
|
||||
if (mpInstance)
|
||||
{
|
||||
mpActiveModel = mpInstance->GetDisplayModel();
|
||||
mPosition = mpInstance->GetPosition();
|
||||
mRotation = CQuaternion::FromEuler(mpInstance->GetRotation());
|
||||
mScale = mpInstance->GetScale();
|
||||
SetName("[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->GetInstanceName());
|
||||
MarkTransformChanged();
|
||||
|
||||
mHasValidPosition = ((mpInstance->GetAttribFlags() & ePositionAttrib) != 0);
|
||||
mHasVolumePreview = ((mpInstance->GetAttribFlags() & eVolumeAttrib) != 0);
|
||||
|
||||
// Create volume preview node
|
||||
if (mHasVolumePreview)
|
||||
{
|
||||
u32 VolumeShape = mpInstance->GetVolumeShape();
|
||||
CModel *pVolumeModel = nullptr;
|
||||
|
||||
if ((VolumeShape == 0) || (VolumeShape == 1)) // Box/OrientedBox
|
||||
pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeBox.cmdl");
|
||||
|
||||
else if (VolumeShape == 2) // Sphere
|
||||
pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeSphere.cmdl");
|
||||
|
||||
if (pVolumeModel)
|
||||
{
|
||||
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel);
|
||||
mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false);
|
||||
mpVolumePreviewNode->Scale(mpInstance->GetVolume());
|
||||
mpVolumePreviewNode->ForceAlphaEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Shouldn't ever happen
|
||||
SetName("ScriptNode - NO INSTANCE");
|
||||
}
|
||||
|
||||
if (mpActiveModel)
|
||||
mLocalAABox = mpActiveModel->AABox();
|
||||
else
|
||||
mLocalAABox = CAABox::skOne;
|
||||
}
|
||||
|
||||
ENodeType CScriptNode::NodeType()
|
||||
{
|
||||
return eScriptNode;
|
||||
}
|
||||
|
||||
std::string CScriptNode::PrefixedName() const
|
||||
{
|
||||
return "[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->GetInstanceName();
|
||||
}
|
||||
|
||||
void CScriptNode::AddToRenderer(CRenderer *pRenderer)
|
||||
{
|
||||
if (!mpInstance) return;
|
||||
|
||||
if (!mpActiveModel)
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
else
|
||||
{
|
||||
if (!mpActiveModel->IsBuffered())
|
||||
mpActiveModel->BufferGL();
|
||||
|
||||
if (!mpActiveModel->HasTransparency(0))
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
else
|
||||
{
|
||||
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 (IsSelected())
|
||||
{
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
|
||||
if (mHasVolumePreview)
|
||||
mpVolumePreviewNode->AddToRenderer(pRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptNode::Draw(ERenderOptions Options)
|
||||
{
|
||||
if (!mpInstance) return;
|
||||
|
||||
if (!mpActiveModel)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
LoadModelMatrix();
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CDrawUtil::DrawShadedCube(CColor::skTransparentPurple);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CGraphics::sLightMode == CGraphics::WorldLighting)
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::sAreaAmbientColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
||||
else
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
|
||||
LoadModelMatrix();
|
||||
LoadLights();
|
||||
|
||||
CGraphics::sPixelBlock.TevColor = mpInstance->GetTevColor().ToVector4f();
|
||||
|
||||
mpActiveModel->Draw(Options, 0);
|
||||
}
|
||||
|
||||
void CScriptNode::DrawAsset(ERenderOptions Options, u32 Asset)
|
||||
{
|
||||
if (!mpInstance) return;
|
||||
if (!mpActiveModel) return;
|
||||
|
||||
if (CGraphics::sLightMode == CGraphics::WorldLighting)
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::sAreaAmbientColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
||||
else
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
|
||||
LoadModelMatrix();
|
||||
LoadLights();
|
||||
|
||||
CGraphics::sPixelBlock.TevColor = mpInstance->GetTevColor().ToVector4f();
|
||||
|
||||
mpActiveModel->DrawSurface(Options, Asset, 0);
|
||||
}
|
||||
|
||||
void CScriptNode::DrawSelection()
|
||||
{
|
||||
CDrawUtil::DrawWireCube(AABox(), CColor::skTransparentWhite);
|
||||
|
||||
if (mpInstance)
|
||||
{
|
||||
for (u32 iIn = 0; iIn < mpInstance->NumInLinks(); iIn++)
|
||||
{
|
||||
const SLink& con = mpInstance->InLink(iIn);
|
||||
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(con.ObjectID);
|
||||
if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed);
|
||||
}
|
||||
|
||||
for (u32 iOut = 0; iOut < mpInstance->NumOutLinks(); iOut++)
|
||||
{
|
||||
const SLink& con = mpInstance->OutLink(iOut);
|
||||
CScriptNode *pLinkNode = mpScene->ScriptNodeByID(con.ObjectID);
|
||||
if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
||||
{
|
||||
if (!mpInstance)
|
||||
return;
|
||||
|
||||
const CRay& Ray = Tester.Ray();
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (BoxResult.first)
|
||||
{
|
||||
if (mpActiveModel)
|
||||
{
|
||||
for (u32 iSurf = 0; iSurf < mpActiveModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
std::pair<bool,float> SurfResult = mpActiveModel->GetSurfaceAABox(iSurf).Transformed(Transform()).IntersectsRay(Ray);
|
||||
|
||||
if (SurfResult.first)
|
||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
||||
}
|
||||
}
|
||||
else Tester.AddNode(this, 0, BoxResult.second);
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
||||
{
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
out.Hit = true;
|
||||
|
||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool CScriptNode::IsVisible() const
|
||||
{
|
||||
// Reimplementation of CSceneNode::IsHidden() to allow for layer and template visiblity to be taken into account
|
||||
return (mVisible && mpInstance->Layer()->IsVisible() && mpInstance->Template()->IsVisible());
|
||||
}
|
||||
|
||||
CScriptObject* CScriptNode::Object()
|
||||
{
|
||||
return mpInstance;
|
||||
}
|
||||
|
||||
CModel* CScriptNode::ActiveModel()
|
||||
{
|
||||
return mpActiveModel;
|
||||
}
|
||||
|
||||
void CScriptNode::GeneratePosition()
|
||||
{
|
||||
if (!mHasValidPosition)
|
||||
{
|
||||
// Default to center of the active area; this is to preven recursion issues
|
||||
CTransform4f& AreaTransform = mpScene->GetActiveArea()->GetTransform();
|
||||
mPosition = CVector3f(AreaTransform[0][3], AreaTransform[1][3], AreaTransform[2][3]);
|
||||
mHasValidPosition = true;
|
||||
MarkTransformChanged();
|
||||
|
||||
// Ideal way to generate the position is to find a spot close to where it's being used.
|
||||
// To do this I check the location of the objects that this one is linked to.
|
||||
u32 NumLinks = mpInstance->NumInLinks() + mpInstance->NumOutLinks();
|
||||
|
||||
// In the case of one link, apply an offset so the new position isn't the same place as the object it's linked to
|
||||
if (NumLinks == 1)
|
||||
{
|
||||
const SLink& link = (mpInstance->NumInLinks() > 0 ? mpInstance->InLink(0) : mpInstance->OutLink(0));
|
||||
CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID);
|
||||
pNode->GeneratePosition();
|
||||
mPosition = pNode->GetAbsolutePosition();
|
||||
mPosition.z += (pNode->AABox().GetSize().z / 2.f);
|
||||
mPosition.z += (AABox().GetSize().z / 2.f);
|
||||
mPosition.z += 2.f;
|
||||
}
|
||||
|
||||
// For two or more links, average out the position of the connected objects.
|
||||
else if (NumLinks >= 2)
|
||||
{
|
||||
CVector3f NewPos = CVector3f::skZero;
|
||||
|
||||
for (u32 iIn = 0; iIn < mpInstance->NumInLinks(); iIn++)
|
||||
{
|
||||
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->InLink(iIn).ObjectID);
|
||||
|
||||
if (pNode)
|
||||
{
|
||||
pNode->GeneratePosition();
|
||||
NewPos += pNode->AABox().Center();
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 iOut = 0; iOut < mpInstance->NumOutLinks(); iOut++)
|
||||
{
|
||||
CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->OutLink(iOut).ObjectID);
|
||||
|
||||
if (pNode)
|
||||
{
|
||||
pNode->GeneratePosition();
|
||||
NewPos += pNode->AABox().Center();
|
||||
}
|
||||
}
|
||||
|
||||
mPosition = NewPos / NumLinks;
|
||||
mPosition.x += 2.f;
|
||||
}
|
||||
|
||||
MarkTransformChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CScriptNode::HasPreviewVolume()
|
||||
{
|
||||
return mHasVolumePreview;
|
||||
}
|
||||
|
||||
CAABox CScriptNode::PreviewVolumeAABox()
|
||||
{
|
||||
if (!mHasVolumePreview)
|
||||
return CAABox::skZero;
|
||||
else
|
||||
return mpVolumePreviewNode->AABox();
|
||||
}
|
||||
35
Scene/CScriptNode.h
Normal file
35
Scene/CScriptNode.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef CSCRIPTNODE_H
|
||||
#define CSCRIPTNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include "CModelNode.h"
|
||||
#include <Resource/script/CScriptObject.h>
|
||||
|
||||
class CScriptNode : public CSceneNode
|
||||
{
|
||||
CScriptObject *mpInstance;
|
||||
CModel *mpActiveModel;
|
||||
|
||||
bool mHasValidPosition;
|
||||
bool mHasVolumePreview;
|
||||
CModelNode *mpVolumePreviewNode;
|
||||
|
||||
public:
|
||||
CScriptNode(CSceneManager *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0);
|
||||
ENodeType NodeType();
|
||||
std::string PrefixedName() const;
|
||||
void AddToRenderer(CRenderer *pRenderer);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 Asset);
|
||||
void DrawSelection();
|
||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID);
|
||||
bool IsVisible() const;
|
||||
CScriptObject* Object();
|
||||
CModel* ActiveModel();
|
||||
void GeneratePosition();
|
||||
bool HasPreviewVolume();
|
||||
CAABox PreviewVolumeAABox();
|
||||
};
|
||||
|
||||
#endif // CSCRIPTNODE_H
|
||||
113
Scene/CStaticNode.cpp
Normal file
113
Scene/CStaticNode.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "CStaticNode.h"
|
||||
#include <Core/CRenderer.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Common/AnimUtil.h>
|
||||
#include <Common/Math.h>
|
||||
#include <Core/CDrawUtil.h>
|
||||
|
||||
CStaticNode::CStaticNode(CSceneManager *pScene, CSceneNode *pParent, CStaticModel *pModel)
|
||||
: CSceneNode(pScene, pParent)
|
||||
{
|
||||
mpModel = pModel;
|
||||
mLocalAABox = mpModel->AABox();
|
||||
mScale = CVector3f(1.f, 1.f, 1.f);
|
||||
SetName("Static Node");
|
||||
}
|
||||
|
||||
ENodeType CStaticNode::NodeType()
|
||||
{
|
||||
return eStaticNode;
|
||||
}
|
||||
|
||||
void CStaticNode::AddToRenderer(CRenderer *pRenderer)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
if (mpModel->IsOccluder()) return;
|
||||
|
||||
if (!mpModel->IsTransparent())
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
else
|
||||
{
|
||||
u32 sm_count = mpModel->GetSurfaceCount();
|
||||
for (u32 s = 0; s < sm_count; s++)
|
||||
{
|
||||
pRenderer->AddTransparentMesh(this, s, mpModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset);
|
||||
}
|
||||
}
|
||||
|
||||
if (mSelected)
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
}
|
||||
|
||||
void CStaticNode::Draw(ERenderOptions Options)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(0, 0, 0, 1);
|
||||
float Multiplier = CGraphics::sWorldLightMultiplier;
|
||||
CGraphics::sPixelBlock.TevColor = CVector4f(Multiplier,Multiplier,Multiplier,1);
|
||||
CGraphics::sNumLights = 0;
|
||||
CGraphics::UpdateLightBlock();
|
||||
LoadModelMatrix();
|
||||
|
||||
mpModel->Draw(Options);
|
||||
}
|
||||
|
||||
void CStaticNode::DrawAsset(ERenderOptions Options, u32 Asset)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(0,0,0,1);
|
||||
CGraphics::sPixelBlock.TevColor = CVector4f(1,1,1,1);
|
||||
CGraphics::sNumLights = 0;
|
||||
CGraphics::UpdateLightBlock();
|
||||
LoadModelMatrix();
|
||||
|
||||
mpModel->DrawSurface(Options, Asset);
|
||||
//CDrawUtil::DrawWireCube(mpModel->GetSurfaceAABox(Asset), CColor::skWhite);
|
||||
}
|
||||
|
||||
void CStaticNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
||||
{
|
||||
if ((!mpModel) || (mpModel->IsOccluder()))
|
||||
return;
|
||||
|
||||
const CRay& Ray = Tester.Ray();
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (BoxResult.first)
|
||||
{
|
||||
for (u32 iSurf = 0; iSurf < mpModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
std::pair<bool,float> SurfResult = mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()).IntersectsRay(Ray);
|
||||
|
||||
if (SurfResult.first)
|
||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
||||
{
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
out.Hit = true;
|
||||
|
||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
21
Scene/CStaticNode.h
Normal file
21
Scene/CStaticNode.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CSTATICNODE_H
|
||||
#define CSTATICNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include <Resource/model/CStaticModel.h>
|
||||
|
||||
class CStaticNode : public CSceneNode
|
||||
{
|
||||
CStaticModel *mpModel;
|
||||
|
||||
public:
|
||||
CStaticNode(CSceneManager *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID);
|
||||
};
|
||||
|
||||
#endif // CSTATICNODE_H
|
||||
15
Scene/ENodeType.h
Normal file
15
Scene/ENodeType.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef ENODETYPE
|
||||
#define ENODETYPE
|
||||
|
||||
enum ENodeType
|
||||
{
|
||||
eRootNode,
|
||||
eModelNode,
|
||||
eStaticNode,
|
||||
eCollisionNode,
|
||||
eScriptNode,
|
||||
eLightNode
|
||||
};
|
||||
|
||||
#endif // ENODETYPE
|
||||
|
||||
Reference in New Issue
Block a user