diff options
author | hnOsmium0001 <[email protected]> | 2022-04-19 12:36:02 -0700 |
---|---|---|
committer | hnOsmium0001 <[email protected]> | 2022-04-19 12:36:02 -0700 |
commit | 497a0ddb2ab57f6c517543ca20ea1b8333214710 (patch) | |
tree | aa2b806837310e8abe8fdcc32a5b590496196e2b | |
parent | 2a5234a512c19582d261a7ccb692fc634dcb74f0 (diff) |
Add hardcoded dependencies for IresManager, migrate Shader to Ires
-rw-r--r-- | assets/.stationary/Shaders/Default.glsl (renamed from assets/Shaders/S_Default.glsl) | 0 | ||||
-rw-r--r-- | assets/Ires/M_BasicWall.json | 13 | ||||
-rw-r--r-- | assets/Ires/M_Default.json | 13 | ||||
-rw-r--r-- | assets/Ires/M_Player.json | 13 | ||||
-rw-r--r-- | assets/Ires/S_Default.json | 70 | ||||
-rw-r--r-- | assets/Shaders/S_Default.json | 65 | ||||
-rw-r--r-- | source/EditorCore.cpp | 99 | ||||
-rw-r--r-- | source/EditorCore.hpp | 4 | ||||
-rw-r--r-- | source/EditorUtils.hpp | 2 | ||||
-rw-r--r-- | source/Ires.cpp | 180 | ||||
-rw-r--r-- | source/Ires.hpp | 40 | ||||
-rw-r--r-- | source/Material.cpp | 250 | ||||
-rw-r--r-- | source/Material.hpp | 18 | ||||
-rw-r--r-- | source/Shader.cpp | 214 | ||||
-rw-r--r-- | source/Shader.hpp | 45 | ||||
-rw-r--r-- | source/Sprite.cpp | 16 | ||||
-rw-r--r-- | source/Sprite.hpp | 8 | ||||
-rw-r--r-- | source/Texture.cpp | 4 | ||||
-rw-r--r-- | source/Texture.hpp | 4 | ||||
-rw-r--r-- | source/main.cpp | 4 |
20 files changed, 552 insertions, 510 deletions
diff --git a/assets/Shaders/S_Default.glsl b/assets/.stationary/Shaders/Default.glsl index 1d93471..1d93471 100644 --- a/assets/Shaders/S_Default.glsl +++ b/assets/.stationary/Shaders/Default.glsl diff --git a/assets/Ires/M_BasicWall.json b/assets/Ires/M_BasicWall.json index 95cc7b9..a0e2395 100644 --- a/assets/Ires/M_BasicWall.json +++ b/assets/Ires/M_BasicWall.json @@ -1 +1,12 @@ -{"Type":"IresMaterial","Uid":[10768502134278852816,15014213992450765275],"Value":{"ShaderName":"S_Default","Fields":[{"Name":"taint","Type":"Vector","Value":[0.37144365906715393,0.5479920506477356,0.5784313678741455,1.0]}]}}
\ No newline at end of file +{ + "Type": "IresMaterial", + "Uid": [2568492772925683063, 3783268081215530432], + "Value": { + "Shader": [10239352483866045204, 2308094336962663863], + "Fields": [{ + "Name": "taint", + "Type": "Vector", + "Value": [0.03868706524372101, 0.6346951127052307, 0.7892156839370728, 0.0] + }] + } +}
\ No newline at end of file diff --git a/assets/Ires/M_Default.json b/assets/Ires/M_Default.json index daa1a60..0422e94 100644 --- a/assets/Ires/M_Default.json +++ b/assets/Ires/M_Default.json @@ -1 +1,12 @@ -{"Type":"IresMaterial","Uid":[12204622401017240396,7687764162748902358],"Value":{"ShaderName":"S_Default","Fields":[{"Name":"taint","Type":"Vector","Value":[1.0,1.0,1.0,0.0]}]}}
\ No newline at end of file +{ + "Type": "IresMaterial", + "Uid": [1173927873865027620, 6990602806197486151], + "Value": { + "Shader": [10239352483866045204, 2308094336962663863], + "Fields": [{ + "Name": "taint", + "Type": "Vector", + "Value": [1.0, 1.0, 1.0, 0.0] + }] + } +}
\ No newline at end of file diff --git a/assets/Ires/M_Player.json b/assets/Ires/M_Player.json index 4065cf8..b2494dc 100644 --- a/assets/Ires/M_Player.json +++ b/assets/Ires/M_Player.json @@ -1 +1,12 @@ -{"Type":"IresMaterial","Uid":[9758347138487553657,17909177141494883507],"Value":{"ShaderName":"S_Default","Fields":[{"Name":"taint","Type":"Vector","Value":[1.0,1.0,1.0,0.0]}]}}
\ No newline at end of file +{ + "Type": "IresMaterial", + "Uid": [8784140338803637141, 14601353797962284625], + "Value": { + "Shader": [10239352483866045204, 2308094336962663863], + "Fields": [{ + "Name": "taint", + "Type": "Vector", + "Value": [1.0, 1.0, 1.0, 0.0] + }] + } +}
\ No newline at end of file diff --git a/assets/Ires/S_Default.json b/assets/Ires/S_Default.json new file mode 100644 index 0000000..15c16d9 --- /dev/null +++ b/assets/Ires/S_Default.json @@ -0,0 +1,70 @@ +{ + "Type": "IresShader", + "Uid": [10239352483866045204, 2308094336962663863], + "Value": { + "SourceFile": ".stationary/Shaders/Default.glsl", + "Inputs": [ + { + "Semantic": "Position", + "Name": "pos", + "ScalarType": "float", + "Width": 1, + "Height": 3, + "OpenGLLocation": 0 + }, + { + "Semantic": "TexCoords1", + "Name": "texcoord", + "ScalarType": "float", + "Width": 1, + "Height": 2, + "OpenGLLocation": 1 + }, + { + "Semantic": "Color1", + "Name": "color", + "ScalarType": "float", + "Width": 1, + "Height": 4, + "OpenGLLocation": 2 + } + ], + "Outputs": [ + { + "Name": "fragColor", + "ScalarType": "float", + "Width": 1, + "Height": 4, + "OpenGLLocation": 0 + } + ], + "Uniforms": [ + { + "Type": "Math", + "AutoFill": true, + "Value": { + "Name": "transformation", + "ScalarType": "float", + "Width": 4, + "Height": 4 + } + }, + { + "Type": "Math", + "Value": { + "Name": "taint", + "Semantic": "Color1", + "ScalarType": "float", + "Width": 1, + "Height": 4 + } + }, + { + "Type": "Sampler", + "Value": { + "Name": "textureAtlas" + } + } + ] + } +}
\ No newline at end of file diff --git a/assets/Shaders/S_Default.json b/assets/Shaders/S_Default.json deleted file mode 100644 index df37792..0000000 --- a/assets/Shaders/S_Default.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "Inputs": [ - { - "Semantic": "Position", - "Name": "pos", - "ScalarType": "float", - "Width": 1, - "Height": 3, - "OpenGLLocation": 0 - }, - { - "Semantic": "TexCoords1", - "Name": "texcoord", - "ScalarType": "float", - "Width": 1, - "Height": 2, - "OpenGLLocation": 1 - }, - { - "Semantic": "Color1", - "Name": "color", - "ScalarType": "float", - "Width": 1, - "Height": 4, - "OpenGLLocation": 2 - } - ], - "Outputs": [ - { - "Name": "fragColor", - "ScalarType": "float", - "Width": 1, - "Height": 4, - "OpenGLLocation": 0 - } - ], - "Uniforms": [ - { - "Type": "Math", - "AutoFill": true, - "Value": { - "Name": "transformation", - "ScalarType": "float", - "Width": 4, - "Height": 4 - } - }, - { - "Type": "Math", - "Value": { - "Name": "taint", - "Semantic": "Color1", - "ScalarType": "float", - "Width": 1, - "Height": 4 - } - }, - { - "Type": "Sampler", - "Value": { - "Name": "textureAtlas" - } - } - ] -}
\ No newline at end of file diff --git a/source/EditorCore.cpp b/source/EditorCore.cpp index 1be6418..59da2b3 100644 --- a/source/EditorCore.cpp +++ b/source/EditorCore.cpp @@ -66,9 +66,6 @@ void EditorContentBrowser::Show(bool* open) { if (ImGui::Selectable("Settings", mPane == P_Settings)) { mPane = P_Settings; } - if (ImGui::Selectable("Shaders", mPane == P_Shader)) { - mPane = P_Shader; - } if (ImGui::Selectable("Ires", mPane == P_Ires)) { mPane = P_Ires; } @@ -83,37 +80,6 @@ void EditorContentBrowser::Show(bool* open) { ImGui::SliderFloat("Height", &mBrowserHeight, 0.1f, 1.0f); } break; - case P_Shader: { - if (ImGui::Button("Refresh")) { - // TODO reload shaders while keeping existing references working - } - ImGui::SameLine(); - if (ImGui::Button("Save all")) { - auto& shaders = ShaderManager::instance->GetShaders(); - for (auto&& [DISCARD, shader] : shaders) { - shader->SaveMetadataToFile(shader->GetDesignatedMetadataPath()); - } - } - - auto& shaders = ShaderManager::instance->GetShaders(); - for (auto it = shaders.begin(); it != shaders.end(); ++it) { - auto shader = it->second.Get(); - auto& name = shader->GetName(); - - bool selected = mInspector->selectedItPtr == shader; - if (ImGui::Selectable(name.c_str(), selected)) { - mInspector->SelectTarget(EditorInspector::ITT_Shader, shader); - } - - if (ImGui::BeginDragDropSource()) { - // Reason: intentionally using pointer as Fpayload - ImGui::SetDragDropPayload(BRUSSEL_TAG_Shader, &shader, sizeof(shader)); // NOLINT(bugprone-sizeof-expression) - ImGui::Text("Shader '%s'", name.c_str()); - ImGui::EndDragDropSource(); - } - } - } break; - case P_Ires: { auto itt = mInspector->selectedItt; auto itPtr = mInspector->selectedItPtr; @@ -251,20 +217,6 @@ void PushKeyCodeRecorder(App* app, int* writeKey, bool* writeKeyStatus) { return false; }); } - -void ShowShaderName(const Shader* shader) { - if (shader) { - auto& name = shader->GetName(); - bool isAnnoymous = name.empty(); - if (isAnnoymous) { - ImGui::Text("Shader <annoymous at %p>", (void*)shader); - } else { - ImGui::Text("Shader: %s", name.c_str()); - } - } else { - ImGui::TextUnformatted("Shader: <null>"); - } -} } // namespace ProjectBrussel_UNITY_ID EditorInstance::EditorInstance(App* app, GameWorld* world) @@ -297,10 +249,6 @@ void EditorInstance::Show() { ShowInspector(static_cast<GameObject*>(mEdInspector.selectedItPtr)); } break; - case EditorInspector::ITT_Shader: { - ShowInspector(static_cast<Shader*>(mEdInspector.selectedItPtr)); - } break; - case EditorInspector::ITT_Ires: { auto ires = static_cast<IresObject*>(mEdInspector.selectedItPtr); ShowInspector(ires); @@ -322,53 +270,6 @@ void EditorInstance::ShowWorldProperties() { // TOOD move resource-specific and gameobject-specific inspector code into attachments mechanism -void EditorInstance::ShowInspector(Shader* shader) { - using namespace Tags; - using namespace ProjectBrussel_UNITY_ID; - - EaShader* attachment; - if (auto ea = shader->GetEditorAttachment()) { - attachment = static_cast<EaShader*>(ea); - } else { - attachment = new EaShader(); - attachment->shader = shader; - shader->SetEditorAttachment(attachment); - } - - auto& info = shader->GetInfo(); - auto& name = shader->GetName(); - bool isAnnoymous = name.empty(); - ShowShaderName(shader); - - if (ImGui::Button("Reload metadata", isAnnoymous)) { - shader->LoadMetadataFromFile(shader->GetDesignatedMetadataPath()); - } - ImGui::SameLine(); - if (ImGui::Button("Save metadata", isAnnoymous)) { - shader->SaveMetadataToFile(shader->GetDesignatedMetadataPath()); - } - ImGui::SameLine(); - if (ImGui::Button("Gather info")) { - shader->GatherInfoShaderIntrospection(); - } - - if (ImGui::CollapsingHeader("Inputs")) { - for (auto& input : info.inputs) { - input.ShowInfo(); - } - } - if (ImGui::CollapsingHeader("Outputs")) { - for (auto& output : info.outputs) { - output.ShowInfo(); - } - } - if (ImGui::CollapsingHeader("Uniforms")) { - for (auto& uniform : info.uniforms) { - uniform->ShowInfo(); - } - } -} - void EditorInstance::ShowInspector(IresObject* ires) { ires->ShowEditor(*this); } diff --git a/source/EditorCore.hpp b/source/EditorCore.hpp index 84e42d0..13dc2d0 100644 --- a/source/EditorCore.hpp +++ b/source/EditorCore.hpp @@ -13,7 +13,6 @@ struct EditorInspector { enum TargetType { ITT_GameObject, - ITT_Shader, ITT_Ires, ITT_None, }; @@ -30,7 +29,6 @@ class EditorContentBrowser { private: enum Pane { P_Settings, - P_Shader, P_Ires, }; @@ -81,8 +79,6 @@ public: private: void ShowWorldProperties(); - void ShowInspector(Shader* shader); - void ShowInspector(Material* material); void ShowInspector(IresObject* ires); void ShowInspector(GameObject* object); diff --git a/source/EditorUtils.hpp b/source/EditorUtils.hpp index 6e152f6..67ffb0c 100644 --- a/source/EditorUtils.hpp +++ b/source/EditorUtils.hpp @@ -5,8 +5,6 @@ #include <imgui.h> #include <string> -#define BRUSSEL_TAG_Shader "Shader" -#define BRUSSEL_TAG_Material "Mat" // To check whether a payload is of this type, use starts_with() #define BRUSSEL_TAG_PREFIX_GameObject "GameObject" #define BRUSSEL_TAG_PREFIX_Ires "Ires" diff --git a/source/Ires.cpp b/source/Ires.cpp index 6b161d4..f60fcb7 100644 --- a/source/Ires.cpp +++ b/source/Ires.cpp @@ -7,6 +7,7 @@ #include "Material.hpp" #include "RapidJsonHelper.hpp" #include "ScopeGuard.hpp" +#include "Shader.hpp" #include "Sprite.hpp" #include "Texture.hpp" #include "Utils.hpp" @@ -16,8 +17,10 @@ #include <rapidjson/document.h> #include <rapidjson/filereadstream.h> #include <rapidjson/filewritestream.h> +#include <rapidjson/prettywriter.h> #include <rapidjson/writer.h> #include <algorithm> +#include <cassert> namespace fs = std::filesystem; using namespace std::literals; @@ -29,6 +32,7 @@ IresObject::IresObject(Kind kind) std::string_view IresObject::ToString(Kind kind) { switch (kind) { case KD_Texture: return BRUSSEL_TAG_PREFIX_Ires "Texture"sv; + case KD_Shader: return BRUSSEL_TAG_PREFIX_Ires "Shader"sv; case KD_Material: return BRUSSEL_TAG_PREFIX_Ires "Material"sv; case KD_SpriteFiles: return BRUSSEL_TAG_PREFIX_Ires "SpriteFiles"sv; case KD_Spritesheet: return BRUSSEL_TAG_PREFIX_Ires "Spritesheet"sv; @@ -39,6 +43,7 @@ std::string_view IresObject::ToString(Kind kind) { IresObject::Kind IresObject::FromString(std::string_view name) { if (name == BRUSSEL_TAG_PREFIX_Ires "Texture"sv) return KD_Texture; + if (name == BRUSSEL_TAG_PREFIX_Ires "Shader"sv) return KD_Shader; if (name == BRUSSEL_TAG_PREFIX_Ires "Material"sv) return KD_Material; if (name == BRUSSEL_TAG_PREFIX_Ires "SpriteFiles"sv) return KD_SpriteFiles; if (name == BRUSSEL_TAG_PREFIX_Ires "Spritesheet"sv) return KD_Spritesheet; @@ -48,6 +53,7 @@ IresObject::Kind IresObject::FromString(std::string_view name) { std::unique_ptr<IresObject> IresObject::Create(Kind kind) { switch (kind) { case KD_Texture: return std::make_unique<IresTexture>(); + case KD_Shader: return std::make_unique<IresShader>(); case KD_Material: return std::make_unique<IresMaterial>(); case KD_SpriteFiles: return std::make_unique<IresSpriteFiles>(); case KD_Spritesheet: return std::make_unique<IresSpritesheet>(); @@ -68,6 +74,10 @@ void IresObject::SetName(std::string name) { } } +void IresObject::ShowNullName(EditorInstance& editor, Kind kind) { + ImGui::Text("<null>"); +} + void IresObject::ShowName() const { if (IsAnnoymous()) { ImGui::Text("<annoymous %p>", (void*)this); @@ -84,6 +94,13 @@ void IresObject::ShowFullName() const { } } +void IresObject::ShowNullReference(EditorInstance& editor, Kind kind) { + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]); + ImGui::Text("<null>"); + ImGui::PopStyleColor(); + ImGui::AddUnderLine(ImGui::GetStyle().Colors[ImGuiCol_Button]); +} + void IresObject::ShowReference(EditorInstance& editor) { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]); if (IsAnnoymous()) { @@ -119,16 +136,29 @@ void IresObject::ShowEditor(EditorInstance& editor) { } } -void IresObject::WriteFull(IresObject* ires, rapidjson::Value& value, rapidjson::Document& root) { +void IresObject::WriteFull(IresWritingContext& ctx, IresObject* ires, rapidjson::Value& value, rapidjson::Document& root) { rapidjson::Value rvIres(rapidjson::kObjectType); - ires->Write(rvIres, root); + ires->Write(ctx, rvIres, root); value.AddMember("Type", rapidjson::StringRef(ToString(ires->GetKind())), root.GetAllocator()); value.AddMember("Uid", ires->mUid.Write(root), root.GetAllocator()); value.AddMember("Value", rvIres, root.GetAllocator()); } -std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value) { +std::unique_ptr<IresObject> IresObject::ReadFull(IresLoadingContext& ctx, const rapidjson::Value& value) { + auto ires = ReadBasic(value); + if (!ires) { + return nullptr; + } + + if (!ReadPartial(ctx, ires.get(), value)) { + return nullptr; + } + + return ires; +} + +std::unique_ptr<IresObject> IresObject::ReadBasic(const rapidjson::Value& value) { auto rvType = rapidjson::GetProperty(value, rapidjson::kStringType, "Type"sv); if (!rvType) return nullptr; auto kind = FromString(rapidjson::AsStringView(*rvType)); @@ -139,24 +169,20 @@ std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value) if (!rvUid) return nullptr; ires->mUid.Read(*rvUid); - if (!ReadPartial(ires.get(), value)) { - return nullptr; - } - return ires; } -bool IresObject::ReadPartial(IresObject* ires, const rapidjson::Value& value) { +bool IresObject::ReadPartial(IresLoadingContext& ctx, IresObject* ires, const rapidjson::Value& value) { auto rvValue = rapidjson::GetProperty(value, "Value"sv); if (!rvValue) return false; - ires->Read(*rvValue); + ires->Read(ctx, *rvValue); return true; } -void IresObject::Write(rapidjson::Value& value, rapidjson::Document& root) const { +void IresObject::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { } -void IresObject::Read(const rapidjson::Value& value) { +void IresObject::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { } void IresManager::DiscoverFilesDesignatedLocation() { @@ -165,8 +191,38 @@ void IresManager::DiscoverFilesDesignatedLocation() { } void IresManager::DiscoverFiles(const fs::path& dir) { - // NOTE: by default does not follow symlinks - // for (auto& item : fs::recursive_directory_iterator(dir)) { + struct LoadCandidate { + fs::path path; + rapidjson::Document data; + RcPtr<IresObject> ires; + }; + + class IresLoadTimeContext final : public IresLoadingContext { + public: + // NOTE: pointer stability required + robin_hood::unordered_node_map<Uid, LoadCandidate> candidates; + std::vector<std::vector<LoadCandidate*>> candidatesByKind; + + IresLoadTimeContext() { + candidatesByKind.resize(IresObject::KD_COUNT); + } + + std::vector<LoadCandidate*>& GetByKind(IresObject::Kind kind) { + int i = static_cast<int>(kind); + return candidatesByKind[i]; + } + + virtual IresObject* FindIres(const Uid& uid) const override { + auto iter = candidates.find(uid); + if (iter != candidates.end()) { + auto& cand = iter->second; + return cand.ires.Get(); + } else { + return nullptr; + } + } + } ctx; + for (auto& item : fs::directory_iterator(dir)) { if (!item.is_regular_file()) { continue; @@ -175,9 +231,62 @@ void IresManager::DiscoverFiles(const fs::path& dir) { continue; } - auto ires = Load(item.path()); + auto file = Utils::OpenCstdioFile(item.path(), Utils::Read); + if (!file) { + fprintf(stderr, "Ires file [" PLATFORM_PATH_STR "] Failed to open file.", item.path().c_str()); + continue; + } + DEFER { fclose(file); }; + + char readerBuffer[65536]; + rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + + rapidjson::Document root; + root.ParseStream(stream); + + auto ires = IresObject::ReadBasic(root); if (!ires) { - fprintf(stderr, "Failed to load Ires at '" PLATFORM_PATH_STR "'.", item.path().c_str()); + fprintf(stderr, "Ires file: [" PLATFORM_PATH_STR "] Failed to parse header.", item.path().c_str()); + continue; + } + + // Load name from filename + ires->mName = item.path().filename().replace_extension().string(); + auto& iresName = ires->mName; + + // Load uid should be handled by IresObject::ReadBasic + assert(!ires->mUid.IsNull()); + auto iresUid = ires->GetUid(); + + auto iresKind = ires->GetKind(); + + auto&& [iter, DISCARD] = ctx.candidates.try_emplace( + iresUid, + LoadCandidate{ + .path = item.path(), + .data = std::move(root), + .ires = RcPtr(ires.release()), + }); + auto& cand = iter->second; + + ctx.GetByKind(iresKind).push_back(&cand); + } + + // Load Ires in order by type, there are dependencies between them + // TODO full arbitary dependency between Ires + for (int i = 0; i < IresObject::KD_COUNT; ++i) { + auto kind = static_cast<IresObject::Kind>(i); + auto& list = ctx.GetByKind(kind); + for (auto cand : list) { + auto& ires = cand->ires; + + if (!IresObject::ReadPartial(ctx, ires.Get(), cand->data)) { + fprintf(stderr, "Ires file: [" PLATFORM_PATH_STR "] Failed to parse object data.", cand->path.c_str()); + continue; + } + + ires->mMan = this; + mObjByUid.try_emplace(ires->GetUid(), ires); } } } @@ -218,7 +327,7 @@ IresObject* IresManager::Load(const fs::path& filePath) { rapidjson::Document root; root.ParseStream(stream); - auto ires = IresObject::ReadFull(root); + auto ires = IresObject::ReadFull(*this, root); if (!ires) { return nullptr; } @@ -229,32 +338,24 @@ IresObject* IresManager::Load(const fs::path& filePath) { ires->mName = filePath.filename().replace_extension().string(); Add(ires.get()); - // TODO subdirectory support -#if 0 - auto iden = fs::path(filePath).replace_extension().lexically_relative(dir).string(); - std::replace(iden.begin(), iden.end(), '\\', '/'); - - std::string_view idenView(iden); - - // Trim heading slashes - while (idenView.front() == '/') { - idenView = std::string_view(idenView.data() + 1, idenView.size()); - } - // Trim trailing slashes - while (idenView.back() == '/') { - idenView = std::string_view(idenView.data(), idenView.size() - 1); - } -#endif - return ires.release(); } +static fs::path GetDesignatedPath(IresObject* ires) { + return AppConfig::assetDirPath / "Ires" / fs::path(ires->GetName()).replace_extension(".json"); +} + void IresManager::Delete(IresObject* ires) { // TODO } bool IresManager::Rename(IresObject* ires, std::string newName) { + auto oldPath = GetDesignatedPath(ires); ires->mName = std::move(newName); + auto newPath = GetDesignatedPath(ires); + if (fs::exists(oldPath)) { + fs::rename(oldPath, newPath); + } // TODO validate no name duplication #if 0 @@ -276,10 +377,6 @@ bool IresManager::Rename(IresObject* ires, std::string newName) { return true; } -static fs::path GetDesignatedPath(IresObject* ires) { - return AppConfig::assetDirPath / "Ires" / fs::path(ires->GetName()).replace_extension(".json"); -} - void IresManager::Reload(IresObject* ires) { auto file = Utils::OpenCstdioFile(GetDesignatedPath(ires), Utils::Read); if (!file) return; @@ -291,7 +388,7 @@ void IresManager::Reload(IresObject* ires) { rapidjson::Document root; root.ParseStream(stream); - IresObject::ReadPartial(ires, root); + IresObject::ReadPartial(*this, ires, root); } void IresManager::Save(IresObject* ires) { @@ -301,7 +398,7 @@ void IresManager::Save(IresObject* ires) { void IresManager::Save(IresObject* ires, const fs::path& filePath) { rapidjson::Document root(rapidjson::kObjectType); - IresObject::WriteFull(ires, root, root); + IresObject::WriteFull(*this, ires, root, root); auto file = Utils::OpenCstdioFile(filePath, Utils::WriteTruncate); if (!file) return; @@ -309,11 +406,12 @@ void IresManager::Save(IresObject* ires, const fs::path& filePath) { char writerBuffer[65536]; rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer)); - rapidjson::Writer<rapidjson::FileWriteStream> writer(stream); + rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(stream); + writer.SetFormatOptions(rapidjson::PrettyFormatOptions::kFormatSingleLineArray); root.Accept(writer); } -IresObject* IresManager::FindIres(const Uid& uid) { +IresObject* IresManager::FindIres(const Uid& uid) const { auto iter = mObjByUid.find(uid); if (iter != mObjByUid.end()) { return iter->second.Get(); diff --git a/source/Ires.hpp b/source/Ires.hpp index b6e351c..5875264 100644 --- a/source/Ires.hpp +++ b/source/Ires.hpp @@ -14,6 +14,8 @@ // Forward declarations class EditorInstance; class IresManager; +class IresWritingContext; +class IresLoadingContext; class IresObject : public RefCounted { friend class IresManager; @@ -21,6 +23,7 @@ class IresObject : public RefCounted { public: enum Kind { KD_Texture, + KD_Shader, KD_Material, KD_SpriteFiles, KD_Spritesheet, @@ -49,22 +52,45 @@ public: void SetName(std::string name); const Uid& GetUid() const { return mUid; } + static void ShowNullName(EditorInstance& editor, Kind kind); void ShowName() const; void ShowFullName() const; + + static void ShowNullReference(EditorInstance& editor, Kind kind); virtual void ShowReference(EditorInstance& editor); virtual void ShowEditor(EditorInstance& editor); EditorAttachment* GetEditorAttachment() const { return mEditorAttachment.get(); } void SetEditorAttachment(EditorAttachment* attachment) { mEditorAttachment.reset(attachment); } - static void WriteFull(IresObject* ires, rapidjson::Value& value, rapidjson::Document& root); - static std::unique_ptr<IresObject> ReadFull(const rapidjson::Value& value); - static bool ReadPartial(IresObject* ires, const rapidjson::Value& value); - virtual void Write(rapidjson::Value& value, rapidjson::Document& root) const; - virtual void Read(const rapidjson::Value& value); + static void WriteFull(IresWritingContext& ctx, IresObject* ires, rapidjson::Value& value, rapidjson::Document& root); + + /// Sequentially call ReadBasic() and then ReadPartial() + static std::unique_ptr<IresObject> ReadFull(IresLoadingContext& ctx, const rapidjson::Value& value); + /// Reads the type and UID of the object from data, and return a newly constructed Ires object. + static std::unique_ptr<IresObject> ReadBasic(const rapidjson::Value& value); + /// Reads all object-speific data from the root-level data object into the given Ires object. + static bool ReadPartial(IresLoadingContext& ctx, IresObject* ires, const rapidjson::Value& value); + + virtual void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const; + virtual void Read(IresLoadingContext& ctx, const rapidjson::Value& value); + +protected: + rapidjson::Value WriteIresRef(IresObject* object); +}; + +class IresWritingContext { +public: + virtual ~IresWritingContext() = default; +}; + +class IresLoadingContext { +public: + virtual ~IresLoadingContext() = default; + virtual IresObject* FindIres(const Uid& uid) const = 0; }; -class IresManager { +class IresManager final : public IresWritingContext, public IresLoadingContext { public: static inline IresManager* instance = nullptr; @@ -85,5 +111,5 @@ public: void Save(IresObject* ires, const std::filesystem::path& filePath); const auto& GetObjects() const { return mObjByUid; } - IresObject* FindIres(const Uid& uid); + virtual IresObject* FindIres(const Uid& uid) const override; }; diff --git a/source/Material.cpp b/source/Material.cpp index 0031ef8..abb2f57 100644 --- a/source/Material.cpp +++ b/source/Material.cpp @@ -319,17 +319,107 @@ void Material::UseUniforms() const { } } -bool Material::Write(rapidjson::Value& value, rapidjson::Document& root) const { +IresMaterial::IresMaterial() + : IresObject(KD_Material) + , mInstance(new Material()) { + mInstance->mIres = this; +} + +Material* IresMaterial::GetInstance() const { + return mInstance.Get(); +} + +void IresMaterial::InvalidateInstance() { + if (mInstance != nullptr) { + mInstance->mIres = nullptr; + } + mInstance.Attach(new Material()); + mInstance->mIres = this; +} + +void IresMaterial::ShowEditor(EditorInstance& editor) { + using namespace Tags; + + IresObject::ShowEditor(editor); + + auto shader = mInstance->GetShader(); + if (shader) { + shader->GetIres()->ShowReference(editor); + } else { + IresObject::ShowNullReference(editor, KD_Shader); + } + if (ImGui::BeginDragDropTarget()) { + if (auto payload = ImGui::AcceptDragDropPayload(ToString(KD_Shader).data())) { + auto shader = *static_cast<IresShader* const*>(payload->Data); + mInstance->SetShader(shader->GetInstance()); + } + ImGui::EndDragDropTarget(); + } + + if (!shader) return; + auto& shaderInfo = shader->GetInfo(); + auto shaderIres = shader->GetIres(); + + for (auto& field : mInstance->mBoundScalars) { + auto& decl = static_cast<ShaderMathVariable&>(*shaderInfo.uniforms[field.infoUniformIndex]); + decl.ShowInfo(); + + ImGui::Indent(); + switch (decl.scalarType) { + case GL_FLOAT: ImGui::InputFloat("##", &field.floatValue); break; + case GL_INT: ImGui::InputInt("##", &field.intValue); break; + // TODO proper uint edit? + case GL_UNSIGNED_INT: ImGui::InputInt("##", (int32_t*)(&field.uintValue), 0, std::numeric_limits<int32_t>::max()); break; + default: ImGui::TextUnformatted("Unsupported scalar type"); break; + } + ImGui::Unindent(); + } + for (auto& field : mInstance->mBoundVectors) { + auto& decl = static_cast<ShaderMathVariable&>(*shaderInfo.uniforms[field.infoUniformIndex]); + decl.ShowInfo(); + + ImGui::Indent(); + switch (decl.semantic) { + case VES_Color1: + case VES_Color2: { + ImGui::ColorEdit4("##", field.value); + } break; + + default: { + ImGui::InputFloat4("##", field.value); + } break; + } + ImGui::Unindent(); + } + for (auto& field : mInstance->mBoundMatrices) { + auto& decl = static_cast<ShaderMathVariable&>(*shaderInfo.uniforms[field.infoUniformIndex]); + decl.ShowInfo(); + + // TODO + } + for (auto& field : mInstance->mBoundTextures) { + auto& decl = static_cast<ShaderSamplerVariable&>(*shaderInfo.uniforms[field.infoUniformIndex]); + decl.ShowInfo(); + + // TODO + } +} + +void IresMaterial::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { using namespace ProjectBrussel_UNITY_ID; - if (!IsValid()) return false; + IresObject::Write(ctx, value, root); - auto& shaderInfo = mShader->GetInfo(); + if (!mInstance->IsValid()) { + return; + } - value.AddMember("ShaderName", mShader->GetName(), root.GetAllocator()); + auto& shaderInfo = mInstance->mShader->GetInfo(); + auto shaderUid = mInstance->mShader->GetIres()->GetUid(); + value.AddMember("Shader", shaderUid.Write(root), root.GetAllocator()); rapidjson::Value fields(rapidjson::kArrayType); - for (auto& scalar : mBoundScalars) { + for (auto& scalar : mInstance->mBoundScalars) { rapidjson::Value rvField(rapidjson::kObjectType); rvField.AddMember("Name", shaderInfo.uniforms[scalar.infoUniformIndex]->name, root.GetAllocator()); rvField.AddMember("Type", "Scalar", root.GetAllocator()); @@ -340,44 +430,50 @@ bool Material::Write(rapidjson::Value& value, rapidjson::Document& root) const { } fields.PushBack(rvField, root.GetAllocator()); } - for (auto& vector : mBoundVectors) { + for (auto& vector : mInstance->mBoundVectors) { rapidjson::Value rvField(rapidjson::kObjectType); rvField.AddMember("Name", shaderInfo.uniforms[vector.infoUniformIndex]->name, root.GetAllocator()); rvField.AddMember("Type", "Vector", root.GetAllocator()); rvField.AddMember("Value", MakeVectorJson(vector, root).Move(), root.GetAllocator()); fields.PushBack(rvField, root.GetAllocator()); } - for (auto& matrix : mBoundMatrices) { + for (auto& matrix : mInstance->mBoundMatrices) { rapidjson::Value rvField(rapidjson::kObjectType); rvField.AddMember("Name", shaderInfo.uniforms[matrix.infoUniformIndex]->name, root.GetAllocator()); rvField.AddMember("Type", "Matrix", root.GetAllocator()); rvField.AddMember("Value", MakeMatrixJson(matrix, root).Move(), root.GetAllocator()); fields.PushBack(rvField, root.GetAllocator()); } - for (auto& texture : mBoundTextures) { + for (auto& texture : mInstance->mBoundTextures) { // TODO } value.AddMember("Fields", fields, root.GetAllocator()); - - return true; } -bool Material::Read(const rapidjson::Value& value) { +void IresMaterial::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { using namespace ProjectBrussel_UNITY_ID; + IresObject::Read(ctx, value); + { - auto rvShaderName = rapidjson::GetProperty(value, rapidjson::kStringType, "ShaderName"sv); - if (!rvShaderName) return false; + auto rvShader = rapidjson::GetProperty(value, "Shader"sv); + if (!rvShader) return; + + Uid uid; + uid.Read(*rvShader); - auto shader = ShaderManager::instance->FindShader(rapidjson::AsStringView(*rvShaderName)); - if (!shader) return false; + auto ires = ctx.FindIres(uid); + if (!ires) return; + if (ires->GetKind() != KD_Shader) return; + auto shader = static_cast<IresShader*>(ires); - mShader.Attach(shader); + mInstance->mShader.Attach(shader->GetInstance()); } - auto& shaderInfo = mShader->GetInfo(); + auto shader = mInstance->mShader.Get(); + auto& shaderInfo = shader->GetInfo(); auto fields = rapidjson::GetProperty(value, rapidjson::kArrayType, "Fields"sv); - if (!fields) return false; + if (!fields) return; for (auto& rvField : fields->GetArray()) { if (!rvField.IsObject()) continue; @@ -391,9 +487,9 @@ bool Material::Read(const rapidjson::Value& value) { auto rvValue = rapidjson::GetProperty(rvField, "Value"sv); if (type == "Scalar"sv) { - ScalarUniform uniform; + Material::ScalarUniform uniform; if (rvName) { - TryFindShaderId(mShader.Get(), rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); + TryFindShaderId(shader, rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); uniform.location = shaderInfo.uniforms[uniform.infoUniformIndex]->location; } if (rvValue->IsFloat()) { @@ -406,127 +502,23 @@ bool Material::Read(const rapidjson::Value& value) { uniform.actualType = GL_UNSIGNED_INT; uniform.uintValue = rvValue->GetUint(); } - mBoundScalars.push_back(std::move(uniform)); + mInstance->mBoundScalars.push_back(std::move(uniform)); } else if (type == "Vector"sv) { auto uniform = ReadVectorFromJson(*rvValue); if (rvName) { - TryFindShaderId(mShader.Get(), rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); + TryFindShaderId(shader, rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); uniform.location = shaderInfo.uniforms[uniform.infoUniformIndex]->location; } - mBoundVectors.push_back(std::move(uniform)); + mInstance->mBoundVectors.push_back(std::move(uniform)); } else if (type == "Matrix"sv) { auto uniform = ReadMatrixFromjson(*rvValue); if (rvName) { - TryFindShaderId(mShader.Get(), rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); + TryFindShaderId(shader, rapidjson::AsStringView(*rvName), uniform.infoUniformIndex); uniform.location = shaderInfo.uniforms[uniform.infoUniformIndex]->location; } - mBoundMatrices.push_back(uniform); + mInstance->mBoundMatrices.push_back(uniform); } else if (type == "Texture"sv) { // TODO } } - - return true; -} - -IresMaterial::IresMaterial() - : IresObject(KD_Material) - , mInstance(new Material()) { -} - -Material* IresMaterial::GetInstance() const { - return mInstance.Get(); -} - -void IresMaterial::InvalidateInstance() { - mInstance.Attach(new Material()); -} - -void IresMaterial::ShowEditor(EditorInstance& editor) { - using namespace Tags; - - IresObject::ShowEditor(editor); - - auto shader = mInstance->GetShader(); - if (shader) { - auto& name = shader->GetName(); - bool isAnnoymous = name.empty(); - if (isAnnoymous) { - ImGui::Text("Shader <annoymous at %p>", (void*)shader); - } else { - ImGui::Text("Shader: %s", name.c_str()); - } - } else { - ImGui::TextUnformatted("Shader: <null>"); - } - if (ImGui::BeginDragDropTarget()) { - if (auto payload = ImGui::AcceptDragDropPayload(BRUSSEL_TAG_Shader)) { - auto shader = *static_cast<Shader* const*>(payload->Data); - mInstance->SetShader(shader); - } - ImGui::EndDragDropTarget(); - } - ImGui::SameLine(); - if (ImGui::Button("GoTo", shader == nullptr)) { - editor.GetInspector().SelectTarget(EditorInspector::ITT_Shader, shader); - } - - if (!shader) return; - auto& info = shader->GetInfo(); - - for (auto& field : mInstance->mBoundScalars) { - auto& decl = static_cast<ShaderMathVariable&>(*info.uniforms[field.infoUniformIndex]); - decl.ShowInfo(); - - ImGui::Indent(); - switch (decl.scalarType) { - case GL_FLOAT: ImGui::InputFloat("##", &field.floatValue); break; - case GL_INT: ImGui::InputInt("##", &field.intValue); break; - // TODO proper uint edit? - case GL_UNSIGNED_INT: ImGui::InputInt("##", (int32_t*)(&field.uintValue), 0, std::numeric_limits<int32_t>::max()); break; - default: ImGui::TextUnformatted("Unsupported scalar type"); break; - } - ImGui::Unindent(); - } - for (auto& field : mInstance->mBoundVectors) { - auto& decl = static_cast<ShaderMathVariable&>(*info.uniforms[field.infoUniformIndex]); - decl.ShowInfo(); - - ImGui::Indent(); - switch (decl.semantic) { - case VES_Color1: - case VES_Color2: { - ImGui::ColorEdit4("##", field.value); - } break; - - default: { - ImGui::InputFloat4("##", field.value); - } break; - } - ImGui::Unindent(); - } - for (auto& field : mInstance->mBoundMatrices) { - auto& decl = static_cast<ShaderMathVariable&>(*info.uniforms[field.infoUniformIndex]); - decl.ShowInfo(); - - // TODO - } - for (auto& field : mInstance->mBoundTextures) { - auto& decl = static_cast<ShaderSamplerVariable&>(*info.uniforms[field.infoUniformIndex]); - decl.ShowInfo(); - - // TODO - } -} - -void IresMaterial::Write(rapidjson::Value& value, rapidjson::Document& root) const { - IresObject::Write(value, root); - mInstance->Write(value, root); -} - -void IresMaterial::Read(const rapidjson::Value& value) { - InvalidateInstance(); - - IresObject::Read(value); - mInstance->Read(value); } diff --git a/source/Material.hpp b/source/Material.hpp index 7cf5603..623a022 100644 --- a/source/Material.hpp +++ b/source/Material.hpp @@ -15,8 +15,14 @@ #include <string_view> #include <vector> +// Forward declarations +class Material; +class IresMaterial; + class Material : public RefCounted { -public: // NOTE: public for internal helpers and editor + friend class IresMaterial; + +public: // NOTE: specialize between scalar vs matrix vs vector to save memory enum UniformType : uint16_t { @@ -62,6 +68,7 @@ public: // NOTE: public for internal helpers and editor /* Transient */ GLint location; }; + IresMaterial* mIres = nullptr; RcPtr<Shader> mShader; std::vector<ScalarUniform> mBoundScalars; std::vector<VectorUniform> mBoundVectors; @@ -91,12 +98,11 @@ public: Shader* GetShader() const; void SetShader(Shader* shader); + IresMaterial* GetIres() const { return mIres; } + bool IsValid() const; void UseUniforms() const; - - bool Write(rapidjson::Value& value, rapidjson::Document& root) const; - bool Read(const rapidjson::Value& value); }; class IresMaterial : public IresObject { @@ -111,6 +117,6 @@ public: void ShowEditor(EditorInstance& editor) override; - void Write(rapidjson::Value& value, rapidjson::Document& root) const override; - void Read(const rapidjson::Value& value) override; + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; }; diff --git a/source/Shader.cpp b/source/Shader.cpp index 61e80a1..fd68a0c 100644 --- a/source/Shader.cpp +++ b/source/Shader.cpp @@ -6,16 +6,13 @@ #include "Utils.hpp" #include <imgui.h> +#include <misc/cpp/imgui_stdlib.h> #include <rapidjson/document.h> -#include <rapidjson/filereadstream.h> -#include <rapidjson/filewritestream.h> -#include <rapidjson/writer.h> #include <cassert> #include <cstddef> #include <cstdlib> #include <utility> -namespace fs = std::filesystem; using namespace std::literals; void ShaderMathVariable::ShowInfo() const { @@ -70,8 +67,7 @@ ShaderVariable* ShaderInfo::FindVariable(const ShaderThingId& thing) { return nullptr; } -Shader::Shader(std::string name) - : mName{ name } { +Shader::Shader() { } Shader::~Shader() { @@ -304,14 +300,6 @@ Shader::ErrorCode Shader::InitFromSource(std::string_view source) { #undef CATCH_ERROR -void Shader::GetDesignatedMetadataPath(char* buffer, int bufferSize) { - snprintf(buffer, bufferSize, "%s/Shaders/%s.json", AppConfig::assetDir.c_str(), mName.c_str()); -} - -fs::path Shader::GetDesignatedMetadataPath() { - return AppConfig::assetDirPath / "Shaders" / fs::path(mName).replace_extension(".json"); -} - namespace ProjectBrussel_UNITY_ID { bool QueryMathInfo(GLenum type, GLenum& scalarType, int& width, int& height) { auto DoOutput = [&](GLenum scalarTypeIn, int widthIn, int heightIn) { @@ -508,10 +496,6 @@ bool Shader::GatherInfoShaderIntrospection() { return true; } -bool Shader::IsAnnoymous() const { - return mName.empty(); -} - bool Shader::IsValid() const { return mProgram != 0; } @@ -570,10 +554,70 @@ bool ReadShaderSamplerVariable(const rapidjson::Value& value, ShaderSamplerVaria } } // namespace ProjectBrussel_UNITY_ID -bool Shader::SaveMetadataToFile(const fs::path& filePath) const { +IresShader::IresShader() + : IresObject(KD_Shader) { + InvalidateInstance(); +} + +Shader* IresShader::GetInstance() const { + return mInstance.Get(); +} + +void IresShader::InvalidateInstance() { + if (mInstance != nullptr) { + mInstance->mIres = nullptr; + } + mInstance.Attach(new Shader()); + mInstance->mIres = this; +} + +void IresShader::ShowEditor(EditorInstance& editor) { + using namespace Tags; + + IresObject::ShowEditor(editor); + + if (ImGui::Button("Gather info")) { + mInstance->GatherInfoShaderIntrospection(); + } + + if (ImGui::InputText("Source file", &mSourceFile, ImGuiInputTextFlags_EnterReturnsTrue)) { + InvalidateInstance(); + } + // In other cases, mSourceFile will be reverted to before edit + + // TODO macros + + ImGui::Separator(); + + auto& info = mInstance->GetInfo(); + if (ImGui::CollapsingHeader("General")) { + ImGui::Text("OpenGL program ID: %u", mInstance->GetProgram()); + } + if (ImGui::CollapsingHeader("Inputs")) { + for (auto& input : info.inputs) { + input.ShowInfo(); + } + } + if (ImGui::CollapsingHeader("Outputs")) { + for (auto& output : info.outputs) { + output.ShowInfo(); + } + } + if (ImGui::CollapsingHeader("Uniforms")) { + for (auto& uniform : info.uniforms) { + uniform->ShowInfo(); + } + } +} + +void IresShader::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { using namespace ProjectBrussel_UNITY_ID; - rapidjson::Document root(rapidjson::kObjectType); + IresObject::Write(ctx, value, root); + + auto& shaderInfo = mInstance->mInfo; + + value.AddMember("SourceFile", mSourceFile, root.GetAllocator()); auto SaveMathVars = [&](const char* name, const std::vector<ShaderMathVariable>& vars) { rapidjson::Value rvThings(rapidjson::kArrayType); @@ -583,42 +627,52 @@ bool Shader::SaveMetadataToFile(const fs::path& filePath) const { rvThings.PushBack(rvThing, root.GetAllocator()); } - root.AddMember(rapidjson::StringRef(name), rvThings, root.GetAllocator()); + value.AddMember(rapidjson::StringRef(name), rvThings, root.GetAllocator()); }; - SaveMathVars("Inputs", mInfo.inputs); - SaveMathVars("Outputs", mInfo.outputs); + SaveMathVars("Inputs", shaderInfo.inputs); + SaveMathVars("Outputs", shaderInfo.outputs); // TODO uniforms +} - auto file = Utils::OpenCstdioFile(filePath, Utils::WriteTruncate); - if (!file) return false; - DEFER { fclose(file); }; +void IresShader::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { + using namespace ProjectBrussel_UNITY_ID; - char writerBuffer[65536]; - rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer)); - rapidjson::Writer<rapidjson::FileWriteStream> writer(stream); - root.Accept(writer); + IresObject::Read(ctx, value); - return true; -} + auto rvSourceFile = rapidjson::GetProperty(value, rapidjson::kStringType, "SourceFile"sv); + if (!rvSourceFile) { + return; + } else { + this->mSourceFile = rapidjson::AsString(*rvSourceFile); -bool Shader::LoadMetadataFromFile(const fs::path& filePath) { - using namespace ProjectBrussel_UNITY_ID; + char shaderFilePath[256]; + snprintf(shaderFilePath, sizeof(shaderFilePath), "%s/%s", AppConfig::assetDir.c_str(), rvSourceFile->GetString()); - mInfo = {}; + auto shaderFile = Utils::OpenCstdioFile(shaderFilePath, Utils::Read); + if (!shaderFile) return; + DEFER { fclose(shaderFile); }; + + fseek(shaderFile, 0, SEEK_END); + auto shaderFileSize = ftell(shaderFile); + rewind(shaderFile); - auto file = Utils::OpenCstdioFile(filePath, Utils::Read); - if (!file) return false; - DEFER { fclose(file); }; + // Also add \0 ourselves + auto buffer = std::make_unique<char[]>(shaderFileSize + 1); + fread(buffer.get(), shaderFileSize, 1, shaderFile); + buffer[shaderFileSize] = '\0'; + std::string_view source(buffer.get(), shaderFileSize); - char readerBuffer[65536]; - rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + if (mInstance->InitFromSource(source) != Shader::EC_Success) { + return; + } + } - rapidjson::Document root; - root.ParseStream(stream); + auto& shaderInfo = mInstance->mInfo; + auto shaderProgram = mInstance->GetProgram(); auto LoadMathVars = [&](std::string_view name, ShaderThingId::Kind kind, std::vector<ShaderMathVariable>& vars) { - auto rvThings = rapidjson::GetProperty(root, rapidjson::kArrayType, name); + auto rvThings = rapidjson::GetProperty(value, rapidjson::kArrayType, name); if (!rvThings) return; for (auto& rv : rvThings->GetArray()) { @@ -626,15 +680,15 @@ bool Shader::LoadMetadataFromFile(const fs::path& filePath) { ShaderMathVariable thing; ReadShaderMathVariable(rv, thing); - mInfo.things.try_emplace(thing.name, ShaderThingId{ kind, (int)vars.size() }); + shaderInfo.things.try_emplace(thing.name, ShaderThingId{ kind, (int)vars.size() }); vars.push_back(std::move(thing)); } }; - LoadMathVars("Inputs"sv, ShaderThingId::KD_Input, mInfo.inputs); - LoadMathVars("Outputs"sv, ShaderThingId::KD_Output, mInfo.outputs); + LoadMathVars("Inputs"sv, ShaderThingId::KD_Input, shaderInfo.inputs); + LoadMathVars("Outputs"sv, ShaderThingId::KD_Output, shaderInfo.outputs); - auto rvUniforms = rapidjson::GetProperty(root, rapidjson::kArrayType, "Uniforms"sv); - if (!rvUniforms) return false; + auto rvUniforms = rapidjson::GetProperty(value, rapidjson::kArrayType, "Uniforms"sv); + if (!rvUniforms) return; for (auto& rvUniform : rvUniforms->GetArray()) { if (!rvUniform.IsObject()) continue; @@ -665,68 +719,12 @@ bool Shader::LoadMetadataFromFile(const fs::path& filePath) { return nullptr; }(); if (uniform) { - mInfo.things.try_emplace(uniform->name, ShaderThingId{ ShaderThingId::KD_Uniform, (int)mInfo.uniforms.size() }); - mInfo.uniforms.emplace_back(std::move(uniform)); - } - } - - for (auto& uniform : mInfo.uniforms) { - uniform->location = glGetUniformLocation(mProgram, uniform->name.c_str()); - } - - return true; -} - -void ShaderManager::DiscoverShaders() { - mShaders.clear(); - - auto path = AppConfig::assetDirPath / "Shaders"; - if (!fs::exists(path)) { - return; - } - - for (auto& item : fs::directory_iterator(path)) { - if (item.is_regular_file() && item.path().extension() == ".glsl") { - auto shaderFile = Utils::OpenCstdioFile(item.path(), Utils::Read); - if (!shaderFile) continue; - DEFER { fclose(shaderFile); }; - - fseek(shaderFile, 0, SEEK_END); - auto shaderFileSize = ftell(shaderFile); - rewind(shaderFile); - - // Also add \0 ourselves - auto buffer = std::make_unique<char[]>(shaderFileSize + 1); - fread(buffer.get(), shaderFileSize, 1, shaderFile); - buffer[shaderFileSize] = '\0'; - std::string_view source(buffer.get(), shaderFileSize); - - RcPtr shader(new Shader(item.path().stem().string())); - std::string_view shaderName(shader->GetName()); - - // Load shader - auto err = shader->InitFromSource(source); - if (err != Shader::EC_Success) { - continue; - } - - // Load shader info if present - fs::path infoPath(item.path()); - infoPath.replace_extension(".json"); - if (fs::exists(infoPath)) { - shader->LoadMetadataFromFile(infoPath); - } - - mShaders.try_emplace(shaderName, std::move(shader)); + shaderInfo.things.try_emplace(uniform->name, ShaderThingId{ ShaderThingId::KD_Uniform, (int)shaderInfo.uniforms.size() }); + shaderInfo.uniforms.emplace_back(std::move(uniform)); } } -} -Shader* ShaderManager::FindShader(std::string_view name) { - auto iter = mShaders.find(name); - if (iter != mShaders.end()) { - return iter->second.Get(); - } else { - return nullptr; + for (auto& uniform : shaderInfo.uniforms) { + uniform->location = glGetUniformLocation(shaderProgram, uniform->name.c_str()); } } diff --git a/source/Shader.hpp b/source/Shader.hpp index 7ad2bbb..fefa67c 100644 --- a/source/Shader.hpp +++ b/source/Shader.hpp @@ -1,22 +1,21 @@ #pragma once -#include "EditorAttachment.hpp" #include "GraphicsTags.hpp" +#include "Ires.hpp" #include "RcPtr.hpp" #include "Utils.hpp" #include <glad/glad.h> #include <robin_hood.h> -#include <filesystem> #include <memory> #include <string_view> #include <vector> // TODO move to variable after pattern matching is in the language -// TODO migrate shader editor to Ires // Forward declarations class Shader; +class IresShader; struct ShaderVariable { enum Kind { @@ -84,10 +83,11 @@ struct ShaderInfo { }; class Shader : public RefCounted { + friend class IresShader; + private: - std::string mName; + IresShader* mIres = nullptr; ShaderInfo mInfo; - std::unique_ptr<EditorAttachment> mEditorAttachment; GLuint mProgram = 0; public: @@ -96,7 +96,7 @@ public: GLuint autofillLoc_DeltaTime = Tags::kInvalidLocation; public: - Shader(std::string name = ""); + Shader(); ~Shader(); Shader(const Shader&) = delete; Shader& operator=(const Shader&) = delete; @@ -139,38 +139,31 @@ public: /// - `#type fragment`: Fragment shader ErrorCode InitFromSource(std::string_view source); - EditorAttachment* GetEditorAttachment() const { return mEditorAttachment.get(); } - void SetEditorAttachment(EditorAttachment* attachment) { mEditorAttachment.reset(attachment); } - - void GetDesignatedMetadataPath(char* buffer, int bufferSize); - std::filesystem::path GetDesignatedMetadataPath(); - /// Rebuild info object using OpenGL shader introspection API. Requires OpenGL 4.3 or above. Overrides existing info object. bool GatherInfoShaderIntrospection(); const ShaderInfo& GetInfo() const { return mInfo; } ShaderInfo& GetInfo() { return mInfo; } /// If not empty, this name must not duplicate with any other shader object in the process. - const std::string& GetName() const { return mName; } GLuint GetProgram() const { return mProgram; } - bool IsAnnoymous() const; - bool IsValid() const; + IresShader* GetIres() const { return mIres; } - bool SaveMetadataToFile(const std::filesystem::path& filePath) const; - /// Overrides existing info object. - bool LoadMetadataFromFile(const std::filesystem::path& filePath); + bool IsValid() const; }; -class ShaderManager { -public: - static inline ShaderManager* instance = nullptr; - +class IresShader : public IresObject { private: - robin_hood::unordered_map<std::string_view, RcPtr<Shader>> mShaders; + RcPtr<Shader> mInstance; + std::string mSourceFile; public: - void DiscoverShaders(); + IresShader(); + + Shader* GetInstance() const; + void InvalidateInstance(); + + void ShowEditor(EditorInstance& editor) override; - const auto& GetShaders() const { return mShaders; } - Shader* FindShader(std::string_view name); + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; }; diff --git a/source/Sprite.cpp b/source/Sprite.cpp index d539452..876b75a 100644 --- a/source/Sprite.cpp +++ b/source/Sprite.cpp @@ -69,15 +69,15 @@ void IresSpriteFiles::InvalidateInstance() { mInstance.Attach(nullptr); } -void IresSpriteFiles::Write(rapidjson::Value& value, rapidjson::Document& root) const { - IresObject::Write(value, root); +void IresSpriteFiles::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { + IresObject::Write(ctx, value, root); value.AddMember("Sprites", rapidjson::WriteVectorPrimitives(root, spriteFiles.begin(), spriteFiles.end()), root.GetAllocator()); } -void IresSpriteFiles::Read(const rapidjson::Value& value) { +void IresSpriteFiles::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { InvalidateInstance(); - IresObject::Read(value); + IresObject::Read(ctx, value); auto rvFileList = rapidjson::GetProperty(value, rapidjson::kArrayType, "Sprites"sv); if (!rvFileList) return; @@ -261,8 +261,8 @@ void IresSpritesheet::ShowEditor(EditorInstance& editor) { } } -void IresSpritesheet::Write(rapidjson::Value& value, rapidjson::Document& root) const { - IresObject::Write(value, root); +void IresSpritesheet::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { + IresObject::Write(ctx, value, root); value.AddMember("SpriteSheet", spritesheetFile, root.GetAllocator()); value.AddMember("WSplit", sheetWSplit, root.GetAllocator()); value.AddMember("HSplit", sheetHSplit, root.GetAllocator()); @@ -271,10 +271,10 @@ void IresSpritesheet::Write(rapidjson::Value& value, rapidjson::Document& root) } } -void IresSpritesheet::Read(const rapidjson::Value& value) { +void IresSpritesheet::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { InvalidateInstance(); - IresObject::Read(value); + IresObject::Read(ctx, value); BRUSSEL_JSON_GET(value, "SpriteSheet", std::string, spritesheetFile, return ); BRUSSEL_JSON_GET(value, "WSplit", int, sheetWSplit, return ); BRUSSEL_JSON_GET(value, "HSplit", int, sheetHSplit, return ); diff --git a/source/Sprite.hpp b/source/Sprite.hpp index d9fb612..b7d357f 100644 --- a/source/Sprite.hpp +++ b/source/Sprite.hpp @@ -45,8 +45,8 @@ public: Sprite* GetInstance(); void InvalidateInstance(); - void Write(rapidjson::Value& value, rapidjson::Document& root) const override; - void Read(const rapidjson::Value& value) override; + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; }; class IresSpritesheet : public IresObject { @@ -75,8 +75,8 @@ public: void ShowEditor(EditorInstance& editor) override; - void Write(rapidjson::Value& value, rapidjson::Document& root) const override; - void Read(const rapidjson::Value& value) override; + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; }; class SpriteMesh { diff --git a/source/Texture.cpp b/source/Texture.cpp index 8fd74ac..8fb657a 100644 --- a/source/Texture.cpp +++ b/source/Texture.cpp @@ -238,10 +238,10 @@ Texture* IresTexture::GetInstance() { return mInstance.Get(); } -void IresTexture::Write(rapidjson::Value& value, rapidjson::Document& root) const { +void IresTexture::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { // TODO } -void IresTexture::Read(const rapidjson::Value& value) { +void IresTexture::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { // TODO } diff --git a/source/Texture.hpp b/source/Texture.hpp index ef4d136..108dfa7 100644 --- a/source/Texture.hpp +++ b/source/Texture.hpp @@ -94,6 +94,6 @@ public: Texture* CreateInstance() const; Texture* GetInstance(); - void Write(rapidjson::Value& value, rapidjson::Document& root) const override; - void Read(const rapidjson::Value& value) override; + void Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const override; + void Read(IresLoadingContext& ctx, const rapidjson::Value& value) override; }; diff --git a/source/main.cpp b/source/main.cpp index dc644ba..b166754 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -4,7 +4,6 @@ #include "EditorNotification.hpp" #include "Ires.hpp" #include "Mesh.hpp" -#include "Shader.hpp" #define GLFW_INCLUDE_NONE #include <GLFW/glfw3.h> @@ -170,10 +169,7 @@ int main(int argc, char* argv[]) { ImGui_ImplOpenGL2_Init(); } - ShaderManager::instance = new ShaderManager(); IresManager::instance = new IresManager(); - - ShaderManager::instance->DiscoverShaders(); IresManager::instance->DiscoverFilesDesignatedLocation(); gVformatStandard.Attach(new VertexFormat()); |