diff --git a/src/Core/GameProject/CPackage.cpp b/src/Core/GameProject/CPackage.cpp index c80bcd94..f57d951d 100644 --- a/src/Core/GameProject/CPackage.cpp +++ b/src/Core/GameProject/CPackage.cpp @@ -49,7 +49,7 @@ void CPackage::Cook() CPackageDependencyListBuilder Builder(this); std::list AssetList; Builder.BuildDependencyList(true, AssetList); - Log::Write(TString::FromInt32(AssetList.size(), 0, 10) + " assets in pak"); + Log::Write(TString::FromInt32(AssetList.size(), 0, 10) + " assets in " + Name() + ".pak"); // Get named resources std::list NamedResources; @@ -207,6 +207,9 @@ void CPackage::Cook() mNeedsRecook = false; Save(); Log::Write("Finished writing " + PakPath.ToUTF8()); + + // Update resource store in case we recooked any assets + mpProject->ResourceStore()->ConditionalSaveStore(); } void CPackage::CompareOriginalAssetList(const std::list& rkNewList) diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index defb6f47..1427ada1 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -214,6 +214,8 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/) } // Resource has been saved; now make sure dependencies, cache data, and packages are all up to date + mFlags |= eREF_HasBeenModified; + UpdateDependencies(); mpStore->SetCacheDataDirty(); @@ -257,7 +259,11 @@ bool CResourceEntry::Cook() bool Success = CResourceCooker::CookResource(this, File); if (Success) - mFlags.ClearFlag(eREF_NeedsRecook); + { + mFlags &= ~eREF_NeedsRecook; + mFlags |= eREF_HasBeenModified; + mpStore->SetCacheDataDirty(); + } return Success; } @@ -281,6 +287,7 @@ CResource* CResourceEntry::Load() CXMLReader Reader(RawAssetPath()); mpResource->Serialize(Reader); + mpStore->TrackLoadedResource(this); gpResourceStore = pOldStore; } diff --git a/src/Core/GameProject/CResourceEntry.h b/src/Core/GameProject/CResourceEntry.h index 0f564758..24907f89 100644 --- a/src/Core/GameProject/CResourceEntry.h +++ b/src/Core/GameProject/CResourceEntry.h @@ -19,8 +19,9 @@ enum EResEntryFlag eREF_Transient = 0x00000002, // Resource is transient (not part of a game project resource DB) eREF_Hidden = 0x00000004, // Resource is hidden, doesn't show up in resource browser eREF_HasBeenModified = 0x00000008, // Resource has been modified and resaved by the user + eREF_IsUserResource = 0x00000010, // Resource was created by the user (i.e. isn't a Retro Studios asset) // Flags that save to the cache file - eREF_SavedFlags = eREF_NeedsRecook | eREF_Hidden | eREF_HasBeenModified + eREF_SavedFlags = eREF_NeedsRecook | eREF_Hidden | eREF_HasBeenModified | eREF_IsUserResource }; DECLARE_FLAGS(EResEntryFlag, FResEntryFlags) diff --git a/src/Core/GameProject/CResourceStore.cpp b/src/Core/GameProject/CResourceStore.cpp index 06187415..1c8598d6 100644 --- a/src/Core/GameProject/CResourceStore.cpp +++ b/src/Core/GameProject/CResourceStore.cpp @@ -14,6 +14,7 @@ using namespace tinyxml2; CResourceStore *gpResourceStore = nullptr; CResourceStore *gpEditorStore = nullptr; +// Constructor for editor store CResourceStore::CResourceStore(const TWideString& rkDatabasePath) : mpProj(nullptr) , mGame(eUnknownGame) @@ -26,6 +27,7 @@ CResourceStore::CResourceStore(const TWideString& rkDatabasePath) mDatabaseName = rkDatabasePath.GetFileName(); } +// Constructor for game exporter CResourceStore::CResourceStore(CGameProject *pProject, CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game) : mpProj(nullptr) , mGame(Game) @@ -38,6 +40,7 @@ CResourceStore::CResourceStore(CGameProject *pProject, CGameExporter *pExporter, SetProject(pProject); } +// Main constructor for game projects CResourceStore::CResourceStore(CGameProject *pProject) : mpProj(nullptr) , mGame(eUnknownGame) diff --git a/src/Core/OpenGL/CShader.cpp b/src/Core/OpenGL/CShader.cpp index 9d675c47..677ad75c 100644 --- a/src/Core/OpenGL/CShader.cpp +++ b/src/Core/OpenGL/CShader.cpp @@ -13,12 +13,14 @@ u64 gFailedCompileCount = 0; u64 gSuccessfulCompileCount = 0; CShader* CShader::spCurrentShader = nullptr; +int CShader::smNumShaders = 0; CShader::CShader() { mVertexShaderExists = false; mPixelShaderExists = false; mProgramExists = false; + smNumShaders++; } CShader::CShader(const char *pkVertexSource, const char *pkPixelSource) @@ -26,6 +28,7 @@ CShader::CShader(const char *pkVertexSource, const char *pkPixelSource) mVertexShaderExists = false; mPixelShaderExists = false; mProgramExists = false; + smNumShaders++; CompileVertexSource(pkVertexSource); CompilePixelSource(pkPixelSource); @@ -39,6 +42,7 @@ CShader::~CShader() if (mProgramExists) glDeleteProgram(mProgram); if (spCurrentShader == this) spCurrentShader = 0; + smNumShaders--; } bool CShader::CompileVertexSource(const char* pkSource) diff --git a/src/Core/OpenGL/CShader.h b/src/Core/OpenGL/CShader.h index 101996b3..edc1c762 100644 --- a/src/Core/OpenGL/CShader.h +++ b/src/Core/OpenGL/CShader.h @@ -23,6 +23,7 @@ class CShader GLint mTextureUniforms[8]; GLint mNumLightsUniform; + static int smNumShaders; static CShader* spCurrentShader; public: @@ -45,6 +46,8 @@ public: static CShader* CurrentShader(); static void KillCachedShader(); + inline static int NumShaders() { return smNumShaders; } + private: void CacheCommonUniforms(); void DumpShaderSource(GLuint Shader, const TString& rkOut); diff --git a/src/Core/Resource/CMaterial.cpp b/src/Core/Resource/CMaterial.cpp index bc163a24..ea40cbe5 100644 --- a/src/Core/Resource/CMaterial.cpp +++ b/src/Core/Resource/CMaterial.cpp @@ -11,6 +11,7 @@ u64 CMaterial::sCurrentMaterial = 0; CColor CMaterial::sCurrentTint = CColor::skWhite; +std::map CMaterial::smShaderMap; CMaterial::CMaterial() : mpShader(nullptr) @@ -64,7 +65,7 @@ CMaterial::~CMaterial() for (u32 iPass = 0; iPass < mPasses.size(); iPass++) delete mPasses[iPass]; - delete mpShader; + ClearShader(); } CMaterial* CMaterial::Clone() @@ -93,13 +94,65 @@ CMaterial* CMaterial::Clone() void CMaterial::GenerateShader(bool AllowRegen /*= true*/) { + HashParameters(); // Calling HashParameters() may change mShaderStatus so call it before checking + if (mShaderStatus != eShaderExists || AllowRegen) { - delete mpShader; - mpShader = CShaderGenerator::GenerateShader(*this); + auto Find = smShaderMap.find(mParametersHash); - if (!mpShader->IsValidProgram()) mShaderStatus = eShaderFailed; - else mShaderStatus = eShaderExists; + if (Find != smShaderMap.end()) + { + SMaterialShader& rShader = Find->second; + + if (rShader.pShader == mpShader) + return; + + ClearShader(); + mpShader = rShader.pShader; + rShader.NumReferences++; + } + + else + { + ClearShader(); + mpShader = CShaderGenerator::GenerateShader(*this); + + if (!mpShader->IsValidProgram()) + { + mShaderStatus = eShaderFailed; + delete mpShader; + mpShader = nullptr; + } + + else + { + mShaderStatus = eShaderExists; + smShaderMap[mParametersHash] = SMaterialShader { 1, mpShader }; + } + } + } +} + +void CMaterial::ClearShader() +{ + if (mpShader) + { + auto Find = smShaderMap.find(mParametersHash); + ASSERT(Find != smShaderMap.end()); + + SMaterialShader& rShader = Find->second; + ASSERT(rShader.pShader == mpShader); + + rShader.NumReferences--; + + if (rShader.NumReferences == 0) + { + delete mpShader; + smShaderMap.erase(Find); + } + + mpShader = nullptr; + mShaderStatus = eNoShader; } } @@ -206,7 +259,12 @@ u64 CMaterial::HashParameters() for (u32 iPass = 0; iPass < mPasses.size(); iPass++) mPasses[iPass]->HashParameters(Hash); - mParametersHash = Hash.GetHash64(); + u64 NewHash = Hash.GetHash64(); + + if (mParametersHash != NewHash) + ClearShader(); + + mParametersHash = NewHash; mRecalcHash = false; } diff --git a/src/Core/Resource/CMaterial.h b/src/Core/Resource/CMaterial.h index e0492d1b..eca9b298 100644 --- a/src/Core/Resource/CMaterial.h +++ b/src/Core/Resource/CMaterial.h @@ -72,6 +72,14 @@ private: std::vector mPasses; + // Reuse shaders between materials that have identical TEV setups + struct SMaterialShader + { + int NumReferences; + CShader *pShader; + }; + static std::map smShaderMap; + public: CMaterial(); CMaterial(EGame Version, FVertexDescription VtxDesc); @@ -79,6 +87,7 @@ public: CMaterial* Clone(); void GenerateShader(bool AllowRegen = true); + void ClearShader(); bool SetCurrent(FRenderOptions Options); u64 HashParameters(); void Update(); diff --git a/src/Core/Scene/CScene.cpp b/src/Core/Scene/CScene.cpp index 7ebc6d16..c3d3d41a 100644 --- a/src/Core/Scene/CScene.cpp +++ b/src/Core/Scene/CScene.cpp @@ -26,6 +26,7 @@ CScene::CScene() CScene::~CScene() { ClearScene(); + delete mpSceneRootNode; } bool CScene::IsNodeIDUsed(u32 ID) const diff --git a/src/Editor/CEditorApplication.cpp b/src/Editor/CEditorApplication.cpp index db547dd9..2a3f6f99 100644 --- a/src/Editor/CEditorApplication.cpp +++ b/src/Editor/CEditorApplication.cpp @@ -161,4 +161,6 @@ void CEditorApplication::OnEditorClose() mEditorWindows.removeOne(pEditor); delete pEditor; } + + CGameProject::ActiveProject()->ResourceStore()->DestroyUnreferencedResources(); } diff --git a/src/Editor/CProjectOverviewDialog.cpp b/src/Editor/CProjectOverviewDialog.cpp index d5993749..e16d8efa 100644 --- a/src/Editor/CProjectOverviewDialog.cpp +++ b/src/Editor/CProjectOverviewDialog.cpp @@ -22,6 +22,7 @@ CProjectOverviewDialog::CProjectOverviewDialog(QWidget *pParent) connect(mpUI->LaunchEditorButton, SIGNAL(clicked()), this, SLOT(LaunchEditor())); connect(mpUI->ViewResourcesButton, SIGNAL(clicked()), this, SLOT(LaunchResourceBrowser())); connect(mpUI->CookPackageButton, SIGNAL(clicked()), this, SLOT(CookPackage())); + connect(mpUI->CookAllDirtyPackagesButton, SIGNAL(clicked(bool)), this, SLOT(CookAllDirtyPackages())); connect(gpEdApp, SIGNAL(AssetsModified()), this, SLOT(SetupPackagesList())); } @@ -176,6 +177,7 @@ void CProjectOverviewDialog::LaunchEditor() void CProjectOverviewDialog::LaunchResourceBrowser() { gpEdApp->ResourceBrowser()->show(); + gpEdApp->ResourceBrowser()->raise(); } void CProjectOverviewDialog::CookPackage() @@ -183,4 +185,11 @@ void CProjectOverviewDialog::CookPackage() u32 PackageIdx = mpUI->PackagesList->currentRow(); CPackage *pPackage = mpProject->PackageByIndex(PackageIdx); pPackage->Cook(); + SetupPackagesList(); +} + +void CProjectOverviewDialog::CookAllDirtyPackages() +{ + gpEdApp->CookAllDirtyPackages(); + SetupPackagesList(); } diff --git a/src/Editor/CProjectOverviewDialog.h b/src/Editor/CProjectOverviewDialog.h index 72ef1a1d..8ebd4960 100644 --- a/src/Editor/CProjectOverviewDialog.h +++ b/src/Editor/CProjectOverviewDialog.h @@ -34,6 +34,7 @@ public slots: void LaunchEditor(); void LaunchResourceBrowser(); void CookPackage(); + void CookAllDirtyPackages(); void SetupWorldsList(); void SetupPackagesList(); diff --git a/src/Editor/CProjectOverviewDialog.ui b/src/Editor/CProjectOverviewDialog.ui index ec91e0bb..7598281c 100644 --- a/src/Editor/CProjectOverviewDialog.ui +++ b/src/Editor/CProjectOverviewDialog.ui @@ -125,6 +125,13 @@ + + + + Cook All Dirty Packages + + + diff --git a/src/Editor/CharacterEditor/CCharacterEditor.cpp b/src/Editor/CharacterEditor/CCharacterEditor.cpp index 4af2afa6..38cebdc8 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.cpp +++ b/src/Editor/CharacterEditor/CCharacterEditor.cpp @@ -45,7 +45,6 @@ CCharacterEditor::CCharacterEditor(CAnimSet *pSet, QWidget *parent) connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(OnViewportHoverBoneChanged(u32))); connect(ui->Viewport, SIGNAL(ViewportClick(QMouseEvent*)), this, SLOT(OnViewportClick())); - connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open())); connect(ui->ActionShowGrid, SIGNAL(toggled(bool)), this, SLOT(ToggleGrid(bool))); connect(ui->ActionShowMesh, SIGNAL(toggled(bool)), this, SLOT(ToggleMeshVisible(bool))); connect(ui->ActionShowSkeleton, SIGNAL(toggled(bool)), this, SLOT(ToggleSkeletonVisible(bool))); @@ -230,26 +229,6 @@ CCharacterEditorViewport* CCharacterEditor::Viewport() const } // ************ PUBLIC SLOTS ************ -void CCharacterEditor::Open() -{ - QString CharFilename = QFileDialog::getOpenFileName(this, "Open Character", "", "Animation Character Set (*.ANCS)"); - if (CharFilename.isEmpty()) return; - - CAnimSet *pSet = (CAnimSet*) gpResourceStore->LoadResource(CharFilename.toStdString()); - - if (pSet) - { - SetActiveAnimSet(pSet); - } - - else - { - QMessageBox::warning(this, "Error", "Couldn't load file: " + CharFilename); - } - - gpResourceStore->DestroyUnreferencedResources(); -} - void CCharacterEditor::ToggleGrid(bool Enable) { ui->Viewport->SetGridEnabled(Enable); diff --git a/src/Editor/CharacterEditor/CCharacterEditor.h b/src/Editor/CharacterEditor/CCharacterEditor.h index c3414598..ef67adaa 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.h +++ b/src/Editor/CharacterEditor/CCharacterEditor.h @@ -56,7 +56,6 @@ public: CCharacterEditorViewport* Viewport() const; public slots: - void Open(); void ToggleGrid(bool Enable); void ToggleMeshVisible(bool Visible); void ToggleSkeletonVisible(bool Visible); diff --git a/src/Editor/CharacterEditor/CCharacterEditor.ui b/src/Editor/CharacterEditor/CCharacterEditor.ui index 512bceab..461151b9 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.ui +++ b/src/Editor/CharacterEditor/CCharacterEditor.ui @@ -49,7 +49,7 @@ false - + @@ -312,12 +312,6 @@ 21 - - - File - - - Animation @@ -336,7 +330,6 @@ - @@ -350,29 +343,12 @@ false - - - - - - :/icons/Open_24px.png:/icons/Open_24px.png - - - Open - - - Open - - - Ctrl+O - - true diff --git a/src/Editor/ModelEditor/CModelEditorWindow.cpp b/src/Editor/ModelEditor/CModelEditorWindow.cpp index bf3c11e2..06bd5d02 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.cpp +++ b/src/Editor/ModelEditor/CModelEditorWindow.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -47,9 +46,7 @@ CModelEditorWindow::CModelEditorWindow(CModel *pModel, QWidget *pParent) // UI initialization UpdateAnimParamUI(-1); ui->IndTextureResSelector->SetAllowedExtensions("TXTR"); - ui->IndTextureResSelector->SetPreviewPanelEnabled(true); ui->PassTextureResSelector->SetAllowedExtensions("TXTR"); - ui->PassTextureResSelector->SetPreviewPanelEnabled(true); ui->PassTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); ui->PassTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); ui->ClearColorPicker->SetColor(QColor(76, 76, 76, 255)); @@ -94,10 +91,8 @@ CModelEditorWindow::CModelEditorWindow(CModel *pModel, QWidget *pParent) ui->AnimParamCSpinBox->setProperty ("ModelEditorWidgetType", eAnimParamCSpinBox); ui->AnimParamDSpinBox->setProperty ("ModelEditorWidgetType", eAnimParamDSpinBox); - connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open())); connect(ui->ActionImport, SIGNAL(triggered()), this, SLOT(Import())); connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save())); - connect(ui->ActionSaveAs, SIGNAL(triggered()), this, SLOT(SaveAs())); connect(ui->ActionConvertToDDS, SIGNAL(triggered()), this, SLOT(ConvertToDDS())); connect(ui->ActionConvertToTXTR, SIGNAL(triggered()), this, SLOT(ConvertToTXTR())); connect(ui->MeshPreviewButton, SIGNAL(clicked()), this, SLOT(SetMeshPreview())); @@ -152,6 +147,7 @@ CModelEditorWindow::CModelEditorWindow(CModel *pModel, QWidget *pParent) CModelEditorWindow::~CModelEditorWindow() { delete mpCurrentModelNode; + delete mpScene; delete ui; } @@ -236,9 +232,9 @@ void CModelEditorWindow::SetActiveMaterial(int MatIndex) ui->DestBlendComboBox->setCurrentIndex(DstFac); if (Settings & CMaterial::eIndStage) - ui->IndTextureResSelector->SetText(TO_QSTRING(mpCurrentMat->IndTexture()->FullSource())); + ui->IndTextureResSelector->SetResource(mpCurrentMat->IndTexture()); else - ui->IndTextureResSelector->SetText(""); + ui->IndTextureResSelector->Clear(); for (u32 iKonst = 0; iKonst < 4; iKonst++) { @@ -318,12 +314,7 @@ void CModelEditorWindow::SetActivePass(int PassIndex) else TexCoordSrc++; if (TexCoordSrc >= 5) TexCoordSrc -= 2; - CTexture *pPassTex = mpCurrentPass->Texture(); - if (pPassTex) - ui->PassTextureResSelector->SetText(TO_QSTRING(pPassTex->FullSource())); - else - ui->PassTextureResSelector->SetText(""); - + ui->PassTextureResSelector->SetResource(mpCurrentPass->Texture()); ui->TevKColorSelComboBox->setCurrentIndex(KColor); ui->TevKAlphaSelComboBox->setCurrentIndex(KAlpha); ui->TevRasSelComboBox->setCurrentIndex(Ras); @@ -715,22 +706,6 @@ void CModelEditorWindow::UpdateAnimParamUI(int Mode) } } -void CModelEditorWindow::Open() -{ - QString ModelFilename = QFileDialog::getOpenFileName(this, "Save model", "", "Retro Model (*.CMDL)"); - if (ModelFilename.isEmpty()) return; - - TResPtr pModel = gpResourceStore->LoadResource(ModelFilename.toStdString()); - if (pModel) - { - SetActiveModel(pModel); - SET_WINDOWTITLE_APPVARS("%APP_FULL_NAME% - Model Editor: " + TO_QSTRING(pModel->Source())); - mOutputFilename = TO_QSTRING(pModel->FullSource()); - } - - gpResourceStore->DestroyUnreferencedResources(); -} - void CModelEditorWindow::Import() { QString FileName = QFileDialog::getOpenFileName(this, "Model", "", "*.obj;*.fbx;*.dae;*.3ds;*.blend"); @@ -777,28 +752,10 @@ void CModelEditorWindow::Import() void CModelEditorWindow::Save() { if (!mpCurrentModel) return; + bool SaveSuccess = mpCurrentModel->Entry()->Save(); - if (mOutputFilename.isEmpty()) - { - SaveAs(); - return; - } - - CFileOutStream CMDLOut(mOutputFilename.toStdString(), IOUtil::eBigEndian); - CModelCooker::CookCMDL(mpCurrentModel, CMDLOut); - QMessageBox::information(this, "Saved", "Model saved!"); -} - -void CModelEditorWindow::SaveAs() -{ - QString FileName = QFileDialog::getSaveFileName(this, "Save model", "", "Retro Model (*.CMDL)"); - if (FileName.isEmpty()) return; - - mOutputFilename = FileName; - Save(); - - TString Name = TString(FileName.toStdString()); - SET_WINDOWTITLE_APPVARS("%APP_FULL_NAME% - Model Editor: " + TO_QSTRING(Name)); + if (SaveSuccess) + gpEdApp->NotifyAssetsModified(); } void CModelEditorWindow::ConvertToDDS() diff --git a/src/Editor/ModelEditor/CModelEditorWindow.h b/src/Editor/ModelEditor/CModelEditorWindow.h index c28cf06a..81c095db 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.h +++ b/src/Editor/ModelEditor/CModelEditorWindow.h @@ -17,6 +17,7 @@ namespace Ui { class CModelEditorWindow; } +// the model editor is messy and old as fuck, it needs a total rewrite class CModelEditorWindow : public IEditor { Q_OBJECT @@ -98,10 +99,8 @@ private: }; private slots: - void Open(); void Import(); void Save(); - void SaveAs(); void ConvertToDDS(); void ConvertToTXTR(); void SetMeshPreview(); diff --git a/src/Editor/ModelEditor/CModelEditorWindow.ui b/src/Editor/ModelEditor/CModelEditorWindow.ui index a96acd7c..acaa9dea 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.ui +++ b/src/Editor/ModelEditor/CModelEditorWindow.ui @@ -172,7 +172,7 @@ 0 - 0 + -489 308 1184 @@ -455,7 +455,7 @@ - + 1 @@ -1128,7 +1128,7 @@ - + 1 @@ -2399,7 +2399,6 @@ false - @@ -2415,12 +2414,8 @@ File - - - - @@ -2432,20 +2427,11 @@ - - - Open - - - - - Exit - - - Esc - - + + + :/icons/Save.png:/icons/Save.png + Save @@ -2455,21 +2441,11 @@ Export to DDS - - - Export curent model's textures - - Import - - - Save as... - - Convert DDS to TXTR @@ -2491,18 +2467,18 @@ ColorChanged(QColor) - - WResourceSelector - QWidget -
Editor/Widgets/WResourceSelector.h
- 1 -
CModelEditorViewport QWidget
Editor/ModelEditor/CModelEditorViewport.h
1
+ + CResourceSelector + QWidget +
Editor/Widgets/CResourceSelector.h
+ 1 +