Reorganized CScene; better organization, less redundant code, responsibility for show/hide shifted to other classes, and in position to implement CSceneIterator

This commit is contained in:
parax0 2016-01-06 03:42:07 -07:00
parent 3fa109d5b8
commit d66b3dee8e
23 changed files with 253 additions and 352 deletions

View File

@ -17,12 +17,12 @@ void CAreaAttributes::SetObject(CScriptObject *pObj)
mGame = pObj->Template()->MasterTemplate()->GetGame(); mGame = pObj->Template()->MasterTemplate()->GetGame();
} }
bool CAreaAttributes::IsLayerEnabled() bool CAreaAttributes::IsLayerEnabled() const
{ {
return mpObj->Layer()->IsActive(); return mpObj->Layer()->IsActive();
} }
bool CAreaAttributes::IsSkyEnabled() bool CAreaAttributes::IsSkyEnabled() const
{ {
CPropertyStruct *pBaseStruct = mpObj->Properties(); CPropertyStruct *pBaseStruct = mpObj->Properties();
@ -39,7 +39,7 @@ bool CAreaAttributes::IsSkyEnabled()
} }
} }
CModel* CAreaAttributes::SkyModel() CModel* CAreaAttributes::SkyModel() const
{ {
CPropertyStruct *pBaseStruct = mpObj->Properties(); CPropertyStruct *pBaseStruct = mpObj->Properties();

View File

@ -12,9 +12,9 @@ public:
CAreaAttributes(CScriptObject *pObj); CAreaAttributes(CScriptObject *pObj);
~CAreaAttributes(); ~CAreaAttributes();
void SetObject(CScriptObject *pObj); void SetObject(CScriptObject *pObj);
bool IsLayerEnabled(); bool IsLayerEnabled() const;
bool IsSkyEnabled(); bool IsSkyEnabled() const;
CModel* SkyModel(); CModel* SkyModel() const;
}; };
#endif // CAREAATTRIBUTES_H #endif // CAREAATTRIBUTES_H

View File

@ -179,6 +179,7 @@ HEADERS += \
Resource/Script/IProperty.h \ Resource/Script/IProperty.h \
Resource/Model/EVertexAttribute.h \ Resource/Model/EVertexAttribute.h \
Render/FRenderOptions.h \ Render/FRenderOptions.h \
Scene/FShowFlags.h \
Scene/CScene.h Scene/CScene.h
# Source Files # Source Files
@ -263,4 +264,5 @@ SOURCES += \
Resource/Cooker/CAreaCooker.cpp \ Resource/Cooker/CAreaCooker.cpp \
Resource/Script/IPropertyTemplate.cpp \ Resource/Script/IPropertyTemplate.cpp \
Resource/Script/IProperty.cpp \ Resource/Script/IProperty.cpp \
Scene/FShowFlags.cpp \
Scene/CScene.cpp Scene/CScene.cpp

View File

@ -20,8 +20,7 @@ u32 CRenderer::sNumRenderers = 0;
// ************ INITIALIZATION ************ // ************ INITIALIZATION ************
CRenderer::CRenderer() CRenderer::CRenderer()
{ {
mOptions = eDrawWorld | eDrawObjects | eDrawLights | eDrawSky | mOptions = eEnableUVScroll | eEnableBackfaceCull;
eEnableUVScroll | eEnableBackfaceCull;
mBloomMode = eNoBloom; mBloomMode = eNoBloom;
mDrawGrid = true; mDrawGrid = true;
mInitialized = false; mInitialized = false;
@ -58,42 +57,6 @@ FRenderOptions CRenderer::RenderOptions() const
return mOptions; return mOptions;
} }
void CRenderer::ToggleWorld(bool b)
{
if (b) mOptions |= eDrawWorld;
else mOptions &= ~eDrawWorld;
}
void CRenderer::ToggleWorldCollision(bool b)
{
if (b) mOptions |= eDrawWorldCollision;
else mOptions &= ~eDrawWorldCollision;
}
void CRenderer::ToggleObjects(bool b)
{
if (b) mOptions |= eDrawObjects;
else mOptions &= ~eDrawObjects;
}
void CRenderer::ToggleObjectCollision(bool b)
{
if (b) mOptions |= eDrawObjectCollision;
else mOptions &= ~eDrawObjectCollision;
}
void CRenderer::ToggleLights(bool b)
{
if (b) mOptions |= eDrawLights;
else mOptions &= ~eDrawLights;
}
void CRenderer::ToggleSky(bool b)
{
if (b) mOptions |= eDrawSky;
else mOptions &= ~eDrawSky;
}
void CRenderer::ToggleBackfaceCull(bool b) void CRenderer::ToggleBackfaceCull(bool b)
{ {
if (b) mOptions |= eEnableBackfaceCull; if (b) mOptions |= eEnableBackfaceCull;

View File

@ -55,12 +55,6 @@ public:
// Getters/Setters // Getters/Setters
FRenderOptions RenderOptions() const; FRenderOptions RenderOptions() const;
void ToggleWorld(bool b);
void ToggleWorldCollision(bool b);
void ToggleObjects(bool b);
void ToggleObjectCollision(bool b);
void ToggleLights(bool b);
void ToggleSky(bool b);
void ToggleBackfaceCull(bool b); void ToggleBackfaceCull(bool b);
void ToggleUVAnimation(bool b); void ToggleUVAnimation(bool b);
void ToggleGrid(bool b); void ToggleGrid(bool b);

View File

@ -6,18 +6,12 @@
enum ERenderOption enum ERenderOption
{ {
eNoRenderOptions = 0x0, eNoRenderOptions = 0x0,
eDrawWorld = 0x1, eEnableUVScroll = 0x1,
eDrawWorldCollision = 0x2, eEnableBackfaceCull = 0x2,
eDrawObjects = 0x4, eEnableOccluders = 0x4,
eDrawObjectCollision = 0x8, eNoMaterialSetup = 0x8,
eDrawLights = 0x10, eEnableBloom = 0x10,
eDrawSky = 0x20, eNoAlpha = 0x20
eEnableUVScroll = 0x40,
eEnableBackfaceCull = 0x80,
eEnableOccluders = 0x100,
eNoMaterialSetup = 0x200,
eEnableBloom = 0x400,
eNoAlpha = 0x800
}; };
DECLARE_FLAGS(ERenderOption, FRenderOptions) DECLARE_FLAGS(ERenderOption, FRenderOptions)

View File

@ -1,6 +1,7 @@
#ifndef SVIEWINFO #ifndef SVIEWINFO
#define SVIEWINFO #define SVIEWINFO
#include "Core/Scene/FShowFlags.h"
#include <Math/CFrustumPlanes.h> #include <Math/CFrustumPlanes.h>
#include <Math/CMatrix4f.h> #include <Math/CMatrix4f.h>
#include <Math/CRay.h> #include <Math/CRay.h>
@ -12,6 +13,7 @@ struct SViewInfo
class CCamera *pCamera; class CCamera *pCamera;
bool GameMode; bool GameMode;
FShowFlags ShowFlags;
CFrustumPlanes ViewFrustum; CFrustumPlanes ViewFrustum;
CMatrix4f RotationOnlyViewMatrix; CMatrix4f RotationOnlyViewMatrix;
}; };

