Split engine to packages NazaraUtils and NZSL (#375)
* Move code to NazaraUtils and NZSL packages
* Reorder includes
* Tests: Remove glslang and spirv-tools deps
* Tests: Remove glslang init
* Remove NazaraUtils tests and fix Vector4Test
* Fix Linux compilation
* Update msys2-build.yml
* Fix assimp package
* Update xmake.lua
* Update xmake.lua
* Fix shader compilation on MinGW
* Final fixes
* The final fix 2: the fix strikes back!
* Disable cache on CI
* The return of the fix™️
This commit is contained in:
@@ -2,10 +2,6 @@
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// http://stackoverflow.com/questions/687490/c0x-how-do-i-expand-a-tuple-into-variadic-template-function-arguments
|
||||
// Merci à Ryan "FullMetal Alchemist" Lahfa
|
||||
// Merci aussi à Freedom de siteduzero.com
|
||||
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/AbstractHash.hpp>
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
@@ -21,193 +17,6 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
// http://www.cppsamples.com/common-tasks/apply-tuple-to-function.html
|
||||
template<typename F, typename Tuple, size_t... S>
|
||||
decltype(auto) ApplyImplFunc(F&& fn, Tuple&& t, std::index_sequence<S...>)
|
||||
{
|
||||
return std::forward<F>(fn)(std::get<S>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
template<typename O, typename F, typename Tuple, size_t... S>
|
||||
decltype(auto) ApplyImplMethod(O& object, F&& fn, Tuple&& t, std::index_sequence<S...>)
|
||||
{
|
||||
return (object .* std::forward<F>(fn))(std::get<S>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
NAZARA_CORE_API extern const UInt8 BitReverseTable256[256];
|
||||
|
||||
// https://stackoverflow.com/questions/28675727/using-crc32-algorithm-to-hash-string-at-compile-time
|
||||
// Generates CRC-32 table, algorithm based from this link:
|
||||
// http://www.hackersdelight.org/hdcodetxt/crc.c.txt
|
||||
constexpr auto GenerateCRC32Table(UInt32 polynomial = 0xEDB88320)
|
||||
{
|
||||
#ifdef NAZARA_COMPILER_MSVC
|
||||
// Disable warning: unary minus operator applied to unsigned type, result still unsigned
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4146)
|
||||
#endif
|
||||
|
||||
constexpr UInt32 byteCount = 256;
|
||||
constexpr UInt32 iterationCount = 8;
|
||||
|
||||
std::array<UInt32, byteCount> crc32Table{};
|
||||
for (UInt32 byte = 0u; byte < byteCount; ++byte)
|
||||
{
|
||||
UInt32 crc = byte;
|
||||
|
||||
for (UInt32 i = 0; i < iterationCount; ++i)
|
||||
{
|
||||
UInt32 mask = static_cast<UInt32>(-(crc & 1));
|
||||
crc = (crc >> 1) ^ (polynomial & mask);
|
||||
}
|
||||
|
||||
crc32Table[byte] = crc;
|
||||
}
|
||||
|
||||
return crc32Table;
|
||||
|
||||
#ifdef NAZARA_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stores CRC-32 table and softly validates it.
|
||||
static constexpr auto crc32Table = GenerateCRC32Table();
|
||||
static_assert(
|
||||
crc32Table.size() == 256 &&
|
||||
crc32Table[1] == 0x77073096 &&
|
||||
crc32Table[255] == 0x2D02EF8D,
|
||||
"gen_crc32_table generated unexpected result."
|
||||
);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Access a non-typed struct field by offset
|
||||
* \return A pointer to the field of the asked type
|
||||
*
|
||||
* \param basePtr Pointer to the start of the struct
|
||||
* \param offset Offset to the field (as generated by offsetof or similar)
|
||||
*/
|
||||
template<typename T>
|
||||
decltype(auto) AccessByOffset(void* basePtr, std::size_t offset)
|
||||
{
|
||||
if constexpr (std::is_lvalue_reference_v<T>)
|
||||
return *reinterpret_cast<std::remove_reference_t<T>*>(static_cast<UInt8*>(basePtr) + offset);
|
||||
else if constexpr (std::is_pointer_v<T>)
|
||||
return reinterpret_cast<T>(static_cast<UInt8*>(basePtr) + offset);
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "AccessByOffset requires a reference or pointer type");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Access a non-typed struct field by offset
|
||||
* \return A pointer to the field of the asked type
|
||||
*
|
||||
* \param basePtr Pointer to the start of the struct
|
||||
* \param offset Offset to the field (as generated by offsetof or similar)
|
||||
*/
|
||||
template<typename T>
|
||||
decltype(auto) AccessByOffset(const void* basePtr, std::size_t offset)
|
||||
{
|
||||
static_assert(std::is_lvalue_reference_v<T> || std::is_pointer_v<T>);
|
||||
|
||||
if constexpr (std::is_lvalue_reference_v<T>)
|
||||
return *reinterpret_cast<std::remove_reference_t<T>*>(static_cast<const UInt8*>(basePtr) + offset);
|
||||
else if constexpr (std::is_pointer_v<T>)
|
||||
return reinterpret_cast<T>(static_cast<const UInt8*>(basePtr) + offset);
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "AccessByOffset requires a reference or pointer type");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Align an offset
|
||||
* \return Aligned offset according to alignment
|
||||
*
|
||||
* \param offset Base offset
|
||||
* \param alignment Non-zero alignment
|
||||
*
|
||||
* \see AlignPow2
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr T Align(T offset, T alignment)
|
||||
{
|
||||
assert(alignment > 0);
|
||||
return ((offset + alignment - 1) / alignment) * alignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Align an offset
|
||||
* \return Aligned offset according to a power of two alignment
|
||||
*
|
||||
* \param offset Base offset
|
||||
* \param alignment Non-zero power of two alignment
|
||||
*
|
||||
* \see Align
|
||||
* \remark This function is quicker than Align but only works with power of two alignment values
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr T AlignPow2(T offset, T alignment)
|
||||
{
|
||||
assert(alignment > 0);
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
|
||||
return (offset + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Applies the tuple to the function (e.g. calls the function using the tuple content as arguments)
|
||||
* \return The result of the function
|
||||
*
|
||||
* \param fn Function
|
||||
* \param t Tuple of arguments for the function
|
||||
*
|
||||
* \see Apply
|
||||
*/
|
||||
template<typename F, typename Tuple>
|
||||
decltype(auto) Apply(F&& fn, Tuple&& t)
|
||||
{
|
||||
constexpr std::size_t tSize = std::tuple_size<typename std::remove_reference<Tuple>::type>::value;
|
||||
|
||||
return Detail::ApplyImplFunc(std::forward<F>(fn), std::forward<Tuple>(t), std::make_index_sequence<tSize>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Applies the tuple to the member function on an object (e.g. calls the member function using the tuple content as arguments)
|
||||
* \return The result of the member function called
|
||||
*
|
||||
* \param object Object of a class
|
||||
* \param fn Member function
|
||||
* \param t Tuple of arguments for the member function
|
||||
*
|
||||
* \see Apply
|
||||
*/
|
||||
template<typename O, typename F, typename Tuple>
|
||||
decltype(auto) Apply(O& object, F&& fn, Tuple&& t)
|
||||
{
|
||||
constexpr std::size_t tSize = std::tuple_size<typename std::remove_reference<Tuple>::type>::value;
|
||||
|
||||
return Detail::ApplyImplMethod(object, std::forward<F>(fn), std::forward<Tuple>(t), std::make_index_sequence<tSize>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Returns the number of bits occupied by the type T
|
||||
* \return Number of bits occupied by the type
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr std::size_t BitCount()
|
||||
{
|
||||
return CHAR_BIT * sizeof(T);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Computes the hash of a hashable object
|
||||
@@ -249,279 +58,12 @@ namespace Nz
|
||||
return hash.End();
|
||||
}
|
||||
|
||||
// From https://stackoverflow.com/questions/28675727/using-crc32-algorithm-to-hash-string-at-compile-time
|
||||
constexpr UInt32 CRC32(const UInt8* input, std::size_t size) noexcept
|
||||
{
|
||||
UInt32 crc = 0xFFFFFFFFu;
|
||||
|
||||
for (std::size_t i = 0u; i < size; ++i)
|
||||
crc = Detail::crc32Table[(crc ^ input[i]) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
constexpr UInt32 CRC32(const char* str) noexcept
|
||||
{
|
||||
UInt32 crc = 0xFFFFFFFFu;
|
||||
|
||||
for (std::size_t i = 0u; str[i]; ++i)
|
||||
crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
constexpr UInt32 CRC32(const std::string_view& str) noexcept
|
||||
{
|
||||
UInt32 crc = 0xFFFFFFFFu;
|
||||
|
||||
for (std::size_t i = 0u; i < str.size(); ++i)
|
||||
crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr UInt32 CRC32(const char (&str)[N]) noexcept
|
||||
{
|
||||
UInt32 crc = 0xFFFFFFFFu;
|
||||
|
||||
for (std::size_t i = 0u; i < N - 1; ++i)
|
||||
crc = Detail::crc32Table[(crc ^ str[i]) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Returns the number of elements in a C-array
|
||||
* \return The number of elements
|
||||
*
|
||||
* \see CountOf
|
||||
*/
|
||||
template<typename T, std::size_t N>
|
||||
constexpr std::size_t CountOf(T(&)[N]) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Returns the number of elements in a container
|
||||
* \return The number of elements
|
||||
*
|
||||
* \param c Container with the member function "size()"
|
||||
*
|
||||
* \see CountOf
|
||||
*/
|
||||
template<typename T>
|
||||
std::size_t CountOf(const T& c)
|
||||
{
|
||||
return c.size();
|
||||
}
|
||||
|
||||
inline bool HashAppend(AbstractHash& hash, const std::string_view& v)
|
||||
{
|
||||
hash.Append(reinterpret_cast<const UInt8*>(v.data()), v.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Combines two hash in one
|
||||
*
|
||||
* \param seed First value that will be modified (expected to be 64bits)
|
||||
* \param v Second value to hash
|
||||
*/
|
||||
// Algorithm from CityHash by Google
|
||||
// http://stackoverflow.com/questions/8513911/how-to-create-a-good-hash-combine-with-64-bit-output-inspired-by-boosthash-co
|
||||
template<typename T>
|
||||
void HashCombine(std::size_t& seed, const T& v)
|
||||
{
|
||||
const UInt64 kMul = 0x9ddfea08eb382d69ULL;
|
||||
|
||||
std::hash<T> hasher;
|
||||
UInt64 a = (hasher(v) ^ seed) * kMul;
|
||||
a ^= (a >> 47);
|
||||
|
||||
UInt64 b = (seed ^ a) * kMul;
|
||||
b ^= (b >> 47);
|
||||
|
||||
seed = static_cast<std::size_t>(b * kMul);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Check if a value is a power of two
|
||||
* \return true if value is a power of two
|
||||
*
|
||||
* \param value Non-zero value
|
||||
*/
|
||||
template<typename T>
|
||||
bool IsPowerOfTwo(T value)
|
||||
{
|
||||
assert(value != 0);
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Helper function to retrieve a key in a map which has to exist
|
||||
* \return Value associated with key
|
||||
*
|
||||
* \param map Map
|
||||
* \param key Key, has to exist in map
|
||||
*/
|
||||
template<typename K, typename V>
|
||||
V& Retrieve(std::unordered_map<K, V>& map, const K& key)
|
||||
{
|
||||
auto it = map.find(key);
|
||||
assert(it != map.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Helper function to retrieve a key in a map which has to exist
|
||||
* \return Value associated with key
|
||||
*
|
||||
* \param map Map
|
||||
* \param key Key, has to exist in map
|
||||
*/
|
||||
template<typename K, typename V>
|
||||
const V& Retrieve(const std::unordered_map<K, V>& map, const K& key)
|
||||
{
|
||||
auto it = map.find(key);
|
||||
assert(it != map.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \brief Reverse the bit order of the integer
|
||||
* \return integer with reversed bits
|
||||
*
|
||||
* \param integer Integer whose bits are to be reversed
|
||||
*/
|
||||
template<typename T>
|
||||
T ReverseBits(T integer)
|
||||
{
|
||||
T reversed = 0;
|
||||
for (std::size_t i = 0; i < sizeof(T); ++i)
|
||||
reversed |= T(Detail::BitReverseTable256[(integer >> i * 8) & 0xFF]) << (sizeof(T) * 8 - (i + 1) * 8);
|
||||
|
||||
return reversed;
|
||||
}
|
||||
|
||||
template<typename To, typename From>
|
||||
To SafeCast(From&& value)
|
||||
{
|
||||
#ifdef NAZARA_COMPILER_MSVC
|
||||
// Disable unreachable code warnings
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
|
||||
#if defined(NAZARA_DEBUG) && !defined(NDEBUG)
|
||||
|
||||
if constexpr (std::is_integral_v<To>)
|
||||
{
|
||||
if constexpr (std::is_enum_v<From>)
|
||||
{
|
||||
return SafeCast<To>(static_cast<std::underlying_type_t<From>>(value));
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<From>)
|
||||
{
|
||||
assert(std::floor(value) == value);
|
||||
|
||||
assert(value <= static_cast<From>(std::numeric_limits<To>::max()));
|
||||
assert(value >= static_cast<From>(std::numeric_limits<To>::lowest()));
|
||||
}
|
||||
else if constexpr (std::is_integral_v<From>)
|
||||
{
|
||||
// Type capable of storing the biggest value between the two types
|
||||
using MaxValueType = std::conditional_t<(sizeof(From) > sizeof(To) || (sizeof(From) == sizeof(To) && std::is_signed_v<To>)), From, To>;
|
||||
// Type capable of storing the smallest value between the two types
|
||||
using MinValueType = std::conditional_t<(sizeof(From) > sizeof(To) || (sizeof(From) == sizeof(To) && std::is_signed_v<From>)), From, To>;
|
||||
|
||||
if constexpr (!std::is_signed_v<To>)
|
||||
assert(value >= 0);
|
||||
|
||||
assert(static_cast<MaxValueType>(value) <= static_cast<MaxValueType>(std::numeric_limits<To>::max()));
|
||||
assert(static_cast<MinValueType>(value) >= static_cast<MinValueType>(std::numeric_limits<To>::lowest()));
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_enum_v<To>)
|
||||
{
|
||||
return static_cast<To>(SafeCast<std::underlying_type_t<To>>(value));
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<To>)
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<From>)
|
||||
{
|
||||
// Type capable of storing the biggest value between the two types
|
||||
using MaxValueType = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
|
||||
// Type capable of storing the smallest value between the two types
|
||||
using MinValueType = std::conditional_t<(sizeof(From) > sizeof(To)), From, To>;
|
||||
|
||||
assert(static_cast<MaxValueType>(value) <= static_cast<MaxValueType>(std::numeric_limits<To>::max()));
|
||||
assert(static_cast<MinValueType>(value) >= static_cast<MinValueType>(std::numeric_limits<To>::lowest()));
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_reference_v<To>)
|
||||
{
|
||||
if constexpr (std::is_reference_v<From>)
|
||||
{
|
||||
using BaseFromType = std::remove_reference_t<std::remove_cv_t<From>>;
|
||||
using BaseToType = std::remove_reference_t<std::remove_cv_t<To>>;
|
||||
|
||||
if constexpr (!std::is_same_v<BaseFromType, BaseToType> && std::is_base_of_v<From, To> && std::is_polymorphic_v<From>)
|
||||
{
|
||||
using ToPtr = std::add_pointer_t<std::remove_reference_t<To>>;
|
||||
assert(dynamic_cast<ToPtr>(&value) != nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_pointer_v<To>)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<From>)
|
||||
{
|
||||
using BaseFromType = std::remove_pointer_t<std::remove_cv_t<From>>;
|
||||
using BaseToType = std::remove_pointer_t<std::remove_cv_t<To>>;
|
||||
|
||||
if constexpr (!std::is_same_v<BaseFromType, BaseToType> && std::is_base_of_v<From, To> && std::is_polymorphic_v<From>)
|
||||
{
|
||||
assert(dynamic_cast<To>(value) != nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return static_cast<To>(value);
|
||||
|
||||
#ifdef NAZARA_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
std::unique_ptr<T> StaticUniquePointerCast(std::unique_ptr<U>&& ptr)
|
||||
{
|
||||
return std::unique_ptr<T>(SafeCast<T*>(ptr.release()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto UnderlyingCast(T value) -> std::underlying_type_t<T>
|
||||
{
|
||||
return static_cast<std::underlying_type_t<T>>(value);
|
||||
}
|
||||
|
||||
template<typename T> struct PointedType<T*> { using type = T; };
|
||||
template<typename T> struct PointedType<T* const> { using type = T; };
|
||||
template<typename T> struct PointedType<T* volatile> { using type = T; };
|
||||
template<typename T> struct PointedType<T* const volatile> { using type = T; };
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool Serialize(SerializationContext& context, T&& value)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user