Added UI component, resource & system. Now renders on screen and live reloads

This commit is contained in:
Antoine Pilote
2024-09-10 22:27:15 -04:00
parent 552fe0ee04
commit ebedefb6a7
21 changed files with 366 additions and 66 deletions

View File

@@ -79,6 +79,11 @@ FileType File::GetFileType() const
return FileType::Mesh;
}
if (ext == ".html")
{
return FileType::UI;
}
return FileType::Unkown;
}

View File

@@ -17,6 +17,7 @@ namespace Nuake
Map,
Assembly,
Solution,
Audio
Audio,
UI
};
}

View File

@@ -2,12 +2,16 @@
#include "src/Rendering/Shaders/ShaderManager.h"
#include "src/Resource/Project.h"
#include "src/Resource/ResourceManager.h"
#include "src/Resource/UI.h"
#include "src/Scene/Components/BSPBrushComponent.h"
#include "src/Scene/Components/ModelComponent.h"
#include "src/Scene/Components/ParentComponent.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
#include "src/Scene/Components/SpriteComponent.h"
#include <src/Scene/Components/SkinnedModelComponent.h>
#include "src/Scene/Components/UIComponent.h"
#include <glad/glad.h>
#include <src/Vendors/imgui/imgui.h>
@@ -34,6 +38,9 @@ namespace Nuake
mShadingBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB, GL_RGB16F, GL_FLOAT));
mShadingBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_DEPTH_COMPONENT), GL_DEPTH_ATTACHMENT); // Depth
mTempFrameBuffer = CreateScope<FrameBuffer>(false, defaultResolution);
mTempFrameBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGBA), GL_COLOR_ATTACHMENT0);
mToneMapBuffer = CreateScope<FrameBuffer>(false, defaultResolution);
mToneMapBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT0);
@@ -141,6 +148,8 @@ namespace Nuake
mGBuffer->QueueResize(framebufferResolution);
GBufferPass(scene);
mTempFrameBuffer->QueueResize(framebuffer.GetSize());
// SSAO
const auto& sceneEnv = scene.GetEnvironment();
if (sceneEnv->SSAOEnabled)
@@ -169,18 +178,6 @@ namespace Nuake
DebugRendererPass(scene);
#ifdef AMD
framebuffer.Bind();
{
RenderCommand::Clear();
Shader* shader = ShaderManager::GetShader("Resources/Shaders/copy.shader");
shader->Bind();
shader->SetUniform("u_Source", mShadingBuffer->GetTexture().get(), 0);
Renderer::DrawQuad();
}
framebuffer.Unbind();
#else
Ref<Texture> finalOutput = mShadingBuffer->GetTexture();
if (scene.GetEnvironment()->BloomEnabled)
{
@@ -207,10 +204,7 @@ namespace Nuake
sceneEnv->mVolumetric->SetDepth(mGBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get());
sceneEnv->mVolumetric->Draw(mProjection, mView, mCamPos, lightList);
//finalOutput = mVolumetric->GetFinalOutput().get();
// combine
framebuffer.Bind();
{
RenderCommand::Clear();
@@ -261,18 +255,6 @@ namespace Nuake
RenderCommand::Clear();
Shader* shader = ShaderManager::GetShader("Resources/Shaders/outline.shader");
shader->Bind();
//mGBuffer->GetTexture(GL_COLOR_ATTACHMENT3)->Bind(0);
//mGBuffer->GetTexture(GL_DEPTH_ATTACHMENT)->Bind(1);
//shader->SetUniforms(
//{
// {"u_EntityID", mOutlineEntityID == -1 ? -1 : mOutlineEntityID + 1},
// {"u_EntityTexture", 0},
// {"u_OutlineColor", projectSettings.PrimaryColor},
// {"u_Depth", 1},
// {"u_Radius", projectSettings.OutlineRadius * projectSettings.ResolutionScale},
//});
shader->SetUniform("u_EntityID", mOutlineEntityID == -1 ? -1 : mOutlineEntityID + 1);
shader->SetUniform("u_EntityTexture", mGBuffer->GetTexture(GL_COLOR_ATTACHMENT3).get(), 0);
shader->SetUniform("u_OutlineColor", projectSettings.PrimaryColor);
@@ -423,18 +405,6 @@ namespace Nuake
}
mVignetteBuffer->Unbind();
//framebuffer.Bind();
//{
// RenderCommand::Clear();
// Shader* shader = ShaderManager::GetShader("Resources/Shaders/add.shader");
// shader->Bind();
//
// shader->SetUniform("u_Source", mVignetteBuffer->GetTexture().get(), 0);
// shader->SetUniform("u_Source2", mOutlineBuffer->GetTexture().get(), 1);
// Renderer::DrawQuad();
//}
//framebuffer.Unbind();
framebuffer.Bind();
{
RenderCommand::Clear();
@@ -445,29 +415,45 @@ namespace Nuake
Renderer::DrawQuad();
}
framebuffer.Unbind();
#endif
mTempFrameBuffer->Bind();
{
RenderCommand::Clear();
Shader* shader = ShaderManager::GetShader("Resources/Shaders/copy.shader");
shader->Bind();
shader->SetUniform("u_Source", framebuffer.GetTexture().get(), 0);
Renderer::DrawQuad();
}
mTempFrameBuffer->Unbind();
const auto uiView = scene.m_Registry.view<UIComponent>();
for (auto ui : uiView)
{
const UIComponent& uiComponent = uiView.get<UIComponent>(ui);
if (!ResourceManager::IsResourceLoaded(uiComponent.UIResource))
{
continue;
}
// Fetch resource from resource manager using UUID
Ref<UIResource> uiResource = ResourceManager::GetResource<UIResource>(uiComponent.UIResource);
uiResource->Resize(framebuffer.GetSize());
// Copy UI onto final viewport
framebuffer.Bind();
{
Shader* shader = ShaderManager::GetShader("Resources/Shaders/add.shader");
shader->Bind();
shader->SetUniform("u_Source", mTempFrameBuffer->GetTexture().get(), 0);
shader->SetUniform("u_Source2", uiResource->GetOutputTexture().get(), 1);
Renderer::DrawQuad();
}
framebuffer.Unbind();
}
glDepthMask(true);
// Barrel distortion
//mVignetteBuffer->Bind();
//{
// RenderCommand::Clear();
// Shader* shader = ShaderManager::GetShader("Resources/Shaders/vignette.shader");
// shader->Bind();
//
// shader->SetUniform("u_Intensity", sceneEnv->VignetteIntensity);
// shader->SetUniform("u_Extend", sceneEnv->VignetteExtend);
// shader->SetUniform("u_Source", mBarrelDistortionBuffer->GetTexture().get(), 0);
// Renderer::DrawQuad();
//}
//mVignetteBuffer->Unbind();
RenderCommand::Enable(RendererEnum::DEPTH_TEST);
Renderer::EndDraw();
}

