From 28ce6dcff7315f5f3071b5a00cd58a180dd33505 Mon Sep 17 00:00:00 2001 From: N0ffie Date: Sat, 12 Apr 2025 19:34:26 +0200 Subject: [PATCH 1/7] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bf12953..3a7dbe7 100644 --- a/README.md +++ b/README.md @@ -18,21 +18,22 @@ This document outlines the coding standards and best practices for the CIGUI lib - Header files: `.hpp` for C++ headers, `.h` for C-compatible headers - Implementation files: `.cpp` - Template implementation files: `.inl` -- File names: lowercase with underscores (e.g., `grid_layout.hpp`) +- File names: PascalCase (e.g., `grid_layout.hpp`) #### Classes and Types - Class names: PascalCase (e.g., `Button`, `GridLayout`) -- Type aliases/typedefs: PascalCase (e.g., `using WidgetPtr = std::shared_ptr`) +- Type aliases/typedefs: lowercase (e.g., `using view_ptr = std::shared_ptr`) - Enum names: PascalCase -- Enum values: PascalCase (e.g., `enum class Alignment { TopLeft, Center, BottomRight }`) +- Enum values: PascalCase/UPPERCASE (e.g., `enum class Alignment { TopLeft, Center, BottomRight }` or `enum class Direction { LEFT, UP, RIGHT, DOWN }`) #### Functions and Variables -- Function names: camelCase (e.g., `getPosition()`, `setVisible()`) +- API function names: camelCase (e.g., `getPosition()`, `setVisible()`) +- Internal function names: lowercase (e.g. `render_view()`, `get_visibility()`) - Variable names: camelCase (e.g., `buttonText`, `isVisible`) -- Member variables: prefix with `m_` (e.g., `m_position`, `m_size`) -- Static variables: prefix with `s_` (e.g., `s_defaultFont`) +- Member variables: prefix with `m_` + UpperCamelCase (e.g., `m_Position`, `m_Size`) +- Static variables: prefix with `s_` + UpperCamelCase (e.g., `s_DefaultFont`) - Constants and macros: ALL_CAPS with underscores (e.g., `MAX_WIDGETS`, `CIGUI_API`) ### Code Structure From d2ff63b087c5b99421bd1e26964e23fb54cb8d7d Mon Sep 17 00:00:00 2001 From: N0ffie Date: Sat, 12 Apr 2025 20:29:15 +0200 Subject: [PATCH 2/7] Update README.md Wrong example for file name rule --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a7dbe7..412e09e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This document outlines the coding standards and best practices for the CIGUI lib - Header files: `.hpp` for C++ headers, `.h` for C-compatible headers - Implementation files: `.cpp` - Template implementation files: `.inl` -- File names: PascalCase (e.g., `grid_layout.hpp`) +- File names: PascalCase (e.g., `GridLayout.hpp`) #### Classes and Types From 002d97ee27dca4b086565497b3eb7f304aafcdc7 Mon Sep 17 00:00:00 2001 From: noffie Date: Sat, 12 Apr 2025 21:31:00 +0200 Subject: [PATCH 3/7] Changes in respect to the style guide WIP --- include/cigui/core/Layout.hpp | 114 ++++++++++++++++-------------- include/cigui/core/RenderCall.hpp | 34 ++++----- include/cigui/core/Renderer.hpp | 23 +++--- include/cigui/core/View.hpp | 29 ++------ include/cigui/utils/List.hpp | 61 ++++------------ include/cigui/utils/List.inl | 69 +++++++++++++++++- include/cigui/utils/Vectors.hpp | 110 +++++++++++++++++++--------- include/cigui/views/Rectangle.hpp | 5 ++ src/core/RenderCall.cpp | 15 +++- src/core/Renderer.cpp | 19 +++++ src/core/View.cpp | 29 ++++++++ 11 files changed, 319 insertions(+), 189 deletions(-) create mode 100644 src/core/Renderer.cpp create mode 100644 src/core/View.cpp diff --git a/include/cigui/core/Layout.hpp b/include/cigui/core/Layout.hpp index e35fde0..d031e4a 100644 --- a/include/cigui/core/Layout.hpp +++ b/include/cigui/core/Layout.hpp @@ -3,62 +3,72 @@ #include -namespace cig { -enum class LayoutSizes : uint8_t { - None = 0, - Min, - Max, - Fixed, -}; +namespace cig +{ + enum class LayoutSizes : uint8_t + { + None = 0, + Min, + Max, + Fixed, + }; -enum class LayoutAlignment : uint8_t { - None = 0, - Left, - Right, - Top, - Bottom, - Center, -}; + enum class LayoutAlignment : uint8_t + { + None = 0, + Left, + Right, + Top, + Bottom, + Center, + }; -enum class LayoutDirection : uint8_t { - None = 0, - LeftToRight, - RightToLeft, - TopToBottom, - BottomToTop, -}; + enum class LayoutDirection : uint8_t + { + None = 0, + LeftToRight, + RightToLeft, + TopToBottom, + BottomToTop, + }; -enum class LayoutPosition : uint8_t { - None = 0, - Absolute, - Left, - Right, - Top, - Bottom, - Center, -}; + enum class LayoutPosition : uint8_t + { + None = 0, + Absolute, + Left, + Right, + Top, + Bottom, + Center, + }; -struct Layout { - struct { - LayoutSizes rule = LayoutSizes::None; - vec2f minSize = {0.f, 0.f}; - vec2f maxSize = {0.f, 0.f}; - } size; + struct Layout + { + struct + { + LayoutSizes rule = LayoutSizes::None; + vec2f minSize = {0.f, 0.f}; + vec2f maxSize = {0.f, 0.f}; + } size; - struct { - LayoutAlignment rule = LayoutAlignment::None; - vec4f padding = {0.f, 0.f, 0.f, 0.f}; - vec4f margin = {0.f, 0.f, 0.f, 0.f}; - } alignment; + struct + { + LayoutAlignment rule = LayoutAlignment::None; + vec4f padding = {0.f, 0.f, 0.f, 0.f}; + vec4f margin = {0.f, 0.f, 0.f, 0.f}; + } alignment; - struct { - LayoutDirection rule = LayoutDirection::None; - vec2f spacing = {0.f, 0.f}; - } direction; + struct + { + LayoutDirection rule = LayoutDirection::None; + vec2f spacing = {0.f, 0.f}; + } direction; - struct { - LayoutPosition rule = LayoutPosition::None; - vec2f position = {0.f, 0.f}; - } position; -}; -} \ No newline at end of file + struct + { + LayoutPosition rule = LayoutPosition::None; + vec2f position = {0.f, 0.f}; + } position; + }; +} diff --git a/include/cigui/core/RenderCall.hpp b/include/cigui/core/RenderCall.hpp index f697cd4..9904344 100644 --- a/include/cigui/core/RenderCall.hpp +++ b/include/cigui/core/RenderCall.hpp @@ -1,23 +1,23 @@ #pragma once -#include #include -#include -namespace cig { -class RenderCall { - std::shared_ptr drawable; - sf::RenderStates states; +namespace sf { + class Drawable; + class RenderTarget; + struct RenderStates; +} -public: - explicit RenderCall(const sf::RenderStates &rstates, sf::Drawable *ptr) : drawable(ptr), states(rstates) { - if (!drawable) { - throw std::runtime_error("RenderCall::RenderCall(): Drawable is null"); - } - } +namespace cig +{ + class RenderCall + { + std::shared_ptr drawable; + sf::RenderStates states; - void draw(sf::RenderTarget &target, const sf::RenderStates &rstates) const { - target.draw(*drawable, rstates); - } -}; -} \ No newline at end of file + public: + explicit RenderCall(const sf::RenderStates& rstates, sf::Drawable* ptr); + + void draw(sf::RenderTarget& target, const sf::RenderStates& rstates) const; + }; +} diff --git a/include/cigui/core/Renderer.hpp b/include/cigui/core/Renderer.hpp index 7597f1a..100f22a 100644 --- a/include/cigui/core/Renderer.hpp +++ b/include/cigui/core/Renderer.hpp @@ -1,29 +1,24 @@ #pragma once -#pragma once - -#include #include -#include -#include +namespace sf { + class RenderTarget; + class RenderStates; +} namespace cig { + class View; + class RenderCall; class Renderer { public: - explicit Renderer(View *_view) : view(_view) { view->draw(); } + explicit Renderer(View *_view); std::unique_ptr view; - void update() const { - if (view->update()) - view->draw(); - } + void update() const; - void render(sf::RenderTarget &target, const sf::RenderStates &states) const { - auto lambda = [&target, &states](const RenderCall& renderCall) { renderCall.draw(target, states); }; - view->renderCalls().iterate(lambda); - } + void render(sf::RenderTarget &target, const sf::RenderStates &states) const; }; } diff --git a/include/cigui/core/View.hpp b/include/cigui/core/View.hpp index 5617ebf..f307a28 100644 --- a/include/cigui/core/View.hpp +++ b/include/cigui/core/View.hpp @@ -1,14 +1,14 @@ #pragma once - -#include #include -#include -#include +#include +#include namespace cig { + class RenderCall; + class View { protected: List m_RenderCalls; @@ -17,27 +17,12 @@ namespace cig public: virtual ~View() = default; - [[nodiscard]] const List &renderCalls() const { return m_RenderCalls; } + [[nodiscard]] const List& renderCalls() const; std::unique_ptr content; - virtual bool update() { - if (content) - return content->update(); - return false; - } + virtual bool update(); - void draw() { - if (!m_RenderCalls.empty()) { - m_RenderCalls.clear(); - } - content = std::unique_ptr(body()); - if (!content) { - return; - } - content->draw(); - auto &contentRenderCalls = content->renderCalls(); - m_RenderCalls.expand(contentRenderCalls); - } + void draw(); virtual View *body() = 0; }; diff --git a/include/cigui/utils/List.hpp b/include/cigui/utils/List.hpp index 6a086d5..2bde179 100644 --- a/include/cigui/utils/List.hpp +++ b/include/cigui/utils/List.hpp @@ -2,6 +2,7 @@ #include #include + namespace cig { template @@ -12,68 +13,36 @@ namespace cig size_t m_Capacity; protected: - void reserve(const size_t capacity); + void reserve(size_t capacity); public: - explicit List(const size_t capacity = 3) : m_Capacity(capacity) { reserve(capacity); } + explicit List(size_t capacity = 3); - void own(T* data, const size_t size) - { - m_Data = data; - m_Size = size; - } + void own(T* data, size_t size); - void copy(T* data, const size_t size) - { - m_Data = std::make_unique(size); - std::copy(data, data + size, m_Data.get()); - m_Size = size; - } + void copy(T* data, size_t size); - [[nodiscard]] size_t size() const { return m_Size; } + [[nodiscard]] size_t size() const; - T& operator[](size_t index) { return m_Data.get()[index]; } + T& operator[](size_t index); - const T& operator[](size_t index) const { return m_Data.get()[index]; } + const T& operator[](size_t index) const; - void need(const size_t additional_size) - { - if (m_Size + additional_size > m_Capacity) - reserve(m_Capacity + additional_size); - } + void need(size_t additional_size); - [[nodiscard]] bool empty() const { return m_Size == 0; } + [[nodiscard]] bool empty() const; - void clear() { m_Size = 0; } + void clear(); - void push_back(const T& value) - { - if (m_Size >= m_Capacity) - reserve(m_Capacity * growth_scalar + growth_summand); - m_Data.get()[m_Size++] = value; - } + void push_back(const T& value); 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)...); - } + void emplace_back(Args&&... args); - 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); - m_Size += other.size(); - } + void expand(const List& other); template - void iterate(Lambda&& lambda) const - { - for (size_t i = 0; i < m_Size; i++) - lambda(m_Data.get()[i]); - } + void iterate(Lambda&& lambda) const; }; } #include \ No newline at end of file diff --git a/include/cigui/utils/List.inl b/include/cigui/utils/List.inl index bf937bf..4cc57f4 100644 --- a/include/cigui/utils/List.inl +++ b/include/cigui/utils/List.inl @@ -1,12 +1,13 @@ +#include -#define __LIST_FUNC_DEFINE__(rtt) \ +#define LIST_FUNC_DEFINE(rtt) \ template \ rtt List namespace cig { - __LIST_FUNC_DEFINE__(void)::reserve(const size_t capacity) + LIST_FUNC_DEFINE(void)::reserve(const size_t capacity) { if (!m_Data) { @@ -19,4 +20,68 @@ namespace cig m_Data = std::move(newData); m_Capacity = capacity; } + + LIST_FUNC_DEFINE()::List(const size_t capacity) : m_Capacity(capacity) { reserve(capacity); } + + LIST_FUNC_DEFINE(void)::own(T* data, const size_t size) { + 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()); + m_Size = size; + } + + LIST_FUNC_DEFINE(size_t)::size() const { + return m_Size; + } + + LIST_FUNC_DEFINE(T &)::operator[](const size_t index) { + return m_Data.get()[index]; + } + LIST_FUNC_DEFINE(const T &)::operator[](const size_t index) const { + return m_Data.get()[index]; + } + + LIST_FUNC_DEFINE(void)::need(const size_t additional_size) { + if (m_Size + additional_size > m_Capacity) + reserve(m_Capacity + additional_size); + } + + LIST_FUNC_DEFINE(bool)::empty() const { + return m_Size == 0; + } + + LIST_FUNC_DEFINE(void)::clear() { + m_Size = 0; + } + + 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; + } + + + 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)...); + } + + 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); + 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]); + } } + +#undef LIST_FUNC_DEFINE \ No newline at end of file diff --git a/include/cigui/utils/Vectors.hpp b/include/cigui/utils/Vectors.hpp index c44d461..4035f18 100644 --- a/include/cigui/utils/Vectors.hpp +++ b/include/cigui/utils/Vectors.hpp @@ -1,7 +1,10 @@ #pragma once +#include + #include + #define TYPEDEF_VECTOR(NAME, T, N, s) typedef NAME vec##N##s; #define TYPEDEF_VECTORS(NAME, N) \ @@ -20,47 +23,84 @@ TYPEDEF_VECTOR(NAME, unsigned long long, N, ull) #if defined(__GNUC__) || defined(__clang__) - #define UNNAMED_STRUCT __extension__ struct +#define UNNAMED_STRUCT __extension__ struct #else #defien UNNAMED_STRUCT struct #endif +#if CIGUI_DLL +#define VECTOR_TEMPLATE_INST(N, T) CIGUI_TEMPLATE_INST Vector##N; \ -namespace cig { -template -union Vector2 { - UNNAMED_STRUCT { - T x, y; - }; - UNNAMED_STRUCT { - T a, b; - }; -}; +#define VECTOR_INSTANTIATION(N) \ + VECTOR_TEMPLATE_INST(N, float) \ + VECTOR_TEMPLATE_INST(N, double)\ + VECTOR_TEMPLATE_INST(N, long double) \ + VECTOR_TEMPLATE_INST(N, size_t) \ + VECTOR_TEMPLATE_INST(N, int) \ + VECTOR_TEMPLATE_INST(N, short) \ + VECTOR_TEMPLATE_INST(N, long) \ + VECTOR_TEMPLATE_INST(N, long long) \ + VECTOR_TEMPLATE_INST(N, unsigned int) \ + VECTOR_TEMPLATE_INST(N, unsigned short) \ + VECTOR_TEMPLATE_INST(N, unsigned long) \ + VECTOR_TEMPLATE_INST(N, unsigned long long) +#else +#define VECTOR_INSTANTIATION(N) +#endif -TYPEDEF_VECTORS(Vector2, 2) -template -union Vector3 { - UNNAMED_STRUCT { - T x, y, z; - }; - UNNAMED_STRUCT { - T r, g, b; - }; -}; -TYPEDEF_VECTORS(Vector3, 3) +namespace cig +{ + template + union Vector2 + { + UNNAMED_STRUCT + { + T x, y; + }; -template -union Vector4 { - UNNAMED_STRUCT { - T x, y, z, w; - }; - UNNAMED_STRUCT { - T r, g, b, a; - }; - UNNAMED_STRUCT { - T left, top, right, bottom; - }; -}; -TYPEDEF_VECTORS(Vector4, 4) + UNNAMED_STRUCT + { + T a, b; + }; + }; + + TYPEDEF_VECTORS(Vector2, 2) + + template + union Vector3 + { + UNNAMED_STRUCT + { + T x, y, z; + }; + + UNNAMED_STRUCT + { + T r, g, b; + }; + }; + + TYPEDEF_VECTORS(Vector3, 3) + + template + union Vector4 + { + UNNAMED_STRUCT + { + T x, y, z, w; + }; + + UNNAMED_STRUCT + { + T r, g, b, a; + }; + + UNNAMED_STRUCT + { + T left, top, right, bottom; + }; + }; + + TYPEDEF_VECTORS(Vector4, 4) } diff --git a/include/cigui/views/Rectangle.hpp b/include/cigui/views/Rectangle.hpp index c21e9eb..1d62bde 100644 --- a/include/cigui/views/Rectangle.hpp +++ b/include/cigui/views/Rectangle.hpp @@ -1,6 +1,11 @@ #pragma once #include +#include + +namespace sf { + class RectangleShape; +} namespace cig { struct Rectangle : View { diff --git a/src/core/RenderCall.cpp b/src/core/RenderCall.cpp index 5f28270..9873f90 100644 --- a/src/core/RenderCall.cpp +++ b/src/core/RenderCall.cpp @@ -1 +1,14 @@ - \ No newline at end of file +#include +#include +#include +#include + +namespace cig { + RenderCall::RenderCall(const sf::RenderStates& rstates, sf::Drawable* ptr) : drawable(ptr), states(rstates) { + if (!drawable) { throw std::runtime_error("RenderCall::RenderCall(): Drawable is null"); } + } + + void RenderCall::draw(sf::RenderTarget& target, const sf::RenderStates& rstates) const { + target.draw(*drawable, rstates); + } +} \ No newline at end of file diff --git a/src/core/Renderer.cpp b/src/core/Renderer.cpp new file mode 100644 index 0000000..2e852ca --- /dev/null +++ b/src/core/Renderer.cpp @@ -0,0 +1,19 @@ +#include + +#include +#include +#include + +namespace cig { + Renderer::Renderer(View *_view) : view(_view) { view->draw(); } + + void Renderer::update() const { + if (view->update()) + view->draw(); + } + + void Renderer::render(sf::RenderTarget &target, const sf::RenderStates &states) const { + auto lambda = [&target, &states](const RenderCall &renderCall) { renderCall.draw(target, states); }; + view->renderCalls().iterate(lambda); + } +} \ No newline at end of file diff --git a/src/core/View.cpp b/src/core/View.cpp new file mode 100644 index 0000000..f390243 --- /dev/null +++ b/src/core/View.cpp @@ -0,0 +1,29 @@ +#include + +#include + +namespace cig { + const List& View::renderCalls() const + { + return m_RenderCalls; + } + + void View::draw() { + if (!m_RenderCalls.empty()) { + m_RenderCalls.clear(); + } + content = std::unique_ptr(body()); + if (!content) { + return; + } + content->draw(); + auto &contentRenderCalls = content->renderCalls(); + m_RenderCalls.expand(contentRenderCalls); + } + + bool View::update() { + if (content) + return content->update(); + return false; + } +} \ No newline at end of file From f337ff9f0d53b3ec87db119782a07052af823ff9 Mon Sep 17 00:00:00 2001 From: noffie Date: Sun, 13 Apr 2025 17:54:14 +0200 Subject: [PATCH 4/7] WIP: Rewrite with LLGL --- CMakeLists.txt | 96 +++++++++---- cmake/CIGUIConfig.cmake.in | 4 +- examples/CMakeLists.txt | 37 +++-- examples/Full/General/src/main.cpp | 75 +--------- .../Full/General/src/shader/MyShader.frag | 18 +++ .../Full/General/src/shader/MyShader.hlsl | 28 ++++ .../Full/General/src/shader/MyShader.vert | 20 +++ include/cigui/cigui.hpp | 4 +- include/cigui/config.h.in | 9 +- include/cigui/core/App.hpp | 39 ++++++ include/cigui/core/Layout.hpp | 74 ---------- include/cigui/core/RenderCall.hpp | 23 ---- include/cigui/core/Renderer.hpp | 24 ---- include/cigui/core/View.hpp | 29 ---- include/cigui/utils/List.hpp | 3 + include/cigui/utils/List.inl | 15 +- include/cigui/utils/Vectors.hpp | 19 ++- include/cigui/views/Rectangle.hpp | 48 ------- include/cigui/views/views.hpp | 3 - src/core/App.cpp | 129 ++++++++++++++++++ src/core/RenderCall.cpp | 14 -- src/core/Renderer.cpp | 19 --- src/core/View.cpp | 29 ---- tests/CMakeLists.txt | 8 +- 24 files changed, 377 insertions(+), 390 deletions(-) create mode 100644 examples/Full/General/src/shader/MyShader.frag create mode 100644 examples/Full/General/src/shader/MyShader.hlsl create mode 100644 examples/Full/General/src/shader/MyShader.vert create mode 100644 include/cigui/core/App.hpp delete mode 100644 include/cigui/core/Layout.hpp delete mode 100644 include/cigui/core/RenderCall.hpp delete mode 100644 include/cigui/core/Renderer.hpp delete mode 100644 include/cigui/core/View.hpp delete mode 100644 include/cigui/views/Rectangle.hpp delete mode 100644 include/cigui/views/views.hpp create mode 100644 src/core/App.cpp delete mode 100644 src/core/RenderCall.cpp delete mode 100644 src/core/Renderer.cpp delete mode 100644 src/core/View.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e736a4..3e541fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,23 @@ cmake_minimum_required(VERSION 3.14) project(cigui VERSION 0.0.1 - LANGUAGES CXX) + LANGUAGES CXX C) # Options -option(CIGUI_BUILD_SHARED "Build CIGUI as a shared library" ON) +option(CIGUI_BUILD_SHARED "Build CIGUI as a shared library" OFF) option(CIGUI_BUILD_EXAMPLES "Build example applications" ON) option(CIGUI_BUILD_TESTS "Build tests" OFF) -option(CIGUI_ENABLE_ASAN "Enable Address Sanitizer (Debug)" OFF) -option(CIGUI_ENABLE_UBSAN "Enable Undefined Behavior Sanitizer (Debug)" OFF) -option(CIGUI_ENABLE_WARNINGS "Enable additional compiler warnings" ON) + +option(CIGUI_ENABLE_ASAN "Enable Address Sanitizer (Debug)" ON) +option(CIGUI_ENABLE_UBSAN "Enable Undefined Behavior Sanitizer (Debug)" ON) +option(CIGUI_ENABLE_WARNINGS "Enable additional compiler warnings" OFF) + +option(CIGUI_RENDERER_VULKAN "Use Vulkan renderer (if available)" ON) +option(CIGUI_RENDERER_OPENGL "Use OpenGL renderer (if available)" ON) +option(CIGUI_RENDERER_DIRECT3D11 "Use Direct3D 11 renderer (if available on Windows)" OFF) +option(CIGUI_RENDERER_DIRECT3D12 "Use Direct3D 12 renderer (if available on Windows)" ON) +option(CIGUI_RENDERER_METAL "Use Metal renderer (if available on macOS)" ON) + # Set C++ standard @@ -60,19 +68,62 @@ if(CIGUI_BUILD_SHARED) endif() endif() -# Include CPM.cmake for dependency management -include(cmake/CPM.cmake) +# Function to find all libraries in a directory +function(link_libraries_in_directory target directory) + # Find all library files based on platform + if(WIN32) + file(GLOB LIBRARIES "${directory}/*.lib") + elseif(APPLE) + file(GLOB LIBRARIES "${directory}/*.dylib" "${directory}/*.a") + else() # Linux and others + file(GLOB LIBRARIES "${directory}/*.so" "${directory}/*.a") + endif() + + # Link each found library + foreach(LIB ${LIBRARIES}) + target_link_libraries(${target} PRIVATE ${LIB}) + message(STATUS "Linking with library: ${LIB}") + endforeach() +endfunction() -# Add SFML dependency using CPM -CPMAddPackage( - NAME SFML - GITHUB_REPOSITORY SFML/SFML - GIT_TAG 3.0.0 # Adjust to actual SFML 3 version/tag - OPTIONS - "SFML_BUILD_AUDIO OFF" - "SFML_BUILD_NETWORK OFF" - "CMAKE_DEBUG_POSTFIX -d" # Add debug postfix for debug builds -) + +set(LIB_LLGL_PATH "W:/Jann/aLibs/LLGLVD" CACHE STRING "The path to the LLGL installation") + +set(LLGL_PATH "${LIB_LLGL_PATH}/lib/cmake/LLGL") + +set(LLGL_LIB_PATH "${LIB_LLGL_PATH}/lib") +set(LLGL_BIN_PATH "${LIB_LLGL_PATH}/bin") +set(LLGL_INCLUDE_PATH "${LIB_LLGL_PATH}/include") +set(LLGL_CMAKE_PATH "${LIB_LLGL_PATH}/lib/cmake/LLGL") + +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${LLGL_PATH}") + +# Add LLGL dependency +find_package(LLGL REQUIRED HINTS ${LLGL_CMAKE_PATH}) + +set(CMAKE_CXX_STANDARD 20) + +# Configure renderer backends based on platform and options +if(WIN32) + if(CIGUI_RENDERER_DIRECT3D11) + add_definitions(-DCIGUI_RENDERER_D3D11) + endif() + if(CIGUI_RENDERER_DIRECT3D12) + add_definitions(-DCIGUI_RENDERER_D3D12) + endif() +endif() + +if(CIGUI_RENDERER_OPENGL) + add_definitions(-DCIGUI_RENDERER_OPENGL) +endif() + +if(CIGUI_RENDERER_VULKAN) + add_definitions(-DCIGUI_RENDERER_VULKAN) +endif() + +if(APPLE AND CIGUI_RENDERER_METAL) + add_definitions(-DCIGUI_RENDERER_METAL) +endif() # Generate export macros include(GenerateExportHeader) @@ -88,15 +139,15 @@ else() add_library(cigui STATIC) endif() +link_libraries_in_directory(cigui ${LLGL_LIB_PATH}) +target_include_directories(cigui PUBLIC ${LLGL_INCLUDE_PATH}) + # Enable precompiled headers for faster builds if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16) target_precompile_headers(cigui PRIVATE - - - ) endif() @@ -116,9 +167,6 @@ target_include_directories(cigui ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Link with SFML -target_link_libraries(cigui PUBLIC sfml-graphics sfml-window sfml-system) - # Define installation include(GNUInstallDirs) include(CMakePackageConfigHelpers) @@ -175,6 +223,6 @@ endif() # Add tests directory if(CIGUI_BUILD_TESTS) - include(CTest) + include(CTest) add_subdirectory(tests) endif() diff --git a/cmake/CIGUIConfig.cmake.in b/cmake/CIGUIConfig.cmake.in index 9dd02ff..de35001 100644 --- a/cmake/CIGUIConfig.cmake.in +++ b/cmake/CIGUIConfig.cmake.in @@ -3,9 +3,9 @@ # Import targets created by CIGUITargets.cmake include("${CMAKE_CURRENT_LIST_DIR}/CIGUITargets.cmake") -# Ensure SFML is available +# Ensure LLGL is available include(CMakeFindDependencyMacro) -find_dependency(SFML 3 COMPONENTS graphics window system) +find_dependency(LLGL REQUIRED) # Define convenient imported target if it doesn't exist if(NOT TARGET cigui::cigui) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ca6c628..bba7f05 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,20 +6,33 @@ function(add_cigui_example NAME) find_files(EXAMPLE_${NAME}_SOURCES "${NAME}/src" cpp c cxx hpp h hxx inl) add_executable(EXAMPLE_${NAME} ${EXAMPLE_${NAME}_SOURCES}) target_link_libraries(EXAMPLE_${NAME} PRIVATE cigui) + link_libraries_in_directory(EXAMPLE_${NAME} ${LLGL_LIB_PATH}) + target_include_directories(EXAMPLE_${NAME} PRIVATE ${LLGL_INCLUDE_PATH}) set_target_properties(EXAMPLE_${NAME} PROPERTIES OUTPUT_NAME "${NAME}") - - # Copy SFML DLLs to output directory on Windows when building shared - if(WIN32 AND CIGUI_BUILD_SHARED) - add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $ - $ - $ - ) - endif() + + add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${LLGL_BIN_PATH} + $ + COMMENT "Coppied LLGL binaries to example directory" + ) + + add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}/src/shader + $/shader + COMMENT "Coppied shaders to example directory" + ) + + # Copy DLLs to output directory on Windows when building shared + if(WIN32 AND CIGUI_BUILD_SHARED) + add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + ) + endif() endfunction() # Basic example diff --git a/examples/Full/General/src/main.cpp b/examples/Full/General/src/main.cpp index 6ee210c..5494e36 100644 --- a/examples/Full/General/src/main.cpp +++ b/examples/Full/General/src/main.cpp @@ -1,73 +1,6 @@ -// -// Created by n0ffie on 08/04/25. -// +#include -#include +int main() { + cig::App::GetInstance().Run(); +} -#include -#include - -// WIP - not working yet -// Layout unsupported -struct HStack final : cig::View { - using Stack = cig::List; - Stack views; - - void append(View* view) { views.push_back(view); } - - bool update() override { - bool needs_redraw = false; - views.iterate([this, &needs_redraw](View*& view) { if (view->update()) needs_redraw = true; }); - return needs_redraw; - } - - View* body() override { - views.iterate<>([this](View*& view) { view->draw(); }); - views.iterate([this](View*& view) { - this->m_RenderCalls.expand(view->renderCalls()); - }); - return nullptr; - } -}; - -struct NewView final : cig::View { - View* body() override { - auto List = new HStack(); - - auto view = new cig::Rectangle({400, 400}); - view->setBorderColor(sf::Color::Red)->setBorderThickness(5)->setColor(sf::Color::Green); - List->append(view); - - view = new cig::Rectangle({100, 100}); - view->setBorderColor(sf::Color::Blue)->setBorderThickness(5)->setColor(sf::Color::Yellow); - List->append(view); - - return List; - } -}; - -int main(int argc, char** argv) { - sf::RenderWindow window(sf::VideoMode({800, 600}), "Hello World!"); - - const auto view = new NewView(); - const cig::Renderer renderer(view); - - while (window.isOpen()) { - - while (const std::optional event = window.pollEvent()) - { - if (event->is()) - { - window.close(); - } - } - - renderer.update(); - - window.clear(); - renderer.render(window, sf::RenderStates()); - window.display(); - } - - return 0; -} \ No newline at end of file diff --git a/examples/Full/General/src/shader/MyShader.frag b/examples/Full/General/src/shader/MyShader.frag new file mode 100644 index 0000000..61b4020 --- /dev/null +++ b/examples/Full/General/src/shader/MyShader.frag @@ -0,0 +1,18 @@ +// GLSL shader version 1.30 (for OpenGL 3.1) +#version 130 + +#ifdef GL_ES +precision mediump float; +#endif + +// Fragment input from the vertex shader +in vec3 vertexColor; + +// Fragment output color +out vec4 fragColor; + +// Fragment shader main function +void main() +{ + fragColor = vec4(vertexColor, 1); +} diff --git a/examples/Full/General/src/shader/MyShader.hlsl b/examples/Full/General/src/shader/MyShader.hlsl new file mode 100644 index 0000000..d8d4939 --- /dev/null +++ b/examples/Full/General/src/shader/MyShader.hlsl @@ -0,0 +1,28 @@ +// HLSL shader version 4.0 (for Direct3D 11/ 12) + +struct InputVS +{ + float2 position : POSITION; + float3 color : COLOR; +}; + +struct OutputVS +{ + float4 position : SV_Position; + float3 color : COLOR; +}; + +// Vertex shader main function +OutputVS VS(InputVS inp) +{ + OutputVS outp; + outp.position = float4(inp.position, 0, 1); + outp.color = inp.color; + return outp; +} + +// Pixel shader main function +float4 PS(OutputVS inp) : SV_Target +{ + return float4(inp.color, 1); +}; diff --git a/examples/Full/General/src/shader/MyShader.vert b/examples/Full/General/src/shader/MyShader.vert new file mode 100644 index 0000000..e1854d3 --- /dev/null +++ b/examples/Full/General/src/shader/MyShader.vert @@ -0,0 +1,20 @@ +// GLSL shader version 1.30 (for OpenGL 3.1) +#version 130 + +#ifdef GL_ES +precision mediump float; +#endif + +// Vertex attributes (these names must match our vertex format attributes) +in vec2 position; +in vec3 color; + +// Vertex output to the fragment shader +out vec3 vertexColor; + +// Vertex shader main function +void main() +{ + gl_Position = vec4(position, 0, 1); + vertexColor = color; +} diff --git a/include/cigui/cigui.hpp b/include/cigui/cigui.hpp index cb07c78..48c9429 100644 --- a/include/cigui/cigui.hpp +++ b/include/cigui/cigui.hpp @@ -2,11 +2,9 @@ #include -#include -#include -#include #include +#include namespace cig { constexpr unsigned int VERSION_MAJOR = CIGUI_VERSION_MAJOR; diff --git a/include/cigui/config.h.in b/include/cigui/config.h.in index 7e46f48..179563b 100644 --- a/include/cigui/config.h.in +++ b/include/cigui/config.h.in @@ -34,4 +34,11 @@ #define CIGUI_TEMPLATE_API // Special macro for template instantiations -#define CIGUI_TEMPLATE_INST extern template class CIGUI_API \ No newline at end of file +#define CIGUI_TEMPLATE_INST extern template class CIGUI_API + +// Supported LLGL rendering backends - defined by CMake +// #cmakedefine CIGUI_RENDERER_OPENGL +// #cmakedefine CIGUI_RENDERER_VULKAN +// #cmakedefine CIGUI_RENDERER_D3D11 +// #cmakedefine CIGUI_RENDERER_D3D12 +// #cmakedefine CIGUI_RENDERER_METAL \ No newline at end of file diff --git a/include/cigui/core/App.hpp b/include/cigui/core/App.hpp new file mode 100644 index 0000000..7ec2807 --- /dev/null +++ b/include/cigui/core/App.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include + +namespace cig +{ + struct Vertex + { + float position[2]; // 2D vector for X and Y coordinates + uint8_t color[4]; // 4D vector for red, green, blue, and alpha components + }; + + class App + { + protected: + App(); + ~App(); + + LLGL::RenderSystemPtr m_RenderSystem; + LLGL::SwapChain* m_SwapChain; + + 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(); + }; +} diff --git a/include/cigui/core/Layout.hpp b/include/cigui/core/Layout.hpp deleted file mode 100644 index d031e4a..0000000 --- a/include/cigui/core/Layout.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - - -namespace cig -{ - enum class LayoutSizes : uint8_t - { - None = 0, - Min, - Max, - Fixed, - }; - - enum class LayoutAlignment : uint8_t - { - None = 0, - Left, - Right, - Top, - Bottom, - Center, - }; - - enum class LayoutDirection : uint8_t - { - None = 0, - LeftToRight, - RightToLeft, - TopToBottom, - BottomToTop, - }; - - enum class LayoutPosition : uint8_t - { - None = 0, - Absolute, - Left, - Right, - Top, - Bottom, - Center, - }; - - struct Layout - { - struct - { - LayoutSizes rule = LayoutSizes::None; - vec2f minSize = {0.f, 0.f}; - vec2f maxSize = {0.f, 0.f}; - } size; - - struct - { - LayoutAlignment rule = LayoutAlignment::None; - vec4f padding = {0.f, 0.f, 0.f, 0.f}; - vec4f margin = {0.f, 0.f, 0.f, 0.f}; - } alignment; - - struct - { - LayoutDirection rule = LayoutDirection::None; - vec2f spacing = {0.f, 0.f}; - } direction; - - struct - { - LayoutPosition rule = LayoutPosition::None; - vec2f position = {0.f, 0.f}; - } position; - }; -} diff --git a/include/cigui/core/RenderCall.hpp b/include/cigui/core/RenderCall.hpp deleted file mode 100644 index 9904344..0000000 --- a/include/cigui/core/RenderCall.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace sf { - class Drawable; - class RenderTarget; - struct RenderStates; -} - -namespace cig -{ - class RenderCall - { - std::shared_ptr drawable; - sf::RenderStates states; - - public: - explicit RenderCall(const sf::RenderStates& rstates, sf::Drawable* ptr); - - void draw(sf::RenderTarget& target, const sf::RenderStates& rstates) const; - }; -} diff --git a/include/cigui/core/Renderer.hpp b/include/cigui/core/Renderer.hpp deleted file mode 100644 index 100f22a..0000000 --- a/include/cigui/core/Renderer.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -namespace sf { - class RenderTarget; - class RenderStates; -} - -namespace cig { - class View; - class RenderCall; - - class Renderer { - public: - explicit Renderer(View *_view); - - std::unique_ptr view; - - void update() const; - - void render(sf::RenderTarget &target, const sf::RenderStates &states) const; - }; -} diff --git a/include/cigui/core/View.hpp b/include/cigui/core/View.hpp deleted file mode 100644 index f307a28..0000000 --- a/include/cigui/core/View.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace cig -{ - class RenderCall; - - class View { - protected: - List m_RenderCalls; - Layout m_Layout; - - public: - virtual ~View() = default; - - [[nodiscard]] const List& renderCalls() const; - std::unique_ptr content; - - virtual bool update(); - - void draw(); - - virtual View *body() = 0; - }; -} \ No newline at end of file diff --git a/include/cigui/utils/List.hpp b/include/cigui/utils/List.hpp index 2bde179..18a76e8 100644 --- a/include/cigui/utils/List.hpp +++ b/include/cigui/utils/List.hpp @@ -43,6 +43,9 @@ namespace cig template void iterate(Lambda&& lambda) const; + + const T* data() const; + }; } #include \ No newline at end of file diff --git a/include/cigui/utils/List.inl b/include/cigui/utils/List.inl index 4cc57f4..2bdf3b1 100644 --- a/include/cigui/utils/List.inl +++ b/include/cigui/utils/List.inl @@ -1,8 +1,8 @@ -#include +#pragma once -#define LIST_FUNC_DEFINE(rtt) \ - template \ - rtt List +#define LIST_FUNC_DEFINE(rtt) \ + template \ + rtt List namespace cig @@ -21,7 +21,7 @@ namespace cig m_Capacity = capacity; } - LIST_FUNC_DEFINE()::List(const size_t capacity) : m_Capacity(capacity) { reserve(capacity); } + LIST_FUNC_DEFINE( )::List(const size_t capacity) : m_Capacity(capacity) { reserve(capacity); } LIST_FUNC_DEFINE(void)::own(T* data, const size_t size) { m_Data = data; @@ -64,7 +64,6 @@ namespace cig m_Data.get()[m_Size++] = value; } - LIST_FUNC_DEFINE(template void)::emplace_back(Args&&... args) { if (m_Size >= m_Capacity) reserve(m_Capacity * growth_scalar + growth_summand); @@ -82,6 +81,10 @@ namespace cig for (size_t i = 0; i < m_Size; i++) lambda(m_Data.get()[i]); } + + LIST_FUNC_DEFINE(const T *)::data() const { + return m_Data.get(); + } } #undef LIST_FUNC_DEFINE \ No newline at end of file diff --git a/include/cigui/utils/Vectors.hpp b/include/cigui/utils/Vectors.hpp index 4035f18..b1ffbf3 100644 --- a/include/cigui/utils/Vectors.hpp +++ b/include/cigui/utils/Vectors.hpp @@ -23,9 +23,12 @@ TYPEDEF_VECTOR(NAME, unsigned long long, N, ull) #if defined(__GNUC__) || defined(__clang__) -#define UNNAMED_STRUCT __extension__ struct + #define UNNAMED_STRUCT __extension__ struct #else - #defien UNNAMED_STRUCT struct + #define UNNAMED_STRUCT struct + // Disable warning for anonymous structs and unions + #pragma warning(push) + #pragma warning(disable : 4201) #endif #if CIGUI_DLL @@ -104,3 +107,15 @@ namespace cig 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 +#undef VECTOR_INSTANTIATION \ No newline at end of file diff --git a/include/cigui/views/Rectangle.hpp b/include/cigui/views/Rectangle.hpp deleted file mode 100644 index 1d62bde..0000000 --- a/include/cigui/views/Rectangle.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include - -namespace sf { - class RectangleShape; -} - -namespace cig { - struct Rectangle : View { - sf::Color m_Color; - sf::Color m_BorderColor; - float m_BorderThickness = 0; - - Rectangle *setBorderColor(const sf::Color &color) { - m_BorderColor = color; - return this; - } - Rectangle *setBorderThickness(float thickness) { - m_BorderThickness = thickness; - return this; - } - Rectangle *setColor(const sf::Color &color) { - m_Color = color; - return this; - } - Rectangle *setSize(const vec2f &size) { - m_Layout.size.minSize = size; - return this; - } - - View *body() override { - auto m_Shape = new sf::RectangleShape(sf::Vector2f{m_Layout.size.minSize.x, m_Layout.size.minSize.y}); - m_Shape->setFillColor(m_Color); - if (m_BorderThickness > 0) { - m_Shape->setOutlineThickness(m_BorderThickness); - m_Shape->setOutlineColor(m_BorderColor); - } - m_RenderCalls.emplace_back(sf::RenderStates(), m_Shape); - return nullptr; - } - - explicit Rectangle(const vec2f &size) { - m_Layout.size.minSize = size; - } - }; -} \ No newline at end of file diff --git a/include/cigui/views/views.hpp b/include/cigui/views/views.hpp deleted file mode 100644 index 41fd855..0000000 --- a/include/cigui/views/views.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include \ No newline at end of file diff --git a/src/core/App.cpp b/src/core/App.cpp new file mode 100644 index 0000000..8dd7b24 --- /dev/null +++ b/src/core/App.cpp @@ -0,0 +1,129 @@ +#include + +#include +#include + +namespace cig +{ + App::App() + { + // Rectangle + m_Vertices.emplace_back(Vertex{ { 0.5f, -0.5f }, { 0, 255, 0, 255 } }); + m_Vertices.emplace_back(Vertex{ { -0.5f, -0.5f }, { 255, 0, 0, 255 } }); + m_Vertices.emplace_back(Vertex{ { -0.5f, 0.5f }, { 0, 0, 255, 255 } }); + m_Vertices.emplace_back(Vertex{ { 0.5f, 0.5f }, { 255, 0, 0, 255 } }); + m_Vertices.emplace_back(Vertex{ { -0.5f, -0.5f }, { 0, 255, 0, 255 } }); + m_Vertices.emplace_back(Vertex{ { -0.5f, 0.5f }, { 0, 0, 255, 255 } }); + + for (const char* module : { "Direct3D12", "Direct3D11", "Vulkan", "OpenGL" }) { + LLGL::Report report; + m_RenderSystem = LLGL::RenderSystem::Load(module, &report); + if (m_RenderSystem == nullptr) { + LLGL::Log::Errorf("%s", report.GetText()); + } + } + if (m_RenderSystem == nullptr) { + std::cout << "No renderer found!" << std::endl; + return; + } + + 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 + m_SwapChain = m_RenderSystem->CreateSwapChain(swapChainDesc); + + LLGL::VertexFormat vertexFormat; + vertexFormat.AppendAttribute({ "position", LLGL::Format::RG32Float }); + vertexFormat.AppendAttribute({ "color", LLGL::Format::RGBA8UNorm }); + + LLGL::BufferDescriptor VBufferDesc; + VBufferDesc.size = sizeof(Vertex) * m_Vertices.size(); // Size (in bytes) of the buffer + VBufferDesc.bindFlags = LLGL::BindFlags::VertexBuffer; // Use for vertex buffer binding + VBufferDesc.vertexAttribs = vertexFormat.attributes; // Vertex buffer attributes + m_VertexBuffer = m_RenderSystem->CreateBuffer(VBufferDesc, m_Vertices.data()); + + LLGL::ShaderDescriptor VSDesc, FSDesc; + if (ShaderLanguageIsSupported(LLGL::ShadingLanguage::HLSL)) { + VSDesc = { LLGL::ShaderType::Vertex, "shader/MyShader.hlsl", "VMain", "vs_4_0" }; + FSDesc = { LLGL::ShaderType::Fragment, "shader/MyShader.hlsl", "PMain", "ps_4_0" }; + } else if (ShaderLanguageIsSupported(LLGL::ShadingLanguage::GLSL)) { + VSDesc = { LLGL::ShaderType::Vertex, "shader/MyShader.vert" }; + FSDesc = { LLGL::ShaderType::Fragment, "shader/MyShader.frag" }; + } else { + std::cout << "Shading language not supported!" << std::endl; + return; + } + VSDesc.vertex.inputAttribs = vertexFormat.attributes; + + m_ShaderPack.first = m_RenderSystem->CreateShader(VSDesc); + m_ShaderPack.second = m_RenderSystem->CreateShader(FSDesc); + + for (LLGL::Shader* shader : { m_ShaderPack.first, m_ShaderPack.second }) { + if (const LLGL::Report* report = shader->GetReport()) { + if (report->HasErrors()) { + LLGL::Log::Errorf("Shader compile errors:\n%s", report->GetText()); + } else { + LLGL::Log::Printf("Shader compile warnings:\n%s", report->GetText()); + } + } + } + + LLGL::GraphicsPipelineDescriptor pipelineDesc; + pipelineDesc.vertexShader = m_ShaderPack.first; + pipelineDesc.fragmentShader = m_ShaderPack.second; + pipelineDesc.rasterizer.multiSampleEnabled = swapChainDesc.samples > 1; + + m_Pipeline = m_RenderSystem->CreatePipelineState(pipelineDesc); + + m_CmdBuffer = m_RenderSystem->CreateCommandBuffer(LLGL::CommandBufferFlags::ImmediateSubmit); + } + + App::~App() {} + + + bool App::ShaderLanguageIsSupported(LLGL::ShadingLanguage lang) + { + const auto& supportedLangs = m_RenderSystem->GetRenderingCaps().shadingLanguages; + return std::find(supportedLangs.begin(), supportedLangs.end(), lang) != supportedLangs.end(); + } + + App& App::GetInstance() + { + static App instance; + return instance; + } + + void App::Run() + { + 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(); + m_CmdBuffer->SetVertexBuffer(*m_VertexBuffer); + + m_CmdBuffer->BeginRenderPass(*m_SwapChain); + + m_CmdBuffer->SetViewport(m_SwapChain->GetResolution()); + + m_CmdBuffer->Clear(LLGL::ClearFlags::Color); + + m_CmdBuffer->SetPipelineState(*m_Pipeline); + + m_CmdBuffer->Draw(m_Vertices.size(), 0); + + m_CmdBuffer->EndRenderPass(); + + m_CmdBuffer->End(); + + + m_SwapChain->Present(); + } + } +} diff --git a/src/core/RenderCall.cpp b/src/core/RenderCall.cpp deleted file mode 100644 index 9873f90..0000000 --- a/src/core/RenderCall.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include - -namespace cig { - RenderCall::RenderCall(const sf::RenderStates& rstates, sf::Drawable* ptr) : drawable(ptr), states(rstates) { - if (!drawable) { throw std::runtime_error("RenderCall::RenderCall(): Drawable is null"); } - } - - void RenderCall::draw(sf::RenderTarget& target, const sf::RenderStates& rstates) const { - target.draw(*drawable, rstates); - } -} \ No newline at end of file diff --git a/src/core/Renderer.cpp b/src/core/Renderer.cpp deleted file mode 100644 index 2e852ca..0000000 --- a/src/core/Renderer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include -#include -#include - -namespace cig { - Renderer::Renderer(View *_view) : view(_view) { view->draw(); } - - void Renderer::update() const { - if (view->update()) - view->draw(); - } - - void Renderer::render(sf::RenderTarget &target, const sf::RenderStates &states) const { - auto lambda = [&target, &states](const RenderCall &renderCall) { renderCall.draw(target, states); }; - view->renderCalls().iterate(lambda); - } -} \ No newline at end of file diff --git a/src/core/View.cpp b/src/core/View.cpp deleted file mode 100644 index f390243..0000000 --- a/src/core/View.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include - -#include - -namespace cig { - const List& View::renderCalls() const - { - return m_RenderCalls; - } - - void View::draw() { - if (!m_RenderCalls.empty()) { - m_RenderCalls.clear(); - } - content = std::unique_ptr(body()); - if (!content) { - return; - } - content->draw(); - auto &contentRenderCalls = content->renderCalls(); - m_RenderCalls.expand(contentRenderCalls); - } - - bool View::update() { - if (content) - return content->update(); - return false; - } -} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 57106f1..0521662 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,9 +35,7 @@ function(add_cigui_test TEST_NAME) if(WIN32 AND CIGUI_BUILD_SHARED) add_custom_command(TARGET ${TEST_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $ + $ $ $ ) @@ -73,9 +71,7 @@ add_test(NAME cigui_tests COMMAND cigui_tests) if(WIN32 AND CIGUI_BUILD_SHARED) add_custom_command(TARGET cigui_tests POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $ + $ $ $ ) From 550fc291de11bc8ee1d4821415aaecaa7c0378c5 Mon Sep 17 00:00:00 2001 From: n0ffie Date: Sun, 13 Apr 2025 20:24:19 +0200 Subject: [PATCH 5/7] CMake for linux --- CMakeLists.txt | 8 ++++++-- examples/CMakeLists.txt | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e541fa..3ca2eb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,12 +87,16 @@ function(link_libraries_in_directory target directory) endfunction() -set(LIB_LLGL_PATH "W:/Jann/aLibs/LLGLVD" CACHE STRING "The path to the LLGL installation") +set(LIB_LLGL_PATH "/home/n0ffie/deps/LLGLD" CACHE STRING "The path to the LLGL installation") set(LLGL_PATH "${LIB_LLGL_PATH}/lib/cmake/LLGL") set(LLGL_LIB_PATH "${LIB_LLGL_PATH}/lib") -set(LLGL_BIN_PATH "${LIB_LLGL_PATH}/bin") + +if (WIN32) + set(LLGL_BIN_PATH "${LIB_LLGL_PATH}/bin") +endif() + set(LLGL_INCLUDE_PATH "${LIB_LLGL_PATH}/include") set(LLGL_CMAKE_PATH "${LIB_LLGL_PATH}/lib/cmake/LLGL") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index bba7f05..afaf505 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -11,12 +11,21 @@ function(add_cigui_example NAME) set_target_properties(EXAMPLE_${NAME} PROPERTIES OUTPUT_NAME "${NAME}") - add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD + if (WIN32) + add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${LLGL_BIN_PATH} $ COMMENT "Coppied LLGL binaries to example directory" - ) + ) + else() + add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${LLGL_LIB_PATH} + $ + COMMENT "Coppied LLGL binaries to example directory" + ) + endif() add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory From 3679beaa4e00653055b0583bae38a8764eb4f8ad Mon Sep 17 00:00:00 2001 From: noffie Date: Sun, 20 Apr 2025 17:49:15 +0200 Subject: [PATCH 6/7] 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; } } From b12e608567776ad2c43afaecf1b737a95ce617a1 Mon Sep 17 00:00:00 2001 From: noffie Date: Sun, 20 Apr 2025 18:48:25 +0200 Subject: [PATCH 7/7] Add a standalone style guide document Moved the CIGUI style guide from `README.md` to a dedicated `StyleGuide.md` file for better organization. This improves readability and ensures the main README remains focused on project goals and usage. --- README.md | 244 -------------------------------------------------- StyleGuide.md | 240 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 244 deletions(-) create mode 100644 StyleGuide.md diff --git a/README.md b/README.md index c524860..421b5fe 100644 --- a/README.md +++ b/README.md @@ -1,249 +1,5 @@ # cigui -## CIGUI Style Guide - -This document outlines the coding standards and best practices for the CIGUI library. Following these guidelines ensures consistency across the project and makes the codebase more maintainable. - -### General Principles - -- **Clarity over cleverness**: Write code that's easy to understand, not code that's clever. -- **Consistency**: Follow established patterns within the codebase. -- **Documentation**: Document public APIs thoroughly. -- **Testability**: Write code that can be easily tested. - -### Naming Conventions - -#### Files - -- Header files: `.hpp` for C++ headers, `.h` for C-compatible headers -- Implementation files: `.cpp` -- Template implementation files: `.inl` -- File names: lowercase with underscores (e.g., `grid_layout.hpp`) - -#### Classes and Types - -- Class names: PascalCase (e.g., `Button`, `GridLayout`) -- Type aliases/typedefs: PascalCase (e.g., `using WidgetPtr = std::shared_ptr`) -- Enum names: PascalCase -- Enum values: PascalCase (e.g., `enum class Alignment { TopLeft, Center, BottomRight }`) - -#### Functions and Variables - -- Function names: camelCase (e.g., `getPosition()`, `setVisible()`) -- Variable names: camelCase (e.g., `buttonText`, `isVisible`) -- Member variables: prefix with `m_` (e.g., `m_position`, `m_size`) -- Static variables: prefix with `s_` (e.g., `s_defaultFont`) -- Constants and macros: ALL_CAPS with underscores (e.g., `MAX_WIDGETS`, `CIGUI_API`) - -### Code Structure - -#### Namespaces - -- All library code should be inside the `cig` namespace -- Avoid deeply nested namespaces -- Do not use `using namespace` in headers - -```cpp -// Good -namespace cig { - class Button : public View { - // ... - }; -} - -// Bad -using namespace sf; // Don't do this in headers -``` - -#### Headers - -- Always use include guards with project-specific prefix -- Order includes as follows: - 1. Related header - 2. C++ standard library headers - 3. Third-party library headers (SFML) - 4. CIGUI headers -- Forward declare classes when possible to reduce dependencies - -```cpp -// Example of a good header structure -#pragma once - -#include -#include -#include -#include -#include - -namespace cig { - -class View; // Forward declaration - -class CIGUI_API Container { - // Implementation -}; - -} // namespace cig -``` - -#### Classes - -- Separate public, protected, and private sections -- Order within sections: - 1. Constructors/Destructors - 2. Public methods - 3. Event callbacks - 4. Static methods - 5. Member variables - -```cpp -class Button : public View { -public: - // Constructors/Destructors - Button(); - explicit Button(const std::string& text); - ~Button() override; - - // Methods - void setText(const std::string& text); - const std::string& getText() const; - - // Event dispatcher - EventDispatcher onClicked; - -protected: - // Protected methods - void updateAppearance(); - -private: - // Private methods - void initializeGraphics(); - - // Member variables - std::string m_text; - sf::RectangleShape m_background; - bool m_isHovered; -}; -``` - -### Templates - -- Template implementation should be in `.inl` files -- Use explicit instantiation for common types in DLLs -- Document template parameters - -```cpp -// In .hpp file -template -class Container { - // ... -}; - -// Include the implementation -#include - -// In .inl file -template -Container::Container() { - // ... -} - -// In .cpp file for explicit instantiation -template class Container; -template class Container; -``` - -### C++ Features - -- **C++ Standard**: Use C++20 features where appropriate -- **Smart Pointers**: Use `std::unique_ptr` for exclusive ownership, `std::shared_ptr` for shared ownership -- **Auto**: Use `auto` when the type is obvious or when using iterators -- **Range-based for loops**: Prefer over traditional for loops -- **Lambdas**: Use for short callbacks and event handlers -- **Move Semantics**: Support move operations where appropriate - -### Comments and Documentation - -- Use Doxygen-style comments for public APIs -- Comment complex algorithms and non-obvious code -- Avoid redundant comments that just repeat the code - -```cpp -/** - * @brief Creates a button with the specified label text - * - * @param text The text to display on the button - * @param size The size of the button (default: 100x30) - */ -Button(const std::string& text, const sf::Vector2f& size = {100.f, 30.f}); -``` - -### Error Handling - -- Use exceptions for exceptional cases only -- Validate input parameters and handle edge cases -- Document error conditions in function comments - -### Memory Management - -- Prefer automatic memory management with smart pointers -- Explicitly define ownership models in documentation -- Design with RAII principles (Resource Acquisition Is Initialization) - -### DLL/Shared Library Considerations - -- Use `CIGUI_API` macro for all classes and non-inline functions -- Use `CIGUI_TEMPLATE_API` for template classes -- Handle template instantiation properly (see Templates section) - -### SFML Integration - -- Wrap SFML types when extending functionality -- Use SFML conventions for graphics-related code -- Don't expose SFML implementation details in public APIs when avoidable - -### Testing - -- Write unit tests for core functionality -- Test edge cases and error conditions -- Create interactive examples for UI components - -### Formatting - -- Indentation: 4 spaces (no tabs) -- Line length: 100 characters maximum -- Braces: Open brace on same line, close brace on new line -- Space after keywords (if, for, while) -- No space after function names -- Place * and & with the type, not the variable name - -```cpp -// Good formatting example -if (condition) { - doSomething(); -} else { - doSomethingElse(); -} - -void setPosition(const sf::Vector2f& position) { - m_position = position; -} -``` - -### Best Practices - -- Prefer composition over inheritance -- Design interfaces that are hard to use incorrectly -- Follow the Rule of Five/Zero for class design -- Make data members private and provide accessors when needed -- Consider performance implications in UI code (avoid work in draw methods) - ---- - -This style guide is a living document and may evolve as the project grows. When in doubt, maintain consistency with the existing codebase. - ---- - ## Goal ```cpp diff --git a/StyleGuide.md b/StyleGuide.md new file mode 100644 index 0000000..bb6753c --- /dev/null +++ b/StyleGuide.md @@ -0,0 +1,240 @@ +## CIGUI Style Guide + +This document outlines the coding standards and best practices for the CIGUI library. Following these guidelines ensures consistency across the project and makes the codebase more maintainable. + +### General Principles + +- **Clarity over cleverness**: Write code that's easy to understand, not code that's clever. +- **Consistency**: Follow established patterns within the codebase. +- **Documentation**: Document public APIs thoroughly. +- **Testability**: Write code that can be easily tested. + +### Naming Conventions + +#### Files + +- Header files: `.hpp` for C++ headers, `.h` for C-compatible headers +- Implementation files: `.cpp` +- Template implementation files: `.inl` +- File names: lowercase with underscores (e.g., `grid_layout.hpp`) + +#### Classes and Types + +- Class names: PascalCase (e.g., `Button`, `GridLayout`) +- Type aliases/typedefs: PascalCase (e.g., `using WidgetPtr = std::shared_ptr`) +- Enum names: PascalCase +- Enum values: PascalCase (e.g., `enum class Alignment { TopLeft, Center, BottomRight }`) + +#### Functions and Variables + +- Function names: camelCase (e.g., `getPosition()`, `setVisible()`) +- Variable names: camelCase (e.g., `buttonText`, `isVisible`) +- Member variables: prefix with `m_` (e.g., `m_position`, `m_size`) +- Static variables: prefix with `s_` (e.g., `s_defaultFont`) +- Constants and macros: ALL_CAPS with underscores (e.g., `MAX_WIDGETS`, `CIGUI_API`) + +### Code Structure + +#### Namespaces + +- All library code should be inside the `cig` namespace +- Avoid deeply nested namespaces +- Do not use `using namespace` in headers + +```cpp +// Good +namespace cig { + class Button : public View { + // ... + }; +} + +// Bad +using namespace sf; // Don't do this in headers +``` + +#### Headers + +- Always use `#pragma once` +- Order includes as follows: + 1. Related header + 2. C++ standard library headers + 3. Third-party library headers (SFML) + 4. CIGUI headers +- Forward declare classes when possible to reduce dependencies + +```cpp +// Example of a good header structure +#pragma once + +#include +#include +#include +#include +#include + +namespace cig { + +class View; // Forward declaration + +class CIGUI_API Container { + // Implementation +}; + +} // namespace cig +``` + +#### Classes + +- Separate public, protected, and private sections +- Order within sections: + 1. Constructors/Destructors + 2. Public methods + 3. Event callbacks + 4. Static methods + 5. Member variables + +```cpp +class Button : public View { +public: + // Constructors/Destructors + Button(); + explicit Button(const std::string& text); + ~Button() override; + + // Methods + void setText(const std::string& text); + const std::string& getText() const; + + // Event dispatcher + EventDispatcher onClicked; + +protected: + // Protected methods + void updateAppearance(); + +private: + // Private methods + void initializeGraphics(); + + // Member variables + std::string m_text; + sf::RectangleShape m_background; + bool m_isHovered; +}; +``` + +### Templates + +- Template implementation should be in `.inl` files +- Use explicit instantiation for common types in DLLs +- Document template parameters + +```cpp +// In .hpp file +template +class Container { + // ... +}; + +// Include the implementation +#include + +// In .inl file +template +Container::Container() { + // ... +} + +// In .cpp file for explicit instantiation +template class Container; +template class Container; +``` + +### C++ Features + +- **C++ Standard**: Use C++20 features where appropriate +- **Smart Pointers**: Use `std::unique_ptr` for exclusive ownership, `std::shared_ptr` for shared ownership +- **Auto**: Use `auto` when the type is obvious or when using iterators +- **Range-based for loops**: Prefer over traditional for loops +- **Lambdas**: Use for short callbacks and event handlers +- **Move Semantics**: Support move operations where appropriate + +### Comments and Documentation + +- Use Doxygen-style comments for public APIs +- Comment complex algorithms and non-obvious code +- Avoid redundant comments that just repeat the code + +```cpp +/** + * @brief Creates a button with the specified label text + * + * @param text The text to display on the button + * @param size The size of the button (default: 100x30) + */ +Button(const std::string& text, const sf::Vector2f& size = {100.f, 30.f}); +``` + +### Error Handling + +- Use exceptions for exceptional cases only +- Validate input parameters and handle edge cases +- Document error conditions in function comments + +### Memory Management + +- Prefer automatic memory management with smart pointers +- Explicitly define ownership models in documentation +- Design with RAII principles (Resource Acquisition Is Initialization) + +### DLL/Shared Library Considerations +**TODO:** Think about this and add more details + +### SFML Integration + +- Wrap SFML types when extending functionality +- Use SFML conventions for graphics-related code +- Don't expose SFML implementation details in public APIs when avoidable + +### Testing + +- Write unit tests for core functionality +- Test edge cases and error conditions +- Create interactive examples for UI components + +### Formatting + +- Indentation: 4 spaces (no tabs) +- Line length: 100 characters maximum +- Braces: Open brace on same line, close brace on new line +- Space after keywords (if, for, while) +- No space after function names +- Place * and & with the type, not the variable name + +```cpp +// Good formatting example +if (condition) { + doSomething(); +} else { + doSomethingElse(); +} + +void setPosition(const sf::Vector2f& position) { + m_position = position; +} +``` + +### Best Practices + +- Prefer composition over inheritance +- Design interfaces that are hard to use incorrectly +- Follow the Rule of Five/Zero for class design +- Make data members private and provide accessors when needed +- Consider performance implications in UI code (avoid work in draw methods) + +--- + +This style guide is a living document and may evolve as the project grows. When in doubt, maintain consistency with the existing codebase. + +---