added basic structures

This commit is contained in:
2026-01-17 13:48:25 +01:00
parent 0e4689cf35
commit 53c7d564d7
23 changed files with 2247 additions and 0 deletions

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang++",
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}

967
TSE_Base/include/uuid.h Normal file
View File

@@ -0,0 +1,967 @@
#ifndef STDUUID_H
#define STDUUID_H
#include <cstring>
#include <string>
#include <sstream>
#include <iomanip>
#include <array>
#include <string_view>
#include <iterator>
#include <random>
#include <memory>
#include <functional>
#include <type_traits>
#include <optional>
#include <chrono>
#include <numeric>
#include <atomic>
#ifdef __cplusplus
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
# define LIBUUID_CPP20_OR_GREATER
# endif
#endif
#ifdef LIBUUID_CPP20_OR_GREATER
#include <span>
#else
#include <gsl/span>
#endif
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifdef UUID_SYSTEM_GENERATOR
#include <objbase.h>
#endif
#ifdef UUID_TIME_GENERATOR
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")
#endif
#elif defined(__linux__) || defined(__unix__)
#ifdef UUID_SYSTEM_GENERATOR
#include <uuid/uuid.h>
#endif
#elif defined(__APPLE__)
#ifdef UUID_SYSTEM_GENERATOR
#include <CoreFoundation/CFUUID.h>
#endif
#endif
namespace uuids
{
#ifdef __cpp_lib_span
template <class ElementType, std::size_t Extent>
using span = std::span<ElementType, Extent>;
#else
template <class ElementType, std::ptrdiff_t Extent>
using span = gsl::span<ElementType, Extent>;
#endif
namespace detail
{
template <typename TChar>
[[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
{
if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a'));
if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
return 0;
}
template <typename TChar>
[[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
{
return
(ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
(ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) ||
(ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'));
}
template <typename TChar>
[[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const * str) noexcept
{
if (str) return str;
return {};
}
template <typename StringType>
[[nodiscard]]
constexpr std::basic_string_view<
typename StringType::value_type,
typename StringType::traits_type>
to_string_view(StringType const & str) noexcept
{
return str;
}
class sha1
{
public:
using digest32_t = uint32_t[5];
using digest8_t = uint8_t[20];
static constexpr unsigned int block_bytes = 64;
[[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
{
return (value << count) ^ (value >> (32 - count));
}
sha1() { reset(); }
void reset() noexcept
{
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
m_digest[4] = 0xC3D2E1F0;
m_blockByteIndex = 0;
m_byteCount = 0;
}
void process_byte(uint8_t octet)
{
this->m_block[this->m_blockByteIndex++] = octet;
++this->m_byteCount;
if (m_blockByteIndex == block_bytes)
{
this->m_blockByteIndex = 0;
process_block();
}
}
void process_block(void const * const start, void const * const end)
{
const uint8_t* begin = static_cast<const uint8_t*>(start);
const uint8_t* finish = static_cast<const uint8_t*>(end);
while (begin != finish)
{
process_byte(*begin);
begin++;
}
}
void process_bytes(void const * const data, size_t const len)
{
const uint8_t* block = static_cast<const uint8_t*>(data);
process_block(block, block + len);
}
uint32_t const * get_digest(digest32_t digest)
{
size_t const bitCount = this->m_byteCount * 8;
process_byte(0x80);
if (this->m_blockByteIndex > 56) {
while (m_blockByteIndex != 0) {
process_byte(0);
}
while (m_blockByteIndex < 56) {
process_byte(0);
}
}
else {
while (m_blockByteIndex < 56) {
process_byte(0);
}
}
process_byte(0);
process_byte(0);
process_byte(0);
process_byte(0);
process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
process_byte(static_cast<unsigned char>((bitCount) & 0xFF));
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
return digest;
}
uint8_t const * get_digest_bytes(digest8_t digest)
{
digest32_t d32;
get_digest(d32);
size_t di = 0;
digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
digest[di++] = static_cast<uint8_t>(d32[0] >> 0);
digest[di++] = static_cast<uint8_t>(d32[1] >> 24);
digest[di++] = static_cast<uint8_t>(d32[1] >> 16);
digest[di++] = static_cast<uint8_t>(d32[1] >> 8);
digest[di++] = static_cast<uint8_t>(d32[1] >> 0);
digest[di++] = static_cast<uint8_t>(d32[2] >> 24);
digest[di++] = static_cast<uint8_t>(d32[2] >> 16);
digest[di++] = static_cast<uint8_t>(d32[2] >> 8);
digest[di++] = static_cast<uint8_t>(d32[2] >> 0);
digest[di++] = static_cast<uint8_t>(d32[3] >> 24);
digest[di++] = static_cast<uint8_t>(d32[3] >> 16);
digest[di++] = static_cast<uint8_t>(d32[3] >> 8);
digest[di++] = static_cast<uint8_t>(d32[3] >> 0);
digest[di++] = static_cast<uint8_t>(d32[4] >> 24);
digest[di++] = static_cast<uint8_t>(d32[4] >> 16);
digest[di++] = static_cast<uint8_t>(d32[4] >> 8);
digest[di++] = static_cast<uint8_t>(d32[4] >> 0);
return digest;
}
private:
void process_block()
{
uint32_t w[80];
for (size_t i = 0; i < 16; i++) {
w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]);
}
for (size_t i = 16; i < 80; i++) {
w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
uint32_t a = m_digest[0];
uint32_t b = m_digest[1];
uint32_t c = m_digest[2];
uint32_t d = m_digest[3];
uint32_t e = m_digest[4];
for (std::size_t i = 0; i < 80; ++i)
{
uint32_t f = 0;
uint32_t k = 0;
if (i < 20) {
f = (b & c) | (~b & d);
k = 0x5A827999;
}
else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = left_rotate(b, 30);
b = a;
a = temp;
}
m_digest[0] += a;
m_digest[1] += b;
m_digest[2] += c;
m_digest[3] += d;
m_digest[4] += e;
}
private:
digest32_t m_digest;
uint8_t m_block[64];
size_t m_blockByteIndex;
size_t m_byteCount;
};
template <typename CharT>
inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
template <>
inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
template <typename CharT>
inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
template <>
inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
}
// --------------------------------------------------------------------------------------------------------------------------
// UUID format https://tools.ietf.org/html/rfc4122
// --------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------
// Field NDR Data Type Octet # Note
// --------------------------------------------------------------------------------------------------------------------------
// time_low unsigned long 0 - 3 The low field of the timestamp.
// time_mid unsigned short 4 - 5 The middle field of the timestamp.
// time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number.
// clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant.
// clock_seq_low unsigned small 9 The low field of the clock sequence.
// node character 10 - 15 The spatially unique node identifier.
// --------------------------------------------------------------------------------------------------------------------------
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | time_low |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | time_mid | time_hi_and_version |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |clk_seq_hi_res | clk_seq_low | node (0-1) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | node (2-5) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// --------------------------------------------------------------------------------------------------------------------------
// enumerations
// --------------------------------------------------------------------------------------------------------------------------
// indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
enum class uuid_variant
{
// NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format)
// N bit pattern: 0xxx
// > the first 6 octets of the UUID are a 48-bit timestamp (the number of 4 microsecond units of time since 1 Jan 1980 UTC);
// > the next 2 octets are reserved;
// > the next octet is the "address family";
// > the final 7 octets are a 56-bit host ID in the form specified by the address family
ncs,
// RFC 4122/DCE 1.1
// N bit pattern: 10xx
// > big-endian byte order
rfc,
// Microsoft Corporation backward compatibility
// N bit pattern: 110x
// > little endian byte order
// > formely used in the Component Object Model (COM) library
microsoft,
// reserved for possible future definition
// N bit pattern: 111x
reserved
};
// indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
enum class uuid_version
{
none = 0, // only possible for nil or invalid uuids
time_based = 1, // The time-based version specified in RFC 4122
dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing
random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122
name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
};
// Forward declare uuid & to_string so that we can declare to_string as a friend later.
class uuid;
template <class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
std::basic_string<CharT, Traits, Allocator> to_string(uuid const &id);
// --------------------------------------------------------------------------------------------------------------------------
// uuid class
// --------------------------------------------------------------------------------------------------------------------------
class uuid
{
public:
using value_type = uint8_t;
constexpr uuid() noexcept = default;
uuid(value_type(&arr)[16]) noexcept
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
constexpr uuid(std::array<value_type, 16> const & arr) noexcept : data{arr} {}
explicit uuid(span<value_type, 16> bytes)
{
std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
}
template<typename ForwardIterator>
explicit uuid(ForwardIterator first, ForwardIterator last)
{
if (std::distance(first, last) == 16)
std::copy(first, last, std::begin(data));
}
[[nodiscard]] constexpr uuid_variant variant() const noexcept
{
if ((data[8] & 0x80) == 0x00)
return uuid_variant::ncs;
else if ((data[8] & 0xC0) == 0x80)
return uuid_variant::rfc;
else if ((data[8] & 0xE0) == 0xC0)
return uuid_variant::microsoft;
else
return uuid_variant::reserved;
}
[[nodiscard]] constexpr uuid_version version() const noexcept
{
if ((data[6] & 0xF0) == 0x10)
return uuid_version::time_based;
else if ((data[6] & 0xF0) == 0x20)
return uuid_version::dce_security;
else if ((data[6] & 0xF0) == 0x30)
return uuid_version::name_based_md5;
else if ((data[6] & 0xF0) == 0x40)
return uuid_version::random_number_based;
else if ((data[6] & 0xF0) == 0x50)
return uuid_version::name_based_sha1;
else
return uuid_version::none;
}
[[nodiscard]] constexpr bool is_nil() const noexcept
{
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
return true;
}
void swap(uuid & other) noexcept
{
data.swap(other.data);
}
[[nodiscard]] inline span<std::byte const, 16> as_bytes() const
{
return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
}
template <typename StringType>
[[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
{
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
size_t hasBraces = 0;
size_t index = 0;
if (str.empty())
return false;
if (str.front() == '{')
hasBraces = 1;
if (hasBraces && str.back() != '}')
return false;
for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
{
if (str[i] == '-') continue;
if (index >= 16 || !detail::is_hex(str[i]))
{
return false;
}
if (firstDigit)
{
firstDigit = false;
}
else
{
index++;
firstDigit = true;
}
}
if (index < 16)
{
return false;
}
return true;
}
template <typename StringType>
[[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
{
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
size_t hasBraces = 0;
size_t index = 0;
std::array<uint8_t, 16> data{ { 0 } };
if (str.empty()) return {};
if (str.front() == '{')
hasBraces = 1;
if (hasBraces && str.back() != '}')
return {};
for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
{
if (str[i] == '-') continue;
if (index >= 16 || !detail::is_hex(str[i]))
{
return {};
}
if (firstDigit)
{
data[index] = static_cast<uint8_t>(detail::hex2char(str[i]) << 4);
firstDigit = false;
}
else
{
data[index] = static_cast<uint8_t>(data[index] | detail::hex2char(str[i]));
index++;
firstDigit = true;
}
}
if (index < 16)
{
return {};
}
return uuid{ data };
}
private:
std::array<value_type, 16> data{ { 0 } };
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
template<class CharT, class Traits, class Allocator>
friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
friend std::hash<uuid>;
};
// --------------------------------------------------------------------------------------------------------------------------
// operators and non-member functions
// --------------------------------------------------------------------------------------------------------------------------
[[nodiscard]] inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
{
return lhs.data == rhs.data;
}
[[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
{
return !(lhs == rhs);
}
[[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
{
return lhs.data < rhs.data;
}
template <class CharT,
class Traits,
class Allocator>
[[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
{
std::basic_string<CharT, Traits, Allocator> uustr{detail::empty_guid<CharT>};
for (size_t i = 0, index = 0; i < 36; ++i)
{
if (i == 8 || i == 13 || i == 18 || i == 23)
{
continue;
}
uustr[i] = detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
uustr[++i] = detail::guid_encoder<CharT>[id.data[index] & 0x0f];
index++;
}
return uustr;
}
template <class Elem, class Traits>
std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id)
{
s << to_string(id);
return s;
}
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
{
lhs.swap(rhs);
}
// --------------------------------------------------------------------------------------------------------------------------
// namespace IDs that could be used for generating name-based uuids
// --------------------------------------------------------------------------------------------------------------------------
// Name string is a fully-qualified domain name
static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is a URL
static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier)
static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is an X.500 DN, in DER or a text output format (See https://en.wikipedia.org/wiki/X.500, https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One)
static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// --------------------------------------------------------------------------------------------------------------------------
// uuid generators
// --------------------------------------------------------------------------------------------------------------------------
#ifdef UUID_SYSTEM_GENERATOR
class uuid_system_generator
{
public:
using result_type = uuid;
uuid operator()()
{
#ifdef _WIN32
GUID newId;
HRESULT hr = ::CoCreateGuid(&newId);
if (FAILED(hr))
{
throw std::system_error(hr, std::system_category(), "CoCreateGuid failed");
}
std::array<uint8_t, 16> bytes =
{ {
static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
static_cast<unsigned char>((newId.Data1) & 0xFF),
(unsigned char)((newId.Data2 >> 8) & 0xFF),
(unsigned char)((newId.Data2) & 0xFF),
(unsigned char)((newId.Data3 >> 8) & 0xFF),
(unsigned char)((newId.Data3) & 0xFF),
newId.Data4[0],
newId.Data4[1],
newId.Data4[2],
newId.Data4[3],
newId.Data4[4],
newId.Data4[5],
newId.Data4[6],
newId.Data4[7]
} };
return uuid{ std::begin(bytes), std::end(bytes) };
#elif defined(__linux__) || defined(__unix__)
uuid_t id;
uuid_generate(id);
std::array<uint8_t, 16> bytes =
{ {
id[0],
id[1],
id[2],
id[3],
id[4],
id[5],
id[6],
id[7],
id[8],
id[9],
id[10],
id[11],
id[12],
id[13],
id[14],
id[15]
} };
return uuid{ std::begin(bytes), std::end(bytes) };
#elif defined(__APPLE__)
auto newId = CFUUIDCreate(NULL);
auto bytes = CFUUIDGetUUIDBytes(newId);
CFRelease(newId);
std::array<uint8_t, 16> arrbytes =
{ {
bytes.byte0,
bytes.byte1,
bytes.byte2,
bytes.byte3,
bytes.byte4,
bytes.byte5,
bytes.byte6,
bytes.byte7,
bytes.byte8,
bytes.byte9,
bytes.byte10,
bytes.byte11,
bytes.byte12,
bytes.byte13,
bytes.byte14,
bytes.byte15
} };
return uuid{ std::begin(arrbytes), std::end(arrbytes) };
#else
return uuid{};
#endif
}
};
#endif
template <typename UniformRandomNumberGenerator>
class basic_uuid_random_generator
{
public:
using engine_type = UniformRandomNumberGenerator;
explicit basic_uuid_random_generator(engine_type& gen) :
generator(&gen, [](auto) {}) {}
explicit basic_uuid_random_generator(engine_type* gen) :
generator(gen, [](auto) {}) {}
[[nodiscard]] uuid operator()()
{
alignas(uint32_t) uint8_t bytes[16];
for (int i = 0; i < 16; i += 4)
*reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
// variant must be 10xxxxxx
bytes[8] &= 0xBF;
bytes[8] |= 0x80;
// version must be 0100xxxx
bytes[6] &= 0x4F;
bytes[6] |= 0x40;
return uuid{std::begin(bytes), std::end(bytes)};
}
private:
std::uniform_int_distribution<uint32_t> distribution;
std::shared_ptr<UniformRandomNumberGenerator> generator;
};
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
class uuid_name_generator
{
public:
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
: nsuuid(namespace_uuid)
{}
template <typename StringType>
[[nodiscard]] uuid operator()(StringType const & name)
{
reset();
process_characters(detail::to_string_view(name));
return make_uuid();
}
private:
void reset()
{
hasher.reset();
std::byte bytes[16];
auto nsbytes = nsuuid.as_bytes();
std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
hasher.process_bytes(bytes, 16);
}
template <typename CharT, typename Traits>
void process_characters(std::basic_string_view<CharT, Traits> const str)
{
for (uint32_t c : str)
{
hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
if constexpr (!std::is_same_v<CharT, char>)
{
hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
}
}
}
[[nodiscard]] uuid make_uuid()
{
detail::sha1::digest8_t digest;
hasher.get_digest_bytes(digest);
// variant must be 0b10xxxxxx
digest[8] &= 0xBF;
digest[8] |= 0x80;
// version must be 0b0101xxxx
digest[6] &= 0x5F;
digest[6] |= 0x50;
return uuid{ digest, digest + 16 };
}
private:
uuid nsuuid;
detail::sha1 hasher;
};
#ifdef UUID_TIME_GENERATOR
// !!! DO NOT USE THIS IN PRODUCTION
// this implementation is unreliable for good uuids
class uuid_time_generator
{
using mac_address = std::array<unsigned char, 6>;
std::optional<mac_address> device_address;
[[nodiscard]] bool get_mac_address()
{
if (device_address.has_value())
{
return true;
}
#ifdef _WIN32
DWORD len = 0;
auto ret = GetAdaptersInfo(nullptr, &len);
if (ret != ERROR_BUFFER_OVERFLOW) return false;
std::vector<unsigned char> buf(len);
auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front());
ret = GetAdaptersInfo(pips, &len);
if (ret != ERROR_SUCCESS) return false;
mac_address addr;
std::copy(pips->Address, pips->Address + 6, std::begin(addr));
device_address = addr;
#endif
return device_address.has_value();
}
[[nodiscard]] long long get_time_intervals()
{
auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
auto diff = std::chrono::system_clock::now() - start;
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();
return ns / 100;
}
[[nodiscard]] static unsigned short get_clock_sequence()
{
static std::mt19937 clock_gen(std::random_device{}());
static std::uniform_int_distribution<unsigned short> clock_dis;
static std::atomic_ushort clock_sequence = clock_dis(clock_gen);
return clock_sequence++;
}
public:
[[nodiscard]] uuid operator()()
{
if (get_mac_address())
{
std::array<uuids::uuid::value_type, 16> data;
auto tm = get_time_intervals();
auto clock_seq = get_clock_sequence();
auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
memcpy(&data[0], ptm + 4, 4);
memcpy(&data[4], ptm + 2, 2);
memcpy(&data[6], ptm, 2);
memcpy(&data[8], &clock_seq, 2);
// variant must be 0b10xxxxxx
data[8] &= 0xBF;
data[8] |= 0x80;
// version must be 0b0001xxxx
data[6] &= 0x1F;
data[6] |= 0x10;
memcpy(&data[10], &device_address.value()[0], 6);
return uuids::uuid{std::cbegin(data), std::cend(data)};
}
return {};
}
};
#endif
}
namespace std
{
template <>
struct hash<uuids::uuid>
{
using argument_type = uuids::uuid;
using result_type = std::size_t;
[[nodiscard]] result_type operator()(argument_type const &uuid) const
{
#ifdef UUID_HASH_STRING_BASED
std::hash<std::string> hasher;
return static_cast<result_type>(hasher(uuids::to_string(uuid)));
#else
uint64_t l =
static_cast<uint64_t>(uuid.data[0]) << 56 |
static_cast<uint64_t>(uuid.data[1]) << 48 |
static_cast<uint64_t>(uuid.data[2]) << 40 |
static_cast<uint64_t>(uuid.data[3]) << 32 |
static_cast<uint64_t>(uuid.data[4]) << 24 |
static_cast<uint64_t>(uuid.data[5]) << 16 |
static_cast<uint64_t>(uuid.data[6]) << 8 |
static_cast<uint64_t>(uuid.data[7]);
uint64_t h =
static_cast<uint64_t>(uuid.data[8]) << 56 |
static_cast<uint64_t>(uuid.data[9]) << 48 |
static_cast<uint64_t>(uuid.data[10]) << 40 |
static_cast<uint64_t>(uuid.data[11]) << 32 |
static_cast<uint64_t>(uuid.data[12]) << 24 |
static_cast<uint64_t>(uuid.data[13]) << 16 |
static_cast<uint64_t>(uuid.data[14]) << 8 |
static_cast<uint64_t>(uuid.data[15]);
if constexpr (sizeof(result_type) > 4)
{
return result_type(l ^ h);
}
else
{
uint64_t hash64 = l ^ h;
return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
}
#endif
}
};
}
#endif /* STDUUID_H */

View File

@@ -0,0 +1,9 @@
#include "IdGenerator.hpp"
std::mt19937 rnd = std::mt19937();
auto gen = uuids::uuid_random_generator(rnd);
uuids::uuid TSE::GenerateRandomUUID()
{
return gen();
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "uuid.h"
namespace TSE
{
uuids::uuid GenerateRandomUUID();
} // namespace TSE

View File

@@ -0,0 +1,16 @@
#include "MeshContainer.hpp"
TSE::MeshContainer::MeshContainer() = default;
TSE::MeshContainer::MeshContainer(Mesh *m)
: mesh(m) {}
void TSE::MeshContainer::SetMesh(Mesh *m)
{
mesh = m;
}
TSE::Mesh *TSE::MeshContainer::GetMesh() const
{
return mesh;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#define MESH_CONTAINER typeid(TSE::MeshContainer).name()
#include "Types.hpp"
#include "Mesh.hpp"
#include "elements/BehaviourScript.hpp"
namespace TSE
{
class MeshContainer : public BehaviourScript
{
private:
Mesh* mesh = nullptr;
public:
MeshContainer();
explicit MeshContainer(Mesh* mesh);
void SetMesh(Mesh* mesh);
Mesh* GetMesh() const;
inline const char* GetName() override
{
return "Mesh Container";
};
};
} // namespace TSE

View File

@@ -0,0 +1,92 @@
#include "RectBase.hpp"
#include "elements/Transformable.hpp"
TSE::RectBase::RectBase()
{
meshCach = Mesh::GetQuadMesh();
}
TSE::Mesh *TSE::RectBase::GetMesh()
{
return &meshCach;
}
void TSE::RectBase::SetCustomUVs(const std::vector<Vector2> &uvs)
{
meshCach.uvs = uvs;
}
void TSE::RectBase::OnParentChanged(RectBase *parent)
{
if(anchors != Rect(0.5f,0.5f, 0.5f, 0.5f))
RecalculateMesh(parent);
}
bool IsTransformableRect(TSE::Transformable* trans)
{
if(trans == nullptr || !trans->HasBehaviourScript(RECT_BASE)) return false;
return true;
}
void TSE::RectBase::RecalculateMesh(RectBase *parent)
{
// Determin parent size, or fallback to 1x1
Vector2 psize (1,1);
if(parent != nullptr)
psize = parent->tmpSize;
Vector2 phsize = psize * 0.5f;
Vector2 pposoffset (0,0);
if(parent != nullptr)
{
pposoffset = ((parent->pivit * 2) - Vector2::one) * phsize;
}
Vector2 mappedAnchor = (Vector2::Midpoint(anchors.p1,anchors.p2) * 2 - Vector2::one) * phsize;
pposoffset = pposoffset + mappedAnchor;
Vector2 strechscaler = anchors.p2 - anchors.p1;
tmpSize = psize * strechscaler + size;
Vector2 hs = tmpSize * 0.5f;
Vector2 mappedPivit = pivit * 2 - Vector2::one;
Vector2 pivitOffset = hs * mappedPivit;
meshCach.vertecies.clear();
meshCach.vertecies.push_back(Vector2(-hs.x, -hs.y) + pivitOffset);
meshCach.vertecies.push_back(Vector2( hs.x, -hs.y) + pivitOffset);
meshCach.vertecies.push_back(Vector2( hs.x, hs.y) + pivitOffset);
meshCach.vertecies.push_back(Vector2(-hs.x, hs.y) + pivitOffset);
baseObject->position = pposoffset;
lastSize = size;
lastAnchors = anchors;
lastPivit = pivit;
// Notify children of change
auto children = baseObject->GetChildren();
for(auto child : children)
{
if(IsTransformableRect(child))
{
((RectBase*)child->GetBehaviourScript(RECT_BASE))->OnParentChanged(this);
}
}
}
void TSE::RectBase::OnUpdate()
{
if(lastSize != size || lastAnchors != anchors || pivit != lastPivit){
//local change
RectBase* parent = nullptr;
if(baseObject->GetParent() != nullptr)
parent = (RectBase*)baseObject->GetParent()->GetBehaviourScript(RECT_BASE);
RecalculateMesh(parent);
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
#define RECT_BASE typeid(TSE::RectBase).name()
#include "elements/BehaviourScript.hpp"
#include "Rect.hpp"
#include "Vector2.hpp"
#include "Mesh.hpp"
namespace TSE
{
class RectBase : public BehaviourScript
{
private:
Rect lastAnchors = Rect(0.5f, 0.5f, 0.5f, 0.5f);
Vector2 lastSize = Vector2(0,0);
Vector2 lastPivit = Vector2(0.5f,0.5f);
Mesh meshCach;
Vector2 tmpSize;
public:
Rect anchors = Rect(0.5f,0.5f, 0.5f, 0.5f); //streching in parent
Vector2 size = Vector2(1,1); //size
Vector2 pivit = Vector2(0.5f,0.5f); //positioning in parent
RectBase();
Mesh* GetMesh();
void SetCustomUVs(const std::vector<Vector2>& uvs);
private:
void OnParentChanged(RectBase* parent);
void RecalculateMesh(RectBase *parent);
public:
void OnUpdate() override;
inline const char* GetName() override
{
return "Rect Base";
}
};
} // namespace TSE

View File

@@ -0,0 +1,42 @@
#include "Renderable.hpp"
#include <typeinfo>
#include "MeshContainer.hpp"
#include "elements/Transformable.hpp"
namespace TSE
{
Renderable::Renderable() = default;
Renderable::Renderable(Material* mat)
{
SetMaterial(mat);
}
void Renderable::SetMaterial(Material* mat) {
material = mat;
}
Material* Renderable::GetMaterial() {
return material;
}
Mesh* Renderable::GetMeshContainer() const {
if(baseObject->HasBehaviourScript(MESH_CONTAINER))
return dynamic_cast<MeshContainer*>(baseObject->GetBehaviourScript(MESH_CONTAINER))->GetMesh();
// if(baseObject->HasBehaviourScript(RECT_BASE))
// return dynamic_cast<RectBase*>(baseObject->GetBehaviourScript(RECT_BASE))->GetMesh();
return nullptr;
}
const Vector3* Renderable::GetVertices() const {
auto* container = GetMeshContainer();
return container ? container->vertecies.data() : nullptr;
}
const Vector2* Renderable::GetUVs() const {
auto* container = GetMeshContainer();
return container ? container->uvs.data() : nullptr;
}
} // namespace TSE

View File

@@ -0,0 +1,35 @@
#pragma once
#define RENDERABLE typeid(TSE::Renderable).name()
#include "elements/Material.hpp"
#include "interfaces/IRenderable.hpp"
#include "elements/BehaviourScript.hpp"
#include "Mesh.hpp"
namespace TSE
{
class Renderable : public BehaviourScript, public IRenderable
{
private:
Material* material = nullptr;
public:
Renderable();
explicit Renderable(Material* material);
const Vector3* GetVertices() const override;
const Vector2* GetUVs() const override;
const std::vector<ushort> GetIndices() const override;
size_t GetVertexCount() const override;
inline const char* GetName() override
{
return "Renderable";
}
void SetMaterial(Material* material);
Material* GetMaterial();
private:
Mesh* GetMeshContainer() const;
};
} // namespace TSE

View File

@@ -0,0 +1,23 @@
#include "BehaviourScript.hpp"
namespace TSE
{
BehaviourScript::BehaviourScript()
: baseObject(nullptr), enabled(true) {}
void BehaviourScript::SetEnabled(bool value) {
enabled = value;
}
bool BehaviourScript::IsEnabled() const {
return enabled;
}
void BehaviourScript::SetBaseObject(Transformable* obj) {
baseObject = obj;
}
Transformable* BehaviourScript::GetTransform() const {
return baseObject;
}
} // namespace TSE

View File

@@ -0,0 +1,29 @@
#pragma once
namespace TSE
{
class Transformable;
class BehaviourScript
{
public:
BehaviourScript();
virtual ~BehaviourScript() = default;
inline virtual void OnUpdate() { };
inline virtual void OnEnable() { };
inline virtual void OnDisable() { };
inline virtual void Start() { };
virtual const char* GetName() = 0;
inline virtual void CustomDraw(const bool& debug) { };
void SetEnabled(bool v);
bool IsEnabled() const;
void SetBaseObject(Transformable* obj);
Transformable* GetTransform() const;
Transformable* baseObject;
protected:
bool enabled = true;
};
} // namespace TSE

View File

@@ -0,0 +1,96 @@
#include "Layer.hpp"
#include "BehaviourScripts/Renderable.hpp"
#include "elements/BehaviourScript.hpp"
void HandleObject(TSE::Transformable* trans, TSE::TransformationStack& stack, TSE::IRenderer& rnd)
{
using namespace TSE;
if(!trans->IsEnabled()) return;
//OPTIMIZE this if statement
if(trans->HasBehaviourScript(RENDERABLE) && trans->GetBehaviourScript(RENDERABLE)->IsEnabled() && ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial() != nullptr && ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial()->GetShader() != nullptr)
{
rnd.Submit(*trans, ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial()->GetShader(), stack);
}
if(trans->GetChildren().size() > 0)
{
stack.Push(trans->GetLocalMatrix());
for(auto child : trans->GetChildren())
{
HandleObject(child, stack, rnd);
}
stack.Pop();
}
}
TSE::Layer::Layer(string &n)
{
name = n;
}
void TSE::Layer::Render(IRenderer &rnd) const
{
TransformationStack stack;
for(auto obj : objectsToRender)
{
HandleObject(obj, stack, rnd);
}
}
void TSE::Layer::AddTransformable(Transformable *t)
{
objectsToRender.push_back(t);
}
bool TSE::Layer::HasTransformable(const Transformable *t) const
{
for(auto trans2 : objectsToRender)
{
if(t->id == trans2->id)
{
return true;
}
}
return false;
}
void TSE::Layer::RemoveTransformable(const Transformable *t)
{
RemoveTransformable(t->id);
}
void TSE::Layer::RemoveTransformable(const uuids::uuid id)
{
auto it = objectsToRender.begin();
for(auto trans : objectsToRender)
{
if(trans->id == id)
{
objectsToRender.erase(it);
break;
}
it++;
}
}
TSE::string TSE::Layer::GetName() const
{
return name;
}
void TSE::Layer::SetName(const string &n)
{
name = n;
}
std::vector<TSE::Transformable *> &TSE::Layer::GetAllObjects()
{
return objectsToRender;
}
void TSE::Layer::Update()
{
for(auto trans : objectsToRender)
{
trans->Update();
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "Transformable.hpp"
#include "Types.hpp"
#include "interfaces/IRenderer.hpp"
#include <vector>
namespace TSE
{
class Layer
{
private:
string name;
std::vector<Transformable*> objectsToRender;
public:
Layer(string& name);
void Render(IRenderer& rnd) const;
void AddTransformable(Transformable* t);
bool HasTransformable(const Transformable* t) const;
void RemoveTransformable(const Transformable* t);
void RemoveTransformable(const uuids::uuid id);
string GetName() const;
void SetName(const string& name);
std::vector<Transformable*>& GetAllObjects();
void Update();
};
} // namespace TSE

View File

@@ -0,0 +1,81 @@
#include "Material.hpp"
#include <stdexcept>
#include "IdGenerator.hpp"
#include "interfaces/ITexture.hpp"
#include "Types.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
#include "Color.hpp"
#include "Matrix4x4.hpp"
namespace TSE
{
Material::Material()
: name(""), shader(nullptr)
{
id = GenerateRandomUUID();
}
Material::Material(const string& name, IShader* shader, uuids::uuid id)
: name(name), shader(shader), id(id) {}
Material::Material(const string &name, IShader *shader)
: name(name), shader(shader)
{
id = GenerateRandomUUID();
}
bool Material::HasValue(const string &key) const
{
return values.find(key) != values.end();
}
int Material::GetValueCount() const
{
return values.size();
}
std::tuple<std::any, string, string> &Material::GetValueAt(int j)
{
auto it = values.begin();
for (int i = 0; i < j; i++)
{
it++;
}
return it->second;
}
string &Material::GetName()
{
return name;
}
IShader *Material::GetShader() const
{
return shader;
}
void Material::SetShader(IShader *shader)
{
this->shader = shader;
}
uuids::uuid Material::GetID() const
{
return id;
}
template void Material::SetValue<int>(const string&, const int&);
template void Material::SetValue<float>(const string&, const float&);
template void Material::SetValue<Vector2>(const string&, const Vector2&);
template void Material::SetValue<Vector3>(const string&, const Vector3&);
template void Material::SetValue<Vector4>(const string&, const Vector4&);
template void Material::SetValue<Matrix4x4>(const string&, const Matrix4x4&);
template void Material::SetValue<Color>(const string&, const Color&);
template void Material::SetValue<string>(const string&, const string&);
template void Material::SetValue<ITexture>(const string&, const ITexture*);
template int Material::GetValue<int>(const string&) const;
template float Material::GetValue<float>(const string&) const;
template Vector2 Material::GetValue<Vector2>(const string&) const;
template Vector3 Material::GetValue<Vector3>(const string&) const;
template Vector4 Material::GetValue<Vector4>(const string&) const;
template Matrix4x4 Material::GetValue<Matrix4x4>(const string&) const;
template Color Material::GetValue<Color>(const string&) const;
template string Material::GetValue<string>(const string&) const;
template ITexture* Material::GetValue<ITexture*>(const string&) const;
} // namespace TSE

View File

@@ -0,0 +1,65 @@
#pragma once
#include "uuid.h"
#include "interfaces/IShader.hpp"
#include <unordered_map>
#include <any>
#include <string>
#include <tuple>
namespace TSE
{
struct Material
{
private:
string name;
uuids::uuid id;
IShader* shader;
std::unordered_map<string, std::tuple<std::any, string, string>> values;
public:
Material();
Material(const string& name, IShader* shader);
Material(const string& name, IShader* shader, uuids::uuid id);
template<typename T>
void SetValue(const string& key, const T& value);
template<typename T>
T GetValue(const string& key) const;
template<typename T>
void SetValue(const string& key, const T* value);
bool HasValue(const string& key) const;
int GetValueCount() const;
std::tuple<std::any, string, string>& GetValueAt(int i);
string& GetName();
IShader* GetShader() const;
void SetShader(IShader* shader);
uuids::uuid GetID() const;
};
template<typename T>
void Material::SetValue(const string& key, const T& value) {
values[key] = std::make_tuple(value, typeid(T).name(), key);
}
template<typename T>
T Material::GetValue(const string& key) const {
auto it = values.find(key);
if (it == values.end()) {
throw std::runtime_error("Material::GetValue - key '" + key + "' not found");
}
auto [a,b,c] = it->second;
return std::any_cast<T>(a);
}
template<typename T>
void Material::SetValue(const string& key, const T* value) {
values[key] = std::make_tuple(value, typeid(T).name(), key);
}
} // namespace TSE

View File

@@ -0,0 +1,469 @@
#include "Transformable.hpp"
#include "IdGenerator.hpp"
#include "MathF.hpp"
#include "BehaviourScript.hpp"
#include "Layer.hpp"
#include "Debug.hpp"
namespace TSE
{
Transformable::Transformable()
: position(0, 0, 0), scale(1, 1, 1), rotation(), name("")
{
id = GenerateRandomUUID();
objectEntries[id] = this;
}
Transformable::Transformable(uuids::uuid id)
: id(id), position(0, 0, 0), scale(1, 1, 1), rotation(), name("")
{
objectEntries[id] = this;
}
Transformable::Transformable(const string &name)
: position(0, 0, 0), scale(1, 1, 1), rotation(), name(name)
{
id = GenerateRandomUUID();
objectEntries[id] = this;
}
Transformable::Transformable(const string &name, uuids::uuid id)
: id(id), position(0, 0, 0), scale(1, 1, 1), rotation(), name(name)
{
objectEntries[id] = this;
}
Vector3 Transformable::forward() const
{
return Vector3::Normalize(GetGlobalMatrix() * Vector3::forward - GetGlobalMatrix() * Vector3::zero);
}
Vector3 Transformable::right() const
{
return Vector3::Normalize(GetGlobalMatrix() * Vector3::right - GetGlobalMatrix() * Vector3::zero);
}
Vector3 Transformable::up() const
{
return Vector3::Normalize(GetGlobalMatrix() * Vector3::up - GetGlobalMatrix() * Vector3::zero);
}
Vector3 Transformable::GetPosition() const
{
return position;
}
void Transformable::SetPosition(const Vector3 &pos)
{
position = pos;
}
Quaternion Transformable::GetRotation() const
{
return rotation;
}
void Transformable::SetRotation(const Quaternion &rot)
{
rotation = rot;
}
Vector3 Transformable::GetScale() const
{
return scale;
}
void Transformable::SetScale(const Vector3 &s)
{
scale = s;
}
string Transformable::GetName() const
{
return name;
}
uuids::uuid Transformable::GetId() const
{
return id;
}
Vector3 Transformable::GetEuler()
{
return rotation.ToEulerAngles();
}
void Transformable::SetEuler(const Vector3 &euler)
{
rotation = Quaternion::FromEulerAngles(euler);
}
int Transformable::GetComponentCount()
{
return components.size();
}
Matrix4x4 Transformable::GetLocalMatrix() const
{
return Matrix4x4::ToTranslationMatrix(position) * Matrix4x4::ToRotationMatrix(rotation) * Matrix4x4::ToScaleMatrix(scale);;
}
Matrix4x4 Transformable::GetGlobalMatrix() const
{
if (parent != nullptr)
return parent->GetGlobalMatrix() * GetLocalMatrix();
return GetLocalMatrix();
}
Vector3 Transformable::GetGlobalPosition() const
{
return LocalToGlobalPosition(Vector3::zero);
}
Vector3 Transformable::GlobalToLocalPosition(const Vector3& global) const
{
Matrix4x4 globalMatrix = GetGlobalMatrix();
if(globalMatrix.IsAffine())
{
globalMatrix.InvertAffine();
}
else
{
globalMatrix.Invert();
}
return globalMatrix * global;
}
Vector3 Transformable::LocalToGlobalPosition(const Vector3& local) const
{
return GetGlobalMatrix() * local;
}
void Transformable::LookAt_2D(const Vector3& globalTarget)
{
Vector3 to = globalTarget - GetGlobalPosition();
Vector3 toXY = {to.x, to.y, 0.0f};
if(Vector3::Dot(toXY, toXY) < TSE_EPSILON) return;
toXY.Normalize();
Vector3 fwdWorld = rotation.Rotate(Vector3::up);
Vector3 fwdXY = Vector3(fwdWorld.x, fwdWorld.y, 0);
fwdXY.Normalize();
float cosA = std::clamp(Vector3::Dot(fwdXY, toXY), -1.0f, 1.0f);
float sinA = fwdXY.x * toXY.y - fwdXY.y * toXY.x;
float angle = atan2(sinA, cosA);
Quaternion twist = Quaternion::FromAngleAxis(angle, Vector3::forward);
rotation = twist * rotation;
}
void Transformable::SetParent(Transformable *p)
{
Transformable* t(this);
if (parent != nullptr && parent != p) {
auto it = parent->children.begin();
for (int i = 0; i < parent->children.size(); i++)
{
if(**it == *t)
{
parent->children.erase(it);
break;
}
it++;
}
}
if (p != nullptr && p != parent) {
p->children.push_back(t);
}
parent = p;
}
Transformable *Transformable::GetParent() const
{
return parent;
}
const std::vector<Transformable *> &Transformable::GetChildren() const
{
return children;
}
bool Transformable::IsMyChild(Transformable *other)
{
for (auto child : children)
{
if(child->id == other->id)
{
return true;
}
else if(child->IsMyChild(other))
{
return true;
}
}
return false;
}
void Transformable::MoveUp(Layer *l)
{
if(l != nullptr)
{
auto it = l->GetAllObjects().begin();
for(int i = 0; i < l->GetAllObjects().size(); i++)
{
if((*it)->id == id)
{
if(i == 0) return;
std::swap(l->GetAllObjects()[i - 1], l->GetAllObjects()[i]);
}
it++;
}
return;
}
auto it = parent->children.begin();
for(int i = 0; i < parent->children.size(); i++)
{
if((*it)->id == id)
{
if(i == 0) return;
std::swap(parent->children[i - 1], parent->children[i]);
}
it++;
}
}
void Transformable::MoveDown(Layer *l)
{
if(l != nullptr)
{
auto it = l->GetAllObjects().begin();
for(int i = 0; i < l->GetAllObjects().size(); i++)
{
if((*it)->id == id)
{
if(i == l->GetAllObjects().size() - 1) return;
std::swap(l->GetAllObjects()[i + 1], l->GetAllObjects()[i]);
}
it++;
}
return;
}
auto it = parent->children.begin();
for(int i = 0; i < parent->children.size(); i++)
{
if((*it)->id == id)
{
if(i == parent->children.size() - 1) return;
std::swap(parent->children[i + 1], parent->children[i]);
}
it++;
}
}
bool Transformable::IsEnabled() const
{
return _enabled;
}
void Transformable::SetEnabled(bool v)
{
if (_enabled != v) {
_enabled = v;
if (_enabled) OnEnable();
else OnDisable();
}
}
BehaviourScript *Transformable::AddBehaviourScript(BehaviourScript *script)
{
if (!script) return nullptr;
const std::string key = typeid(*script).name();
components.emplace(key, script);
script->SetBaseObject(this);
script->Start();
return script;
}
BehaviourScript *Transformable::GetBehaviourScript(const string &name) const
{
auto it = components.find(name);
return (it != components.end()) ? it->second : nullptr;
}
BehaviourScript *Transformable::GetBehaviourScriptAt(const int i) const
{
auto it = components.begin();
for (int j = 0; j < i; j++)
{
it++;
}
return (*it).second;
}
std::vector<BehaviourScript *> Transformable::GetAllBehaviourScripts(const string &name) const
{
std::vector<BehaviourScript *> res;
auto it = components.begin();
while(it != components.end())
{
if((*it).first == name)
{
res.push_back((*it).second);
}
}
return res;
}
void Transformable::RemoveBehaviourScript(BehaviourScript *script)
{
for (auto it = components.begin(); it != components.end(); ++it) {
if (it->second == script) {
components.erase(it);
break;
}
}
}
bool Transformable::HasBehaviourScript(const string &name) const
{
auto it = components.find(name);
return it != components.end();
}
void Transformable::Update()
{
for (auto& [name, script] : components) {
if (script && script->IsEnabled()) script->OnUpdate();
}
for (auto child : children)
{
child->Update();
}
}
void Transformable::Delete(Transformable *t)
{
objectEntries.erase(t->id);
delete t;
}
void Transformable::Delete(const uuids::uuid id)
{
if(!Exists(id)) return;
Transformable* t = objectEntries.at(id);
objectEntries.erase(id);
delete t;
}
void Transformable::HardDelete(Transformable *t, bool onlyThis)
{
//deleting children
if(!onlyThis)
for(auto child : t->children)
{
HardDelete(child);
}
//deleting atteched scripts
for (auto& [_, script] : t->components)
delete script;
//deleting self
Delete(t);
}
void Transformable::HardDelete(const uuids::uuid id, bool onlyThis)
{
if(!Exists(id)) return;
Transformable* t = objectEntries.at(id);
//deleting children
if(!onlyThis)
for(auto child : t->children)
{
HardDelete(child);
}
//deleting atteched scripts
for (auto& [_, script] : t->components)
delete script;
//deleting self
Delete(t);
}
void Transformable::DeleteAll()
{
auto it = objectEntries.begin();
for(int i = 0; i < objectEntries.size(); i++)
{
delete it->second;
it++;
}
objectEntries.clear();
}
bool Transformable::Exists(const uuids::uuid id)
{
auto it = objectEntries.find(id);
return it != objectEntries.end();
}
bool Transformable::operator==(const Transformable &other) const
{
return other.id == id;
}
bool Transformable::operator!=(const Transformable &other) const
{
return other.id != id;
}
void Transformable::OnEnable()
{
for (auto& [_, script] : components)
if (script && script->IsEnabled()) script->OnEnable();
}
void Transformable::OnDisable()
{
for (auto& [_, script] : components)
if (script && script->IsEnabled()) script->OnDisable();
}
int Transformable::GetTansformableCount()
{
return objectEntries.size();
}
Transformable *Transformable::Find(string name)
{
for(auto obj : objectEntries)
{
if(obj.second->name == name)
{
return obj.second;
}
}
return nullptr;
}
Transformable *Transformable::Find(uuids::uuid id)
{
for(auto obj : objectEntries)
{
if(obj.second->id == id)
{
return obj.second;
}
}
return nullptr;
}
} // namespace TSE

View File

@@ -0,0 +1,106 @@
#pragma once
#include "Vector3.hpp"
#include "Quaternion.hpp"
#include "Matrix4x4.hpp"
#include "uuid.h"
#include "Types.hpp"
#include <list>
#include <string>
#include <unordered_map>
namespace TSE
{
class BehaviourScript;
class Layer;
class Transformable
{
public:
Vector3 position;
Vector3 scale;
Quaternion rotation;
string name;
bool _enabled = true;
uuids::uuid id;
private:
std::unordered_multimap<string, BehaviourScript*> components;
std::vector<Transformable*> children;
Transformable* parent = nullptr;
static std::unordered_map<uuids::uuid, Transformable*> objectEntries;
public:
Transformable();
Transformable(uuids::uuid id);
Transformable(const string& name);
Transformable(const string& name, uuids::uuid id);
~Transformable() = default;
Vector3 forward() const;
Vector3 right() const;
Vector3 up() const;
Vector3 GetPosition() const;
void SetPosition(const Vector3& pos);
Quaternion GetRotation() const;
void SetRotation(const Quaternion& rot);
Vector3 GetScale() const;
void SetScale(const Vector3& scale);
string GetName() const;
uuids::uuid GetId() const;
Vector3 GetEuler();
void SetEuler(const Vector3& euler);
int GetComponentCount();
Matrix4x4 GetLocalMatrix() const;
Matrix4x4 GetGlobalMatrix() const;
Vector3 GetGlobalPosition() const;
Vector3 GlobalToLocalPosition(const Vector3& global) const;
Vector3 LocalToGlobalPosition(const Vector3& local) const;
void LookAt_2D(const Vector3& globalTarget);
void SetParent(Transformable* parent);
Transformable* GetParent() const;
const std::vector<Transformable*>& GetChildren() const;
bool IsMyChild(Transformable* other);
void MoveUp(Layer* l = nullptr);
void MoveDown(Layer* l = nullptr);
bool IsEnabled() const;
void SetEnabled(bool v);
BehaviourScript* AddBehaviourScript(BehaviourScript* script);
BehaviourScript* GetBehaviourScript(const string& name) const;
BehaviourScript* GetBehaviourScriptAt(const int i) const;
std::vector<BehaviourScript*> GetAllBehaviourScripts(const string& name) const;
void RemoveBehaviourScript(BehaviourScript* script);
bool HasBehaviourScript(const string& name) const;
void Update();
static void Delete(Transformable* t);
static void Delete(const uuids::uuid id);
static void HardDelete(Transformable* t, bool onlyThis = false);
static void HardDelete(const uuids::uuid id, bool onlyThis = false);
static void DeleteAll();
static bool Exists(const uuids::uuid id);
bool operator==(const Transformable& other) const;
bool operator!=(const Transformable& other) const;
private:
void OnEnable();
void OnDisable();
public:
static int GetTansformableCount();
static Transformable* Find(string name);
static Transformable* Find(uuids::uuid id);
};
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "Vector2.hpp"
#include "Vector3.hpp"
#include <vector>
namespace TSE
{
class IRenderable
{
public:
virtual const Vector3* GetVertices() const = 0;
virtual const Vector2* GetUVs() const = 0;
virtual const std::vector<ushort> GetIndices() const = 0;
virtual size_t GetVertexCount() const = 0;
virtual ~IRenderable() = default;
};
} // namespace TSE

View File

@@ -0,0 +1,3 @@
#include "IRenderer.hpp"
std::vector<TSE::Camera*> TSE::IRenderer::camerasToRenderWith = std::vector<TSE::Camera*>();

View File

@@ -0,0 +1,26 @@
#pragma once
#include "IShader.hpp"
#include "TransformationStack.hpp"
#include "elements/Transformable.hpp"
namespace TSE
{
class Camera;
class IRenderer
{
public:
static std::vector<Camera*> camerasToRenderWith;
virtual void End() = 0;
virtual void Flush() = 0;
virtual void Begin() = 0;
virtual void Submit(const Transformable& trans, TransformationStack& stack) = 0;
virtual void Submit(const Transformable& trans, IShader* shader, TransformationStack& stack) = 0;
virtual ~IRenderer() = default;
};
} // namespace TSE

View File

@@ -0,0 +1,29 @@
#pragma once
#include "Types.hpp"
#include "Matrix4x4.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
namespace TSE
{
class IShader
{
public:
virtual void Bind() const = 0;
virtual void Unbind() const = 0;
virtual void SetUniform(const char* name, int value) = 0;
virtual void SetUniform(const char* name, const int* value, int count) = 0;
virtual void SetUniform(const char* name, const Matrix4x4* value) = 0;
virtual void SetUniform(const char* name, float value) = 0;
virtual void SetUniform(const char* name, const float* value, int count) = 0;
virtual void SetUniform(const char* name, const Vector2* value) = 0;
virtual void SetUniform(const char* name, const Vector3* value) = 0;
virtual void SetUniform(const char* name, const Vector4* value) = 0;
virtual ~IShader() = default;
};
} // namespace TSE

View File

@@ -0,0 +1,16 @@
#pragma once
#include "Vector2.hpp"
namespace TSE
{
class ITexture
{
public:
virtual ~ITexture() = default;
virtual Vector2 size() const = 0;
virtual float width() const = 0;
virtual float height() const = 0;
virtual uint GetTextureId() const = 0;
};
} // namespace TSE