project-aster/aster/include/aster/core/global.h

259 lines
8.0 KiB
C++

// =============================================
// Aster: global.h
// Copyright (c) 2020-2025 Anish Bhobe
// =============================================
#pragma once
#include "config.h"
#include "constants.h"
#include "aster/util/logger.h"
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <fmt/format.h>
#include <EASTL/shared_ptr.h>
// Macros that can collide with functions.
#if defined(max)
#undef max
#endif
#if defined(min)
#undef min
#endif
#if !defined(NDEBUG)
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
#endif
#include "EASTL/intrusive_ptr.h"
#include "type_traits.h"
#include <EASTL/fixed_string.h>
#include <EASTL/string.h>
#include <vk_mem_alloc.h>
#include <vulkan/vulkan.hpp>
constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
#define DISALLOW_COPY_AND_ASSIGN(CLASS_NAME) \
CLASS_NAME(const CLASS_NAME &other) = delete; \
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
#define PIN_MEMORY(CLASS_NAME) \
CLASS_NAME(const CLASS_NAME &other) = delete; \
CLASS_NAME(CLASS_NAME &&other) noexcept = delete; \
CLASS_NAME &operator=(const CLASS_NAME &other) = delete; \
CLASS_NAME &operator=(CLASS_NAME &&other) noexcept = delete
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
#define TODO(...) assert(!("Unimplemented: " __VA_ARGS__))
#define FIX(...) static_assert(!("Unimplemented: " __VA_ARGS__))
#define UNREACHABLE(...) assert(!("Unreachable: " __VA_ARGS__))
#define AbortIfFailed(RESULT) \
do \
{ \
vk::Result _checkResultValue_; \
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
THEN_ABORT(_checkResultValue_); \
} while (false)
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
do \
{ \
vk::Result _checkResultValue_; \
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, \
_checkResultValue_) \
THEN_ABORT(_checkResultValue_); \
} while (false)
#define AbortIfFailedM(RESULT, MSG) \
do \
{ \
auto _checkResultValue_ = static_cast<vk::Result>(RESULT); \
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
} while (false)
[[nodiscard]] inline bool
Failed(const vk::Result result)
{
return result != vk::Result::eSuccess;
}
namespace concepts
{
template <typename T>
concept VkHandle = vk::isVulkanHandleType<T>::value;
}
using NameString = eastl::fixed_string<char, 32, false>;
template <typename TFlagBits>
struct eastl::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
{
[[nodiscard]] usize
operator()(const vk::Flags<TFlagBits> &val)
{
return std::hash<u32>()(static_cast<u32>(val));
}
};
template <typename T>
[[nodiscard]] usize
HashAny(const T &val)
{
return eastl::hash<std::remove_cvref_t<T>>()(val);
}
[[nodiscard]] inline usize
HashCombine(const usize hash0, const usize hash1)
{
constexpr usize saltValue = 0x9e3779b9;
const usize tempVar = hash1 + saltValue + (hash0 << 6) + (hash0 >> 2);
return hash0 ^ tempVar;
}
struct Time
{
static constexpr f64 MAX_DELTA = 0.1;
inline static f64 m_Elapsed{Qnan<f64>};
inline static f64 m_Delta{Qnan<f64>};
static void
Init()
{
WARN_IF(!std::isnan(m_Elapsed), "Time already init.");
m_Elapsed = glfwGetTime();
m_Delta = 1.0 / 60.0;
}
static void
Update()
{
ERROR_IF(std::isnan(m_Elapsed), "Time not init.");
const auto newElapsed = glfwGetTime();
m_Delta = std::clamp(newElapsed - m_Elapsed, 0.0, MAX_DELTA);
m_Elapsed = newElapsed;
}
};
[[nodiscard]] constexpr usize
ClosestMultiple(const usize val, const usize of)
{
return of * ((val + of - 1) / of);
}
[[nodiscard]] constexpr u32
ClosestMultiple(const u32 val, const u32 of)
{
return of * ((val + of - 1) / of);
}
[[nodiscard]] constexpr bool
IsPowerOfTwo(const usize val)
{
return val && !(val & (val - 1));
}
[[nodiscard]] constexpr bool
IsPowerOfTwo(const u32 val)
{
return val && !(val & (val - 1));
}
[[nodiscard]] constexpr usize
ClosestLargerPowerOfTwo(usize val)
{
val--;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val |= val >> 32;
val++;
return val;
}
[[nodiscard]] constexpr usize
ClosestPowerOfTwo(const usize val)
{
const usize largerPo2 = ClosestLargerPowerOfTwo(val);
const usize smallerPo2 = largerPo2 >> 1;
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
}
[[nodiscard]] constexpr u32
ClosestLargerPowerOfTwo(u32 val)
{
val--;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val++;
return val;
}
[[nodiscard]] constexpr u32
ClosestPowerOfTwo(const u32 val)
{
const u32 largerPo2 = ClosestLargerPowerOfTwo(val);
const u32 smallerPo2 = largerPo2 >> 1;
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
}
[[nodiscard]] constexpr u32
GetMaskOffset(u32 val)
{
u32 count = 0;
while ((val & 1) == 0)
{
count++;
val = val >> 1;
}
return count;
}
template <typename T>
concept VkToString = requires(T a) {
{ vk::to_string(a) } -> std::convertible_to<std::string>;
};
template <VkToString T>
struct fmt::formatter<T> : nested_formatter<std::string>
{
auto
// ReSharper disable once CppInconsistentNaming
format(T result, format_context &ctx) const
{
return write_padded(ctx,
[this, result](auto out) { return fmt::format_to(out, "{}", nested(to_string(result))); });
}
};
template <typename TType, usize TCount, bool TOverflow>
struct fmt::formatter<eastl::fixed_string<TType, TCount, TOverflow>> : nested_formatter<cstr>
{
auto
// ReSharper disable once CppInconsistentNaming
format(const eastl::fixed_string<TType, TCount, TOverflow> &str, format_context &ctx) const
{
return write_padded(ctx, [this, str](auto out) { return fmt::format_to(out, "{}", nested(str.c_str())); });
}
};
template <typename T>
using Ref = eastl::shared_ptr<T>;
template <typename T>
using WeakRef = eastl::weak_ptr<T>;