diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/App.cpp | 19 | ||||
-rw-r--r-- | source/EditorCorePrivate.cpp | 183 | ||||
-rw-r--r-- | source/EditorCorePrivate.hpp | 2 | ||||
-rw-r--r-- | source/EditorUtils.hpp | 19 | ||||
-rw-r--r-- | source/Enum.hpp | 7 | ||||
-rw-r--r-- | source/Renderer.cpp | 157 | ||||
-rw-r--r-- | source/Renderer.hpp | 23 | ||||
-rw-r--r-- | source/Uid.cpp | 4 | ||||
-rw-r--r-- | source/Uid.hpp | 4 |
9 files changed, 306 insertions, 112 deletions
diff --git a/source/App.cpp b/source/App.cpp index 45a7545..8328589 100644 --- a/source/App.cpp +++ b/source/App.cpp @@ -1,5 +1,10 @@ #include "App.hpp" +#include "ScopeGuard.hpp" +#include "Utils.hpp" + +#include <rapidjson/document.h> +#include <rapidjson/filereadstream.h> #include <string> #include <utility> @@ -27,6 +32,20 @@ App::App() mMainCamera.SetEyePos(glm::vec3(0, 0, 1)); mMainCamera.SetTargetDirection(glm::vec3(0, 0, -1)); mMainCamera.SetHasPerspective(false); + + do { + auto file = Utils::OpenCstdioFile("assets/GameRendererBindings.json", Utils::Read); + if (!file) break; + DEFER { fclose(file); }; + + char readerBuffer[65536]; + rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + + rapidjson::Document root; + root.ParseStream(stream); + + mWorldRenderer.LoadBindings(root); + } while (false); } App::~App() { diff --git a/source/EditorCorePrivate.cpp b/source/EditorCorePrivate.cpp index 9fd6087..a30b498 100644 --- a/source/EditorCorePrivate.cpp +++ b/source/EditorCorePrivate.cpp @@ -13,6 +13,7 @@ #include "Player.hpp" #include "SceneThings.hpp" #include "ScopeGuard.hpp" +#include "Utils.hpp" #include "VertexIndex.hpp" #include "YCombinator.hpp" @@ -21,6 +22,10 @@ #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 <cstddef> #include <cstdint> #include <cstdlib> @@ -392,6 +397,21 @@ struct CreatableGameObject { }, }; #undef GAMEOBJECT_CONSTRUCTOR + +void SaveRendererBindings(const Renderer& renderer) { + auto file = Utils::OpenCstdioFile("assets/GameRendererBindings.json", Utils::WriteTruncate); + if (!file) return; + DEFER { fclose(file); }; + + char writerBuffer[65536]; + rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer)); + rapidjson::Writer writer(stream); + + rapidjson::Document root(rapidjson::kObjectType); + renderer.SaveBindings(root, root); + + root.Accept(writer); +} } // namespace ProjectBrussel_UNITY_ID std::unique_ptr<IEditor> IEditor::CreateInstance(App* app) { @@ -652,6 +672,8 @@ void EditorInstance::Show() { } void EditorInstance::ShowWorldProperties() { + using namespace ProjectBrussel_UNITY_ID; + if (mApp->IsGameRunning()) { if (ImGui::Button("Pause")) { mApp->SetGameRunning(false); @@ -668,102 +690,119 @@ void EditorInstance::ShowWorldProperties() { } } + auto& renderer = *mApp->GetWorldRenderer(); auto& camera = *mApp->GetActiveCamera(); - // vvv Camera settings (per instance) - ImGui::TextUnformatted("Active camera:"); - ImGui::Indent(); + if (ImGui::CollapsingHeader("Renderer settings")) { + if (ImGui::Checkbox("Draw shaded", &mRenderer_DrawShaded)) { + renderer.SetRenderOption(Renderer::RO_Shading, mRenderer_DrawShaded); + } + if (ImGui::Checkbox("Draw wireframe", &mRenderer_DrawWireFrame)) { + renderer.SetRenderOption(Renderer::RO_Wireframe, mRenderer_DrawWireFrame); + } - ImGui::TextUnformatted(camera.name.c_str()); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Object at <%p>", &camera); + if (auto ires = Utils::SimpleIresReceptor<IresMaterial>(renderer.binding_WireframeMaterial->GetIres(), *this, IresObject::KD_Material)) { + renderer.binding_WireframeMaterial.Attach(ires->GetInstance()); + SaveRendererBindings(renderer); + } } - ImGui::InputFloat3("Eye", glm::value_ptr(camera.eye)); - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { - ImGui::OpenPopup("##CTXMENU"); - } - ImGui::InputFloat3("Target", glm::value_ptr(camera.target)); - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { - ImGui::OpenPopup("##CTXMENU"); - } - if (ImGui::BeginPopup("##CTXMENU", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) { - if (ImGui::MenuItem("Reset to origin")) { - camera.SetEyePos(glm::vec3(1.0f, 1.0f, 1.0f)); - } - if (ImGui::MenuItem("Reset completely")) { - camera.eye = glm::vec3(0, 0, 1); - camera.target = glm::vec3(0, 0, 0); + if (ImGui::CollapsingHeader("Camera settings")) { + // vvv Camera settings (per instance) + ImGui::TextUnformatted("Active camera:"); + ImGui::Indent(); + + ImGui::TextUnformatted(camera.name.c_str()); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Object at <%p>", &camera); } - ImGui::EndPopup(); - } - if (IsCurrentCameraEditor()) { - const char* preview; - switch (mEcm) { - case ECM_2D: preview = "2D view"; break; - case ECM_Side3D: preview = "Side 3D view"; break; + ImGui::InputFloat3("Eye", glm::value_ptr(camera.eye)); + if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { + ImGui::OpenPopup("##CTXMENU"); + } + ImGui::InputFloat3("Target", glm::value_ptr(camera.target)); + if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { + ImGui::OpenPopup("##CTXMENU"); } - if (ImGui::BeginCombo("Mode", preview)) { - if (ImGui::Selectable("2D view", mEcm == ECM_2D)) { - if (mEcm != ECM_2D) { - mEcm = ECM_2D; + if (ImGui::BeginPopup("##CTXMENU", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) { + if (ImGui::MenuItem("Reset to origin")) { + camera.SetEyePos(glm::vec3(1.0f, 1.0f, 1.0f)); + } + if (ImGui::MenuItem("Reset completely")) { + camera.eye = glm::vec3(0, 0, 1); + camera.target = glm::vec3(0, 0, 0); + } + ImGui::EndPopup(); + } + + if (IsCurrentCameraEditor()) { + const char* preview; + switch (mEcm) { + case ECM_2D: preview = "2D view"; break; + case ECM_Side3D: preview = "Side 3D view"; break; + } + if (ImGui::BeginCombo("Mode", preview)) { + if (ImGui::Selectable("2D view", mEcm == ECM_2D)) { + if (mEcm != ECM_2D) { + mEcm = ECM_2D; - // TODO project eye to world plane + // TODO project eye to world plane - camera.SetHasPerspective(false); + camera.SetHasPerspective(false); + } } - } - if (ImGui::Selectable("Side 3D view", mEcm == ECM_Side3D, ImGuiSelectableFlags_None)) { - if (mEcm != ECM_Side3D) { - mEcm = ECM_Side3D; + if (ImGui::Selectable("Side 3D view", mEcm == ECM_Side3D, ImGuiSelectableFlags_None)) { + if (mEcm != ECM_Side3D) { + mEcm = ECM_Side3D; - auto origEye = camera.eye; - auto origTarget = camera.target; + auto origEye = camera.eye; + auto origTarget = camera.target; - // New setup: focus on the point of world plane that we were originally "hovering above" - camera.target = origEye; - camera.target.z = 0.0f; + // New setup: focus on the point of world plane that we were originally "hovering above" + camera.target = origEye; + camera.target.z = 0.0f; - // New setup: move the eye back at an angle - camera.eye = camera.target; - camera.eye.x += 4.0f * std::cos(60.0f); - camera.eye.y += 0.0f; - camera.eye.z += 4.0f * std::sin(60.0f); + // New setup: move the eye back at an angle + camera.eye = camera.target; + camera.eye.x += 4.0f * std::cos(60.0f); + camera.eye.y += 0.0f; + camera.eye.z += 4.0f * std::sin(60.0f); - camera.SetHasPerspective(true); + camera.SetHasPerspective(true); + } } + ImGui::EndCombo(); } - ImGui::EndCombo(); } - } - ImGui::Checkbox("Perspective", &camera.perspective); - if (camera.perspective) { - float fovDegress = camera.fov / M_PI * 180.0f; - if (ImGui::SliderFloat("FOV", &fovDegress, 1.0f, 180.0f)) { - camera.fov = fovDegress / 180.0f * M_PI; - } - } else { - if (ImGui::InputFloat("Pixels per meter", &camera.pixelsPerMeter)) { - camera.pixelsPerMeter = std::max(camera.pixelsPerMeter, 0.0f); + ImGui::Checkbox("Perspective", &camera.perspective); + if (camera.perspective) { + float fovDegress = camera.fov / M_PI * 180.0f; + if (ImGui::SliderFloat("FOV", &fovDegress, 1.0f, 180.0f)) { + camera.fov = fovDegress / 180.0f * M_PI; + } + } else { + if (ImGui::InputFloat("Pixels per meter", &camera.pixelsPerMeter)) { + camera.pixelsPerMeter = std::max(camera.pixelsPerMeter, 0.0f); + } } - } - ImGui::Unindent(); - // ^^^ Camera settings (per instance) - // vvv Camera control settings - ImGui::TextUnformatted("Camera controls:"); - ImGui::Indent(); + ImGui::Unindent(); + // ^^^ Camera settings (per instance) + // vvv Camera control settings + ImGui::TextUnformatted("Camera controls:"); + ImGui::Indent(); - ImGui::Checkbox("Move camera with WASD", &mMoveCamKeyboard); - ImGui::SliderFloat("Slide speed", &mMoveCamSlideSpeed, 0.1f, 10.0f); + ImGui::Checkbox("Move camera with WASD", &mMoveCamKeyboard); + ImGui::SliderFloat("Slide speed", &mMoveCamSlideSpeed, 0.1f, 10.0f); - ImGui::Checkbox("Move camera with scoll wheel", &mMoveCamScrollWheel); - ImGui::SliderFloat("Scroll speed", &mMoveCamScrollSpeed, 0.01, 10.0f); + ImGui::Checkbox("Move camera with scoll wheel", &mMoveCamScrollWheel); + ImGui::SliderFloat("Scroll speed", &mMoveCamScrollSpeed, 0.01, 10.0f); - ImGui::Unindent(); - // ^^^ Camera control settings + ImGui::Unindent(); + // ^^^ Camera control settings + } } // TOOD move resource-specific and gameobject-specific inspector code into attachments mechanism diff --git a/source/EditorCorePrivate.hpp b/source/EditorCorePrivate.hpp index 4fbfb72..42be050 100644 --- a/source/EditorCorePrivate.hpp +++ b/source/EditorCorePrivate.hpp @@ -102,6 +102,8 @@ private: bool mDragCam_Happening = false; bool mMoveCamKeyboard = false; bool mMoveCamScrollWheel = false; + bool mRenderer_DrawShaded = true; + bool mRenderer_DrawWireFrame = false; public: EditorInstance(App* app); diff --git a/source/EditorUtils.hpp b/source/EditorUtils.hpp index 99c522b..4fd4811 100644 --- a/source/EditorUtils.hpp +++ b/source/EditorUtils.hpp @@ -1,7 +1,9 @@ #pragma once #include "Color.hpp" +#include "EditorCore.hpp" #include "EditorGuizmo.hpp" +#include "Ires.hpp" #include <imgui.h> #include <string> @@ -60,4 +62,21 @@ float CalcImageHeight(glm::vec2 original, int targetWidth); float CalcImageWidth(glm::vec2 original, float targetHeight); ImVec2 FitImage(glm::vec2 original); +// TODO get kind from T +template <class T> +T* SimpleIresReceptor(T* existing, IEditor& editor, IresObject::Kind kind) { + if (existing) { + existing->ShowReference(editor); + } else { + IresObject::ShowReferenceNull(editor); + } + if (ImGui::BeginDragDropTarget()) { + if (auto payload = ImGui::AcceptDragDropPayload(IresObject::ToString(kind).data())) { + return *static_cast<T* const*>(payload->Data); + } + ImGui::EndDragDropTarget(); + } + return nullptr; +} + } // namespace Utils diff --git a/source/Enum.hpp b/source/Enum.hpp index 5e106fe..3b6165e 100644 --- a/source/Enum.hpp +++ b/source/Enum.hpp @@ -101,3 +101,10 @@ public: EnumFlags operator~() const { return EnumFlags(~mValue); } }; + +// Helper class for enumerating enum elements for ImGui::Begin/EndCombo +template <class TEnum> +struct EnumElement { + const char* name; + TEnum value; +}; diff --git a/source/Renderer.cpp b/source/Renderer.cpp index 3497449..e30b64d 100644 --- a/source/Renderer.cpp +++ b/source/Renderer.cpp @@ -1,11 +1,16 @@ #include "Renderer.hpp" #include "GameObject.hpp" +#include "RapidJsonHelper.hpp" +#include <rapidjson/document.h> #include <cassert> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/quaternion.hpp> #include <glm/gtx/quaternion.hpp> +#include <string_view> + +using namespace std::literals; RenderObject::RenderObject() : mVao{ GL_NONE } { @@ -101,6 +106,28 @@ void RenderObject::DeleteGLObjects() { } } +Renderer::Renderer() + : binding_WireframeMaterial{ gDefaultMaterial } // +{ + mRenderOptions[RO_Shading] = true; + mRenderOptions[RO_Wireframe] = false; +} + +void Renderer::LoadBindings(const rapidjson::Value& bindings) { + if (auto rvWireframe = rapidjson::GetProperty(bindings, "WireframeMaterial"sv)) { + Uid uidWireframe; + uidWireframe.Read(*rvWireframe); + // TODO don't assume + binding_WireframeMaterial.Attach(((IresMaterial*)IresManager::instance->FindIres(uidWireframe))->GetInstance()); + } +} + +void Renderer::SaveBindings(rapidjson::Value& into, rapidjson::Document& root) const { + if (auto ires = binding_WireframeMaterial->GetIres()) { + into.AddMember("WireframeMaterial", ires->GetUid().Write(root), root.GetAllocator()); + } +} + void Renderer::BeginFrame(Camera& camera, float currentTime, float deltaTime) { assert(mInsideFrame == false); mInsideFrame = true; @@ -121,50 +148,108 @@ void Renderer::Draw(const RenderObject* objects, const GameObject* gameObject, s assert(mInsideFrame); - auto vpMatrix = mFrame.matrixProj * mFrame.matrixView; + // Desired order: proj * view * (translate * rotate * scale) * vec + // <----- order of application <----- ^^^ input + glm::mat4 objectMatrix(1.0f); + objectMatrix = glm::translate(objectMatrix, gameObject->GetPos()); + objectMatrix *= glm::toMat4(gameObject->GetRotation()); + objectMatrix = glm::scale(objectMatrix, gameObject->GetScale()); + auto mvpMatrix = mFrame.matrixProj * mFrame.matrixView * objectMatrix; - // TODO shader grouping - // TODO material grouping - for (size_t i = 0; i < count; ++i) { - auto& object = objects[i]; - auto indexBuffer = object.GetIndexBuffer(); - auto mat = object.GetMaterial(); - auto shader = mat->GetShader(); + if (GetRenderOption(RO_Shading)) { + // TODO shader grouping + // TODO material grouping + for (size_t i = 0; i < count; ++i) { + auto& object = objects[i]; + auto indexBuffer = object.GetIndexBuffer(); + auto mat = object.GetMaterial(); + auto shader = mat->GetShader(); - glUseProgram(shader->GetProgram()); + glUseProgram(shader->GetProgram()); - // Material uniforms - mat->UseUniforms(); + // Material uniforms + mat->UseUniforms(); - // Next available texture unit ID after all material textures - int texIdx = mat->GetTextures().size(); + // Next available texture unit ID after all material textures + int texIdx = mat->GetTextures().size(); - // Autofill uniforms - if (shader->autofill_Transform != kInvalidLocation) { - glm::mat4 objectMatrix(1.0f); - objectMatrix = glm::translate(objectMatrix, gameObject->GetPos()); - objectMatrix *= glm::toMat4(gameObject->GetRotation()); - objectMatrix = glm::scale(objectMatrix, gameObject->GetScale()); - glm::mat4 transform = vpMatrix * objectMatrix; + // Autofill uniforms + if (shader->autofill_Transform != kInvalidLocation) { + glUniformMatrix4fv(shader->autofill_Transform, 1, GL_FALSE, &mvpMatrix[0][0]); + } + if (shader->autofill_Time != kInvalidLocation) { + glUniform1f(shader->autofill_Time, mFrame.time); + } + if (shader->autofill_DeltaTime != kInvalidLocation) { + glUniform1f(shader->autofill_DeltaTime, mFrame.deltaTime); + } + if (shader->autofill_TextureAtlas != kInvalidLocation && + object.autofill_TextureAtlas != nullptr) + { + glActiveTexture(GL_TEXTURE0 + texIdx); + glBindTexture(GL_TEXTURE_2D, object.autofill_TextureAtlas->GetHandle()); + glUniform1i(shader->autofill_TextureAtlas, texIdx); + ++texIdx; + } - glUniformMatrix4fv(shader->autofill_Transform, 1, GL_FALSE, &transform[0][0]); - } - if (shader->autofill_Time != kInvalidLocation) { - glUniform1f(shader->autofill_Time, mFrame.time); + glBindVertexArray(object.GetGLVao()); + glDrawElements(GL_TRIANGLES, indexBuffer->count, indexBuffer->GetIndexTypeGL(), 0); } - if (shader->autofill_DeltaTime != kInvalidLocation) { - glUniform1f(shader->autofill_DeltaTime, mFrame.deltaTime); - } - if (shader->autofill_TextureAtlas != kInvalidLocation && - object.autofill_TextureAtlas != nullptr) - { - glActiveTexture(GL_TEXTURE0 + texIdx); - glBindTexture(GL_TEXTURE_2D, object.autofill_TextureAtlas->GetHandle()); - glUniform1i(shader->autofill_TextureAtlas, texIdx); - ++texIdx; + } + + if (GetRenderOption(RO_Wireframe)) { + auto& mat = *binding_WireframeMaterial; + auto& shader = *mat.GetShader(); + auto& shaderInfo = shader.GetInfo(); + + glUseProgram(shader.GetProgram()); + mat.UseUniforms(); + + // TODO reduce calls with consecutive wireframe setting + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + for (size_t i = 0; i < count; ++i) { + auto& object = objects[i]; + + auto& vBindings = object.GetVertexBufferBindings().bindings; + auto vf = object.GetVertexFormat(); + + // Setup vertex buffers + for (auto& elm : vf->elements) { + assert(elm.bindingIndex < vBindings.size()); + auto& buffer = vBindings[elm.bindingIndex]; + + int index = shaderInfo.FindInputLocation(elm.semantic); + if (index == -1) { + continue; + } + + glBindBuffer(GL_ARRAY_BUFFER, buffer->handle); + glEnableVertexAttribArray(index); + glVertexAttribPointer( + index, + Tags::VectorLenOf(elm.type), + Tags::FindGLType(elm.type), + Tags::IsNormalized(elm.type), + vf->vertexSize, + (void*)(uintptr_t)elm.offset); + } + + // Setup index buffer + auto indexBuffer = object.GetIndexBuffer(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->handle); + + glDrawElements(GL_TRIANGLES, indexBuffer->count, indexBuffer->GetIndexTypeGL(), 0); } + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glBindVertexArray(object.GetGLVao()); - glDrawElements(GL_TRIANGLES, indexBuffer->count, indexBuffer->GetIndexTypeGL(), 0); + return; } } + +bool Renderer::GetRenderOption(RenderOption option) const { + return mRenderOptions[option]; +} + +void Renderer::SetRenderOption(RenderOption option, bool flag) { + mRenderOptions[option] = flag; +} diff --git a/source/Renderer.hpp b/source/Renderer.hpp index 98a9f28..7d96ce2 100644 --- a/source/Renderer.hpp +++ b/source/Renderer.hpp @@ -6,6 +6,7 @@ #include "VertexIndex.hpp" #include <glad/glad.h> +#include <rapidjson/fwd.h> #include <cstddef> #include <glm/glm.hpp> @@ -56,13 +57,35 @@ struct RendererFrameInfo { }; class Renderer { +public: + // NOTE: see Renderer constructor for default values + enum RenderOption { + /// Render everything directly using objects' provided material and vertex/index data. + RO_Shading, + /// Render everything as wireframes using provided position data. + RO_Wireframe, + RO_COUNT, + }; + +public: + RcPtr<Material> binding_WireframeMaterial; + private: RendererFrameInfo mFrame; bool mInsideFrame = false; + bool mRenderOptions[RO_COUNT] = {}; public: + Renderer(); + + void LoadBindings(const rapidjson::Value& bindings); + void SaveBindings(rapidjson::Value& into, rapidjson::Document& root)const; + void BeginFrame(Camera& camera, float currentTime, float deltaTime); const RendererFrameInfo& GetLastFrameInfo() const { return mFrame; } void Draw(const RenderObject* objects, const GameObject* gameObject, size_t count); void EndFrame(); + + bool GetRenderOption(RenderOption option) const; + void SetRenderOption(RenderOption option, bool flag); }; diff --git a/source/Uid.cpp b/source/Uid.cpp index 1930cd8..7f8fd9d 100644 --- a/source/Uid.cpp +++ b/source/Uid.cpp @@ -45,13 +45,13 @@ void Uid::Read(const rapidjson::Value& value) { this->lower = lower.GetUint64(); } -void Uid::WriteInto(rapidjson::Value& value, rapidjson::Document& root) { +void Uid::WriteInto(rapidjson::Value& value, rapidjson::Document& root) const { value.Reserve(2, root.GetAllocator()); value.PushBack((uint64_t)upper, root.GetAllocator()); value.PushBack((uint64_t)lower, root.GetAllocator()); } -rapidjson::Value Uid::Write(rapidjson::Document& root) { +rapidjson::Value Uid::Write(rapidjson::Document& root) const { rapidjson::Value result(rapidjson::kArrayType); WriteInto(result, root); return result; diff --git a/source/Uid.hpp b/source/Uid.hpp index f58129c..539de03 100644 --- a/source/Uid.hpp +++ b/source/Uid.hpp @@ -25,8 +25,8 @@ struct Uid { std::string WriteString(); void Read(const rapidjson::Value& value); - void WriteInto(rapidjson::Value& value, rapidjson::Document& root); - rapidjson::Value Write(rapidjson::Document& root); + void WriteInto(rapidjson::Value& value, rapidjson::Document& root) const; + rapidjson::Value Write(rapidjson::Document& root) const; auto operator<=>(const Uid&) const = default; }; |