View File

@ -11,21 +11,14 @@
#include <list> #include <list>
#include <string> #include <string>
/**
* This class direly needs a rewrite
* Future plan is to integrate a "scene layer" system, where nodes are grouped into layers
* We would have terrain layer, lights layer, collision layer, multiple script layers, etc
* Advantage of this is that I don't need to write separate functions for every single node type
* They can all be tracked together and the code could be streamlined a lot.
*/
CScene::CScene() CScene::CScene()
: mSplitTerrain(true)
, mNumNodes(0)
, mpSceneRootNode(new CRootNode(this, nullptr))
, mpArea(nullptr)
, mpWorld(nullptr)
, mpAreaRootNode(nullptr)
{ {
mSplitTerrain = true;
mNodeCount = 0;
mpSceneRootNode = new CRootNode(this, nullptr);
mpArea = nullptr;
mpWorld = nullptr;
mpAreaRootNode = nullptr;
} }
CScene::~CScene() CScene::~CScene()
@ -33,107 +26,105 @@ CScene::~CScene()
ClearScene(); ClearScene();
} }
CModelNode* CScene::AddModel(CModel *m) CModelNode* CScene::CreateModelNode(CModel *pModel)
{ {
if (m == nullptr) return nullptr; if (pModel == nullptr) return nullptr;
CModelNode *node = new CModelNode(this, mpSceneRootNode, m); CModelNode *pNode = new CModelNode(this, mpSceneRootNode, pModel);
mModelNodes.push_back(node); mNodes[eShowObjects].push_back(pNode);
mNodeCount++; mNumNodes++;
return node; return pNode;
} }
CStaticNode* CScene::AddStaticModel(CStaticModel *mdl) CStaticNode* CScene::CreateStaticNode(CStaticModel *pModel)
{ {
if (mdl == nullptr) return nullptr; if (pModel == nullptr) return nullptr;
CStaticNode *node = new CStaticNode(this, mpAreaRootNode, mdl); CStaticNode *pNode = new CStaticNode(this, mpAreaRootNode, pModel);
mStaticNodes.push_back(node); mNodes[eShowWorld].push_back(pNode);
mNodeCount++; mNumNodes++;
return node; return pNode;
} }
CCollisionNode* CScene::AddCollision(CCollisionMeshGroup *mesh) CCollisionNode* CScene::CreateCollisionNode(CCollisionMeshGroup *pMesh)
{ {
if (mesh == nullptr) return nullptr; if (pMesh == nullptr) return nullptr;
CCollisionNode *node = new CCollisionNode(this, mpAreaRootNode, mesh); CCollisionNode *pNode = new CCollisionNode(this, mpAreaRootNode, pMesh);
mCollisionNodes.push_back(node); mNodes[eShowWorldCollision].push_back(pNode);
mNodeCount++; mNumNodes++;
return node; return pNode;
} }
CScriptNode* CScene::AddScriptObject(CScriptObject *obj) CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj)
{ {
if (obj == nullptr) return nullptr; if (pObj == nullptr) return nullptr;
CScriptNode *node = new CScriptNode(this, mpAreaRootNode, obj); CScriptNode *pNode = new CScriptNode(this, mpAreaRootNode, pObj);
mScriptNodes.push_back(node); mNodes[eShowObjects].push_back(pNode);
mNodeCount++; mNumNodes++;
return node; return pNode;
} }
CLightNode* CScene::AddLight(CLight *Light) CLightNode* CScene::CreateLightNode(CLight *pLight)
{ {
if (Light == nullptr) return nullptr; if (pLight == nullptr) return nullptr;
CLightNode *node = new CLightNode(this, mpAreaRootNode, Light); CLightNode *pNode = new CLightNode(this, mpAreaRootNode, pLight);
mLightNodes.push_back(node); mNodes[eShowLights].push_back(pNode);
mNodeCount++; mNumNodes++;
return node; return pNode;
} }
void CScene::SetActiveArea(CGameArea* _area) void CScene::SetActiveArea(CGameArea *pArea)
{ {
// Clear existing area // Clear existing area
delete mpAreaRootNode; delete mpAreaRootNode;
mModelNodes.clear(); mNodes.clear();
mStaticNodes.clear();
mCollisionNodes.clear();
mScriptNodes.clear();
mLightNodes.clear();
mAreaAttributesObjects.clear(); mAreaAttributesObjects.clear();
mpActiveAreaAttributes = nullptr;
mScriptNodeMap.clear(); mScriptNodeMap.clear();
// Create nodes for new area // Create nodes for new area
mpArea = _area; mpArea = pArea;
mpAreaRootNode = new CRootNode(this, mpSceneRootNode); mpAreaRootNode = new CRootNode(this, mpSceneRootNode);
if (mSplitTerrain) if (mSplitTerrain)
{ {
u32 count = mpArea->GetStaticModelCount(); u32 Count = mpArea->GetStaticModelCount();
for (u32 m = 0; m < count; m++)
AddStaticModel(mpArea->GetStaticModel(m)); for (u32 iMdl = 0; iMdl < Count; iMdl++)
CreateStaticNode(mpArea->GetStaticModel(iMdl));
} }
else else
{ {
u32 count = mpArea->GetTerrainModelCount(); u32 Count = mpArea->GetTerrainModelCount();
for (u32 m = 0; m < count; m++)
for (u32 iMdl = 0; iMdl < Count; iMdl++)
{ {
CModel *mdl = mpArea->GetTerrainModel(m); CModel *pModel = mpArea->GetTerrainModel(iMdl);
CModelNode *node = AddModel(mdl); CModelNode *pNode = CreateModelNode(pModel);
node->SetDynamicLighting(false); pNode->SetDynamicLighting(false);
} }
} }
AddCollision(mpArea->GetCollision()); CreateCollisionNode(mpArea->GetCollision());
u32 NumLayers = mpArea->GetScriptLayerCount(); u32 NumLayers = mpArea->GetScriptLayerCount();
for (u32 l = 0; l < NumLayers; l++)
{
CScriptLayer *layer = mpArea->GetScriptLayer(l);
u32 NumObjects = layer->GetNumObjects();
mScriptNodes.reserve(mScriptNodes.size() + NumObjects);
for (u32 o = 0; o < NumObjects; o++) for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
{
CScriptLayer *pLayer = mpArea->GetScriptLayer(iLyr);
u32 NumObjects = pLayer->GetNumObjects();
mNodes[eShowObjects].reserve(mNodes[eShowObjects].size() + NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++)
{ {
CScriptObject *pObj = layer->ObjectByIndex(o); CScriptObject *pObj = pLayer->ObjectByIndex(iObj);
CScriptNode *Node = AddScriptObject( pObj ); CScriptNode *pNode = CreateScriptNode(pObj);
Node->BuildLightList(mpArea); pNode->BuildLightList(mpArea);
// Add to map // Add to map
mScriptNodeMap[pObj->InstanceID()] = Node; mScriptNodeMap[pObj->InstanceID()] = pNode;
// AreaAttributes check // AreaAttributes check
switch (pObj->ObjectTypeID()) switch (pObj->ObjectTypeID())
@ -149,16 +140,15 @@ void CScene::SetActiveArea(CGameArea* _area)
CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer(); CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer();
if (pGenLayer) if (pGenLayer)
{ {
for (u32 o = 0; o < pGenLayer->GetNumObjects(); o++) for (u32 iObj = 0; iObj < pGenLayer->GetNumObjects(); iObj++)
{ {
CScriptObject *pObj = pGenLayer->ObjectByIndex(o); CScriptObject *pObj = pGenLayer->ObjectByIndex(iObj);
CScriptNode *Node = AddScriptObject(pObj); CScriptNode *pNode = CreateScriptNode(pObj);
// Add to map // Add to map
mScriptNodeMap[pObj->InstanceID()] = Node; mScriptNodeMap[pObj->InstanceID()] = pNode;
} }
} }
PickEnvironmentObjects();
// Ensure script nodes have valid positions + build light lists // Ensure script nodes have valid positions + build light lists
for (auto it = mScriptNodeMap.begin(); it != mScriptNodeMap.end(); it++) for (auto it = mScriptNodeMap.begin(); it != mScriptNodeMap.end(); it++)
@ -170,27 +160,27 @@ void CScene::SetActiveArea(CGameArea* _area)
u32 NumLightLayers = mpArea->GetLightLayerCount(); u32 NumLightLayers = mpArea->GetLightLayerCount();
CGraphics::sAreaAmbientColor = CColor::skBlack; CGraphics::sAreaAmbientColor = CColor::skBlack;
for (u32 ly = 0; ly < NumLightLayers; ly++) for (u32 iLyr = 0; iLyr < NumLightLayers; iLyr++)
{ {
u32 NumLights = mpArea->GetLightCount(ly); u32 NumLights = mpArea->GetLightCount(iLyr);
for (u32 l = 0; l < NumLights; l++) for (u32 iLit = 0; iLit < NumLights; iLit++)
{ {
CLight *Light = mpArea->GetLight(ly, l); CLight *pLight = mpArea->GetLight(iLyr, iLit);
if (Light->GetType() == eLocalAmbient) if (pLight->GetType() == eLocalAmbient)
CGraphics::sAreaAmbientColor += Light->GetColor(); CGraphics::sAreaAmbientColor += pLight->GetColor();
AddLight(Light); CreateLightNode(pLight);
} }
} }
std::cout << CSceneNode::NumNodes() << " nodes\n"; Log::Write( TString::FromInt32(CSceneNode::NumNodes()) + " nodes" );
} }
void CScene::SetActiveWorld(CWorld* _world) void CScene::SetActiveWorld(CWorld* pWorld)
{ {
mpWorld = _world; mpWorld = pWorld;
} }
void CScene::ClearScene() void CScene::ClearScene()
@ -201,113 +191,51 @@ void CScene::ClearScene()
delete mpAreaRootNode; delete mpAreaRootNode;
} }
mModelNodes.clear(); mNodes.clear();
mStaticNodes.clear(); mNumNodes = 0;
mCollisionNodes.clear();
mScriptNodes.clear();
mLightNodes.clear();
mpArea = nullptr; mpArea = nullptr;
mpWorld = nullptr; mpWorld = nullptr;
mNodeCount = 0;
} }
void CScene::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) void CScene::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
{ {
FRenderOptions Options = pRenderer->RenderOptions(); // Override show flags in game mode
FShowFlags ShowFlags = (ViewInfo.GameMode ? gGameModeShowFlags : ViewInfo.ShowFlags);
if (Options & eDrawWorld || ViewInfo.GameMode) for (auto it = mNodes.begin(); it != mNodes.end(); it++)
{ {
for (u32 n = 0; n < mModelNodes.size(); n++) if (ShowFlags & it->first)
if (mModelNodes[n]->IsVisible()) {
mModelNodes[n]->AddToRenderer(pRenderer, ViewInfo); std::vector<CSceneNode*>& rNodeVec = it->second;
for (u32 n = 0; n < mStaticNodes.size(); n++) for (u32 iNode = 0; iNode < rNodeVec.size(); iNode++)
if (mStaticNodes[n]->IsVisible()) if (rNodeVec[iNode]->IsVisible())
mStaticNodes[n]->AddToRenderer(pRenderer, ViewInfo); rNodeVec[iNode]->AddToRenderer(pRenderer, ViewInfo);
} }
if (Options & eDrawWorldCollision && !ViewInfo.GameMode)
{
for (u32 n = 0; n < mCollisionNodes.size(); n++)
if (mCollisionNodes[n]->IsVisible())
mCollisionNodes[n]->AddToRenderer(pRenderer, ViewInfo);
}
if (Options & eDrawLights && !ViewInfo.GameMode)
{
for (u32 n = 0; n < mLightNodes.size(); n++)
if (mLightNodes[n]->IsVisible())
mLightNodes[n]->AddToRenderer(pRenderer, ViewInfo);
}
if ((Options & eDrawObjects) || (Options & eDrawObjectCollision) || ViewInfo.GameMode)
{
for (u32 n = 0; n < mScriptNodes.size(); n++)
if (mScriptNodes[n]->IsVisible())
mScriptNodes[n]->AddToRenderer(pRenderer, ViewInfo);
} }
} }
SRayIntersection CScene::SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo) SRayIntersection CScene::SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo)
{ {
// Terribly hacky stuff to avoid having tons of redundant code FShowFlags ShowFlags = (ViewInfo.GameMode ? gGameModeShowFlags : ViewInfo.ShowFlags);
// because I'm too lazy to rewrite CSceneManager right now and fix it
// (I'm probably going to do it soon...)
FRenderOptions renderOptions = ViewInfo.pRenderer->RenderOptions();
std::vector<CSceneNode*> *pNodeVectors[5] = {
reinterpret_cast<std::vector<CSceneNode*>*>(&mModelNodes),
reinterpret_cast<std::vector<CSceneNode*>*>(&mStaticNodes),
reinterpret_cast<std::vector<CSceneNode*>*>(&mCollisionNodes),
reinterpret_cast<std::vector<CSceneNode*>*>(&mScriptNodes),
reinterpret_cast<std::vector<CSceneNode*>*>(&mLightNodes),
};
bool NodesVisible[5] = {
true, ((renderOptions & eDrawWorld) != 0), ((renderOptions & eDrawWorldCollision) != 0),
((renderOptions & ((FRenderOptions) (eDrawObjects | eDrawObjectCollision))) != 0), ((renderOptions & eDrawLights) != 0)
};
// Override visibility for game mode
if (ViewInfo.GameMode)
{
NodesVisible[0] = false;
NodesVisible[1] = true;
NodesVisible[2] = false;
NodesVisible[3] = true;
NodesVisible[4] = false;
}
// Less hacky stuff
CRayCollisionTester Tester(Ray); CRayCollisionTester Tester(Ray);
for (u32 iVec = 0; iVec < 5; iVec++) for (auto it = mNodes.begin(); it != mNodes.end(); it++)
{ {
if (!NodesVisible[iVec]) continue; if (ShowFlags & it->first)
{
std::vector<CSceneNode*>& rNodeVec = it->second;
std::vector<CSceneNode*>& vec = *pNodeVectors[iVec]; for (u32 iNode = 0; iNode < rNodeVec.size(); iNode++)
if (rNodeVec[iNode]->IsVisible())
for (u32 iNode = 0; iNode < vec.size(); iNode++) rNodeVec[iNode]->RayAABoxIntersectTest(Tester, ViewInfo);
if (vec[iNode]->IsVisible()) }
vec[iNode]->RayAABoxIntersectTest(Tester, ViewInfo);
} }
return Tester.TestNodes(ViewInfo); return Tester.TestNodes(ViewInfo);
} }
void CScene::PickEnvironmentObjects()
{
// Pick AreaAttributes
for (auto it = mAreaAttributesObjects.begin(); it != mAreaAttributesObjects.end(); it++)
{
if ((*it).IsLayerEnabled())
{
mpActiveAreaAttributes = &(*it);
break;
}
}
}
CScriptNode* CScene::ScriptNodeByID(u32 InstanceID) CScriptNode* CScene::ScriptNodeByID(u32 InstanceID)
{ {
auto it = mScriptNodeMap.find(InstanceID); auto it = mScriptNodeMap.find(InstanceID);
@ -324,26 +252,38 @@ CScriptNode* CScene::NodeForObject(CScriptObject *pObj)
CLightNode* CScene::NodeForLight(CLight *pLight) CLightNode* CScene::NodeForLight(CLight *pLight)
{ {
// Slow. Is there a better way to do this? // Slow. Is there a better way to do this?
for (auto it = mLightNodes.begin(); it != mLightNodes.end(); it++) std::vector<CSceneNode*>& rLights = mNodes[eShowLights];
if ((*it)->Light() == pLight) return *it;
for (auto it = rLights.begin(); it != rLights.end(); it++)
{
CLightNode *pNode = static_cast<CLightNode*>(*it);
if (pNode->Light() == pLight) return pNode;
}
return nullptr; return nullptr;
} }
CModel* CScene::GetActiveSkybox() CModel* CScene::GetActiveSkybox()
{ {
if (mpActiveAreaAttributes) bool SkyEnabled = false;
for (u32 iAtt = 0; iAtt < mAreaAttributesObjects.size(); iAtt++)
{ {
if (mpActiveAreaAttributes->IsSkyEnabled()) const CAreaAttributes& rkAttributes = mAreaAttributesObjects[iAtt];
if (rkAttributes.IsSkyEnabled()) SkyEnabled = true;
if (rkAttributes.IsLayerEnabled())
{ {
CModel *pSky = mpActiveAreaAttributes->SkyModel(); if (rkAttributes.IsSkyEnabled())
if (pSky) return pSky; {
else return mpWorld->GetDefaultSkybox(); SkyEnabled = true;
CModel *pSky = rkAttributes.SkyModel();
if (pSky) return pSky;
}
} }
else
return nullptr;
} }
if (SkyEnabled) return mpWorld->GetDefaultSkybox();
else return nullptr; else return nullptr;
} }

View File

@ -8,6 +8,7 @@
#include "CScriptNode.h" #include "CScriptNode.h"
#include "CStaticNode.h" #include "CStaticNode.h"
#include "CCollisionNode.h" #include "CCollisionNode.h"
#include "FShowFlags.h"
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
#include "Core/Render/SViewInfo.h" #include "Core/Render/SViewInfo.h"
#include "Core/Resource/CGameArea.h" #include "Core/Resource/CGameArea.h"
@ -23,13 +24,9 @@ class CScene
{ {
bool mSplitTerrain; bool mSplitTerrain;
u32 mNodeCount; u32 mNumNodes;
std::vector<CModelNode*> mModelNodes;
std::vector<CStaticNode*> mStaticNodes;
std::vector<CCollisionNode*> mCollisionNodes;
std::vector<CScriptNode*> mScriptNodes;
std::vector<CLightNode*> mLightNodes;
CRootNode *mpSceneRootNode; CRootNode *mpSceneRootNode;
std::unordered_map<EShowFlag, std::vector<CSceneNode*>> mNodes;
TResPtr<CGameArea> mpArea; TResPtr<CGameArea> mpArea;
TResPtr<CWorld> mpWorld; TResPtr<CWorld> mpWorld;
@ -37,7 +34,6 @@ class CScene
// Environment // Environment
std::vector<CAreaAttributes> mAreaAttributesObjects; std::vector<CAreaAttributes> mAreaAttributesObjects;
CAreaAttributes *mpActiveAreaAttributes;
// Objects // Objects
std::unordered_map<u32, CScriptNode*> mScriptNodeMap; std::unordered_map<u32, CScriptNode*> mScriptNodeMap;
@ -47,17 +43,16 @@ public:
~CScene(); ~CScene();
// Scene Management // Scene Management
CModelNode* AddModel(CModel *mdl); CModelNode* CreateModelNode(CModel *pModel);
CStaticNode* AddStaticModel(CStaticModel *mdl); CStaticNode* CreateStaticNode(CStaticModel *pModel);
CCollisionNode* AddCollision(CCollisionMeshGroup *mesh); CCollisionNode* CreateCollisionNode(CCollisionMeshGroup *pMesh);
CScriptNode* AddScriptObject(CScriptObject *obj); CScriptNode* CreateScriptNode(CScriptObject *pObj);
CLightNode* AddLight(CLight *Light); CLightNode* CreateLightNode(CLight *pLight);
void SetActiveArea(CGameArea *_area); void SetActiveArea(CGameArea *pArea);
void SetActiveWorld(CWorld *_world); void SetActiveWorld(CWorld *pWorld);
void ClearScene(); void ClearScene();
void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
SRayIntersection SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo); SRayIntersection SceneRayCast(const CRay& rkRay, const SViewInfo& rkViewInfo);
void PickEnvironmentObjects();
CScriptNode* ScriptNodeByID(u32 InstanceID); CScriptNode* ScriptNodeByID(u32 InstanceID);
CScriptNode* NodeForObject(CScriptObject *pObj); CScriptNode* NodeForObject(CScriptObject *pObj);
CLightNode* NodeForLight(CLight *pLight); CLightNode* NodeForLight(CLight *pLight);

View File

@ -58,6 +58,7 @@ public:
virtual void DrawSelection(); virtual void DrawSelection();
virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester, const SViewInfo& ViewInfo); virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester, const SViewInfo& ViewInfo);
virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo) = 0; virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo) = 0;
virtual void PostLoad() {}
virtual bool AllowsTranslate() const { return true; } virtual bool AllowsTranslate() const { return true; }
virtual bool AllowsRotate() const { return true; } virtual bool AllowsRotate() const { return true; }
virtual bool AllowsScale() const { return true; } virtual bool AllowsScale() const { return true; }

