Memory safety and Window Events
Adding memory checks and Window Event Listener + Memory Checks (debug) + Listening to window events + Runtime Directory Structure (Vision)
This commit is contained in:
parent
550fc291de
commit
3679beaa4e
13 changed files with 491 additions and 100 deletions
31
README.md
31
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"
|
||||
}
|
||||
```
|
|
@ -1,6 +1,10 @@
|
|||
#include <cigui/core/App.hpp>
|
||||
#include <cigui/cigui.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <iosteam>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello World" << std::endl;
|
||||
|
|
|
@ -4,7 +4,19 @@
|
|||
#include <cigui/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cigui/App.hpp>
|
||||
#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 {
|
||||
constexpr unsigned int VERSION_MAJOR = CIGUI_VERSION_MAJOR;
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <cigui/config.h>
|
||||
#include <filesystem>
|
||||
#include <LLGL/LLGL.h>
|
||||
|
||||
#include <cigui/utils/List.hpp>
|
||||
#include <cigui/utils/Vectors.hpp>
|
||||
|
||||
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<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();
|
||||
|
||||
LLGL::RenderSystemPtr m_RenderSystem;
|
||||
LLGL::SwapChain* m_SwapChain;
|
||||
void Initialize(int argc = 0, char** argv = nullptr);
|
||||
|
||||
std::pair<LLGL::Shader*, LLGL::Shader*> m_ShaderPack;
|
||||
LLGL::PipelineState* m_Pipeline;
|
||||
LLGL::Buffer* m_VertexBuffer;
|
||||
LLGL::CommandBuffer* m_CmdBuffer;
|
||||
LLGL::Window* m_Window;
|
||||
|
||||
bool ShaderLanguageIsSupported(LLGL::ShadingLanguage lang);
|
||||
|
||||
List<Vertex> m_Vertices;
|
||||
public:
|
||||
static App& GetInstance();
|
||||
|
||||
void Run();
|
||||
int Run();
|
||||
};
|
||||
}
|
||||
|
|
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;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace cig
|
|||
template <typename T, size_t growth_scalar = 1, size_t growth_summand = 3>
|
||||
class List
|
||||
{
|
||||
std::unique_ptr<T> 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;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
template <typename T, size_t growth_scalar, size_t growth_summand> \
|
||||
rtt List<T, growth_scalar, growth_summand>
|
||||
|
||||
#include <cigui/core/Memory.hpp>
|
||||
|
||||
namespace cig
|
||||
{
|
||||
|
@ -11,26 +12,40 @@ namespace cig
|
|||
{
|
||||
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;
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<T> newData(static_cast<T*>(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<T>(m_Data, m_Size, capacity);
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
LIST_FUNC_DEFINE( )::List(const size_t capacity) : m_Capacity(capacity) { reserve(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(T* data, const size_t size) {
|
||||
m_Data = std::make_unique<T[]>(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<T>(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 <typename... 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)...);
|
||||
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.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 <typename Lambda> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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
|
|
@ -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<T>; \
|
||||
|
@ -57,15 +49,15 @@ namespace cig
|
|||
template <typename T>
|
||||
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 <typename T>
|
||||
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 <typename T>
|
||||
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
|
||||
|
|
132
src/core/App.cpp
132
src/core/App.cpp
|
@ -3,9 +3,11 @@
|
|||
#include <iostream>
|
||||
#include <LLGL/Utils/VertexFormat.h>
|
||||
|
||||
|
||||
#include <cigui/core/Memory.hpp>
|
||||
namespace cig
|
||||
{
|
||||
App::App()
|
||||
App::App() : m_WindowListener(std::make_shared<WindowListener>(*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<LLGL::Window>(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<uint32_t>(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<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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue