Compare commits
6 commits
main
...
dev/n0ffie
Author | SHA1 | Date | |
---|---|---|---|
b12e608567 | |||
3679beaa4e | |||
550fc291de | |||
f337ff9f0d | |||
002d97ee27 | |||
4a004dcb8b |
29 changed files with 1177 additions and 660 deletions
100
CMakeLists.txt
100
CMakeLists.txt
|
@ -1,15 +1,23 @@
|
||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
project(cigui
|
project(cigui
|
||||||
VERSION 0.0.1
|
VERSION 0.0.1
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX C)
|
||||||
|
|
||||||
# Options
|
# 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_EXAMPLES "Build example applications" ON)
|
||||||
option(CIGUI_BUILD_TESTS "Build tests" OFF)
|
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_ASAN "Enable Address Sanitizer (Debug)" ON)
|
||||||
option(CIGUI_ENABLE_WARNINGS "Enable additional compiler warnings" 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
|
# Set C++ standard
|
||||||
|
@ -60,19 +68,66 @@ if(CIGUI_BUILD_SHARED)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Include CPM.cmake for dependency management
|
# Function to find all libraries in a directory
|
||||||
include(cmake/CPM.cmake)
|
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(
|
set(LIB_LLGL_PATH "/home/n0ffie/deps/LLGLD" CACHE STRING "The path to the LLGL installation")
|
||||||
NAME SFML
|
|
||||||
GITHUB_REPOSITORY SFML/SFML
|
set(LLGL_PATH "${LIB_LLGL_PATH}/lib/cmake/LLGL")
|
||||||
GIT_TAG 3.0.0 # Adjust to actual SFML 3 version/tag
|
|
||||||
OPTIONS
|
set(LLGL_LIB_PATH "${LIB_LLGL_PATH}/lib")
|
||||||
"SFML_BUILD_AUDIO OFF"
|
|
||||||
"SFML_BUILD_NETWORK OFF"
|
if (WIN32)
|
||||||
"CMAKE_DEBUG_POSTFIX -d" # Add debug postfix for debug builds
|
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")
|
||||||
|
|
||||||
|
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
|
# Generate export macros
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
@ -88,15 +143,15 @@ else()
|
||||||
add_library(cigui STATIC)
|
add_library(cigui STATIC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
link_libraries_in_directory(cigui ${LLGL_LIB_PATH})
|
||||||
|
target_include_directories(cigui PUBLIC ${LLGL_INCLUDE_PATH})
|
||||||
|
|
||||||
# Enable precompiled headers for faster builds
|
# Enable precompiled headers for faster builds
|
||||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16)
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16)
|
||||||
target_precompile_headers(cigui PRIVATE
|
target_precompile_headers(cigui PRIVATE
|
||||||
<string>
|
<string>
|
||||||
<memory>
|
<memory>
|
||||||
<functional>
|
<functional>
|
||||||
<SFML/Graphics.hpp>
|
|
||||||
<SFML/Window.hpp>
|
|
||||||
<SFML/System.hpp>
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -116,9 +171,6 @@ target_include_directories(cigui
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
)
|
)
|
||||||
|
|
||||||
# Link with SFML
|
|
||||||
target_link_libraries(cigui PUBLIC sfml-graphics sfml-window sfml-system)
|
|
||||||
|
|
||||||
# Define installation
|
# Define installation
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
@ -175,6 +227,6 @@ endif()
|
||||||
|
|
||||||
# Add tests directory
|
# Add tests directory
|
||||||
if(CIGUI_BUILD_TESTS)
|
if(CIGUI_BUILD_TESTS)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
275
README.md
275
README.md
|
@ -1,249 +1,5 @@
|
||||||
# cigui
|
# 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<View>`)
|
|
||||||
- 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 <cigui/config.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <SFML/Graphics/Drawable.hpp>
|
|
||||||
#include <cigui/utils/rect.hpp>
|
|
||||||
|
|
||||||
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<MouseEvent> 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<typename T>
|
|
||||||
class Container {
|
|
||||||
// ...
|
|
||||||
};
|
|
||||||
|
|
||||||
// Include the implementation
|
|
||||||
#include <cigui/widgets/container.inl>
|
|
||||||
|
|
||||||
// In .inl file
|
|
||||||
template<typename T>
|
|
||||||
Container<T>::Container() {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// In .cpp file for explicit instantiation
|
|
||||||
template class Container<int>;
|
|
||||||
template class Container<std::string>;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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
|
## Goal
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
@ -281,4 +37,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"
|
||||||
|
}
|
||||||
```
|
```
|
240
StyleGuide.md
Normal file
240
StyleGuide.md
Normal file
|
@ -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<View>`)
|
||||||
|
- 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 <cigui/config.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <cigui/utils/rect.hpp>
|
||||||
|
|
||||||
|
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<MouseEvent> 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<typename T>
|
||||||
|
class Container {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
|
||||||
|
// Include the implementation
|
||||||
|
#include <cigui/widgets/container.inl>
|
||||||
|
|
||||||
|
// In .inl file
|
||||||
|
template<typename T>
|
||||||
|
Container<T>::Container() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// In .cpp file for explicit instantiation
|
||||||
|
template class Container<int>;
|
||||||
|
template class Container<std::string>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
---
|
|
@ -3,9 +3,9 @@
|
||||||
# Import targets created by CIGUITargets.cmake
|
# Import targets created by CIGUITargets.cmake
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/CIGUITargets.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/CIGUITargets.cmake")
|
||||||
|
|
||||||
# Ensure SFML is available
|
# Ensure LLGL is available
|
||||||
include(CMakeFindDependencyMacro)
|
include(CMakeFindDependencyMacro)
|
||||||
find_dependency(SFML 3 COMPONENTS graphics window system)
|
find_dependency(LLGL REQUIRED)
|
||||||
|
|
||||||
# Define convenient imported target if it doesn't exist
|
# Define convenient imported target if it doesn't exist
|
||||||
if(NOT TARGET cigui::cigui)
|
if(NOT TARGET cigui::cigui)
|
||||||
|
|
|
@ -6,20 +6,42 @@ function(add_cigui_example NAME)
|
||||||
find_files(EXAMPLE_${NAME}_SOURCES "${NAME}/src" cpp c cxx hpp h hxx inl)
|
find_files(EXAMPLE_${NAME}_SOURCES "${NAME}/src" cpp c cxx hpp h hxx inl)
|
||||||
add_executable(EXAMPLE_${NAME} ${EXAMPLE_${NAME}_SOURCES})
|
add_executable(EXAMPLE_${NAME} ${EXAMPLE_${NAME}_SOURCES})
|
||||||
target_link_libraries(EXAMPLE_${NAME} PRIVATE cigui)
|
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}")
|
set_target_properties(EXAMPLE_${NAME} PROPERTIES OUTPUT_NAME "${NAME}")
|
||||||
|
|
||||||
# Copy SFML DLLs to output directory on Windows when building shared
|
if (WIN32)
|
||||||
if(WIN32 AND CIGUI_BUILD_SHARED)
|
add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD
|
||||||
add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
${LLGL_BIN_PATH}
|
||||||
$<TARGET_FILE:sfml-graphics>
|
$<TARGET_FILE_DIR:EXAMPLE_${NAME}>
|
||||||
$<TARGET_FILE:sfml-window>
|
COMMENT "Coppied LLGL binaries to example directory"
|
||||||
$<TARGET_FILE:sfml-system>
|
)
|
||||||
$<TARGET_FILE:cigui>
|
else()
|
||||||
$<TARGET_FILE_DIR:EXAMPLE_${NAME}>
|
add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD
|
||||||
)
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
endif()
|
${LLGL_LIB_PATH}
|
||||||
|
$<TARGET_FILE_DIR:EXAMPLE_${NAME}>
|
||||||
|
COMMENT "Coppied LLGL binaries to example directory"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(TARGET EXAMPLE_${NAME} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${NAME}/src/shader
|
||||||
|
$<TARGET_FILE_DIR:EXAMPLE_${NAME}>/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
|
||||||
|
$<TARGET_FILE:cigui>
|
||||||
|
$<TARGET_FILE_DIR:EXAMPLE_${NAME}>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Basic example
|
# Basic example
|
||||||
|
|
|
@ -1,73 +1,10 @@
|
||||||
//
|
|
||||||
// Created by n0ffie on 08/04/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <cigui/cigui.hpp>
|
#include <cigui/cigui.hpp>
|
||||||
#include <cigui/utils/List.hpp>
|
|
||||||
|
|
||||||
// WIP - not working yet
|
|
||||||
// Layout unsupported
|
|
||||||
struct HStack final : cig::View {
|
|
||||||
using Stack = cig::List<View*>;
|
|
||||||
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) {
|
int main(int argc, char** argv) {
|
||||||
sf::RenderWindow window(sf::VideoMode({800, 600}), "Hello World!");
|
MEM_CHECKED_MAIN(return_code) {
|
||||||
|
auto app = cig::App();
|
||||||
const auto view = new NewView();
|
return_code = app.Run();
|
||||||
const cig::Renderer renderer(view);
|
|
||||||
|
|
||||||
while (window.isOpen()) {
|
|
||||||
|
|
||||||
while (const std::optional event = window.pollEvent())
|
|
||||||
{
|
|
||||||
if (event->is<sf::Event::Closed>())
|
|
||||||
{
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.update();
|
|
||||||
|
|
||||||
window.clear();
|
|
||||||
renderer.render(window, sf::RenderStates());
|
|
||||||
window.display();
|
|
||||||
}
|
}
|
||||||
|
return return_code;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
18
examples/Full/General/src/shader/MyShader.frag
Normal file
18
examples/Full/General/src/shader/MyShader.frag
Normal file
|
@ -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);
|
||||||
|
}
|
28
examples/Full/General/src/shader/MyShader.hlsl
Normal file
28
examples/Full/General/src/shader/MyShader.hlsl
Normal file
|
@ -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);
|
||||||
|
};
|
20
examples/Full/General/src/shader/MyShader.vert
Normal file
20
examples/Full/General/src/shader/MyShader.vert
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
#include <iosteam>
|
#include <iostream>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "Hello World" << std::endl;
|
std::cout << "Hello World" << std::endl;
|
||||||
|
|
|
@ -2,11 +2,21 @@
|
||||||
|
|
||||||
|
|
||||||
#include <cigui/config.h>
|
#include <cigui/config.h>
|
||||||
#include <cigui/core/Renderer.hpp>
|
|
||||||
#include <cigui/core/View.hpp>
|
|
||||||
#include <cigui/views/views.hpp>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <cigui/utils/MemoryDebug.hpp>
|
||||||
|
|
||||||
|
#include <cigui/core/App.hpp>
|
||||||
|
|
||||||
|
#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 {
|
namespace cig {
|
||||||
constexpr unsigned int VERSION_MAJOR = CIGUI_VERSION_MAJOR;
|
constexpr unsigned int VERSION_MAJOR = CIGUI_VERSION_MAJOR;
|
||||||
|
|
|
@ -34,4 +34,11 @@
|
||||||
#define CIGUI_TEMPLATE_API
|
#define CIGUI_TEMPLATE_API
|
||||||
|
|
||||||
// Special macro for template instantiations
|
// Special macro for template instantiations
|
||||||
#define CIGUI_TEMPLATE_INST extern template class CIGUI_API
|
#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
|
79
include/cigui/core/App.hpp
Normal file
79
include/cigui/core/App.hpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cigui/config.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <LLGL/LLGL.h>
|
||||||
|
|
||||||
|
#include <cigui/utils/List.hpp>
|
||||||
|
#include <cigui/utils/Vectors.hpp>
|
||||||
|
|
||||||
|
namespace cig
|
||||||
|
{
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
class App
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
LLGL::RenderSystemPtr m_RenderSystem;
|
||||||
|
std::pair<LLGL::Shader*, LLGL::Shader*> 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<WindowListener> m_WindowListener;
|
||||||
|
|
||||||
|
[[nodiscard]] bool ShaderLanguageIsSupported(LLGL::ShadingLanguage lang) const;
|
||||||
|
|
||||||
|
List<Vertex> m_Vertices;
|
||||||
|
|
||||||
|
vec2u m_WindowSize;
|
||||||
|
void resized(vec2u size);
|
||||||
|
|
||||||
|
void update(bool force = false);
|
||||||
|
void render() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool save() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
App();
|
||||||
|
~App();
|
||||||
|
|
||||||
|
void Initialize(int argc = 0, char** argv = nullptr);
|
||||||
|
|
||||||
|
int Run();
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,64 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cigui/utils/Vectors.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
18
include/cigui/core/Memory.hpp
Normal file
18
include/cigui/core/Memory.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace cig::Memory
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
T* alloc(size_t count = 1);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* realloc(T* data, size_t from, size_t to);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dealloc(T* data);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* dupalloc(const T* data, size_t count = 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cigui/core/Memory.inl>
|
49
include/cigui/core/Memory.inl
Normal file
49
include/cigui/core/Memory.inl
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cigui/utils/MemoryDebug.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cig::Memory
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
T* alloc(const size_t count) {
|
||||||
|
assert(count > 0 || "Count must be greater than 0");
|
||||||
|
T* data = static_cast<T*>(calloc(count, sizeof(T)));
|
||||||
|
MEMORY_ALLOCATOR_DEBUG(data, count);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<T>(to);
|
||||||
|
std::copy(data, data + from, newData);
|
||||||
|
dealloc<T>(data);
|
||||||
|
MEMORY_REALLOCATOR_DEBUG(data, newData, to);
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dealloc(T* data)
|
||||||
|
{
|
||||||
|
assert(data || "Data must exist");
|
||||||
|
MEMORY_DEALLOCATOR_DEBUG(data);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<T>(count);
|
||||||
|
std::copy(data, data + count, ndata);
|
||||||
|
MEMORY_DUPALLOCATOR_DEBUG(data, count);
|
||||||
|
return ndata;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <sfml/Graphics.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace cig {
|
|
||||||
class RenderCall {
|
|
||||||
std::shared_ptr<sf::Drawable> drawable;
|
|
||||||
sf::RenderStates states;
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(sf::RenderTarget &target, const sf::RenderStates &rstates) const {
|
|
||||||
target.draw(*drawable, rstates);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <cigui/core/View.hpp>
|
|
||||||
#include <cigui/core/RenderCall.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace cig {
|
|
||||||
|
|
||||||
class Renderer {
|
|
||||||
public:
|
|
||||||
explicit Renderer(View *_view) : view(_view) { view->draw(); }
|
|
||||||
|
|
||||||
std::unique_ptr<View> view;
|
|
||||||
|
|
||||||
void update() const {
|
|
||||||
if (view->update())
|
|
||||||
view->draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <cigui/utils/List.hpp>
|
|
||||||
#include <cigui/core/Layout.hpp>
|
|
||||||
#include <cigui/core/RenderCall.hpp>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
namespace cig
|
|
||||||
{
|
|
||||||
class View {
|
|
||||||
protected:
|
|
||||||
List<RenderCall> m_RenderCalls;
|
|
||||||
Layout m_Layout;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~View() = default;
|
|
||||||
|
|
||||||
[[nodiscard]] const List<RenderCall> &renderCalls() const { return m_RenderCalls; }
|
|
||||||
std::unique_ptr<View> content;
|
|
||||||
|
|
||||||
virtual bool update() {
|
|
||||||
if (content)
|
|
||||||
return content->update();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw() {
|
|
||||||
if (!m_RenderCalls.empty()) {
|
|
||||||
m_RenderCalls.clear();
|
|
||||||
}
|
|
||||||
content = std::unique_ptr<View>(body());
|
|
||||||
if (!content) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
content->draw();
|
|
||||||
auto &contentRenderCalls = content->renderCalls();
|
|
||||||
m_RenderCalls.expand(contentRenderCalls);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual View *body() = 0;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -2,78 +2,51 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace cig
|
namespace cig
|
||||||
{
|
{
|
||||||
template <typename T, size_t growth_scalar = 1, size_t growth_summand = 3>
|
template <typename T, size_t growth_scalar = 1, size_t growth_summand = 3>
|
||||||
class List
|
class List
|
||||||
{
|
{
|
||||||
std::unique_ptr<T> m_Data;
|
T* m_Data = nullptr;
|
||||||
size_t m_Size = 0;
|
size_t m_Size = 0;
|
||||||
size_t m_Capacity;
|
size_t m_Capacity;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void reserve(const size_t capacity);
|
void reserve(size_t capacity);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit List(const size_t capacity = 3) : m_Capacity(capacity) { reserve(capacity); }
|
explicit List(size_t capacity = 3);
|
||||||
|
~List();
|
||||||
|
|
||||||
void own(T* data, const size_t size)
|
void own(T* data, size_t size);
|
||||||
{
|
|
||||||
m_Data = data;
|
|
||||||
m_Size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy(T* data, const size_t size)
|
void copy(const T* data, size_t size);
|
||||||
{
|
|
||||||
m_Data = std::make_unique<T[]>(size);
|
|
||||||
std::copy(data, data + size, m_Data.get());
|
|
||||||
m_Size = 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)
|
void need(size_t additional_size);
|
||||||
{
|
|
||||||
if (m_Size + additional_size > m_Capacity)
|
|
||||||
reserve(m_Capacity + 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)
|
void push_back(const T& value);
|
||||||
{
|
|
||||||
if (m_Size >= m_Capacity)
|
|
||||||
reserve(m_Capacity * growth_scalar + growth_summand);
|
|
||||||
m_Data.get()[m_Size++] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace_back(Args&&... args)
|
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>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
void expand(const List<T>& other)
|
void expand(const List<T>& 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Lambda>
|
template <typename Lambda>
|
||||||
void iterate(Lambda&& lambda) const
|
void iterate(Lambda&& lambda) const;
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_Size; i++)
|
const T* data() const;
|
||||||
lambda(m_Data.get()[i]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#include <cigui/utils/List.inl>
|
#include <cigui/utils/List.inl>
|
|
@ -1,22 +1,105 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#define __LIST_FUNC_DEFINE__(rtt) \
|
#define LIST_FUNC_DEFINE(rtt) \
|
||||||
template <typename T, size_t growth_scalar, size_t growth_summand> \
|
template <typename T, size_t growth_scalar, size_t growth_summand> \
|
||||||
rtt List<T, growth_scalar, growth_summand>
|
rtt List<T, growth_scalar, growth_summand>
|
||||||
|
|
||||||
|
#include <cigui/core/Memory.hpp>
|
||||||
|
|
||||||
namespace cig
|
namespace cig
|
||||||
{
|
{
|
||||||
__LIST_FUNC_DEFINE__(void)::reserve(const size_t capacity)
|
LIST_FUNC_DEFINE(void)::reserve(const size_t capacity)
|
||||||
{
|
{
|
||||||
if (!m_Data)
|
if (!m_Data)
|
||||||
{
|
{
|
||||||
m_Data = std::unique_ptr<T>(static_cast<T*>(calloc(capacity, sizeof(T))));
|
m_Data = Memory::alloc<T>(capacity);
|
||||||
m_Capacity = capacity;
|
m_Capacity = capacity;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::unique_ptr<T> newData(static_cast<T*>(calloc(capacity, sizeof(T))));
|
m_Data = Memory::realloc<T>(m_Data, m_Size, capacity);
|
||||||
std::copy(m_Data.get(), m_Data.get() + m_Size, newData.get());
|
|
||||||
m_Data = std::move(newData);
|
|
||||||
m_Capacity = capacity;
|
m_Capacity = capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t growth_scalar, size_t growth_summand>
|
||||||
|
List<T, growth_scalar, growth_summand>::~List()
|
||||||
|
{
|
||||||
|
if (m_Data)
|
||||||
|
Memory::dealloc<T>(m_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, size_t growth_scalar, size_t growth_summand>
|
||||||
|
List<T, growth_scalar, growth_summand>::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<T>(m_Data);
|
||||||
|
}
|
||||||
|
m_Data = data;
|
||||||
|
m_Size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FUNC_DEFINE(void)::copy(const T* data, const size_t size) {
|
||||||
|
m_Data = Memory::dupalloc<T>(data, size);
|
||||||
|
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[index];
|
||||||
|
}
|
||||||
|
LIST_FUNC_DEFINE(const T &)::operator[](const size_t index) const {
|
||||||
|
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 + growth_summand);
|
||||||
|
}
|
||||||
|
|
||||||
|
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[m_Size++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FUNC_DEFINE(template <typename... Args> void)::emplace_back(Args&&... args) {
|
||||||
|
if (m_Size >= m_Capacity)
|
||||||
|
reserve(m_Capacity * growth_scalar + growth_summand);
|
||||||
|
m_Data[m_Size++] = T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FUNC_DEFINE(void)::expand(const List<T>& other) {
|
||||||
|
need(other.size());
|
||||||
|
std::copy(other.m_Data, other.m_Data + other.size(), m_Data + m_Size);
|
||||||
|
m_Size += other.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FUNC_DEFINE(template <typename Lambda> void)::iterate(Lambda&& lambda) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_Size; i++)
|
||||||
|
lambda(m_Data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FUNC_DEFINE(const T*)::data() const {
|
||||||
|
return m_Data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef LIST_FUNC_DEFINE
|
159
include/cigui/utils/MemoryDebug.hpp
Normal file
159
include/cigui/utils/MemoryDebug.hpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
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<void*, ptr_info> allocations;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<typename T>
|
||||||
|
void log_deallocator(const T* ptr)
|
||||||
|
{
|
||||||
|
allocations.erase(allocations.find((void*)ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<typename T>
|
||||||
|
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<std::chrono::nanoseconds>(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
|
1
include/cigui/utils/MemoryDebug.inl
Normal file
1
include/cigui/utils/MemoryDebug.inl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#pragma once
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cigui/config.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
#define TYPEDEF_VECTOR(NAME, T, N, s) typedef NAME<T> vec##N##s;
|
#define TYPEDEF_VECTOR(NAME, T, N, s) typedef NAME<T> vec##N##s;
|
||||||
|
|
||||||
#define TYPEDEF_VECTORS(NAME, N) \
|
#define TYPEDEF_VECTORS(NAME, N) \
|
||||||
|
@ -19,48 +22,93 @@
|
||||||
TYPEDEF_VECTOR(NAME, long long, N, ll) \
|
TYPEDEF_VECTOR(NAME, long long, N, ll) \
|
||||||
TYPEDEF_VECTOR(NAME, unsigned long long, N, ull)
|
TYPEDEF_VECTOR(NAME, unsigned long long, N, ull)
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
|
||||||
#define UNNAMED_STRUCT __extension__ struct
|
#if CIGUI_DLL
|
||||||
|
#define VECTOR_TEMPLATE_INST(N, T) CIGUI_TEMPLATE_INST Vector##N<T>; \
|
||||||
|
|
||||||
|
#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
|
#else
|
||||||
#defien UNNAMED_STRUCT struct
|
#define VECTOR_INSTANTIATION(N)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace cig {
|
namespace cig
|
||||||
template <typename T>
|
{
|
||||||
union Vector2 {
|
template <typename T>
|
||||||
UNNAMED_STRUCT {
|
union Vector2
|
||||||
T x, y;
|
{
|
||||||
};
|
struct
|
||||||
UNNAMED_STRUCT {
|
{
|
||||||
T a, b;
|
T x, y;
|
||||||
};
|
} dims;
|
||||||
};
|
|
||||||
|
|
||||||
TYPEDEF_VECTORS(Vector2, 2)
|
struct
|
||||||
|
{
|
||||||
|
T width, height;
|
||||||
|
} sizes;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
TYPEDEF_VECTORS(Vector2, 2)
|
||||||
union Vector3 {
|
|
||||||
UNNAMED_STRUCT {
|
|
||||||
T x, y, z;
|
|
||||||
};
|
|
||||||
UNNAMED_STRUCT {
|
|
||||||
T r, g, b;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
TYPEDEF_VECTORS(Vector3, 3)
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
union Vector4 {
|
union Vector3
|
||||||
UNNAMED_STRUCT {
|
{
|
||||||
T x, y, z, w;
|
struct
|
||||||
};
|
{
|
||||||
UNNAMED_STRUCT {
|
T x, y, z;
|
||||||
T r, g, b, a;
|
} dims;
|
||||||
};
|
|
||||||
UNNAMED_STRUCT {
|
struct
|
||||||
T left, top, right, bottom;
|
{
|
||||||
};
|
T r, g, b;
|
||||||
};
|
} color;
|
||||||
TYPEDEF_VECTORS(Vector4, 4)
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
T width, height, depth;
|
||||||
|
} sizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
TYPEDEF_VECTORS(Vector3, 3)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
union Vector4
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
T x, y, z, w;
|
||||||
|
} dims;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
T r, g, b, a;
|
||||||
|
} color;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
T left, top, right, bottom;
|
||||||
|
} dirs;
|
||||||
|
};
|
||||||
|
|
||||||
|
TYPEDEF_VECTORS(Vector4, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef TYPEDEF_VECTOR
|
||||||
|
#undef TYPEDEF_VECTORS
|
||||||
|
|
||||||
|
#if CIGUI_DLL
|
||||||
|
#undef VECTOR_TEMPLATE_INST
|
||||||
|
#endif
|
||||||
|
#undef VECTOR_INSTANTIATION
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cigui/core/View.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cigui/views/Rectangle.hpp>
|
|
197
src/core/App.cpp
Normal file
197
src/core/App.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
#include <cigui/core/App.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <LLGL/Utils/VertexFormat.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <cigui/core/Memory.hpp>
|
||||||
|
namespace cig
|
||||||
|
{
|
||||||
|
App::App() : m_WindowListener(std::make_shared<WindowListener>(*this))
|
||||||
|
{
|
||||||
|
// 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.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;
|
||||||
|
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.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::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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::resized(vec2u size)
|
||||||
|
{
|
||||||
|
m_WindowSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::Initialize(int argc, char** argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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->Clear(LLGL::ClearFlags::Color, clear_value);
|
||||||
|
|
||||||
|
m_CmdBuffer->SetPipelineState(*m_Pipeline);
|
||||||
|
|
||||||
|
{
|
||||||
|
m_CmdBuffer->Draw(static_cast<uint32_t>(m_Vertices.size()), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_CmdBuffer->EndRenderPass();
|
||||||
|
}
|
||||||
|
m_CmdBuffer->End();
|
||||||
|
|
||||||
|
m_SwapChain->Present();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::save() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int App::Run()
|
||||||
|
{
|
||||||
|
if (!m_RenderSystem)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
m_Window = &LLGL::CastTo<LLGL::Window>(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -35,9 +35,7 @@ function(add_cigui_test TEST_NAME)
|
||||||
if(WIN32 AND CIGUI_BUILD_SHARED)
|
if(WIN32 AND CIGUI_BUILD_SHARED)
|
||||||
add_custom_command(TARGET ${TEST_NAME} POST_BUILD
|
add_custom_command(TARGET ${TEST_NAME} POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
$<TARGET_FILE:sfml-graphics>
|
$<TARGET_FILE:LLGL>
|
||||||
$<TARGET_FILE:sfml-window>
|
|
||||||
$<TARGET_FILE:sfml-system>
|
|
||||||
$<TARGET_FILE:cigui>
|
$<TARGET_FILE:cigui>
|
||||||
$<TARGET_FILE_DIR:${TEST_NAME}>
|
$<TARGET_FILE_DIR:${TEST_NAME}>
|
||||||
)
|
)
|
||||||
|
@ -73,9 +71,7 @@ add_test(NAME cigui_tests COMMAND cigui_tests)
|
||||||
if(WIN32 AND CIGUI_BUILD_SHARED)
|
if(WIN32 AND CIGUI_BUILD_SHARED)
|
||||||
add_custom_command(TARGET cigui_tests POST_BUILD
|
add_custom_command(TARGET cigui_tests POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
$<TARGET_FILE:sfml-graphics>
|
$<TARGET_FILE:LLGL>
|
||||||
$<TARGET_FILE:sfml-window>
|
|
||||||
$<TARGET_FILE:sfml-system>
|
|
||||||
$<TARGET_FILE:cigui>
|
$<TARGET_FILE:cigui>
|
||||||
$<TARGET_FILE_DIR:cigui_tests>
|
$<TARGET_FILE_DIR:cigui_tests>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue