From aae5e81ec27d17801ab3b91d9d476bff21107672 Mon Sep 17 00:00:00 2001 From: loic <910041@gmail.com> Date: Thu, 12 Dec 2024 03:55:03 +0800 Subject: [PATCH] feat: add logging console and refactor Application class --- AtmosphericEngine/CMakeLists.txt | 3 +- AtmosphericEngine/application.cpp | 78 +++++++++--------------- AtmosphericEngine/application.hpp | 26 ++++++-- AtmosphericEngine/console.cpp | 87 +++++++++++++++++++++++++++ AtmosphericEngine/console.hpp | 31 +++++++++- AtmosphericEngine/graphics_server.cpp | 35 +++-------- AtmosphericEngine/graphics_server.hpp | 14 +---- AtmosphericEngine/server.cpp | 1 + AtmosphericEngine/server.hpp | 1 + AtmosphericEngine/window.hpp | 2 +- vcpkg.json | 1 + 11 files changed, 177 insertions(+), 102 deletions(-) diff --git a/AtmosphericEngine/CMakeLists.txt b/AtmosphericEngine/CMakeLists.txt index 6fb48e4..f95049e 100644 --- a/AtmosphericEngine/CMakeLists.txt +++ b/AtmosphericEngine/CMakeLists.txt @@ -15,6 +15,7 @@ option(BUILD_SHARED_LIBS OFF) find_package(Bullet CONFIG REQUIRED) find_package(fmt REQUIRED) +find_package(spdlog REQUIRED) find_package(lua REQUIRED) add_subdirectory(external/entt) @@ -62,5 +63,5 @@ target_include_directories(AtmosphericEngine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} target_precompile_headers(AtmosphericEngine PRIVATE pch.hpp) target_link_libraries(AtmosphericEngine PUBLIC - GLEW::GLEW glfw glm::glm fmt::fmt EnTT::EnTT BulletSoftBody BulletDynamics BulletCollision LinearMath ${LUA_LIBRARIES} sol2 raudio + GLEW::GLEW glfw glm::glm fmt::fmt spdlog::spdlog EnTT::EnTT BulletSoftBody BulletDynamics BulletCollision LinearMath ${LUA_LIBRARIES} sol2 raudio ) diff --git a/AtmosphericEngine/application.cpp b/AtmosphericEngine/application.cpp index 44a3027..657577a 100644 --- a/AtmosphericEngine/application.cpp +++ b/AtmosphericEngine/application.cpp @@ -4,26 +4,30 @@ #include "scene.hpp" #include "impostor.hpp" -Application::Application() +Application::Application(AppConfig config) : _config(config) { - Log("Launching..."); - _window = std::make_shared();; // Multi-window not supported now + // setbuf(stdout, NULL); // Cancel output stream buffering so that output can be seen immediately + + _window = std::make_shared(WindowProps { + .title = config.windowTitle, + .width = config.windowWidth, + .height = config.windowHeight + }); // Multi-window not supported now _window->Init(); _window->InitImGui(); } Application::~Application() { - Log("Exiting..."); + ENGINE_LOG("Exiting..."); _window->DeinitImGui(); + for (const auto& go : _entities) delete go; } void Application::Run() { - Log("Initializing subsystems..."); - console.Init(this); input.Init(this); audio.Init(this); @@ -33,9 +37,9 @@ void Application::Run() for (auto& subsystem : _subsystems) { subsystem->Init(this); } - this->_initialized = true; + ENGINE_LOG("Subsystems initialized."); - Log("Subsystems initialized."); + OnInit(); OnLoad(); @@ -48,31 +52,24 @@ void Application::Run() std::thread fork(&Application::Update, this, currFrame); Render(currFrame); fork.join(); - SyncTransformWithPhysics(); #endif _clock++; }); } -void Application::LoadScene(SceneDef& scene) -{ - Log("Loading scene..."); +void Application::LoadScene(SceneDef& scene) { + ENGINE_LOG("Loading scene..."); graphics.LoadTextures(scene.textures); - script.Print("Textures created."); + ENGINE_LOG("Textures created."); - graphics.LoadColorShader(ShaderProgram(scene.shaders["color"])); - graphics.LoadDebugShader(ShaderProgram(scene.shaders["debug_line"])); - graphics.LoadDepthShader(ShaderProgram(scene.shaders["depth"])); - graphics.LoadDepthCubemapShader(ShaderProgram(scene.shaders["depth_cubemap"])); - graphics.LoadTerrainShader(ShaderProgram(scene.shaders["terrain"])); - graphics.LoadPostProcessShader(ShaderProgram(scene.shaders["hdr"])); - script.Print("Shaders created."); + graphics.LoadShaders(scene.shaders); + ENGINE_LOG("Shaders created."); for (const auto& mat : scene.materials) { graphics.materials.push_back(new Material(mat)); } - script.Print("Materials created."); + ENGINE_LOG("Materials created."); for (const auto& go : scene.gameObjects) { auto entity = CreateGameObject(go.position, go.rotation, go.scale); @@ -81,11 +78,10 @@ void Application::LoadScene(SceneDef& scene) entity->AddCamera(go.camera.value()); } if (go.light.has_value()) { - Log(fmt::format("Adding light to {}", go.name)); entity->AddLight(go.light.value()); } } - script.Print("Game objects created."); + ENGINE_LOG("Game objects created."); mainCamera = graphics.GetMainCamera(); mainLight = graphics.GetMainLight(); @@ -120,7 +116,7 @@ void Application::ReloadScene() { void Application::Quit() { - Log("Requested to quit."); + ENGINE_LOG("Requested to quit."); _window->Close(); } @@ -140,9 +136,9 @@ void Application::Update(const FrameData& props) subsystem->Process(dt); } - #if SHOW_PROCESS_COST - Log(fmt::format("Update costs {} ms", (GetWindowTime() - time) * 1000)); - #endif +#if SHOW_PROCESS_COST + ENGINE_LOG(fmt::format("Update costs {} ms", (GetWindowTime() - time) * 1000)); +#endif } void Application::Render(const FrameData& props) @@ -305,6 +301,7 @@ void Application::Render(const FrameData& props) if (_showEngineView) { ImGui::Begin("Engine Subsystems"); { + console.DrawImGui(dt); input.DrawImGui(dt); audio.DrawImGui(dt); graphics.DrawImGui(dt); @@ -318,34 +315,13 @@ void Application::Render(const FrameData& props) _window->EndImGuiFrame(); - #if SHOW_RENDER_AND_DRAW_COST - Log(fmt::format("[Engine] Render & draw cost {} ms", (GetWindowTime() - time) * 1000)); - #endif +#if SHOW_RENDER_AND_DRAW_COST + ENGINE_LOG(fmt::format("Render & draw cost {} ms", (GetWindowTime() - time) * 1000)); +#endif } void Application::SyncTransformWithPhysics() { - float time = GetWindowTime(); - - //ecs.SyncTransformWithPhysics(); - for (auto go : _entities) - { - auto impostor = dynamic_cast(go->GetComponent("Physics")); - if (impostor == nullptr) - continue; - go->SyncObjectTransform(impostor->GetWorldTransform()); - } - - #if SHOW_SYNC_COST - Log(fmt::format("Sync cost {} ms", (Time() - time) * 1000)); - #endif -} - -void Application::Log(std::string message) -{ - #if RUNTIME_LOG_ON - fmt::print("[Engine] {}\n", message); - #endif } uint64_t Application::GetClock() diff --git a/AtmosphericEngine/application.hpp b/AtmosphericEngine/application.hpp index 44ba689..dbd4cac 100644 --- a/AtmosphericEngine/application.hpp +++ b/AtmosphericEngine/application.hpp @@ -1,10 +1,11 @@ #pragma once +#include "config.hpp" #include "globals.hpp" #include "imgui.h" +#include "console.hpp" #include "audio_manager.hpp" #include "graphics_server.hpp" #include "physics_server.hpp" -#include "console.hpp" #include "input.hpp" #include "script.hpp" @@ -27,17 +28,31 @@ struct FrameData float deltaTime; }; +struct AppConfig { + std::string windowTitle = INIT_SCREEN_TITLE; + int windowWidth = INIT_SCREEN_WIDTH; + int windowHeight = INIT_SCREEN_HEIGHT; + bool fullscreen = false; + bool vsync = true; + bool enable3D = true; + bool enableAudio = true; + bool enablePhysics = true; + float physicsTimeStep = 1.0f / 60.0f; +}; + using EntityID = uint64_t; class Application { public: - Application(); + Application(AppConfig config = {}); ~Application(); void Run(); - virtual void OnLoad() = 0; + virtual void OnInit() {} // Load resources + virtual void OnLoad() = 0; // Setup game objects (side effects) virtual void OnUpdate(float dt, float time) = 0; + virtual void OnReload() {} // Reset game objects (side effects clean up and recreate) uint64_t GetClock(); @@ -65,7 +80,6 @@ class Application { void LoadScene(SceneDef& scene); void ReloadScene(); - void Log(std::string message); void Quit(); std::shared_ptr GetWindow(); @@ -81,10 +95,12 @@ class Application { GameObject* CreateGameObject(glm::vec3 position = glm::vec3(0.0f), glm::vec3 rotation = glm::vec3(0.0f), glm::vec3 scale = glm::vec3(1.0f)); private: + AppConfig _config; + + std::shared_ptr _window = nullptr; std::vector> _subsystems; bool _initialized = false; - std::shared_ptr _window = nullptr; uint64_t _clock = 0; uint16_t _sceneIndex = 0; std::optional _currentSceneDef = std::nullopt; diff --git a/AtmosphericEngine/console.cpp b/AtmosphericEngine/console.cpp index e6fec13..143b357 100644 --- a/AtmosphericEngine/console.cpp +++ b/AtmosphericEngine/console.cpp @@ -1,4 +1,7 @@ #include "console.hpp" +#include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "script.hpp" Console* Console::_instance = nullptr; @@ -13,4 +16,88 @@ Console::Console() Console::~Console() { +} + +void Console::Init(Application* app) +{ + Server::Init(app); + + auto console_sink = std::make_shared(); + auto logger = std::make_shared("console", console_sink); + spdlog::set_default_logger(logger); +} + +void Console::Process(float dt) +{ + +} + +void Console::DrawImGui(float dt) +{ + if (ImGui::CollapsingHeader("Console", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::Text("Log Level:"); + if (ImGui::RadioButton("Info", spdlog::level::info == spdlog::default_logger()->level())) { + spdlog::default_logger()->set_level(spdlog::level::info); + } + ImGui::SameLine(); + if (ImGui::RadioButton("Warn", spdlog::level::warn == spdlog::default_logger()->level())) { + spdlog::default_logger()->set_level(spdlog::level::warn); + } + ImGui::SameLine(); + if (ImGui::RadioButton("Error", spdlog::level::err == spdlog::default_logger()->level())) { + spdlog::default_logger()->set_level(spdlog::level::err); + } + + ImGui::Separator(); + + if (ImGui::BeginChild("Log", ImVec2(0, 300))) { + ImGui::Text("Log:"); + ImGui::EndChild(); + } + + ImGui::Separator(); + + // TODO: command palette + static char command[256] = ""; + if (ImGui::InputText("Command", command, IM_ARRAYSIZE(command), ImGuiInputTextFlags_EnterReturnsTrue)) { + ExecuteCommand(command); + command[0] = '\0'; + } + } +} + +void Console::Info(const std::string& message) +{ +#if RUNTIME_LOG_ON + spdlog::info(message); +#endif +} + +void Console::Warn(const std::string& message) +{ +#if RUNTIME_LOG_ON + spdlog::warn(message); +#endif +} + +void Console::Error(const std::string& message) +{ +#if RUNTIME_LOG_ON + spdlog::error(message); +#endif +} + +void Console::RegisterCommand(const std::string& cmd, std::function&)> callback) +{ + _commands[cmd] = callback; +} + +void Console::ExecuteCommand(const std::string& cmd) +{ + auto it = _commands.find(cmd); + if (it != _commands.end()) { + it->second({}); + } + + Script::Get()->Run(cmd); } \ No newline at end of file diff --git a/AtmosphericEngine/console.hpp b/AtmosphericEngine/console.hpp index db1a65b..97e0f7c 100644 --- a/AtmosphericEngine/console.hpp +++ b/AtmosphericEngine/console.hpp @@ -1,8 +1,13 @@ #pragma once #include "globals.hpp" +#include "config.hpp" #include "server.hpp" -/// Logging system +struct LogEntry { + std::string message; +}; + +/// Logging and command palette system class Console : public Server { private: @@ -15,6 +20,26 @@ class Console : public Server } Console(); - ~Console(); -}; \ No newline at end of file + + void Init(Application* app) override; + void Process(float dt) override; + void DrawImGui(float dt) override; + + void Info(const std::string& message); + void Warn(const std::string& message); + void Error(const std::string& message); + + void RegisterCommand(const std::string& cmd, std::function&)> callback); + void ExecuteCommand(const std::string& cmd); + +private: + bool _showInfo = true; + bool _showWarn = true; + bool _showError = true; + + std::unordered_map&)>> _commands; +}; + +#define LOG(msg, ...) Console::Get()->Info(fmt::format(msg, ##__VA_ARGS__)) +#define ENGINE_LOG(msg, ...) Console::Get()->Info("[Engine] " + fmt::format(msg, ##__VA_ARGS__)) \ No newline at end of file diff --git a/AtmosphericEngine/graphics_server.cpp b/AtmosphericEngine/graphics_server.cpp index 42ad436..b7a762a 100644 --- a/AtmosphericEngine/graphics_server.cpp +++ b/AtmosphericEngine/graphics_server.cpp @@ -300,34 +300,13 @@ void GraphicsServer::LoadTextures(const std::vector& paths) } } -void GraphicsServer::LoadDepthShader(const ShaderProgram& program) -{ - depthShader = program; -} - -void GraphicsServer::LoadDepthCubemapShader(const ShaderProgram& program) -{ - depthCubemapShader = program; -} - -void GraphicsServer::LoadColorShader(const ShaderProgram& program) -{ - colorShader = program; -} - -void GraphicsServer::LoadDebugShader(const ShaderProgram& program) -{ - debugShader = program; -} - -void GraphicsServer::LoadTerrainShader(const ShaderProgram& program) -{ - terrainShader = program; -} - -void GraphicsServer::LoadPostProcessShader(const ShaderProgram& program) -{ - postProcessShader = program; +void GraphicsServer::LoadShaders(const std::unordered_map& shaders) { + depthShader = ShaderProgram(shaders.at("depth")); + depthCubemapShader = ShaderProgram(shaders.at("depth_cubemap")); + colorShader = ShaderProgram(shaders.at("color")); + debugShader = ShaderProgram(shaders.at("debug_line")); + terrainShader = ShaderProgram(shaders.at("terrain")); + postProcessShader = ShaderProgram(shaders.at("hdr")); } void GraphicsServer::ReloadShaders() diff --git a/AtmosphericEngine/graphics_server.hpp b/AtmosphericEngine/graphics_server.hpp index 0635e85..1665d86 100644 --- a/AtmosphericEngine/graphics_server.hpp +++ b/AtmosphericEngine/graphics_server.hpp @@ -104,19 +104,7 @@ class GraphicsServer : public Server void LoadTextures(const std::vector& paths); - void LoadDepthShader(const ShaderProgram& program); - - void LoadDepthCubemapShader(const ShaderProgram& program); - - void LoadColorShader(const ShaderProgram& program); - - void LoadDebugShader(const ShaderProgram& program); - - void LoadTerrainShader(const ShaderProgram& program); - - void LoadPostProcessShader(const ShaderProgram& program); - - void PushDebugLine(DebugVertex from, DebugVertex to); + void LoadShaders(const std::unordered_map& shaders); void ReloadShaders(); diff --git a/AtmosphericEngine/server.cpp b/AtmosphericEngine/server.cpp index a2b7045..b419252 100644 --- a/AtmosphericEngine/server.cpp +++ b/AtmosphericEngine/server.cpp @@ -14,6 +14,7 @@ Server::~Server() void Server::Init(Application* app) { _app = app; + _initialized = true; } void Server::Process(float dt) diff --git a/AtmosphericEngine/server.hpp b/AtmosphericEngine/server.hpp index 4f0ff22..89f916e 100644 --- a/AtmosphericEngine/server.hpp +++ b/AtmosphericEngine/server.hpp @@ -15,6 +15,7 @@ class Server { protected: Application* _app; + bool _initialized = false; float _timeStep; int _maxNumSteps; float _paused = false; diff --git a/AtmosphericEngine/window.hpp b/AtmosphericEngine/window.hpp index 08143ee..1538e19 100644 --- a/AtmosphericEngine/window.hpp +++ b/AtmosphericEngine/window.hpp @@ -98,7 +98,7 @@ class Window { return _instance; } - Window(WindowProps props = WindowProps()); + Window(WindowProps props = {}); ~Window(); void Init(); diff --git a/vcpkg.json b/vcpkg.json index 51c9cd2..c0e9c41 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -8,6 +8,7 @@ "glm", "bullet3", "fmt", + "spdlog", "lua", "tinygltf" ]