From 3679beaa4e00653055b0583bae38a8764eb4f8ad Mon Sep 17 00:00:00 2001 From: noffie Date: Sun, 20 Apr 2025 17:49:15 +0200 Subject: [PATCH] Memory safety and Window Events Adding memory checks and Window Event Listener + Memory Checks (debug) + Listening to window events + Runtime Directory Structure (Vision) --- README.md | 31 ++++++ examples/Full/General/src/main.cpp | 10 +- examples/Full/TicTacToe/src/main.cpp | 2 +- include/cigui/cigui.hpp | 14 ++- include/cigui/core/App.hpp | 72 +++++++++--- include/cigui/core/Memory.hpp | 18 +++ include/cigui/core/Memory.inl | 49 +++++++++ include/cigui/utils/List.hpp | 5 +- include/cigui/utils/List.inl | 49 ++++++--- include/cigui/utils/MemoryDebug.hpp | 159 +++++++++++++++++++++++++++ include/cigui/utils/MemoryDebug.inl | 1 + include/cigui/utils/Vectors.hpp | 49 ++++----- src/core/App.cpp | 132 ++++++++++++++++------ 13 files changed, 491 insertions(+), 100 deletions(-) create mode 100644 include/cigui/core/Memory.hpp create mode 100644 include/cigui/core/Memory.inl create mode 100644 include/cigui/utils/MemoryDebug.hpp create mode 100644 include/cigui/utils/MemoryDebug.inl diff --git a/README.md b/README.md index bf12953..c524860 100644 --- a/README.md +++ b/README.md @@ -281,4 +281,35 @@ struct MainApp : public cig::App { ) } } +``` + +## Data structures + +### Runtime +``` +./ +|- Themes +| |- ExampleTheme.json +| \- themes.txt +|- Settings.json +\- App.json +``` + +#### Themes +``` +# themes.txt + +1, ExampleTheme.json +--- +default: 1 +``` + +```json5 +// ExampleTheme.json +{ + "Name": "Standard Cigui Theme", + "background-color": [20, 20, 20], + "primary": [120, 20, 50], + "other": "auto" // calculates the secondary and any further color automatically based on "primary" +} ``` \ No newline at end of file diff --git a/examples/Full/General/src/main.cpp b/examples/Full/General/src/main.cpp index 5494e36..0f607a1 100644 --- a/examples/Full/General/src/main.cpp +++ b/examples/Full/General/src/main.cpp @@ -1,6 +1,10 @@ -#include +#include -int main() { - cig::App::GetInstance().Run(); +int main(int argc, char** argv) { + MEM_CHECKED_MAIN(return_code) { + auto app = cig::App(); + return_code = app.Run(); + } + return return_code; } diff --git a/examples/Full/TicTacToe/src/main.cpp b/examples/Full/TicTacToe/src/main.cpp index 99707b4..1055224 100644 --- a/examples/Full/TicTacToe/src/main.cpp +++ b/examples/Full/TicTacToe/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include int main() { std::cout << "Hello World" << std::endl; diff --git a/include/cigui/cigui.hpp b/include/cigui/cigui.hpp index 48c9429..9193b02 100644 --- a/include/cigui/cigui.hpp +++ b/include/cigui/cigui.hpp @@ -4,7 +4,19 @@ #include #include -#include +#include + +#include + +#ifdef _DEBUG +#define MEM_CHECKED_MAIN(rtc) \ + int rtc = 0; \ + MEMORY_INFO_DUMP(); \ + for (bool exit_main_mem_check_dump_tmp_var = true; exit_main_mem_check_dump_tmp_var == true; MEMORY_INFO_DUMP(), exit_main_mem_check_dump_tmp_var = false) +#else +#define MEM_CHECKED_MAIN(rtc) int rtc = 0; +#endif + namespace cig { constexpr unsigned int VERSION_MAJOR = CIGUI_VERSION_MAJOR; diff --git a/include/cigui/core/App.hpp b/include/cigui/core/App.hpp index 7ec2807..75ebdf2 100644 --- a/include/cigui/core/App.hpp +++ b/include/cigui/core/App.hpp @@ -1,13 +1,27 @@ #pragma once #include +#include #include #include +#include namespace cig { - struct Vertex + class LocalFilesystem + { + std::filesystem::path executable_path; + std::filesystem::path working_directory; + public: + explicit LocalFilesystem(const char* arg0) + { + executable_path = std::filesystem::current_path() / arg0; + working_directory = std::filesystem::current_path(); + } + }; + + struct alignas(4) Vertex { float position[2]; // 2D vector for X and Y coordinates uint8_t color[4]; // 4D vector for red, green, blue, and alpha components @@ -16,24 +30,50 @@ namespace cig class App { protected: + LLGL::RenderSystemPtr m_RenderSystem; + std::pair m_ShaderPack; + + LLGL::SwapChain* m_SwapChain = nullptr; + LLGL::PipelineState* m_Pipeline = nullptr; + LLGL::Buffer* m_VertexBuffer = nullptr; + LLGL::CommandBuffer* m_CmdBuffer = nullptr; + LLGL::Window* m_Window = nullptr; + + class WindowListener final : public LLGL::Window::EventListener + { + public: + explicit WindowListener(App& app); + + void OnResize(LLGL::Window& sender, const LLGL::Extent2D& clientAreaSize) override; + + void OnQuit(LLGL::Window& sender, bool& veto) override; + + void OnLostFocus(LLGL::Window& sender) override; + + void OnGetFocus(LLGL::Window& sender) override; + private: + App& m_App; + }; + std::shared_ptr m_WindowListener; + + [[nodiscard]] bool ShaderLanguageIsSupported(LLGL::ShadingLanguage lang) const; + + List m_Vertices; + + vec2u m_WindowSize; + void resized(vec2u size); + + void update(bool force = false); + void render() const; + + [[nodiscard]] bool save() const; + + public: App(); ~App(); - LLGL::RenderSystemPtr m_RenderSystem; - LLGL::SwapChain* m_SwapChain; + void Initialize(int argc = 0, char** argv = nullptr); - std::pair m_ShaderPack; - LLGL::PipelineState* m_Pipeline; - LLGL::Buffer* m_VertexBuffer; - LLGL::CommandBuffer* m_CmdBuffer; - LLGL::Window* m_Window; - - bool ShaderLanguageIsSupported(LLGL::ShadingLanguage lang); - - List m_Vertices; - public: - static App& GetInstance(); - - void Run(); + int Run(); }; } diff --git a/include/cigui/core/Memory.hpp b/include/cigui/core/Memory.hpp new file mode 100644 index 0000000..b824d22 --- /dev/null +++ b/include/cigui/core/Memory.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace cig::Memory +{ + template + T* alloc(size_t count = 1); + + template + T* realloc(T* data, size_t from, size_t to); + + template + void dealloc(T* data); + + template + T* dupalloc(const T* data, size_t count = 1); +} + +#include \ No newline at end of file diff --git a/include/cigui/core/Memory.inl b/include/cigui/core/Memory.inl new file mode 100644 index 0000000..2ed3c27 --- /dev/null +++ b/include/cigui/core/Memory.inl @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include + + +namespace cig::Memory +{ + template + T* alloc(const size_t count) { + assert(count > 0 || "Count must be greater than 0"); + T* data = static_cast(calloc(count, sizeof(T))); + MEMORY_ALLOCATOR_DEBUG(data, count); + return data; + } + + template + T* realloc(T* data, const size_t from, const size_t to) + { + assert((from > 0 && data) || "Data must exist"); + assert((to > 0 && to > from) ||"Destination must be greater than Source"); + T* newData = alloc(to); + std::copy(data, data + from, newData); + dealloc(data); + MEMORY_REALLOCATOR_DEBUG(data, newData, to); + return newData; + } + + template + void dealloc(T* data) + { + assert(data || "Data must exist"); + MEMORY_DEALLOCATOR_DEBUG(data); + free(data); + } + + template + T* dupalloc(const T* data, const size_t count) + { + assert(data || "Data must exist"); + assert(count > 0 || "Count must be greater than 0"); + T* ndata = alloc(count); + std::copy(data, data + count, ndata); + MEMORY_DUPALLOCATOR_DEBUG(data, count); + return ndata; + } +} \ No newline at end of file diff --git a/include/cigui/utils/List.hpp b/include/cigui/utils/List.hpp index 18a76e8..752d754 100644 --- a/include/cigui/utils/List.hpp +++ b/include/cigui/utils/List.hpp @@ -8,7 +8,7 @@ namespace cig template class List { - std::unique_ptr m_Data; + T* m_Data = nullptr; size_t m_Size = 0; size_t m_Capacity; @@ -17,10 +17,11 @@ namespace cig public: explicit List(size_t capacity = 3); + ~List(); void own(T* data, size_t size); - void copy(T* data, size_t size); + void copy(const T* data, size_t size); [[nodiscard]] size_t size() const; diff --git a/include/cigui/utils/List.inl b/include/cigui/utils/List.inl index 2bdf3b1..656c6ed 100644 --- a/include/cigui/utils/List.inl +++ b/include/cigui/utils/List.inl @@ -4,6 +4,7 @@ template \ rtt List +#include namespace cig { @@ -11,26 +12,40 @@ namespace cig { if (!m_Data) { - m_Data = std::unique_ptr(static_cast(calloc(capacity, sizeof(T)))); + m_Data = Memory::alloc(capacity); m_Capacity = capacity; return; } - std::unique_ptr newData(static_cast(calloc(capacity, sizeof(T)))); - std::copy(m_Data.get(), m_Data.get() + m_Size, newData.get()); - m_Data = std::move(newData); + m_Data = Memory::realloc(m_Data, m_Size, capacity); m_Capacity = capacity; } - LIST_FUNC_DEFINE( )::List(const size_t capacity) : m_Capacity(capacity) { reserve(capacity); } + template + List::~List() + { + if (m_Data) + Memory::dealloc(m_Data); + } + + + template + List::List(const size_t capacity) + : m_Capacity(capacity) + { + reserve(capacity); + } LIST_FUNC_DEFINE(void)::own(T* data, const size_t size) { + if (m_Data) + { + Memory::dealloc(m_Data); + } m_Data = data; m_Size = size; } - LIST_FUNC_DEFINE(void)::copy(T* data, const size_t size) { - m_Data = std::make_unique(size); - std::copy(data, data + size, m_Data.get()); + LIST_FUNC_DEFINE(void)::copy(const T* data, const size_t size) { + m_Data = Memory::dupalloc(data, size); m_Size = size; } @@ -39,15 +54,15 @@ namespace cig } LIST_FUNC_DEFINE(T &)::operator[](const size_t index) { - return m_Data.get()[index]; + return m_Data[index]; } LIST_FUNC_DEFINE(const T &)::operator[](const size_t index) const { - return m_Data.get()[index]; + return m_Data[index]; } LIST_FUNC_DEFINE(void)::need(const size_t additional_size) { if (m_Size + additional_size > m_Capacity) - reserve(m_Capacity + additional_size); + reserve(m_Capacity + additional_size + growth_summand); } LIST_FUNC_DEFINE(bool)::empty() const { @@ -61,29 +76,29 @@ namespace cig LIST_FUNC_DEFINE(void)::push_back(const T& value) { if (m_Size >= m_Capacity) reserve(m_Capacity * growth_scalar + growth_summand); - m_Data.get()[m_Size++] = value; + m_Data[m_Size++] = value; } LIST_FUNC_DEFINE(template void)::emplace_back(Args&&... args) { if (m_Size >= m_Capacity) reserve(m_Capacity * growth_scalar + growth_summand); - m_Data.get()[m_Size++] = T(std::forward(args)...); + m_Data[m_Size++] = T(std::forward(args)...); } LIST_FUNC_DEFINE(void)::expand(const List& other) { need(other.size()); - std::copy(other.m_Data.get(), other.m_Data.get() + other.size(), m_Data.get() + m_Size); + std::copy(other.m_Data, other.m_Data + other.size(), m_Data + m_Size); m_Size += other.size(); } LIST_FUNC_DEFINE(template void)::iterate(Lambda&& lambda) const { for (size_t i = 0; i < m_Size; i++) - lambda(m_Data.get()[i]); + lambda(m_Data[i]); } - LIST_FUNC_DEFINE(const T *)::data() const { - return m_Data.get(); + LIST_FUNC_DEFINE(const T*)::data() const { + return m_Data; } } diff --git a/include/cigui/utils/MemoryDebug.hpp b/include/cigui/utils/MemoryDebug.hpp new file mode 100644 index 0000000..6da49d6 --- /dev/null +++ b/include/cigui/utils/MemoryDebug.hpp @@ -0,0 +1,159 @@ +#pragma once + +#ifdef _DEBUG +#include +#include +#include + +namespace cig::Memory::Debug +{ + namespace PrettyDurationDump + { + inline std::string DumpDurationPretty(const std::chrono::nanoseconds& duration) + { + using timetype = unsigned long long; + struct + { + bool hours = false; + bool minutes = false; + bool seconds = false; + bool milliseconds = false; + bool microseconds = false; + } m_TimeFlag; + + timetype precice_nanoseconds = duration.count(); + timetype nanoseconds = precice_nanoseconds % 1000; + + timetype precice_microseconds = precice_nanoseconds / 1000; + timetype microseconds = precice_microseconds % 1000; + if (microseconds > 0) m_TimeFlag.microseconds = true; + + timetype precice_milliseconds = precice_microseconds / 1000; + timetype milliseconds = precice_milliseconds % 1000; + if (milliseconds > 0) m_TimeFlag.milliseconds = true; + + timetype precice_seconds = precice_milliseconds / 1000; + timetype seconds = precice_seconds % 60; + if (seconds > 0) m_TimeFlag.seconds = true; + + timetype precice_minutes = precice_seconds / 60; + timetype minutes = precice_minutes % 60; + if (minutes > 0) m_TimeFlag.minutes = true; + + timetype precice_hours = precice_minutes / 60; + timetype hours = precice_hours; + if (hours > 0) m_TimeFlag.hours = true; + + std::stringstream ss; + + if (m_TimeFlag.hours) + ss << hours << "h "; + if (m_TimeFlag.minutes) + ss << minutes << "m "; + if (m_TimeFlag.seconds) + ss << seconds << "s "; + if (m_TimeFlag.milliseconds) + ss << milliseconds << "ms "; + if (m_TimeFlag.microseconds) + ss << microseconds << "us "; + ss << nanoseconds << "ns"; + + return ss.str(); + } + } + + struct ptr_info + { + size_t count, bytes; + const char* var; + const char* file; + const char* func; + int line; + }; + + inline std::unordered_map allocations; + + template + void log_allocation(const T* ptr, const size_t size, const char* var = "", const char* file = "", const char* func = "", int line = 0) + { + allocations[(void*)ptr] = { + size, + sizeof(T), + var, + file, + func, + line + }; + } + + template + void log_deallocator(const T* ptr) + { + allocations.erase(allocations.find((void*)ptr)); + } + + template + void log_reallocator(const T* ptr, const T* newptr, const size_t to, const char* var = "", const char* file = "", const char* func = "", int line = 0) + { + log_allocation(newptr, to, var, file, func, line); + } + + template + void log_dupallocator(const T* ptr, const size_t size, const char* var = "", const char* file = "", const char* func = "", int line = 0) + { + log_allocation(ptr, size, var, file, func, line); + } + + inline void log_info_dump(const char* file, const char* func, int line) + { + static std::chrono::high_resolution_clock::time_point s_LastDump; + static bool s_FirstDump = true; + if (s_FirstDump) + { + s_LastDump = std::chrono::high_resolution_clock::now(); + s_FirstDump = false; + return; + } + + std::cout << "\n------------------------------------ Allocator Debug Info ------------------------------------" << std::endl; + if (file) + std::cout << "\tFile: \t\t" << file << std::endl; + if (func) + std::cout << "\tFunction: \t" << func << std::endl; + if (line) + std::cout << "\tLine: \t\t" << line << std::endl; + // time since last dump + + auto now = std::chrono::high_resolution_clock::now(); + const auto diff = std::chrono::duration_cast(now - s_LastDump); + + std::cout << "\tLast dump:\t" << PrettyDurationDump::DumpDurationPretty(diff) << " ago" << std::endl; + s_LastDump = std::chrono::high_resolution_clock::now(); + + std::cout << "\tAllocations: " << allocations.size() << std::endl; + for (auto& [ptr, info] : allocations) + { + std::cout << "Allocation: " << ptr + << "\n\tSize: " << info.count + << "\n\tBytes: " << info.bytes * info.count + << "\n\tFile: " << info.file + << "\n\tFunction: " << info.func + << "\n\tLine: " << info.line + << "\n\tVariable: " << info.var + << std::endl; + } + std::cout << "----------------------------------------------------------------------------------------------" << std::endl; + } +} + +#define MEMORY_ALLOCATOR_DEBUG(ptr, size) cig::Memory::Debug::log_allocation(ptr, size, #ptr, __FILE__, __FUNCTION__, __LINE__) +#define MEMORY_DEALLOCATOR_DEBUG(ptr) cig::Memory::Debug::log_deallocator(ptr) +#define MEMORY_REALLOCATOR_DEBUG(ptr, newptr, to) cig::Memory::Debug::log_reallocator(ptr, newptr, to, #newptr, __FILE__, __FUNCTION__, __LINE__) +#define MEMORY_DUPALLOCATOR_DEBUG(ptr, size) cig::Memory::Debug::log_dupallocator(ptr, size, #ptr, __FILE__, __FUNCTION__, __LINE__) +#define MEMORY_INFO_DUMP() cig::Memory::Debug::log_info_dump(__FILE__, __FUNCTION__, __LINE__) +#else +#define MEMORY_ALLOCATOR_DEBUG(ptr, size) +#define MEMORY_DEALLOCATOR_DEBUG(ptr) +#define MEMORY_REALLOCATOR_DEBUG(ptr, from, to) +#define MEMORY_DUPALLOCATOR_DEBUG(ptr, size) +#endif \ No newline at end of file diff --git a/include/cigui/utils/MemoryDebug.inl b/include/cigui/utils/MemoryDebug.inl new file mode 100644 index 0000000..73b4b86 --- /dev/null +++ b/include/cigui/utils/MemoryDebug.inl @@ -0,0 +1 @@ +#pragma once diff --git a/include/cigui/utils/Vectors.hpp b/include/cigui/utils/Vectors.hpp index b1ffbf3..161dccb 100644 --- a/include/cigui/utils/Vectors.hpp +++ b/include/cigui/utils/Vectors.hpp @@ -22,14 +22,6 @@ TYPEDEF_VECTOR(NAME, long long, N, ll) \ TYPEDEF_VECTOR(NAME, unsigned long long, N, ull) -#if defined(__GNUC__) || defined(__clang__) - #define UNNAMED_STRUCT __extension__ struct -#else - #define UNNAMED_STRUCT struct - // Disable warning for anonymous structs and unions - #pragma warning(push) - #pragma warning(disable : 4201) -#endif #if CIGUI_DLL #define VECTOR_TEMPLATE_INST(N, T) CIGUI_TEMPLATE_INST Vector##N; \ @@ -57,15 +49,15 @@ namespace cig template union Vector2 { - UNNAMED_STRUCT + struct { T x, y; - }; + } dims; - UNNAMED_STRUCT + struct { - T a, b; - }; + T width, height; + } sizes; }; TYPEDEF_VECTORS(Vector2, 2) @@ -73,15 +65,20 @@ namespace cig template union Vector3 { - UNNAMED_STRUCT + struct { T x, y, z; - }; + } dims; - UNNAMED_STRUCT + struct { T r, g, b; - }; + } color; + + struct + { + T width, height, depth; + } sizes; }; TYPEDEF_VECTORS(Vector3, 3) @@ -89,32 +86,28 @@ namespace cig template union Vector4 { - UNNAMED_STRUCT + struct { T x, y, z, w; - }; + } dims; - UNNAMED_STRUCT + struct { T r, g, b, a; - }; + } color; - UNNAMED_STRUCT + struct { T left, top, right, bottom; - }; + } dirs; }; TYPEDEF_VECTORS(Vector4, 4) } -#if !defined(__GNUC__) && !defined(__clang__) -#pragma warning(pop) -#endif - -#undef UNNAMED_STRUCT #undef TYPEDEF_VECTOR #undef TYPEDEF_VECTORS + #if CIGUI_DLL #undef VECTOR_TEMPLATE_INST #endif diff --git a/src/core/App.cpp b/src/core/App.cpp index 8dd7b24..6c1d621 100644 --- a/src/core/App.cpp +++ b/src/core/App.cpp @@ -3,9 +3,11 @@ #include #include + +#include namespace cig { - App::App() + App::App() : m_WindowListener(std::make_shared(*this)) { // Rectangle m_Vertices.emplace_back(Vertex{ { 0.5f, -0.5f }, { 0, 255, 0, 255 } }); @@ -28,9 +30,13 @@ namespace cig } LLGL::SwapChainDescriptor swapChainDesc; - swapChainDesc.resolution = { 800, 600 }; // Framebuffer resolution of 800x600 pixels - swapChainDesc.fullscreen = false; // No fullscreen, use windowed mode - swapChainDesc.samples = 8; // 8 samples for anti-aliasing + swapChainDesc.resizable = true; + swapChainDesc.debugName = "SwapChain"; + swapChainDesc.swapBuffers = 2; + swapChainDesc.resolution.width = 800; + swapChainDesc.resolution.height = 600; // Framebuffer resolution of 800x600 pixels + swapChainDesc.fullscreen = false; // No fullscreen, use windowed mode + swapChainDesc.samples = 8; // 8 samples for anti-aliasing m_SwapChain = m_RenderSystem->CreateSwapChain(swapChainDesc); LLGL::VertexFormat vertexFormat; @@ -70,60 +76,122 @@ namespace cig } LLGL::GraphicsPipelineDescriptor pipelineDesc; - pipelineDesc.vertexShader = m_ShaderPack.first; - pipelineDesc.fragmentShader = m_ShaderPack.second; - pipelineDesc.rasterizer.multiSampleEnabled = swapChainDesc.samples > 1; + pipelineDesc.vertexShader = m_ShaderPack.first; + pipelineDesc.fragmentShader = m_ShaderPack.second; + pipelineDesc.primitiveTopology = LLGL::PrimitiveTopology::TriangleList; + pipelineDesc.rasterizer.multiSampleEnabled = swapChainDesc.samples > 1; m_Pipeline = m_RenderSystem->CreatePipelineState(pipelineDesc); m_CmdBuffer = m_RenderSystem->CreateCommandBuffer(LLGL::CommandBufferFlags::ImmediateSubmit); } - App::~App() {} + App::~App() + { + } - bool App::ShaderLanguageIsSupported(LLGL::ShadingLanguage lang) + App::WindowListener::WindowListener(App& app) : m_App(app) {} + + void App::WindowListener::OnResize(LLGL::Window& sender, const LLGL::Extent2D& clientAreaSize) + { + EventListener::OnResize(sender, clientAreaSize); + m_App.m_SwapChain->ResizeBuffers(clientAreaSize); + m_App.resized({clientAreaSize.width, clientAreaSize.height}); + m_App.update(true); + m_App.render(); + } + + + void App::WindowListener::OnQuit(LLGL::Window& sender, bool& veto) + { + EventListener::OnQuit(sender, veto); + veto = !m_App.save() || veto; + std::cout << "App: Quit" << std::endl; + } + + void App::WindowListener::OnLostFocus(LLGL::Window& sender) + { + EventListener::OnLostFocus(sender); + std::cout << "App: Lost focus" << std::endl; + } + + void App::WindowListener::OnGetFocus(LLGL::Window& sender) + { + EventListener::OnGetFocus(sender); + std::cout << "App: Got focus" << std::endl; + } + + + bool App::ShaderLanguageIsSupported(LLGL::ShadingLanguage lang) const { const auto& supportedLangs = m_RenderSystem->GetRenderingCaps().shadingLanguages; return std::find(supportedLangs.begin(), supportedLangs.end(), lang) != supportedLangs.end(); } - App& App::GetInstance() + void App::resized(vec2u size) { - static App instance; - return instance; + m_WindowSize = size; } - void App::Run() + void App::Initialize(int argc, char** argv) { - if (!m_RenderSystem) - return; - m_Window = &LLGL::CastTo(m_SwapChain->GetSurface()); - m_Window->SetTitle("Hello Triangle"); - m_Window->Show(); - while (!m_Window->HasQuit()) { - m_Window->ProcessEvents(); + } - m_CmdBuffer->Begin(); + void App::update(bool force) + { + + } + + void App::render() const + { + static LLGL::ClearValue clear_value(.1f,.1f,.1f,1.f); + + m_CmdBuffer->Begin(); + { m_CmdBuffer->SetVertexBuffer(*m_VertexBuffer); m_CmdBuffer->BeginRenderPass(*m_SwapChain); + { + m_CmdBuffer->SetViewport(m_SwapChain->GetResolution()); - m_CmdBuffer->SetViewport(m_SwapChain->GetResolution()); + m_CmdBuffer->Clear(LLGL::ClearFlags::Color, clear_value); - m_CmdBuffer->Clear(LLGL::ClearFlags::Color); - - m_CmdBuffer->SetPipelineState(*m_Pipeline); - - m_CmdBuffer->Draw(m_Vertices.size(), 0); + m_CmdBuffer->SetPipelineState(*m_Pipeline); + { + m_CmdBuffer->Draw(static_cast(m_Vertices.size()), 0); + } + } m_CmdBuffer->EndRenderPass(); - - m_CmdBuffer->End(); - - - m_SwapChain->Present(); } + m_CmdBuffer->End(); + + m_SwapChain->Present(); + } + + bool App::save() const + { + return true; + } + + int App::Run() + { + if (!m_RenderSystem) + return -1; + + m_Window = &LLGL::CastTo(m_SwapChain->GetSurface()); + + m_Window->AddEventListener(m_WindowListener); + + m_Window->SetTitle("Common Interface GUI"); + m_Window->Show(); + + while (LLGL::Surface::ProcessEvents() && !m_Window->HasQuit()) { + update(); + render(); + } + return 0; } }