aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhnOsmium0001 <[email protected]>2022-04-19 12:36:02 -0700
committerhnOsmium0001 <[email protected]>2022-04-19 12:36:02 -0700
commit497a0ddb2ab57f6c517543ca20ea1b8333214710 (patch)
treeaa2b806837310e8abe8fdcc32a5b590496196e2b
parent2a5234a512c19582d261a7ccb692fc634dcb74f0 (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.json13
-rw-r--r--assets/Ires/M_Default.json13
-rw-r--r--assets/Ires/M_Player.json13
-rw-r--r--assets/Ires/S_Default.json70
-rw-r--r--assets/Shaders/S_Default.json65
-rw-r--r--source/EditorCore.cpp99
-rw-r--r--source/EditorCore.hpp4
-rw-r--r--source/EditorUtils.hpp2
-rw-r--r--source/Ires.cpp180
-rw-r--r--source/Ires.hpp40
-rw-r--r--source/Material.cpp250
-rw-r--r--source/Material.hpp18
-rw-r--r--source/Shader.cpp214
-rw-r--r--source/Shader.hpp45
-rw-r--r--source/Sprite.cpp16
-rw-r--r--source/Sprite.hpp8
-rw-r--r--source/Texture.cpp4
-rw-r--r--source/Texture.hpp4
-rw-r--r--source/main.cpp4
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());