diff --git a/src/Core/Resource/CMaterial.cpp b/src/Core/Resource/CMaterial.cpp index f80ab1e0..e1ed6ac2 100644 --- a/src/Core/Resource/CMaterial.cpp +++ b/src/Core/Resource/CMaterial.cpp @@ -78,13 +78,16 @@ CMaterial* CMaterial::Clone() return pOut; } -void CMaterial::GenerateShader() +void CMaterial::GenerateShader(bool AllowRegen /*= true*/) { - delete mpShader; - mpShader = CShaderGenerator::GenerateShader(*this); + if (mShaderStatus != eShaderExists || AllowRegen) + { + delete mpShader; + mpShader = CShaderGenerator::GenerateShader(*this); - if (!mpShader->IsValidProgram()) mShaderStatus = eShaderFailed; - else mShaderStatus = eShaderExists; + if (!mpShader->IsValidProgram()) mShaderStatus = eShaderFailed; + else mShaderStatus = eShaderExists; + } } bool CMaterial::SetCurrent(FRenderOptions Options) diff --git a/src/Core/Resource/CMaterial.h b/src/Core/Resource/CMaterial.h index 5875a685..68b1623f 100644 --- a/src/Core/Resource/CMaterial.h +++ b/src/Core/Resource/CMaterial.h @@ -76,7 +76,7 @@ public: CMaterial(EGame version, FVertexDescription vtxDesc); ~CMaterial(); CMaterial* Clone(); - void GenerateShader(); + void GenerateShader(bool AllowRegen = true); bool SetCurrent(FRenderOptions Options); u64 HashParameters(); void Update(); diff --git a/src/Core/Resource/Model/CModel.cpp b/src/Core/Resource/Model/CModel.cpp index 7d207bd4..fbece173 100644 --- a/src/Core/Resource/Model/CModel.cpp +++ b/src/Core/Resource/Model/CModel.cpp @@ -75,6 +75,20 @@ void CModel::BufferGL() mBuffered = true; } +void CModel::GenerateMaterialShaders() +{ + for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++) + { + CMaterialSet *pSet = mMaterialSets[iSet]; + + for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++) + { + CMaterial *pMat = pSet->MaterialByIndex(iMat); + pMat->GenerateShader(false); + } + } +} + void CModel::ClearGLBuffer() { mVBO.Clear(); diff --git a/src/Core/Resource/Model/CModel.h b/src/Core/Resource/Model/CModel.h index 5ceaee2f..a60005ba 100644 --- a/src/Core/Resource/Model/CModel.h +++ b/src/Core/Resource/Model/CModel.h @@ -23,6 +23,7 @@ public: ~CModel(); void BufferGL(); + void GenerateMaterialShaders(); void ClearGLBuffer(); void Draw(FRenderOptions Options, u32 MatSet); void DrawSurface(FRenderOptions Options, u32 Surface, u32 MatSet); diff --git a/src/Core/Resource/Model/CStaticModel.cpp b/src/Core/Resource/Model/CStaticModel.cpp index 509dd9cb..4ada49d8 100644 --- a/src/Core/Resource/Model/CStaticModel.cpp +++ b/src/Core/Resource/Model/CStaticModel.cpp @@ -89,6 +89,12 @@ void CStaticModel::BufferGL() mBuffered = true; } +void CStaticModel::GenerateMaterialShaders() +{ + if (mpMaterial) + mpMaterial->GenerateShader(false); +} + void CStaticModel::ClearGLBuffer() { mVBO.Clear(); diff --git a/src/Core/Resource/Model/CStaticModel.h b/src/Core/Resource/Model/CStaticModel.h index b6ba40fc..de2be5b6 100644 --- a/src/Core/Resource/Model/CStaticModel.h +++ b/src/Core/Resource/Model/CStaticModel.h @@ -22,6 +22,7 @@ public: void AddSurface(SSurface *pSurface); void BufferGL(); + void GenerateMaterialShaders(); void ClearGLBuffer(); void Draw(FRenderOptions Options); void DrawSurface(FRenderOptions Options, u32 Surface); diff --git a/src/Core/Scene/CModelNode.cpp b/src/Core/Scene/CModelNode.cpp index 6decb1b7..f0d157ca 100644 --- a/src/Core/Scene/CModelNode.cpp +++ b/src/Core/Scene/CModelNode.cpp @@ -19,6 +19,15 @@ ENodeType CModelNode::NodeType() return eModelNode; } +void CModelNode::PostLoad() +{ + if (mpModel) + { + mpModel->BufferGL(); + mpModel->GenerateMaterialShaders(); + } +} + void CModelNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) { if (!mpModel) return; diff --git a/src/Core/Scene/CModelNode.h b/src/Core/Scene/CModelNode.h index 795994f4..edded4cf 100644 --- a/src/Core/Scene/CModelNode.h +++ b/src/Core/Scene/CModelNode.h @@ -18,6 +18,7 @@ public: explicit CModelNode(CScene *pScene, CSceneNode *pParent = 0, CModel *pModel = 0); virtual ENodeType NodeType(); + virtual void PostLoad(); virtual void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); virtual void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); virtual void DrawSelection(); diff --git a/src/Core/Scene/CScene.cpp b/src/Core/Scene/CScene.cpp index 633c9f61..d36e5479 100644 --- a/src/Core/Scene/CScene.cpp +++ b/src/Core/Scene/CScene.cpp @@ -1,4 +1,5 @@ #include "CScene.h" +#include "CSceneIterator.h" #include "Core/Render/CGraphics.h" #include "Core/Resource/CResCache.h" #include "Core/Resource/CPoiToWorld.h" @@ -14,6 +15,7 @@ CScene::CScene() : mSplitTerrain(true) + , mRanPostLoad(false) , mNumNodes(0) , mpSceneRootNode(new CRootNode(this, nullptr)) , mpArea(nullptr) @@ -177,6 +179,7 @@ void CScene::SetActiveArea(CGameArea *pArea) } } + mRanPostLoad = false; Log::Write( TString::FromInt32(CSceneNode::NumNodes()) + " nodes" ); } @@ -185,6 +188,12 @@ void CScene::SetActiveWorld(CWorld* pWorld) mpWorld = pWorld; } +void CScene::PostLoad() +{ + mpSceneRootNode->OnLoadFinished(); + mRanPostLoad = true; +} + void CScene::ClearScene() { if (mpAreaRootNode) @@ -202,6 +211,10 @@ void CScene::ClearScene() void CScene::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) { + // Call PostLoad the first time the scene is rendered to ensure the OpenGL context has been created before it runs. + if (!mRanPostLoad) + PostLoad(); + // Override show flags in game mode FShowFlags ShowFlags = (ViewInfo.GameMode ? gkGameModeShowFlags : ViewInfo.ShowFlags); FNodeFlags NodeFlags = NodeFlagsForShowFlags(ShowFlags); diff --git a/src/Core/Scene/CScene.h b/src/Core/Scene/CScene.h index 04fde572..8f2fa421 100644 --- a/src/Core/Scene/CScene.h +++ b/src/Core/Scene/CScene.h @@ -25,6 +25,7 @@ class CScene friend class CSceneIterator; bool mSplitTerrain; + bool mRanPostLoad; u32 mNumNodes; CRootNode *mpSceneRootNode; @@ -52,6 +53,7 @@ public: CLightNode* CreateLightNode(CLight *pLight); void SetActiveArea(CGameArea *pArea); void SetActiveWorld(CWorld *pWorld); + void PostLoad(); void ClearScene(); void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); SRayIntersection SceneRayCast(const CRay& rkRay, const SViewInfo& rkViewInfo); diff --git a/src/Core/Scene/CSceneIterator.h b/src/Core/Scene/CSceneIterator.h index 6c7e7f67..900a609b 100644 --- a/src/Core/Scene/CSceneIterator.h +++ b/src/Core/Scene/CSceneIterator.h @@ -36,6 +36,11 @@ public: return mpCurNode; } + inline operator bool() const + { + return DoneIterating(); + } + inline CSceneNode* operator*() const { return mpCurNode; diff --git a/src/Core/Scene/CSceneNode.cpp b/src/Core/Scene/CSceneNode.cpp index 6cfdfd87..8abf912f 100644 --- a/src/Core/Scene/CSceneNode.cpp +++ b/src/Core/Scene/CSceneNode.cpp @@ -80,6 +80,14 @@ CColor CSceneNode::WireframeColor() const } // ************ MAIN FUNCTIONALITY ************ +void CSceneNode::OnLoadFinished() +{ + PostLoad(); + + for (auto it = mChildren.begin(); it != mChildren.end(); it++) + (*it)->OnLoadFinished(); +} + void CSceneNode::Unparent() { // May eventually want to reset XForm so global position = local position diff --git a/src/Core/Scene/CSceneNode.h b/src/Core/Scene/CSceneNode.h index 3423e8af..f3b42ff4 100644 --- a/src/Core/Scene/CSceneNode.h +++ b/src/Core/Scene/CSceneNode.h @@ -67,6 +67,7 @@ public: virtual CColor TintColor(const SViewInfo& ViewInfo) const; virtual CColor WireframeColor() const; + void OnLoadFinished(); void Unparent(); void RemoveChild(CSceneNode *pChild); void DeleteChildren(); @@ -121,14 +122,8 @@ public: void SetVisible(bool Visible); // Static - static int NumNodes(); + inline static int NumNodes() { return smNumNodes; } static CColor skSelectionTint; }; -// ************ INLINE FUNCTIONS ************ -inline int CSceneNode::NumNodes() -{ - return smNumNodes; -} - #endif // CSCENENODE_H diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 41ec37d0..008e1fd8 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -74,6 +74,15 @@ ENodeType CScriptNode::NodeType() return eScriptNode; } +void CScriptNode::PostLoad() +{ + if (mpActiveModel) + { + mpActiveModel->BufferGL(); + mpActiveModel->GenerateMaterialShaders(); + } +} + void CScriptNode::OnTransformed() { if (mpInstance) diff --git a/src/Core/Scene/CScriptNode.h b/src/Core/Scene/CScriptNode.h index c4931897..aff1bdf8 100644 --- a/src/Core/Scene/CScriptNode.h +++ b/src/Core/Scene/CScriptNode.h @@ -27,6 +27,7 @@ class CScriptNode : public CSceneNode public: CScriptNode(CScene *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0); ENodeType NodeType(); + void PostLoad(); void OnTransformed(); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); diff --git a/src/Core/Scene/CStaticNode.cpp b/src/Core/Scene/CStaticNode.cpp index 99e5f9cf..581d21f1 100644 --- a/src/Core/Scene/CStaticNode.cpp +++ b/src/Core/Scene/CStaticNode.cpp @@ -19,6 +19,15 @@ ENodeType CStaticNode::NodeType() return eStaticNode; } +void CStaticNode::PostLoad() +{ + if (mpModel) + { + mpModel->BufferGL(); + mpModel->GenerateMaterialShaders(); + } +} + void CStaticNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo) { if (!mpModel) return; diff --git a/src/Core/Scene/CStaticNode.h b/src/Core/Scene/CStaticNode.h index bab0f96f..d328444c 100644 --- a/src/Core/Scene/CStaticNode.h +++ b/src/Core/Scene/CStaticNode.h @@ -11,6 +11,7 @@ class CStaticNode : public CSceneNode public: CStaticNode(CScene *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0); ENodeType NodeType(); + void PostLoad(); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); void DrawSelection();