View File

@ -119,12 +119,10 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
if (ShouldDraw) if (ShouldDraw)
{ {
// Otherwise, we proceed as normal // Otherwise, we proceed as normal
FRenderOptions options = pRenderer->RenderOptions(); if ((ViewInfo.ShowFlags & eShowObjectCollision) && (!ViewInfo.GameMode))
if ((options & eDrawObjectCollision) && (!ViewInfo.GameMode))
mpCollisionNode->AddToRenderer(pRenderer, ViewInfo); mpCollisionNode->AddToRenderer(pRenderer, ViewInfo);
if (options & eDrawObjects || ViewInfo.GameMode) if (ViewInfo.ShowFlags & eShowObjectGeometry || ViewInfo.GameMode)
{ {
if (ViewInfo.ViewFrustum.BoxInFrustum(AABox())) if (ViewInfo.ViewFrustum.BoxInFrustum(AABox()))
{ {
@ -282,85 +280,81 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester& Tester, const SView
SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo) SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo)
{ {
FRenderOptions options = ViewInfo.pRenderer->RenderOptions(); FRenderOptions Options = ViewInfo.pRenderer->RenderOptions();
SRayIntersection out; SRayIntersection out;
out.pNode = this; out.pNode = this;
out.ComponentIndex = AssetID; out.ComponentIndex = AssetID;
if (options & eDrawObjects || ViewInfo.GameMode) // Model test
if (UsesModel())
{ {
// Model test CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
if (UsesModel())
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((Options & eEnableBackfaceCull) == 0));
if (Result.first)
{ {
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); out.Hit = true;
CRay TransformedRay = Ray.Transformed(Transform().Inverse()); CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0)); CVector3f WorldHitPoint = Transform() * HitPoint;
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
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;
} }
// Billboard test
// todo: come up with a better way to share this code between CScriptNode and CLightNode
else else
out.Hit = false;
}
// Billboard test
// todo: come up with a better way to share this code between CScriptNode and CLightNode
else
{
// Step 1: check whether the ray intersects with the plane the billboard is on
CPlane BillboardPlane(-ViewInfo.pCamera->Direction(), mPosition);
std::pair<bool,float> PlaneTest = Math::RayPlaneIntersecton(Ray, BillboardPlane);
if (PlaneTest.first)
{ {
// Step 1: check whether the ray intersects with the plane the billboard is on // Step 2: transform the hit point into the plane's local space
CPlane BillboardPlane(-ViewInfo.pCamera->Direction(), mPosition); CVector3f PlaneHitPoint = Ray.PointOnRay(PlaneTest.second);
std::pair<bool,float> PlaneTest = Math::RayPlaneIntersecton(Ray, BillboardPlane); CVector3f RelHitPoint = PlaneHitPoint - mPosition;
if (PlaneTest.first) CVector3f PlaneForward = -ViewInfo.pCamera->Direction();
CVector3f PlaneRight = -ViewInfo.pCamera->RightVector();
CVector3f PlaneUp = ViewInfo.pCamera->UpVector();
CQuaternion PlaneRot = CQuaternion::FromAxes(PlaneRight, PlaneForward, PlaneUp);
CVector3f RotatedHitPoint = PlaneRot.Inverse() * RelHitPoint;
CVector2f LocalHitPoint = RotatedHitPoint.xz() / BillboardScale();
// Step 3: check whether the transformed hit point is in the -1 to 1 range
if ((LocalHitPoint.x >= -1.f) && (LocalHitPoint.x <= 1.f) && (LocalHitPoint.y >= -1.f) && (LocalHitPoint.y <= 1.f))
{ {
// Step 2: transform the hit point into the plane's local space // Step 4: look up the hit texel and check whether it's transparent or opaque
CVector3f PlaneHitPoint = Ray.PointOnRay(PlaneTest.second); CVector2f TexCoord = (LocalHitPoint + CVector2f(1.f)) * 0.5f;
CVector3f RelHitPoint = PlaneHitPoint - mPosition; TexCoord.x = -TexCoord.x + 1.f;
float TexelAlpha = mpBillboard->ReadTexelAlpha(TexCoord);
CVector3f PlaneForward = -ViewInfo.pCamera->Direction(); if (TexelAlpha < 0.25f)
CVector3f PlaneRight = -ViewInfo.pCamera->RightVector(); out.Hit = false;
CVector3f PlaneUp = ViewInfo.pCamera->UpVector();
CQuaternion PlaneRot = CQuaternion::FromAxes(PlaneRight, PlaneForward, PlaneUp);
CVector3f RotatedHitPoint = PlaneRot.Inverse() * RelHitPoint;
CVector2f LocalHitPoint = RotatedHitPoint.xz() / BillboardScale();
// Step 3: check whether the transformed hit point is in the -1 to 1 range
if ((LocalHitPoint.x >= -1.f) && (LocalHitPoint.x <= 1.f) && (LocalHitPoint.y >= -1.f) && (LocalHitPoint.y <= 1.f))
{
// Step 4: look up the hit texel and check whether it's transparent or opaque
CVector2f TexCoord = (LocalHitPoint + CVector2f(1.f)) * 0.5f;
TexCoord.x = -TexCoord.x + 1.f;
float TexelAlpha = mpBillboard->ReadTexelAlpha(TexCoord);
if (TexelAlpha < 0.25f)
out.Hit = false;
else
{
// It's opaque... we have a hit!
out.Hit = true;
out.Distance = PlaneTest.second;
}
}
else else
out.Hit = false; {
// It's opaque... we have a hit!
out.Hit = true;
out.Distance = PlaneTest.second;
}
} }
else else
out.Hit = false; out.Hit = false;
} }
else
out.Hit = false;
} }
else out.Hit = false;
return out; return out;
} }

