Initial commit of current work on Prime World Editor

This commit is contained in:
parax0
2015-07-26 17:39:49 -04:00
commit 66e8c2ebcb
305 changed files with 33469 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
#include "CBoundingBoxNode.h"
CBoundingBoxNode::CBoundingBoxNode()
{
}
CBoundingBoxNode::~CBoundingBoxNode()
{
}

16
Scene/CBoundingBoxNode.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,15 @@
#ifndef ENODETYPE
#define ENODETYPE
enum ENodeType
{
eRootNode,
eModelNode,
eStaticNode,
eCollisionNode,
eScriptNode,
eLightNode
};
#endif // ENODETYPE