View File

@@ -94,6 +94,7 @@ namespace Nuake
Scope<FrameBuffer> mDOFBuffer;
Scope<FrameBuffer> mOutlineBuffer;
Scope<FrameBuffer> mDisplayDepthBuffer;
Scope<FrameBuffer> mTempFrameBuffer;
// Shapes
Ref<BoxGizmo> mBoxGizmo;

View File

@@ -5,6 +5,7 @@
#include "src/Resource/ResourceManager.h"
#include "src/Rendering/Textures/Material.h"
#include "src/Resource/Model.h"
#include "src/Resource/UI.h"
using namespace Nuake;
@@ -94,6 +95,13 @@ Ref<Model> ResourceLoader::LoadModel(const std::string& path)
return model;
}
Ref<UIResource> ResourceLoader::LoadUI(const std::string& path)
{
auto uiResource = CreateRef<UIResource>(path);
uiResource->ID = UUID();
return uiResource;
}
UUID ResourceLoader::ReadUUID(json j)
{
if (j.contains("UUID"))

View File

@@ -7,6 +7,7 @@ namespace Nuake
{
class Material;
class Model;
class UIResource;
class ResourceLoader
{
@@ -21,6 +22,7 @@ namespace Nuake
static Ref<Material> LoadMaterial(const std::string& path);
static Ref<Model> LoadModel(const std::string& path);
static Ref<UIResource> LoadUI(const std::string& path);
private:
static UUID ReadUUID(json j);

72
Nuake/src/Resource/UI.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "UI.h"
#include "Engine.h"
#include "src/FileSystem/FileSystem.h"
#include "src/Rendering/Buffers/Framebuffer.h"
#include "src/UI/NuakeUI.h"
#include "src/UI/Parsers/CanvasParser.h"
#include "src/UI/UIInputManager.h"
using namespace Nuake;
using namespace NuakeUI;
MyInputManager* UIResource::inputManager = nullptr;
UIResource::UIResource(const std::string& path) :
filePath(path)
{
const Vector2 defaultSize = { 1280, 720 };
framebuffer = CreateRef<FrameBuffer>(true, defaultSize);
framebuffer->SetTexture(CreateRef<Texture>(defaultSize, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE));
if (!inputManager)
{
inputManager = new MyInputManager(*Engine::GetCurrentWindow());
}
CanvasParser parser;
canvas = parser.Parse(FileSystem::RelativeToAbsolute(path));
canvas->SetInputManager(inputManager);
canvas->ComputeLayout(defaultSize);
}
void UIResource::Draw()
{
framebuffer->Bind();
{
RenderCommand::Clear();
if (canvas)
{
canvas->Draw();
}
}
framebuffer->Unbind();
}
void UIResource::Resize(const Vector2& size)
{
framebuffer->QueueResize(size);
canvas->ComputeLayout(size);
}
void UIResource::Reload()
{
if (!FileSystem::FileExists(filePath))
{
return;
}
CanvasParser parser;
canvas = parser.Parse(FileSystem::RelativeToAbsolute(filePath));
if (canvas)
{
canvas->SetInputManager(inputManager);
canvas->ComputeLayout(framebuffer->GetSize());
}
}
Ref<Texture> UIResource::GetOutputTexture() const
{
return framebuffer->GetTexture();
}

35
Nuake/src/Resource/UI.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include "Resource.h"
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
namespace NuakeUI
{
class Canvas;
}
namespace Nuake
{
class FrameBuffer;
class MyInputManager;
class Texture;
class UIResource : public Resource
{
public:
UIResource(const std::string& path);
~UIResource() = default;
void Draw();
void Resize(const Vector2& size);
void Reload();
Ref<Texture> GetOutputTexture() const;
private:
Ref<NuakeUI::Canvas> canvas;
Ref<FrameBuffer> framebuffer;
static MyInputManager* inputManager;
std::string filePath;
};
}

View File

@@ -0,0 +1 @@
#include "UIComponent.h"

View File

@@ -0,0 +1,17 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "src/Resource/UUID.h"
namespace Nuake
{
struct UIComponent
{
NUAKECOMPONENT(UIComponent, "UI Component");
UUID UIResource = UUID(0);
std::string CSharpUIController;
std::string UIFilePath;
bool IsWorldSpace;
// TODO: Z-Ordering
};
}

View File

@@ -12,7 +12,8 @@
#include "src/Scene/Systems/QuakeMapBuilder.h"
#include "src/Scene/Systems/ParticleSystem.h"
#include "src/Scene/Systems/AnimationSystem.h"
#include <src/Scene/Systems/AudioSystem.h>
#include "src/Scene/Systems/AudioSystem.h"
#include "src/Scene/Systems/UISystem.h"
#include "src/Rendering/SceneRenderer.h"
#include "src/Rendering/Renderer.h"
@@ -54,6 +55,7 @@ namespace Nuake
// Adding systems - Order is important
m_Systems.push_back(CreateRef<PhysicsSystem>(this));
m_Systems.push_back(CreateRef<UISystem>(this));
m_Systems.push_back(CreateRef<ScriptingSystem>(this));
m_Systems.push_back(CreateRef<AnimationSystem>(this));
m_Systems.push_back(CreateRef<TransformSystem>(this));
@@ -237,7 +239,6 @@ namespace Nuake
}
}
return false;
}