View File

@ -1,19 +0,0 @@
#ifndef EVISIBILITYFLAGS
#define EVISIBILITYFLAGS
#include <Common/EnumUtil.h>
enum EVisibilityFlags
{
eShowNomr = 0x00,
eShowWorld = 0x01,
eShowWorldCollision = 0x02,
eShowObjects = 0x04,
eShowObjectCollision = 0x08,
eShowLights = 0x10,
eShowAll = 0x1F
};
DEFINE_ENUM_FLAGS(EVisibilityFlags)
#endif // EVISIBILITYFLAGS

View File

@ -0,0 +1,3 @@
#include "FShowFlags.h"
const FShowFlags gkGameModeShowFlags = eShowWorld | eShowObjectGeometry | eShowSky;

View File

@ -0,0 +1,23 @@
#ifndef FSHOWFLAGS
#define FSHOWFLAGS
#include <Common/Flags.h>
enum EShowFlag
{
eShowNone = 0x00,
eShowWorld = 0x01,
eShowWorldCollision = 0x02,
eShowObjectGeometry = 0x04,
eShowObjectCollision = 0x08,
eShowObjects = 0x0C,
eShowLights = 0x10,
eShowSky = 0x20,
eShowAll = 0x3F
};
DECLARE_FLAGS(EShowFlag, FShowFlags)
extern const FShowFlags gkGameModeShowFlags;
#endif // FSHOWFLAGS