View File

@@ -0,0 +1,70 @@
#include "UISystem.h"
#include "src/Resource/ResourceManager.h"
#include "src/Resource/ResourceLoader.h"
#include "src/Resource/UI.h"
#include "src/Scene/Scene.h"
#include "src/FileSystem/File.h"
#include "src/Scene/Components/UIComponent.h"
#include "src/FileSystem/FileSystem.h"
namespace Nuake
{
UISystem::UISystem(Scene* scene)
{
m_Scene = scene;
}
bool UISystem::Init()
{
return true;
}
void UISystem::Update(Timestep ts)
{
auto uiView = m_Scene->m_Registry.view<UIComponent>();
for (auto e : uiView)
{
auto& uiViewComponent = uiView.get<UIComponent>(e);
const std::string& filePath = uiViewComponent.UIFilePath;
if (uiViewComponent.UIResource == 0)
{
if (filePath.empty() || !FileSystem::FileExists(filePath))
{
continue;
}
Ref<UIResource> uiResource = ResourceLoader::LoadUI(filePath);
uiViewComponent.UIResource = uiResource->ID;
uis[uiViewComponent.UIResource] = uiResource;
ResourceManager::RegisterResource(uiResource);
}
else
{
if (FileSystem::FileExists(filePath))
{
Ref<File> file = FileSystem::GetFile(filePath);
if (file->GetHasBeenModified())
{
uis[uiViewComponent.UIResource]->Reload();
file->SetHasBeenModified(false);
}
uis[uiViewComponent.UIResource]->Draw();
}
}
}
}
void UISystem::FixedUpdate(Timestep ts)
{
}
void UISystem::EditorUpdate()
{
}
void UISystem::Exit()
{
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "src/Resource/UUID.h"
#include "src/Scene/Systems/System.h"
#include "src/Core/Maths.h"
namespace Nuake
{
class UIResource;
class UISystem : public System
{
public:
UISystem(Scene* scene);
bool Init() override;
void Update(Timestep ts) override;
void EditorUpdate() override;
void FixedUpdate(Timestep ts) override;
void Draw() override {}
void Exit() override;
private:
std::map<UUID, Ref<UIResource>> uis;
};
}

View File

@@ -10,7 +10,7 @@
namespace NuakeUI
{
class Canvas;
typedef std::shared_ptr<Canvas> CanvasPtr;
using CanvasPtr = std::shared_ptr<Canvas>;
class Canvas
{

View File

@@ -1,5 +1,6 @@
#include "Node.h"
#include "../Renderer.h"
#include "src/FileSystem/FileSystem.h"
#include "NodeState.h"
#include "../StringHelper.h"
@@ -480,7 +481,7 @@ namespace NuakeUI
}
else
{
auto texture = std::make_shared<Texture>(value.string);
auto texture = CreateRef<Texture>(value.string);
ComputedStyle.BackgroundImage = texture;
}
}

View File

@@ -11,6 +11,7 @@
#include <iostream>
#include <charconv>
#include <thread>
namespace NuakeUI
{
@@ -249,12 +250,25 @@ namespace NuakeUI
}
}
CanvasPtr CanvasParser::Parse(const std::string& path)
Ref<Canvas> CanvasParser::Parse(const std::string& path)
{
_parsingPath = path;
tinyxml2::XMLDocument doc;
if (tinyxml2::XMLError error = doc.LoadFile(path.c_str()))
tinyxml2::XMLError error;
bool fileLoaded = false;
for (int i = 0; i < 5; ++i) { // Try 5 times
error = doc.LoadFile(path.c_str());
if (error == tinyxml2::XML_SUCCESS) {
fileLoaded = true;
break;
}
else if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Wait before retrying
}
}
if (error)
{
doc.PrintError();
return nullptr;

View File

@@ -1,4 +1,5 @@
#pragma once
#include "src/Core/Core.h"
#include "../Nodes/Canvas.h"
#include <functional>
@@ -31,7 +32,7 @@ namespace NuakeUI
bool HasNodeType(const std::string& name) const;
refNew GetNodeType(const std::string& name) const;
CanvasPtr Parse(const std::string& file);
Ref<Canvas> Parse(const std::string& file);
private:
void ScanFragment(tinyxml2::XMLElement* e, NodePtr node);
void WriteValueFromString(std::variant<int, float, bool, std::string, char>& var, const std::string& str);