View File

@ -189,6 +189,9 @@ void CDamageableTriggerExtra::AddToRenderer(CRenderer *pRenderer, const SViewInf
if (ViewInfo.GameMode && !mpInstance->IsActive()) if (ViewInfo.GameMode && !mpInstance->IsActive())
return; return;
if ((ViewInfo.ShowFlags & eShowObjectGeometry) == 0)
return;
if (mRenderSide != eNoRender) if (mRenderSide != eNoRender)
{ {
if (ViewInfo.ViewFrustum.BoxInFrustum(AABox())) if (ViewInfo.ViewFrustum.BoxInFrustum(AABox()))

View File

@ -72,6 +72,7 @@ void CDoorExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
{ {
if (!mpShieldModel) return; if (!mpShieldModel) return;
if (ViewInfo.GameMode && !mpInstance->IsActive()) return; if (ViewInfo.GameMode && !mpInstance->IsActive()) return;
if ((ViewInfo.ShowFlags & eShowObjectGeometry) == 0) return;
if (mpParent->IsVisible() && ViewInfo.ViewFrustum.BoxInFrustum(AABox())) if (mpParent->IsVisible() && ViewInfo.ViewFrustum.BoxInFrustum(AABox()))
{ {

View File

@ -27,7 +27,7 @@ CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene,
void CRadiusSphereExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo) void CRadiusSphereExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo)
{ {
if (!rkViewInfo.GameMode && mpRadius && mpParent->IsVisible() && mpParent->IsSelected()) if (!rkViewInfo.GameMode && (rkViewInfo.ShowFlags & eShowObjectGeometry) && mpRadius && mpParent->IsVisible() && mpParent->IsSelected())
{ {
CAABox BoundingBox = Bounds(); CAABox BoundingBox = Bounds();

View File

@ -82,7 +82,7 @@ void CWaypointExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewIn
// won't work properly because we haven't finished loading the scene yet. // won't work properly because we haven't finished loading the scene yet.
if (!mLinksBuilt) BuildLinks(); if (!mLinksBuilt) BuildLinks();
if (!ViewInfo.GameMode && mpParent->IsVisible() && !mpParent->IsSelected()) if (!ViewInfo.GameMode && (ViewInfo.ShowFlags & eShowObjectGeometry) && mpParent->IsVisible() && !mpParent->IsSelected())
{ {
for (u32 iLink = 0; iLink < mLinks.size(); iLink++) for (u32 iLink = 0; iLink < mLinks.size(); iLink++)
{ {

View File

@ -17,6 +17,7 @@ CBasicViewport::CBasicViewport(QWidget *pParent) :
{ {
setMouseTracking(true); setMouseTracking(true);
mCamera.SetAspectRatio((float) width() / height()); mCamera.SetAspectRatio((float) width() / height());
mViewInfo.ShowFlags = eShowAll;
mViewInfo.pCamera = &mCamera; mViewInfo.pCamera = &mCamera;
mViewInfo.GameMode = false; mViewInfo.GameMode = false;
} }

View File

@ -9,7 +9,6 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
: CBasicViewport(pParent), : CBasicViewport(pParent),
mpEditor(nullptr), mpEditor(nullptr),
mpScene(nullptr), mpScene(nullptr),
mDrawSky(true),
mGizmoTransforming(false), mGizmoTransforming(false),
mpHoverNode(nullptr), mpHoverNode(nullptr),
mHoverPoint(CVector3f::skZero), mHoverPoint(CVector3f::skZero),
@ -22,6 +21,7 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
mViewInfo.pScene = mpScene; mViewInfo.pScene = mpScene;
mViewInfo.pRenderer = mpRenderer; mViewInfo.pRenderer = mpRenderer;
mViewInfo.ShowFlags = eShowWorld | eShowObjectGeometry | eShowLights | eShowSky;
CreateContextMenu(); CreateContextMenu();
} }
@ -37,9 +37,12 @@ void CSceneViewport::SetScene(INodeEditor *pEditor, CScene *pScene)
mpScene = pScene; mpScene = pScene;
} }
void CSceneViewport::SetSkyEnabled(bool b) void CSceneViewport::SetShowFlag(EShowFlag Flag, bool Visible)
{ {
mDrawSky = b; if (Visible)
mViewInfo.ShowFlags |= Flag;
else
mViewInfo.ShowFlags &= ~Flag;
} }
CRenderer* CSceneViewport::Renderer() CRenderer* CSceneViewport::Renderer()
@ -191,7 +194,7 @@ void CSceneViewport::Paint()
mpRenderer->BeginFrame(); mpRenderer->BeginFrame();
if (mDrawSky || mViewInfo.GameMode) if ((mViewInfo.ShowFlags & eShowSky) || mViewInfo.GameMode)
{ {
CModel *pSky = mpScene->GetActiveSkybox(); CModel *pSky = mpScene->GetActiveSkybox();
if (pSky) mpRenderer->RenderSky(pSky, mViewInfo); if (pSky) mpRenderer->RenderSky(pSky, mViewInfo);
@ -336,7 +339,7 @@ void CSceneViewport::OnHideLayer()
void CSceneViewport::OnUnhideAll() void CSceneViewport::OnUnhideAll()
{ {
// implement when scene iterator exists! // implement when scene iterator is implemented!
} }
void CSceneViewport::OnContextMenuClose() void CSceneViewport::OnContextMenuClose()

View File

@ -12,9 +12,6 @@ class CSceneViewport : public CBasicViewport
CScene *mpScene; CScene *mpScene;
CRenderer *mpRenderer; CRenderer *mpRenderer;
// Render settings
bool mDrawSky;
// Scene interaction // Scene interaction
bool mGizmoHovering; bool mGizmoHovering;
bool mGizmoTransforming; bool mGizmoTransforming;
@ -34,7 +31,11 @@ public:
CSceneViewport(QWidget *pParent = 0); CSceneViewport(QWidget *pParent = 0);
~CSceneViewport(); ~CSceneViewport();
void SetScene(INodeEditor *pEditor, CScene *pScene); void SetScene(INodeEditor *pEditor, CScene *pScene);
<<<<<<< Updated upstream
void SetSkyEnabled(bool b); void SetSkyEnabled(bool b);
=======
void SetShowFlag(EShowFlag Flag, bool Visible);
>>>>>>> Stashed changes
CRenderer* Renderer(); CRenderer* Renderer();
CSceneNode* HoverNode(); CSceneNode* HoverNode();
CVector3f HoverPoint(); CVector3f HoverPoint();

View File

@ -351,27 +351,27 @@ void CWorldEditor::OnTransformSpinBoxEdited(CVector3f)
// These functions are from "Go to slot" in the designer // These functions are from "Go to slot" in the designer
void CWorldEditor::on_ActionDrawWorld_triggered() void CWorldEditor::on_ActionDrawWorld_triggered()
{ {
ui->MainViewport->Renderer()->ToggleWorld(ui->ActionDrawWorld->isChecked()); ui->MainViewport->SetShowFlag(eShowWorld, ui->ActionDrawWorld->isChecked());
} }
void CWorldEditor::on_ActionDrawCollision_triggered() void CWorldEditor::on_ActionDrawCollision_triggered()
{ {
ui->MainViewport->Renderer()->ToggleWorldCollision(ui->ActionDrawCollision->isChecked()); ui->MainViewport->SetShowFlag(eShowWorldCollision, ui->ActionDrawCollision->isChecked());
} }
void CWorldEditor::on_ActionDrawObjects_triggered() void CWorldEditor::on_ActionDrawObjects_triggered()
{ {
ui->MainViewport->Renderer()->ToggleObjects(ui->ActionDrawObjects->isChecked()); ui->MainViewport->SetShowFlag(eShowObjectGeometry, ui->ActionDrawObjects->isChecked());
} }
void CWorldEditor::on_ActionDrawLights_triggered() void CWorldEditor::on_ActionDrawLights_triggered()
{ {
ui->MainViewport->Renderer()->ToggleLights(ui->ActionDrawLights->isChecked()); ui->MainViewport->SetShowFlag(eShowLights, ui->ActionDrawLights->isChecked());
} }
void CWorldEditor::on_ActionDrawSky_triggered() void CWorldEditor::on_ActionDrawSky_triggered()
{ {
ui->MainViewport->SetSkyEnabled(ui->ActionDrawSky->isChecked()); ui->MainViewport->SetShowFlag(eShowSky, ui->ActionDrawSky->isChecked());
} }
void CWorldEditor::on_ActionNoLighting_triggered() void CWorldEditor::on_ActionNoLighting_triggered()
@ -464,7 +464,7 @@ void CWorldEditor::on_ActionDecrementGizmo_triggered()
void CWorldEditor::on_ActionDrawObjectCollision_triggered() void CWorldEditor::on_ActionDrawObjectCollision_triggered()
{ {
ui->MainViewport->Renderer()->ToggleObjectCollision(ui->ActionDrawObjectCollision->isChecked()); ui->MainViewport->SetShowFlag(eShowObjectCollision, ui->ActionDrawObjectCollision->isChecked());
} }
void CWorldEditor::on_ActionGameMode_triggered() void CWorldEditor::on_ActionGameMode_triggered()

View File

@ -354,7 +354,7 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>1</number>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>