diff --git a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp index a32029868..38e0f8b98 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataValue.cpp @@ -133,15 +133,14 @@ FString UCesiumMetadataValueBlueprintLibrary::GetString( FCesiumPropertyArray UCesiumMetadataValueBlueprintLibrary::GetArray( UPARAM(ref) const FCesiumMetadataValue& Value) { - return FCesiumPropertyArray(); - //return mpark::visit( - // [](auto value) -> FCesiumPropertyArray { - // if constexpr (CesiumGltf::IsMetadataArray::value) { - // return FCesiumPropertyArray(value); - // } - // return FCesiumPropertyArray(); - // }, - // Value._value); + return mpark::visit( + [](auto value) -> FCesiumPropertyArray { + if constexpr (CesiumGltf::IsMetadataArray::value) { + return FCesiumPropertyArray(value); + } + return FCesiumPropertyArray(); + }, + Value._value); } bool UCesiumMetadataValueBlueprintLibrary::IsEmpty( @@ -153,12 +152,21 @@ template /*static*/ TTo FCesiumMetadataValue::convertTo( const ValueType& Value, const TTo& DefaultValue) noexcept { - return DefaultValue; - //return mpark::visit( - // [DefaultValue](auto value) { - // return CesiumMetadataConversions::convert( - // value, - // DefaultValue); - // }, - // Value); -} + return mpark::visit( + [DefaultValue](auto value) { + return CesiumMetadataConversions::convert( + value, + DefaultValue); + }, + Value); +} + +FCesiumMetadataValue& FCesiumMetadataValue::operator=( + const FCesiumMetadataValue& rhs) noexcept = default; +FCesiumMetadataValue& +FCesiumMetadataValue::operator=(FCesiumMetadataValue&& rhs) noexcept = default; +FCesiumMetadataValue::FCesiumMetadataValue( + const FCesiumMetadataValue& rhs) noexcept = default; +FCesiumMetadataValue::FCesiumMetadataValue( + FCesiumMetadataValue&& rhs) noexcept = default; +FCesiumMetadataValue ::~FCesiumMetadataValue() noexcept = default; diff --git a/Source/CesiumRuntime/Private/CesiumPropertyTableProperty.cpp b/Source/CesiumRuntime/Private/CesiumPropertyTableProperty.cpp index 7f95d52ae..59d96562d 100644 --- a/Source/CesiumRuntime/Private/CesiumPropertyTableProperty.cpp +++ b/Source/CesiumRuntime/Private/CesiumPropertyTableProperty.cpp @@ -26,8 +26,9 @@ template < bool Normalized, typename TResult, typename Callback> -TResult -propertyTablePropertyCallback(const std::any& property, Callback&& callback) { +inline TResult singlePropertyTablePropertyCallback( + const std::any& property, + Callback&& callback) noexcept { const PropertyTablePropertyView* pProperty = std::any_cast>( &property); @@ -55,62 +56,66 @@ template TResult scalarPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback( - property, - std::forward(callback)); + return singlePropertyTablePropertyCallback< + int8_t, + Normalized, + TResult, + Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< uint8_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< int16_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< uint16_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< int32_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< uint32_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< int64_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< uint64_t, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback( + return singlePropertyTablePropertyCallback( property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback( - property, - std::forward(callback)); + return singlePropertyTablePropertyCallback< + double, + false, + TResult, + Callback>(property, std::forward(callback)); default: return callback(PropertyTablePropertyView()); } @@ -134,64 +139,64 @@ template TResult scalarArrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, false, TResult, @@ -219,64 +224,64 @@ template TResult vecNPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::vec, false, TResult, @@ -303,7 +308,7 @@ template TResult vecNPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { if (valueType.Type == ECesiumMetadataType::Vec2) { return vecNPropertyTablePropertyCallback<2, Normalized, TResult, Callback>( property, @@ -347,64 +352,64 @@ template TResult vecNArrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, false, TResult, @@ -432,7 +437,7 @@ template TResult vecNArrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { if (valueType.Type == ECesiumMetadataType::Vec2) { return vecNArrayPropertyTablePropertyCallback< 2, @@ -478,64 +483,64 @@ template TResult matNPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< glm::mat, false, TResult, @@ -562,7 +567,7 @@ template TResult matNPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { if (valueType.Type == ECesiumMetadataType::Mat2) { return matNPropertyTablePropertyCallback<2, Normalized, TResult, Callback>( property, @@ -606,64 +611,64 @@ template TResult matNArrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.ComponentType) { case ECesiumMetadataComponentType::Int8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint8: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint16: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Int64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Uint64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, Normalized, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float32: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataComponentType::Float64: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView>, false, TResult, @@ -691,7 +696,7 @@ template TResult matNArrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { if (valueType.Type == ECesiumMetadataType::Mat2) { return matNArrayPropertyTablePropertyCallback< 2, @@ -723,7 +728,7 @@ template TResult arrayPropertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, - Callback&& callback) { + Callback&& callback) noexcept { switch (valueType.Type) { case ECesiumMetadataType::Scalar: return scalarArrayPropertyTablePropertyCallback< @@ -745,13 +750,13 @@ TResult arrayPropertyTablePropertyCallback( TResult, Callback>(property, valueType, std::forward(callback)); case ECesiumMetadataType::Boolean: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, false, TResult, Callback>(property, std::forward(callback)); case ECesiumMetadataType::String: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< PropertyArrayView, false, TResult, @@ -766,7 +771,7 @@ TResult propertyTablePropertyCallback( const std::any& property, const FCesiumMetadataValueType& valueType, bool normalized, - Callback&& callback) { + Callback&& callback) noexcept { if (valueType.bIsArray) { return normalized ? arrayPropertyTablePropertyCallback( @@ -815,11 +820,11 @@ TResult propertyTablePropertyCallback( valueType, std::forward(callback)); case ECesiumMetadataType::Boolean: - return propertyTablePropertyCallback( + return singlePropertyTablePropertyCallback( property, std::forward(callback)); case ECesiumMetadataType::String: - return propertyTablePropertyCallback< + return singlePropertyTablePropertyCallback< std::string_view, false, TResult, @@ -868,7 +873,7 @@ int64 UCesiumPropertyTablePropertyBlueprintLibrary::GetPropertySize( Property._property, Property._valueType, Property._normalized, - [](const auto& view) -> int64 { return view.size(); }); + [](const auto& view) noexcept -> int64 { return view.size(); }); } int64 UCesiumPropertyTablePropertyBlueprintLibrary::GetArraySize( @@ -877,26 +882,26 @@ int64 UCesiumPropertyTablePropertyBlueprintLibrary::GetArraySize( Property._property, Property._valueType, Property._normalized, - [](const auto& view) -> int64 { return view.arrayCount(); }); + [](const auto& view) noexcept -> int64 { return view.arrayCount(); }); } namespace { template struct Convertifier { int64 FeatureID; - TTo DefaultValue; + const TTo& DefaultValue; template - TTo operator()(const PropertyTablePropertyView& v) { + TTo operator()( + const PropertyTablePropertyView& v) noexcept { // size() returns zero if the view is invalid. if (FeatureID < 0 || FeatureID >= v.size()) { return DefaultValue; } auto maybeValue = v.get(FeatureID); if (maybeValue) { - auto value = *maybeValue; - return CesiumMetadataConversions::convert( - value, + return CesiumMetadataConversions::convert( + *maybeValue, DefaultValue); } return DefaultValue; diff --git a/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.cpp b/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.cpp index 9fd9aa87c..45e6ba667 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "CesiumGltfSpecUtility.h" using namespace CesiumGltf; diff --git a/Source/CesiumRuntime/Public/CesiumMetadataConversions.h b/Source/CesiumRuntime/Public/CesiumMetadataConversions.h index 754109f6a..7c89cafe4 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataConversions.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataConversions.h @@ -43,1883 +43,1883 @@ template struct CesiumMetadataConversions { static T convert(T from, T defaultValue) { return from; } }; -//#pragma region Conversions to boolean -// -///** -// * Converts from a scalar to a bool. -// */ -//template -//struct CesiumMetadataConversions< -// bool, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a scalar to a boolean. Zero is converted to false, while nonzero -// * values are converted to true. -// * -// * @param from The scalar to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static bool convert(TFrom from, bool defaultValue) { -// return from != static_cast(0); -// } -//}; -// -///** -// * Converts from std::string_view to a bool. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts the contents of a std::string_view to a boolean. -// * -// * "0", "false", and "no" (case-insensitive) are converted to false, while -// * "1", "true", and "yes" are converted to true. All other strings will return -// * the default value. -// * -// * @param from The std::string_view to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static bool convert(const std::string_view& from, bool defaultValue) { -// FString f(from.size(), from.data()); -// -// if (f.Compare("1", ESearchCase::IgnoreCase) == 0 || -// f.Compare("true", ESearchCase::IgnoreCase) == 0 || -// f.Compare("yes", ESearchCase::IgnoreCase) == 0) { -// return true; -// } -// -// if (f.Compare("0", ESearchCase::IgnoreCase) == 0 || -// f.Compare("false", ESearchCase::IgnoreCase) == 0 || -// f.Compare("no", ESearchCase::IgnoreCase) == 0) { -// return false; -// } -// -// return defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to integer -// -///** -// * Converts from one integer type to another. -// */ -//template -//struct CesiumMetadataConversions< -// TTo, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// CesiumGltf::IsMetadataInteger::value && -// !std::is_same_v>> { -// /** -// * Converts a value of the given integer to another integer type. If the -// * integer cannot be losslessly converted to the desired type, the default -// * value is returned. -// * -// * @param from The integer value to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static TTo convert(TFrom from, TTo defaultValue) { -// return CesiumUtility::losslessNarrowOrDefault(from, defaultValue); -// } -//}; -// -///** -// * Converts from a floating-point type to an integer. -// */ -//template -//struct CesiumMetadataConversions< -// TTo, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// CesiumGltf::IsMetadataFloating::value>> { -// /** -// * Converts a floating-point value to an integer type. This truncates the -// * floating-point value, rounding it towards zero. -// * -// * If the value is outside the range of the integer type, the default value is -// * returned. -// * -// * @param from The floating-point value to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static TTo convert(TFrom from, TTo defaultValue) { -// if (double(std::numeric_limits::max()) < from || -// double(std::numeric_limits::lowest()) > from) { -// // Floating-point number is outside the range of this integer type. -// return defaultValue; -// } -// -// return static_cast(from); -// } -//}; -// -///** -// * Converts from std::string_view to a signed integer. -// */ -//template -//struct CesiumMetadataConversions< -// TTo, -// std::string_view, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { -// /** -// * Converts the contents of a std::string_view to a signed integer. This -// * assumes that the entire std::string_view represents the number, not just a -// * part of it. -// * -// * This returns the default value if no number is parsed from the string. -// * -// * @param from The std::string_view to parse from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static TTo convert(const std::string_view& from, TTo defaultValue) { -// // Amazingly, C++ has no* string parsing functions that work with strings -// // that might not be null-terminated. So we have to copy to a std::string -// // (which _is_ guaranteed to be null terminated) before parsing. -// // * except std::from_chars, but compiler/library support for the -// // floating-point version of that method is spotty at best. -// std::string temp(from); -// -// char* pLastUsed; -// int64_t parsedValue = std::strtoll(temp.c_str(), &pLastUsed, 10); -// if (pLastUsed == temp.c_str() + temp.size()) { -// // Successfully parsed the entire string as an integer of this type. -// return CesiumUtility::losslessNarrowOrDefault(parsedValue, defaultValue); -// } -// -// // Failed to parse as an integer. Maybe we can parse as a double and -// // truncate it? -// double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); -// if (pLastUsed == temp.c_str() + temp.size()) { -// // Successfully parsed the entire string as a double. -// // Convert it to an integer if we can. -// double truncated = glm::trunc(parsedDouble); -// -// int64_t asInteger = static_cast(truncated); -// double roundTrip = static_cast(asInteger); -// if (roundTrip == truncated) { -// return CesiumUtility::losslessNarrowOrDefault(asInteger, defaultValue); -// } -// } -// -// return defaultValue; -// } -//}; -// -///** -// * Converts from std::string_view to an unsigned integer. -// */ -//template -//struct CesiumMetadataConversions< -// TTo, -// std::string_view, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { -// /** -// * Converts the contents of a std::string_view to an signed integer. This -// * assumes that the entire std::string_view represents the number, not just a -// * part of it. -// * -// * This returns the default value if no number is parsed from the string. -// * -// * @param from The std::string_view to parse from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static TTo convert(const std::string_view& from, TTo defaultValue) { -// // Amazingly, C++ has no* string parsing functions that work with strings -// // that might not be null-terminated. So we have to copy to a std::string -// // (which _is_ guaranteed to be null terminated) before parsing. -// // * except std::from_chars, but compiler/library support for the -// // floating-point version of that method is spotty at best. -// std::string temp(from); -// -// char* pLastUsed; -// uint64_t parsedValue = std::strtoull(temp.c_str(), &pLastUsed, 10); -// if (pLastUsed == temp.c_str() + temp.size()) { -// // Successfully parsed the entire string as an integer of this type. -// return CesiumUtility::losslessNarrowOrDefault(parsedValue, defaultValue); -// } -// -// // Failed to parse as an integer. Maybe we can parse as a double and -// // truncate it? -// double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); -// if (pLastUsed == temp.c_str() + temp.size()) { -// // Successfully parsed the entire string as a double. -// // Convert it to an integer if we can. -// double truncated = glm::trunc(parsedDouble); -// -// uint64_t asInteger = static_cast(truncated); -// double roundTrip = static_cast(asInteger); -// if (roundTrip == truncated) { -// return CesiumUtility::losslessNarrowOrDefault(asInteger, defaultValue); -// } -// } -// -// return defaultValue; -// } -//}; -// -///** -// * Converts from a boolean to an integer type. -// */ -//template -//struct CesiumMetadataConversions< -// TTo, -// bool, -// std::enable_if_t::value>> { -// /** -// * Converts a boolean to an integer. This returns 1 for true, 0 for -// * false. -// * -// * @param from The boolean value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static TTo convert(bool from, TTo defaultValue) { return from ? 1 : 0; } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to float -// -///** -// * Converts from a boolean to a float. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a float. This returns 1.0f for true, 0.0f for -// * false. -// * -// * @param from The boolean value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static float convert(bool from, float defaultValue) { -// return from ? 1.0f : 0.0f; -// } -//}; -// -///** -// * Converts from an integer type to a float. -// */ -//template -//struct CesiumMetadataConversions< -// float, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts an integer to a float. The value may lose precision during -// * conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static float convert(TFrom from, float defaultValue) { -// return static_cast(from); -// } -//}; -// -///** -// * Converts from a double to a float. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a double to a float. The value may lose precision during -// * conversion. -// * -// * If the value is outside the range of a float, the default value is -// * returned. -// * -// * @param from The double value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static float convert(double from, float defaultValue) { -// if (from > std::numeric_limits::max() || -// from < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// return static_cast(from); -// } -//}; -// -///** -// * Converts from a std::string_view to a float. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a float. This assumes that the entire -// * std::string_view represents the number, not just a part of it. -// * -// * This returns the default value if no number is parsed from the string. -// * -// * @param from The std::string_view to parse from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static float convert(const std::string_view& from, float defaultValue) { -// // Amazingly, C++ has no* string parsing functions that work with strings -// // that might not be null-terminated. So we have to copy to a std::string -// // (which _is_ guaranteed to be null terminated) before parsing. -// // * except std::from_chars, but compiler/library support for the -// // floating-point version of that method is spotty at best. -// std::string temp(from); -// -// char* pLastUsed; -// float parsedValue = std::strtof(temp.c_str(), &pLastUsed); -// if (pLastUsed == temp.c_str() + temp.size() && !std::isinf(parsedValue)) { -// // Successfully parsed the entire string as a float. -// return parsedValue; -// } -// return defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to double -// -///** -// * Converts from a boolean to a double. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a double. This returns 1.0 for true, 0.0 for -// * false. -// * -// * @param from The boolean value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static double convert(bool from, double defaultValue) { -// return from ? 1.0 : 0.0; -// } -//}; -// -///** -// * Converts from any integer type to a double. -// */ -//template -//struct CesiumMetadataConversions< -// double, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts any integer type to a double. The value may lose precision during -// * conversion. -// * -// * @param from The boolean value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static double convert(TFrom from, double defaultValue) { -// return static_cast(from); -// } -//}; -// -///** -// * Converts from a float to a double. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts from a float to a double. -// * -// * @param from The float value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static double convert(float from, double defaultValue) { -// return static_cast(from); -// } -//}; -// -///** -// * Converts from std::string_view to a double. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a double. This assumes that the entire -// * std::string_view represents the number, not just a part of it. -// * -// * This returns the default value if no number is parsed from the string. -// * -// * @param from The std::string_view to parse from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static double convert(const std::string_view& from, double defaultValue) { -// // Amazingly, C++ has no* string parsing functions that work with strings -// // that might not be null-terminated. So we have to copy to a std::string -// // (which _is_ guaranteed to be null terminated) before parsing. -// // * except std::from_chars, but compiler/library support for the -// // floating-point version of that method is spotty at best. -// std::string temp(from); -// -// char* pLastUsed; -// double parsedValue = std::strtod(temp.c_str(), &pLastUsed); -// if (pLastUsed == temp.c_str() + temp.size() && !std::isinf(parsedValue)) { -// // Successfully parsed the entire string as a double. -// return parsedValue; -// } -// return defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to string -// -///** -// * Converts from a boolean to a string. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FString. Returns "true" for true and "false" for -// * false. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FString convert(bool from, const FString& defaultValue) { -// return from ? "true" : "false"; -// } -//}; -// -///** -// * Converts from a scalar to a string. -// */ -//template -//struct CesiumMetadataConversions< -// FString, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a scalar to a FString. -// * -// * @param from The scalar to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FString convert(TFrom from, const FString& defaultValue) { -// return FString(std::to_string(from).c_str()); -// } -//}; -// -//static const std::string VectorComponents = "XYZW"; -// -///** -// * Converts from a glm::vecN to a string. -// */ -//template -//struct CesiumMetadataConversions< -// FString, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a glm::vecN to a FString. This follows the format that ToString() -// * functions call on the Unreal vector equivalents. For example, a glm::vec3 -// * will return a string in the format "X=... Y=... Z=...". -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FString convert(const TFrom& from, const FString& defaultValue) { -// std::string result; -// for (glm::length_t i = 0; i < from.length(); i++) { -// if (i > 0) { -// result += " "; -// } -// result += VectorComponents[i]; -// result += "="; -// result += std::to_string(from[i]); -// } -// return FString(result.c_str()); -// } -//}; -// -///** -// * Converts from a glm::matN to a string. -// */ -//template -//struct CesiumMetadataConversions< -// FString, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a glm::matN to a FString. This follows the format that ToString() -// * functions call on the Unreal matrix equivalents. Each row is -// * returned in square brackets, e.g. "[1 2 3 4]", with spaces in-between. -// * -// * @param from The glm::matN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FString convert(const TFrom& from, const FString& defaultValue) { -// std::string result; -// glm::length_t dimensions = from.length(); -// glm::mat3 matrix; -// matrix[0]; -// // glm::matNs are column-major, but Unreal matrices are row-major and print -// // their values by row. -// for (glm::length_t r = 0; r < dimensions; r++) { -// if (r > 0) { -// result += " "; -// } -// result += "["; -// for (glm::length_t c = 0; c < dimensions; c++) { -// if (c > 0) { -// result += " "; -// } -// result += std::to_string(from[c][r]); -// } -// result += "]"; -// } -// return FString(result.c_str()); -// } -//}; -// -///** -// * Converts from a std::string_view to a FString. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts from a std::string_view to a FString. -// */ -// static FString -// convert(const std::string_view& from, const FString& defaultValue) { -// return FString(UTF8_TO_TCHAR(std::string(from.data(), from.size()).data())); -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to integer vec2 -///** -// * Converts from a boolean to a 32-bit signed integer vec2. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FIntPoint. The boolean is converted to an integer -// * value of 1 for true or 0 for false. The returned vector is initialized with -// * this value in both of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint convert(bool from, const FIntPoint& defaultValue) { -// int32 value = from ? 1 : 0; -// return FIntPoint(value); -// } -//}; -// -///** -// * Converts from a signed integer type to a 32-bit signed integer vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// std::is_signed_v>> { -// /** -// * Converts a signed integer to a FIntPoint. The returned vector is -// * initialized with the value in both of its components. If the integer cannot -// * be losslessly converted to a 32-bit signed representation, the default -// * value is returned. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { -// if (from > std::numeric_limits::max() || -// from < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// return FIntPoint(static_cast(from)); -// } -//}; -// -///** -// * Converts from an unsigned integer type to a 32-bit signed integer vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// !std::is_signed_v>> { -// /** -// * Converts an unsigned integer to a FIntPoint. The returned vector is -// * initialized with the value in both of its components. If the integer cannot -// * be losslessly converted to a 32-bit signed representation, the default -// * value is returned. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { -// if (from > static_cast(std::numeric_limits::max())) { -// return defaultValue; -// } -// return FIntPoint(static_cast(from)); -// } -//}; -// -///** -// * Converts from a floating-point value to a 32-bit signed integer vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a floating-point value to a FIntPoint. This truncates the -// * floating-point value, rounding it towards zero, and puts it in both of the -// * resulting vector's components. -// * -// * If the value is outside the range that a 32-bit signed integer can -// * represent, the default value is returned. -// * -// * @param from The floating-point value to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { -// if (double(std::numeric_limits::max()) < from || -// double(std::numeric_limits::lowest()) > from) { -// // Floating-point number is outside the range. -// return defaultValue; -// } -// return FIntPoint(static_cast(from)); -// } -//}; -// -///** -// * Converts from a glm::vecN of a signed integer type to a 32-bit signed integer -// * vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// glm::vec, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { -// /** -// * Converts a glm::vecN of signed integers to a FIntPoint. This only uses the -// * first two components of the vecN. If either of the first two values cannot -// * be converted to a 32-bit signed integer, the default value is returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint -// convert(const glm::vec& from, const FIntPoint& defaultValue) { -// for (size_t i = 0; i < 2; i++) { -// if (from[i] > std::numeric_limits::max() || -// from[i] < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// } -// -// return FIntPoint( -// static_cast(from[0]), -// static_cast(from[1])); -// } -//}; -// -///** -// * Converts from a glm::vecN of an unsigned integer type to a 32-bit signed -// * integer vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// glm::vec, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { -// /** -// * Converts a glm::vecN of unsigned integers to a FIntPoint. This only uses -// * the first two components of the vecN. If either of the first two values -// * cannot be converted to a 32-bit signed integer, the default value is -// * returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint -// convert(const glm::vec& from, const FIntPoint& defaultValue) { -// for (size_t i = 0; i < 2; i++) { -// if (from[i] > -// static_cast(std::numeric_limits::max())) { -// return defaultValue; -// } -// } -// -// return FIntPoint( -// static_cast(from[0]), -// static_cast(from[1])); -// } -//}; -// -///** -// * Converts from a glm::vecN of a floating-point type to a 32-bit signed -// * integer vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FIntPoint, -// glm::vec, -// std::enable_if_t::value>> { -// /** -// * Converts a glm::vecN of floating-point numbers to a FIntPoint. This only -// * uses the first two components of the vecN. If either of the first two -// * values cannot be converted to a 32-bit signed integer, the default value is -// * returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint -// convert(const glm::vec& from, const FIntPoint& defaultValue) { -// for (size_t i = 0; i < 2; i++) { -// if (from[i] > double(std::numeric_limits::max()) || -// from[i] < double(std::numeric_limits::lowest())) { -// return defaultValue; -// } -// } -// -// return FIntPoint( -// static_cast(from[0]), -// static_cast(from[1])); -// } -//}; -// -///** -// * Converts from a std::string_view to a 32-bit signed integer vec2. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FIntPoint. This expects the values to be -// * written in the "X=... Y=..." format. If this function fails to parse -// * a FIntPoint, the default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntPoint -// convert(const std::string_view& from, const FIntPoint& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// -// // For some reason, FIntPoint doesn't have an InitFromString method, so -// // copy the one from FVector. -// int32 X = 0, Y = 0; -// const bool bSuccessful = FParse::Value(*string, TEXT("X="), X) && -// FParse::Value(*string, TEXT("Y="), Y); -// return bSuccessful ? FIntPoint(X, Y) : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to double vec2 -///** -// * Converts from a boolean to a double-precision floating-point vec2. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FVector2D. The boolean is converted to a double -// * value of 1.0 for true or 0.0 for false. The returned vector is -// initialized -// * with this value in both of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector2D convert(bool from, const FVector2D& defaultValue) { -// double value = from ? 1.0 : 0.0; -// return FVector2D(value); -// } -//}; -// -///** -// * Converts from an integer type to a double-precision floating-point vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FVector2D, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts an integer to a FVector2D. The returned vector is initialized -// * with the value in both of its components. The value may lose precision -// * during conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector2D convert(TFrom from, const FVector2D& defaultValue) { -// return FVector2D(static_cast(from)); -// } -//}; -// -///** -// * Converts from a floating-point value to a double-precision floating-point -// * vec2. -// */ -//template -//struct CesiumMetadataConversions< -// FVector2D, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a floating-point value to a FVector2D. The returned vector is -// * initialized with the value in all of its components. -// * -// * @param from The floating-point value to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector2D convert(TFrom from, const FVector2D& defaultValue) { -// return FVector2D(static_cast(from)); -// } -//}; -// -///** -// * Converts from a glm::vecN of any type to a double-precision floating-point -// * vec2. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vecN of any type to a FVector2D. This only uses the first -// * two components of the vecN. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector2D -// convert(const glm::vec& from, const FVector2D& defaultValue) { -// return FVector2D( -// static_cast(from[0]), -// static_cast(from[1])); -// } -//}; -// -///** -// * Converts from a std::string_view to a double-precision floating-point -// * vec2. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FVector2D. This uses -// * FVector2D::InitFromString, which expects the values to be written in the -// * "X=... Y=..." format. If this function fails to parse a FVector2D, the -// * default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector2D -// convert(const std::string_view& from, const FVector2D& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// -// FVector2D result; -// return result.InitFromString(string) ? result : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to integer vec3 -// -///** -// * Converts from a boolean to a 32-bit signed integer vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FIntVector. The boolean is converted to an integer -// * value of 1 for true or 0 for false. The returned vector is initialized with -// * this value in all of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector convert(bool from, const FIntVector& defaultValue) { -// int32 value = from ? 1 : 0; -// return FIntVector(value); -// } -//}; -// -///** -// * Converts from a signed integer to a 32-bit signed integer vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// std::is_signed_v>> { -// /** -// * Converts a signed integer to a FIntVector. The returned vector is -// * initialized with the value in all of its components. If the integer -// * cannot be losslessly converted to a 32-bit signed representation, the -// * default value is returned. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector convert(TFrom from, const FIntVector& defaultValue) { -// if (from > std::numeric_limits::max() || -// from < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// return FIntVector(static_cast(from)); -// } -//}; -// -///** -// * Converts from an unsigned integer to a 32-bit signed integer vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// TFrom, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && -// !std::is_signed_v>> { -// /** -// * Converts an unsigned integer to a FIntVector. The returned vector is -// * initialized with the value in all of its components. If the integer -// * cannot be losslessly converted to a 32-bit signed representation, the -// * default value is returned. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector convert(TFrom from, const FIntVector& defaultValue) { -// if (from > static_cast(std::numeric_limits::max())) { -// return defaultValue; -// } -// return FIntVector(static_cast(from)); -// } -//}; -// -///** -// * Converts from a floating-point value to a 32-bit signed integer vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a floating-point value to a FIntVector. This truncates the -// * floating-point value, rounding it towards zero, and puts it in all of the -// * resulting vector's components. -// * -// * If the value is outside the range that a 32-bit signed integer can -// * represent, the default value is returned. -// * -// * @param from The floating-point value to convert from. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector convert(TFrom from, const FIntVector& defaultValue) { -// if (double(std::numeric_limits::max()) < from || -// double(std::numeric_limits::lowest()) > from) { -// // Floating-point number is outside the range. -// return defaultValue; -// } -// return FIntVector(static_cast(from)); -// } -//}; -// -///** -// * Converts from a glm::vecN of signed integers to a 32-bit signed integer vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// glm::vec, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { -// /** -// * Converts a glm::vecN of signed integers to a FIntVector. -// * -// * If converting from a vec2, the vec2 becomes the first two components of -// * the FIntVector, while the third component is set to zero. -// * -// * If converting from a vec4, only the first three components of the vec4 are -// * used, and the fourth is dropped. -// * -// * If any of the relevant components cannot be converted to 32-bit signed -// * integers, the default value is returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector -// convert(const glm::vec& from, const FIntVector& defaultValue) { -// glm::length_t count = glm::min(N, static_cast(3)); -// for (size_t i = 0; i < count; i++) { -// if (from[i] > std::numeric_limits::max() || -// from[i] < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// } -// -// if constexpr (N == 2) { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// 0); -// } else { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -// } -//}; -// -///** -// * Converts from a glm::vecN of unsigned integers to a 32-bit signed integer -// * vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// glm::vec, -// std::enable_if_t< -// CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { -// /** -// * Converts a glm::vecN of unsigned integers to a FIntVector. -// * -// * If converting from a vec2, the vec2 becomes the first two components of -// * the FIntVector, while the third component is set to zero. -// * -// * If converting from a vec4, only the first three components of the vec4 are -// * used, and the fourth is dropped. -// * -// * If any of the relevant components cannot be converted to 32-bit signed -// * integers, the default value is returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector -// convert(const glm::vec& from, const FIntVector& defaultValue) { -// glm::length_t count = glm::min(N, static_cast(3)); -// for (size_t i = 0; i < count; i++) { -// if (from[i] > -// static_cast(std::numeric_limits::max())) { -// return defaultValue; -// } -// } -// -// if constexpr (N == 2) { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// 0); -// } else { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -// } -//}; -// -///** -// * Converts from a glm::vecN of floating-point numbers to a 32-bit signed -// * integer vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FIntVector, -// glm::vec, -// std::enable_if_t::value>> { -// /** -// * Converts a glm::vecN of floating-point numbers to a FIntVector. -// * -// * If converting from a vec2, the vec2 becomes the first two components of -// * the FIntVector, while the third component is set to zero. -// * -// * If converting from a vec4, only the first three components of the vec4 are -// * used, and the fourth is dropped. -// * -// * If any of the relevant components cannot be converted to 32-bit signed -// * integers, the default value is returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector -// convert(const glm::vec& from, const FIntVector& defaultValue) { -// glm::length_t count = glm::min(N, static_cast(3)); -// for (size_t i = 0; i < 3; i++) { -// if (from[i] > double(std::numeric_limits::max()) || -// from[i] < double(std::numeric_limits::lowest())) { -// return defaultValue; -// } -// } -// -// if constexpr (N == 2) { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// 0); -// } else { -// return FIntVector( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -// } -//}; -// -///** -// * Converts from a std::string_view to a 32-bit signed integer vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FIntVector. This expects the values to be -// * written in the "X=... Y=... Z=..." format. If this function fails to parse -// * a FIntVector, the default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FIntVector -// convert(const std::string_view& from, const FIntVector& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// -// // For some reason, FIntVector doesn't have an InitFromString method, so -// // copy the one from FVector. -// int32 X = 0, Y = 0, Z = 0; -// const bool bSuccessful = FParse::Value(*string, TEXT("X="), X) && -// FParse::Value(*string, TEXT("Y="), Y) && -// FParse::Value(*string, TEXT("Z="), Z); -// return bSuccessful ? FIntVector(X, Y, Z) : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to float vec3 -///** -// * Converts from a boolean to a single-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FVector3f. The boolean is converted to a float -// * value of 1.0f for true or 0.0f for false. The returned vector is -// * initialized with this value in all of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f convert(bool from, const FVector3f& defaultValue) { -// float value = from ? 1.0f : 0.0f; -// return FVector3f(value); -// } -//}; -// -///** -// * Converts from an integer type to a single-precision floating-point vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FVector3f, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts an integer to a FVector3f. The returned vector is initialized with -// * the value in all of its components. The value may lose precision during -// * conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f convert(TFrom from, const FVector3f& defaultValue) { -// return FVector3f(static_cast(from)); -// } -//}; -// -///** -// * Converts from a float to a single-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a float to a FVector3f. The returned vector is initialized with -// * the value in all of its components. -// * -// * @param from The float to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f convert(float from, const FVector3f& defaultValue) { -// return FVector3f(from); -// } -//}; -// -///** -// * Converts from a double to a single-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a double to a FVector3f. This attempts to convert the double to a -// * float, then initialize a vector with the value in all of its components. If -// * the double cannot be converted, the default value is returned. -// * -// * @param from The double to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f convert(double from, const FVector3f& defaultValue) { -// if (from > double(std::numeric_limits::max()) || -// from < double(std::numeric_limits::lowest())) { -// return defaultValue; -// } -// return FVector3f(static_cast(from)); -// } -//}; -// -///** -// * Converts from a glm::vec2 of any type to a single-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec2 of any type to a FVector3f. Similar to how an -// * FVector3f can be constructed from an FIntPoint, the vec2 becomes the first -// * two components of the FVector3f, while the third component is set to zero. -// * If the vec2 is of an integer type, its values may lose precision during -// * conversion. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f -// convert(const glm::vec<2, T>& from, const FVector3f& defaultValue) { -// if constexpr (std::is_same_v) { -// // Check if all double values can be converted to floats. -// for (size_t i = 0; i < 2; i++) { -// if (from[i] > double(std::numeric_limits::max()) || -// from[i] < double(std::numeric_limits::lowest())) { -// return defaultValue; -// } -// } -// } -// -// return FVector3f( -// static_cast(from[0]), -// static_cast(from[1]), -// 0.0f); -// } -//}; -// -///** -// * Converts from a glm::vec3 of any type to a single-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec3 of any type to a FVector3f. If any of the original -// * vec3 values cannot be converted to a float, the default value is -// * returned. -// * -// * @param from The glm::vecN to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f -// convert(const glm::vec<3, T>& from, const FVector3f& defaultValue) { -// if constexpr (std::is_same_v) { -// // Check if all double values can be converted to floats. -// for (size_t i = 0; i < 3; i++) { -// if (from[i] > double(std::numeric_limits::max()) || -// from[i] < double(std::numeric_limits::lowest())) { -// return defaultValue; -// } -// } -// } -// -// return FVector3f( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -//}; -// -///** -// * Converts from a glm::vec4 of any type to a single-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec4 of any type to a FVector3f. If any of the first three -// * values cannot be converted to a float, the default value is returned. -// * -// * @param from The glm::vec4 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f -// convert(const glm::vec<4, T>& from, const FVector3f& defaultValue) { -// if constexpr (std::is_same_v) { -// // Check if all double values can be converted to floats. -// for (size_t i = 0; i < 3; i++) { -// if (from[i] > std::numeric_limits::max() || -// from[i] < std::numeric_limits::lowest()) { -// return defaultValue; -// } -// } -// } -// return FVector3f( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -//}; -// -///** -// * Converts from a std::string_view to a single-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FVector3f. This uses -// * FVector3f::InitFromString, which expects the values to be written in the -// * "X=... Y=... Z=..." format. If this function fails to parse a FVector3f, -// * the default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector3f -// convert(const std::string_view& from, const FVector3f& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// FVector3f result; -// return result.InitFromString(string) ? result : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to double vec3 -///** -// * Converts from a boolean to a double-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FVector. The boolean is converted to a float -// * value of 1.0 for true or 0.0 for false. The returned vector is -// * initialized with this value in all of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector convert(bool from, const FVector& defaultValue) { -// float value = from ? 1.0 : 0.0; -// return FVector(value); -// } -//}; -// -///** -// * Converts from an integer type to a double-precision floating-point vec3. -// */ -//template -//struct CesiumMetadataConversions< -// FVector, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts an integer to a FVector. The returned vector is initialized with -// * the value in all of its components. The value may lose precision during -// * conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector convert(TFrom from, const FVector& defaultValue) { -// return FVector(static_cast(from)); -// } -//}; -// -///** -// * Converts from a float to a double-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a float to a FVector. The returned vector is initialized with -// * the value in all of its components. -// * -// * @param from The float to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector convert(float from, const FVector& defaultValue) { -// return FVector(static_cast(from)); -// } -//}; -// -///** -// * Converts from a double to a single-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a double to a FVector. The returned vector is initialized with -// * the value in all of its components. -// * -// * @param from The double to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector convert(double from, const FVector& defaultValue) { -// return FVector(from); -// } -//}; -// -///** -// * Converts from a glm::vec2 of any type to a double-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec2 of any type to a FVector. Similar to how an -// * FVector can be constructed from an FIntPoint, the vec2 becomes the first -// * two components of the FVector, while the third component is set to zero. -// * If the vec2 is of an integer type, its values may lose precision during -// * conversion. -// * -// * @param from The glm::vec2 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector -// convert(const glm::vec<2, T>& from, const FVector& defaultValue) { -// return FVector( -// static_cast(from[0]), -// static_cast(from[1]), -// 0.0); -// } -//}; -// -///** -// * Converts from a glm::vec3 of any type to a double-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec3 of any type to a FVector. If the vec3 is of an integer -// * type, its values may lose precision during conversion. -// * -// * @param from The glm::vec3 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector -// convert(const glm::vec<3, T>& from, const FVector& defaultValue) { -// return FVector( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -//}; -// -///** -// * Converts from a glm::vec4 of any type to a double-precision floating-point -// * vec3. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec4 of any type to a FVector. This only uses the first -// * three components of the vec4, dropping the fourth. If the vec3 is of an -// * integer type, its values may lose precision during conversion. -// * -// * @param from The glm::vec4 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector -// convert(const glm::vec<4, T>& from, const FVector& defaultValue) { -// return FVector( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2])); -// } -//}; -// -///** -// * Converts from a std::string_view to a double-precision floating-point vec3. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FVector. This uses -// * FVector::InitFromString, which expects the values to be written in the -// * "X=... Y=... Z=..." format. If this function fails to parse a FVector, -// * the default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector -// convert(const std::string_view& from, const FVector& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// FVector result; -// return result.InitFromString(string) ? result : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to double vec4 -// -///** -// * Converts from a boolean to a double-precision floating-point vec4. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FVector4. The boolean is converted to a double -// * value of 1.0 for true or 0.0 for false. The returned vector is -// * initialized with this value in all of its components. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 convert(bool from, const FVector4& defaultValue) { -// double value = from ? 1.0 : 0.0; -// return FVector4(value, value, value, value); -// } -//}; -// -///** -// * Converts from an integer type to a double-precision floating-point vec4. -// */ -//template -//struct CesiumMetadataConversions< -// FVector4, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts an integer to a FVector4. The returned vector is initialized with -// * the value in all of its components. The value may lose precision during -// * conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 convert(TFrom from, const FVector4& defaultValue) { -// double value = static_cast(from); -// return FVector4(from, from, from, from); -// } -//}; -// -///** -// * Converts from a float to a double-precision floating-point vec4. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a float to a FVector4. The returned vector is initialized with -// * the value in all of its components. -// * -// * @param from The float to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 convert(float from, const FVector& defaultValue) { -// double value = static_cast(from); -// return FVector4(from, from, from, from); -// } -//}; -// -///** -// * Converts from a double to a double-precision floating-point vec4. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a double to a FVector4. The returned vector is initialized with -// * the value in all of its components. -// * -// * @param from The double to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 convert(double from, const FVector4& defaultValue) { -// return FVector4(from, from, from, from); -// } -//}; -// -///** -// * Converts from a glm::vec2 of any type to a double-precision floating-point -// * vec4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec2 of any type to a FVector4. The vec2 becomes the first -// * two components of the FVector4, while the third and fourth components are -// * set to zero. -// * -// * If the vec2 is of an integer type, its values may lose -// * precision during conversion. -// * -// * @param from The glm::vec2 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 -// convert(const glm::vec<2, T>& from, const FVector4& defaultValue) { -// return FVector4( -// static_cast(from[0]), -// static_cast(from[1]), -// 0.0, -// 0.0); -// } -//}; -// -///** -// * Converts from a glm::vec3 of any type to a double-precision floating-point -// * vec4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec3 of any type to a FVector4. The vec3 becomes the first -// * three components of the FVector4, while the fourth component is set to -// * zero. -// * -// * If the vec3 is of an integer type, its values may lose precision during -// * conversion. -// * -// * @param from The glm::vec3 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 -// convert(const glm::vec<3, T>& from, const FVector4& defaultValue) { -// return FVector4( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2]), -// 0.0); -// } -//}; -// -///** -// * Converts from a glm::vec4 of any type to a double-precision floating-point -// * vec4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::vec4 of any type to a FVector4. If the vec4 is of an -// * integer type, its values may lose precision during conversion. -// * -// * @param from The glm::vec4 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 -// convert(const glm::vec<4, T>& from, const FVector4& defaultValue) { -// return FVector4( -// static_cast(from[0]), -// static_cast(from[1]), -// static_cast(from[2]), -// static_cast(from[3])); -// } -//}; -// -///** -// * Converts from a std::string_view to a double-precision floating-point vec4. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a std::string_view to a FVector4. This uses -// * FVector4::InitFromString, which expects the values to be written in the -// * "X=... Y=... Z=..." format. It allows the "W=..." component is optional; if -// * left out, the fourth component will be initialized as 1.0. -// * -// * If this function fails to parse a FVector, the default value is returned. -// * -// * @param from The std::string_view to be parsed. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FVector4 -// convert(const std::string_view& from, const FVector4& defaultValue) { -// FString string = -// CesiumMetadataConversions::convert( -// from, -// FString("")); -// FVector4 result; -// return result.InitFromString(string) ? result : defaultValue; -// } -//}; -// -//#pragma endregion -// -//#pragma region Conversions to double mat4 -// -//static const FPlane4d ZeroPlane(0.0, 0.0, 0.0, 0.0); -// -///** -// * Converts from a glm::mat2 to a double-precision floating-point mat4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::mat2 of any type to a FMatrix. The mat2 is used to -// * initialize the values of the FMatrix at the corresponding indices. -// * The rest of the components are all set to zero. -// * -// * If the mat2 is of an integer type, its values may lose precision during -// * conversion. -// * -// * @param from The mat2 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FMatrix -// convert(const glm::mat<2, 2, T>& from, const FMatrix& defaultValue) { -// // glm is column major, but Unreal is row major. -// FPlane4d row1(ZeroPlane); -// row1.X = static_cast(from[0][0]); -// row1.Y = static_cast(from[1][0]); -// -// FPlane4d row2(ZeroPlane); -// row2.X = static_cast(from[0][1]); -// row2.Y = static_cast(from[1][1]); -// -// return FMatrix(row1, row2, ZeroPlane, ZeroPlane); -// } -//}; -// -///** -// * Converts from a glm::mat3 to a double-precision floating-point mat4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::mat3 of any type to a FMatrix. The mat3 is used to -// * initialize the values of the FMatrix at the corresponding indices. -// * The rest of the components are all set to zero. -// * -// * If the mat3 is of an integer type, its values may lose precision during -// * conversion. -// * -// * @param from The mat3 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FMatrix -// convert(const glm::mat<3, 3, T>& from, const FMatrix& defaultValue) { -// // glm is column major, but Unreal is row major. -// FPlane4d row1(ZeroPlane); -// row1.X = static_cast(from[0][0]); -// row1.Y = static_cast(from[1][0]); -// row1.Z = static_cast(from[2][0]); -// -// FPlane4d row2(ZeroPlane); -// row2.X = static_cast(from[0][1]); -// row2.Y = static_cast(from[1][1]); -// row2.Z = static_cast(from[2][1]); -// -// FPlane4d row3(ZeroPlane); -// row3.X = static_cast(from[0][2]); -// row3.Y = static_cast(from[1][2]); -// row3.Z = static_cast(from[2][2]); -// -// return FMatrix(row1, row2, row3, ZeroPlane); -// } -//}; -// -///** -// * Converts from a glm::mat4 to a double-precision floating-point mat4. -// */ -//template -//struct CesiumMetadataConversions> { -// /** -// * Converts a glm::mat4 of any type to a FMatrix. If the mat4 is of an integer -// * type, its values may lose precision during conversion. -// * -// * @param from The mat4 to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FMatrix -// convert(const glm::mat<4, 4, T>& from, const FMatrix& defaultValue) { -// // glm is column major, but Unreal is row major. -// FPlane4d row1( -// static_cast(from[0][0]), -// static_cast(from[1][0]), -// static_cast(from[2][0]), -// static_cast(from[3][0])); -// -// FPlane4d row2(ZeroPlane); -// row2.X = static_cast(from[0][1]); -// row2.Y = static_cast(from[1][1]); -// row2.Z = static_cast(from[2][1]); -// row2.W = static_cast(from[3][1]); -// -// FPlane4d row3(ZeroPlane); -// row3.X = static_cast(from[0][2]); -// row3.Y = static_cast(from[1][2]); -// row3.Z = static_cast(from[2][2]); -// row3.W = static_cast(from[3][2]); -// -// FPlane4d row4(ZeroPlane); -// row4.X = static_cast(from[0][3]); -// row4.Y = static_cast(from[1][3]); -// row4.Z = static_cast(from[2][3]); -// row4.W = static_cast(from[3][3]); -// -// return FMatrix(row1, row2, row3, row4); -// } -//}; -// -///** -// * Converts from a boolean to a double-precision floating-point mat4. -// */ -//template <> struct CesiumMetadataConversions { -// /** -// * Converts a boolean to a FMatrix. The boolean is converted to a double -// * value of 1.0 for true or 0.0 for false. The returned matrix is -// * initialized with this value along its diagonal. -// * -// * @param from The boolean to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FMatrix convert(bool from, const FMatrix& defaultValue) { -// glm::dmat4 mat4(from ? 1.0 : 0.0); -// return CesiumMetadataConversions::convert( -// mat4, -// defaultValue); -// ; -// } -//}; -// -///** -// * Converts from a scalar type to a double-precision floating-point mat4. -// */ -//template -//struct CesiumMetadataConversions< -// FMatrix, -// TFrom, -// std::enable_if_t::value>> { -// /** -// * Converts a scalar to a FMatrix. The returned vector is initialized -// * with the value along its diagonal. If the scalar is an integer, the value -// * may lose precision during conversion. -// * -// * @param from The integer value to be converted. -// * @param defaultValue The default value to be returned if conversion fails. -// */ -// static FMatrix convert(TFrom from, const FMatrix& defaultValue) { -// glm::dmat4 mat4(static_cast(from)); -// return CesiumMetadataConversions::convert( -// mat4, -// defaultValue); -// } -//}; -// -//#pragma endregion +#pragma region Conversions to boolean + +/** + * Converts from a scalar to a bool. + */ +template +struct CesiumMetadataConversions< + bool, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a scalar to a boolean. Zero is converted to false, while nonzero + * values are converted to true. + * + * @param from The scalar to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static bool convert(TFrom from, bool defaultValue) { + return from != static_cast(0); + } +}; + +/** + * Converts from std::string_view to a bool. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts the contents of a std::string_view to a boolean. + * + * "0", "false", and "no" (case-insensitive) are converted to false, while + * "1", "true", and "yes" are converted to true. All other strings will return + * the default value. + * + * @param from The std::string_view to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static bool convert(const std::string_view& from, bool defaultValue) { + FString f(from.size(), from.data()); + + if (f.Compare("1", ESearchCase::IgnoreCase) == 0 || + f.Compare("true", ESearchCase::IgnoreCase) == 0 || + f.Compare("yes", ESearchCase::IgnoreCase) == 0) { + return true; + } + + if (f.Compare("0", ESearchCase::IgnoreCase) == 0 || + f.Compare("false", ESearchCase::IgnoreCase) == 0 || + f.Compare("no", ESearchCase::IgnoreCase) == 0) { + return false; + } + + return defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to integer + +/** + * Converts from one integer type to another. + */ +template +struct CesiumMetadataConversions< + TTo, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + CesiumGltf::IsMetadataInteger::value && + !std::is_same_v>> { + /** + * Converts a value of the given integer to another integer type. If the + * integer cannot be losslessly converted to the desired type, the default + * value is returned. + * + * @param from The integer value to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static TTo convert(TFrom from, TTo defaultValue) { + return CesiumUtility::losslessNarrowOrDefault(from, defaultValue); + } +}; + +/** + * Converts from a floating-point type to an integer. + */ +template +struct CesiumMetadataConversions< + TTo, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + CesiumGltf::IsMetadataFloating::value>> { + /** + * Converts a floating-point value to an integer type. This truncates the + * floating-point value, rounding it towards zero. + * + * If the value is outside the range of the integer type, the default value is + * returned. + * + * @param from The floating-point value to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static TTo convert(TFrom from, TTo defaultValue) { + if (double(std::numeric_limits::max()) < from || + double(std::numeric_limits::lowest()) > from) { + // Floating-point number is outside the range of this integer type. + return defaultValue; + } + + return static_cast(from); + } +}; + +/** + * Converts from std::string_view to a signed integer. + */ +template +struct CesiumMetadataConversions< + TTo, + std::string_view, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { + /** + * Converts the contents of a std::string_view to a signed integer. This + * assumes that the entire std::string_view represents the number, not just a + * part of it. + * + * This returns the default value if no number is parsed from the string. + * + * @param from The std::string_view to parse from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static TTo convert(const std::string_view& from, TTo defaultValue) { + // Amazingly, C++ has no* string parsing functions that work with strings + // that might not be null-terminated. So we have to copy to a std::string + // (which _is_ guaranteed to be null terminated) before parsing. + // * except std::from_chars, but compiler/library support for the + // floating-point version of that method is spotty at best. + std::string temp(from); + + char* pLastUsed; + int64_t parsedValue = std::strtoll(temp.c_str(), &pLastUsed, 10); + if (pLastUsed == temp.c_str() + temp.size()) { + // Successfully parsed the entire string as an integer of this type. + return CesiumUtility::losslessNarrowOrDefault(parsedValue, defaultValue); + } + + // Failed to parse as an integer. Maybe we can parse as a double and + // truncate it? + double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); + if (pLastUsed == temp.c_str() + temp.size()) { + // Successfully parsed the entire string as a double. + // Convert it to an integer if we can. + double truncated = glm::trunc(parsedDouble); + + int64_t asInteger = static_cast(truncated); + double roundTrip = static_cast(asInteger); + if (roundTrip == truncated) { + return CesiumUtility::losslessNarrowOrDefault(asInteger, defaultValue); + } + } + + return defaultValue; + } +}; + +/** + * Converts from std::string_view to an unsigned integer. + */ +template +struct CesiumMetadataConversions< + TTo, + std::string_view, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { + /** + * Converts the contents of a std::string_view to an signed integer. This + * assumes that the entire std::string_view represents the number, not just a + * part of it. + * + * This returns the default value if no number is parsed from the string. + * + * @param from The std::string_view to parse from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static TTo convert(const std::string_view& from, TTo defaultValue) { + // Amazingly, C++ has no* string parsing functions that work with strings + // that might not be null-terminated. So we have to copy to a std::string + // (which _is_ guaranteed to be null terminated) before parsing. + // * except std::from_chars, but compiler/library support for the + // floating-point version of that method is spotty at best. + std::string temp(from); + + char* pLastUsed; + uint64_t parsedValue = std::strtoull(temp.c_str(), &pLastUsed, 10); + if (pLastUsed == temp.c_str() + temp.size()) { + // Successfully parsed the entire string as an integer of this type. + return CesiumUtility::losslessNarrowOrDefault(parsedValue, defaultValue); + } + + // Failed to parse as an integer. Maybe we can parse as a double and + // truncate it? + double parsedDouble = std::strtod(temp.c_str(), &pLastUsed); + if (pLastUsed == temp.c_str() + temp.size()) { + // Successfully parsed the entire string as a double. + // Convert it to an integer if we can. + double truncated = glm::trunc(parsedDouble); + + uint64_t asInteger = static_cast(truncated); + double roundTrip = static_cast(asInteger); + if (roundTrip == truncated) { + return CesiumUtility::losslessNarrowOrDefault(asInteger, defaultValue); + } + } + + return defaultValue; + } +}; + +/** + * Converts from a boolean to an integer type. + */ +template +struct CesiumMetadataConversions< + TTo, + bool, + std::enable_if_t::value>> { + /** + * Converts a boolean to an integer. This returns 1 for true, 0 for + * false. + * + * @param from The boolean value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static TTo convert(bool from, TTo defaultValue) { return from ? 1 : 0; } +}; + +#pragma endregion + +#pragma region Conversions to float + +/** + * Converts from a boolean to a float. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a float. This returns 1.0f for true, 0.0f for + * false. + * + * @param from The boolean value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static float convert(bool from, float defaultValue) { + return from ? 1.0f : 0.0f; + } +}; + +/** + * Converts from an integer type to a float. + */ +template +struct CesiumMetadataConversions< + float, + TFrom, + std::enable_if_t::value>> { + /** + * Converts an integer to a float. The value may lose precision during + * conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static float convert(TFrom from, float defaultValue) { + return static_cast(from); + } +}; + +/** + * Converts from a double to a float. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a double to a float. The value may lose precision during + * conversion. + * + * If the value is outside the range of a float, the default value is + * returned. + * + * @param from The double value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static float convert(double from, float defaultValue) { + if (from > std::numeric_limits::max() || + from < std::numeric_limits::lowest()) { + return defaultValue; + } + return static_cast(from); + } +}; + +/** + * Converts from a std::string_view to a float. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a float. This assumes that the entire + * std::string_view represents the number, not just a part of it. + * + * This returns the default value if no number is parsed from the string. + * + * @param from The std::string_view to parse from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static float convert(const std::string_view& from, float defaultValue) { + // Amazingly, C++ has no* string parsing functions that work with strings + // that might not be null-terminated. So we have to copy to a std::string + // (which _is_ guaranteed to be null terminated) before parsing. + // * except std::from_chars, but compiler/library support for the + // floating-point version of that method is spotty at best. + std::string temp(from); + + char* pLastUsed; + float parsedValue = std::strtof(temp.c_str(), &pLastUsed); + if (pLastUsed == temp.c_str() + temp.size() && !std::isinf(parsedValue)) { + // Successfully parsed the entire string as a float. + return parsedValue; + } + return defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to double + +/** + * Converts from a boolean to a double. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a double. This returns 1.0 for true, 0.0 for + * false. + * + * @param from The boolean value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static double convert(bool from, double defaultValue) { + return from ? 1.0 : 0.0; + } +}; + +/** + * Converts from any integer type to a double. + */ +template +struct CesiumMetadataConversions< + double, + TFrom, + std::enable_if_t::value>> { + /** + * Converts any integer type to a double. The value may lose precision during + * conversion. + * + * @param from The boolean value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static double convert(TFrom from, double defaultValue) { + return static_cast(from); + } +}; + +/** + * Converts from a float to a double. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts from a float to a double. + * + * @param from The float value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static double convert(float from, double defaultValue) { + return static_cast(from); + } +}; + +/** + * Converts from std::string_view to a double. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a double. This assumes that the entire + * std::string_view represents the number, not just a part of it. + * + * This returns the default value if no number is parsed from the string. + * + * @param from The std::string_view to parse from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static double convert(const std::string_view& from, double defaultValue) { + // Amazingly, C++ has no* string parsing functions that work with strings + // that might not be null-terminated. So we have to copy to a std::string + // (which _is_ guaranteed to be null terminated) before parsing. + // * except std::from_chars, but compiler/library support for the + // floating-point version of that method is spotty at best. + std::string temp(from); + + char* pLastUsed; + double parsedValue = std::strtod(temp.c_str(), &pLastUsed); + if (pLastUsed == temp.c_str() + temp.size() && !std::isinf(parsedValue)) { + // Successfully parsed the entire string as a double. + return parsedValue; + } + return defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to string + +/** + * Converts from a boolean to a string. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FString. Returns "true" for true and "false" for + * false. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FString convert(bool from, const FString& defaultValue) { + return from ? "true" : "false"; + } +}; + +/** + * Converts from a scalar to a string. + */ +template +struct CesiumMetadataConversions< + FString, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a scalar to a FString. + * + * @param from The scalar to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FString convert(TFrom from, const FString& defaultValue) { + return FString(std::to_string(from).c_str()); + } +}; + +static const std::string VectorComponents = "XYZW"; + +/** + * Converts from a glm::vecN to a string. + */ +template +struct CesiumMetadataConversions< + FString, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a glm::vecN to a FString. This follows the format that ToString() + * functions call on the Unreal vector equivalents. For example, a glm::vec3 + * will return a string in the format "X=... Y=... Z=...". + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FString convert(const TFrom& from, const FString& defaultValue) { + std::string result; + for (glm::length_t i = 0; i < from.length(); i++) { + if (i > 0) { + result += " "; + } + result += VectorComponents[i]; + result += "="; + result += std::to_string(from[i]); + } + return FString(result.c_str()); + } +}; + +/** + * Converts from a glm::matN to a string. + */ +template +struct CesiumMetadataConversions< + FString, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a glm::matN to a FString. This follows the format that ToString() + * functions call on the Unreal matrix equivalents. Each row is + * returned in square brackets, e.g. "[1 2 3 4]", with spaces in-between. + * + * @param from The glm::matN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FString convert(const TFrom& from, const FString& defaultValue) { + std::string result; + glm::length_t dimensions = from.length(); + glm::mat3 matrix; + matrix[0]; + // glm::matNs are column-major, but Unreal matrices are row-major and print + // their values by row. + for (glm::length_t r = 0; r < dimensions; r++) { + if (r > 0) { + result += " "; + } + result += "["; + for (glm::length_t c = 0; c < dimensions; c++) { + if (c > 0) { + result += " "; + } + result += std::to_string(from[c][r]); + } + result += "]"; + } + return FString(result.c_str()); + } +}; + +/** + * Converts from a std::string_view to a FString. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts from a std::string_view to a FString. + */ + static FString + convert(const std::string_view& from, const FString& defaultValue) { + return FString(UTF8_TO_TCHAR(std::string(from.data(), from.size()).data())); + } +}; + +#pragma endregion + +#pragma region Conversions to integer vec2 +/** + * Converts from a boolean to a 32-bit signed integer vec2. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FIntPoint. The boolean is converted to an integer + * value of 1 for true or 0 for false. The returned vector is initialized with + * this value in both of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint convert(bool from, const FIntPoint& defaultValue) { + int32 value = from ? 1 : 0; + return FIntPoint(value); + } +}; + +/** + * Converts from a signed integer type to a 32-bit signed integer vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + std::is_signed_v>> { + /** + * Converts a signed integer to a FIntPoint. The returned vector is + * initialized with the value in both of its components. If the integer cannot + * be losslessly converted to a 32-bit signed representation, the default + * value is returned. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { + if (from > std::numeric_limits::max() || + from < std::numeric_limits::lowest()) { + return defaultValue; + } + return FIntPoint(static_cast(from)); + } +}; + +/** + * Converts from an unsigned integer type to a 32-bit signed integer vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + !std::is_signed_v>> { + /** + * Converts an unsigned integer to a FIntPoint. The returned vector is + * initialized with the value in both of its components. If the integer cannot + * be losslessly converted to a 32-bit signed representation, the default + * value is returned. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { + if (from > static_cast(std::numeric_limits::max())) { + return defaultValue; + } + return FIntPoint(static_cast(from)); + } +}; + +/** + * Converts from a floating-point value to a 32-bit signed integer vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a floating-point value to a FIntPoint. This truncates the + * floating-point value, rounding it towards zero, and puts it in both of the + * resulting vector's components. + * + * If the value is outside the range that a 32-bit signed integer can + * represent, the default value is returned. + * + * @param from The floating-point value to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint convert(TFrom from, const FIntPoint& defaultValue) { + if (double(std::numeric_limits::max()) < from || + double(std::numeric_limits::lowest()) > from) { + // Floating-point number is outside the range. + return defaultValue; + } + return FIntPoint(static_cast(from)); + } +}; + +/** + * Converts from a glm::vecN of a signed integer type to a 32-bit signed integer + * vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + glm::vec, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { + /** + * Converts a glm::vecN of signed integers to a FIntPoint. This only uses the + * first two components of the vecN. If either of the first two values cannot + * be converted to a 32-bit signed integer, the default value is returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint + convert(const glm::vec& from, const FIntPoint& defaultValue) { + for (size_t i = 0; i < 2; i++) { + if (from[i] > std::numeric_limits::max() || + from[i] < std::numeric_limits::lowest()) { + return defaultValue; + } + } + + return FIntPoint( + static_cast(from[0]), + static_cast(from[1])); + } +}; + +/** + * Converts from a glm::vecN of an unsigned integer type to a 32-bit signed + * integer vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + glm::vec, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { + /** + * Converts a glm::vecN of unsigned integers to a FIntPoint. This only uses + * the first two components of the vecN. If either of the first two values + * cannot be converted to a 32-bit signed integer, the default value is + * returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint + convert(const glm::vec& from, const FIntPoint& defaultValue) { + for (size_t i = 0; i < 2; i++) { + if (from[i] > + static_cast(std::numeric_limits::max())) { + return defaultValue; + } + } + + return FIntPoint( + static_cast(from[0]), + static_cast(from[1])); + } +}; + +/** + * Converts from a glm::vecN of a floating-point type to a 32-bit signed + * integer vec2. + */ +template +struct CesiumMetadataConversions< + FIntPoint, + glm::vec, + std::enable_if_t::value>> { + /** + * Converts a glm::vecN of floating-point numbers to a FIntPoint. This only + * uses the first two components of the vecN. If either of the first two + * values cannot be converted to a 32-bit signed integer, the default value is + * returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint + convert(const glm::vec& from, const FIntPoint& defaultValue) { + for (size_t i = 0; i < 2; i++) { + if (from[i] > double(std::numeric_limits::max()) || + from[i] < double(std::numeric_limits::lowest())) { + return defaultValue; + } + } + + return FIntPoint( + static_cast(from[0]), + static_cast(from[1])); + } +}; + +/** + * Converts from a std::string_view to a 32-bit signed integer vec2. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FIntPoint. This expects the values to be + * written in the "X=... Y=..." format. If this function fails to parse + * a FIntPoint, the default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntPoint + convert(const std::string_view& from, const FIntPoint& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + + // For some reason, FIntPoint doesn't have an InitFromString method, so + // copy the one from FVector. + int32 X = 0, Y = 0; + const bool bSuccessful = FParse::Value(*string, TEXT("X="), X) && + FParse::Value(*string, TEXT("Y="), Y); + return bSuccessful ? FIntPoint(X, Y) : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to double vec2 +/** + * Converts from a boolean to a double-precision floating-point vec2. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FVector2D. The boolean is converted to a double + * value of 1.0 for true or 0.0 for false. The returned vector is + initialized + * with this value in both of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector2D convert(bool from, const FVector2D& defaultValue) { + double value = from ? 1.0 : 0.0; + return FVector2D(value); + } +}; + +/** + * Converts from an integer type to a double-precision floating-point vec2. + */ +template +struct CesiumMetadataConversions< + FVector2D, + TFrom, + std::enable_if_t::value>> { + /** + * Converts an integer to a FVector2D. The returned vector is initialized + * with the value in both of its components. The value may lose precision + * during conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector2D convert(TFrom from, const FVector2D& defaultValue) { + return FVector2D(static_cast(from)); + } +}; + +/** + * Converts from a floating-point value to a double-precision floating-point + * vec2. + */ +template +struct CesiumMetadataConversions< + FVector2D, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a floating-point value to a FVector2D. The returned vector is + * initialized with the value in all of its components. + * + * @param from The floating-point value to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector2D convert(TFrom from, const FVector2D& defaultValue) { + return FVector2D(static_cast(from)); + } +}; + +/** + * Converts from a glm::vecN of any type to a double-precision floating-point + * vec2. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vecN of any type to a FVector2D. This only uses the first + * two components of the vecN. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector2D + convert(const glm::vec& from, const FVector2D& defaultValue) { + return FVector2D( + static_cast(from[0]), + static_cast(from[1])); + } +}; + +/** + * Converts from a std::string_view to a double-precision floating-point + * vec2. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FVector2D. This uses + * FVector2D::InitFromString, which expects the values to be written in the + * "X=... Y=..." format. If this function fails to parse a FVector2D, the + * default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector2D + convert(const std::string_view& from, const FVector2D& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + + FVector2D result; + return result.InitFromString(string) ? result : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to integer vec3 + +/** + * Converts from a boolean to a 32-bit signed integer vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FIntVector. The boolean is converted to an integer + * value of 1 for true or 0 for false. The returned vector is initialized with + * this value in all of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector convert(bool from, const FIntVector& defaultValue) { + int32 value = from ? 1 : 0; + return FIntVector(value); + } +}; + +/** + * Converts from a signed integer to a 32-bit signed integer vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + std::is_signed_v>> { + /** + * Converts a signed integer to a FIntVector. The returned vector is + * initialized with the value in all of its components. If the integer + * cannot be losslessly converted to a 32-bit signed representation, the + * default value is returned. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector convert(TFrom from, const FIntVector& defaultValue) { + if (from > std::numeric_limits::max() || + from < std::numeric_limits::lowest()) { + return defaultValue; + } + return FIntVector(static_cast(from)); + } +}; + +/** + * Converts from an unsigned integer to a 32-bit signed integer vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + TFrom, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && + !std::is_signed_v>> { + /** + * Converts an unsigned integer to a FIntVector. The returned vector is + * initialized with the value in all of its components. If the integer + * cannot be losslessly converted to a 32-bit signed representation, the + * default value is returned. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector convert(TFrom from, const FIntVector& defaultValue) { + if (from > static_cast(std::numeric_limits::max())) { + return defaultValue; + } + return FIntVector(static_cast(from)); + } +}; + +/** + * Converts from a floating-point value to a 32-bit signed integer vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a floating-point value to a FIntVector. This truncates the + * floating-point value, rounding it towards zero, and puts it in all of the + * resulting vector's components. + * + * If the value is outside the range that a 32-bit signed integer can + * represent, the default value is returned. + * + * @param from The floating-point value to convert from. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector convert(TFrom from, const FIntVector& defaultValue) { + if (double(std::numeric_limits::max()) < from || + double(std::numeric_limits::lowest()) > from) { + // Floating-point number is outside the range. + return defaultValue; + } + return FIntVector(static_cast(from)); + } +}; + +/** + * Converts from a glm::vecN of signed integers to a 32-bit signed integer vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + glm::vec, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && std::is_signed_v>> { + /** + * Converts a glm::vecN of signed integers to a FIntVector. + * + * If converting from a vec2, the vec2 becomes the first two components of + * the FIntVector, while the third component is set to zero. + * + * If converting from a vec4, only the first three components of the vec4 are + * used, and the fourth is dropped. + * + * If any of the relevant components cannot be converted to 32-bit signed + * integers, the default value is returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector + convert(const glm::vec& from, const FIntVector& defaultValue) { + glm::length_t count = glm::min(N, static_cast(3)); + for (size_t i = 0; i < count; i++) { + if (from[i] > std::numeric_limits::max() || + from[i] < std::numeric_limits::lowest()) { + return defaultValue; + } + } + + if constexpr (N == 2) { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + 0); + } else { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } + } +}; + +/** + * Converts from a glm::vecN of unsigned integers to a 32-bit signed integer + * vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + glm::vec, + std::enable_if_t< + CesiumGltf::IsMetadataInteger::value && !std::is_signed_v>> { + /** + * Converts a glm::vecN of unsigned integers to a FIntVector. + * + * If converting from a vec2, the vec2 becomes the first two components of + * the FIntVector, while the third component is set to zero. + * + * If converting from a vec4, only the first three components of the vec4 are + * used, and the fourth is dropped. + * + * If any of the relevant components cannot be converted to 32-bit signed + * integers, the default value is returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector + convert(const glm::vec& from, const FIntVector& defaultValue) { + glm::length_t count = glm::min(N, static_cast(3)); + for (size_t i = 0; i < count; i++) { + if (from[i] > + static_cast(std::numeric_limits::max())) { + return defaultValue; + } + } + + if constexpr (N == 2) { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + 0); + } else { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } + } +}; + +/** + * Converts from a glm::vecN of floating-point numbers to a 32-bit signed + * integer vec3. + */ +template +struct CesiumMetadataConversions< + FIntVector, + glm::vec, + std::enable_if_t::value>> { + /** + * Converts a glm::vecN of floating-point numbers to a FIntVector. + * + * If converting from a vec2, the vec2 becomes the first two components of + * the FIntVector, while the third component is set to zero. + * + * If converting from a vec4, only the first three components of the vec4 are + * used, and the fourth is dropped. + * + * If any of the relevant components cannot be converted to 32-bit signed + * integers, the default value is returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector + convert(const glm::vec& from, const FIntVector& defaultValue) { + glm::length_t count = glm::min(N, static_cast(3)); + for (size_t i = 0; i < 3; i++) { + if (from[i] > double(std::numeric_limits::max()) || + from[i] < double(std::numeric_limits::lowest())) { + return defaultValue; + } + } + + if constexpr (N == 2) { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + 0); + } else { + return FIntVector( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } + } +}; + +/** + * Converts from a std::string_view to a 32-bit signed integer vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FIntVector. This expects the values to be + * written in the "X=... Y=... Z=..." format. If this function fails to parse + * a FIntVector, the default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FIntVector + convert(const std::string_view& from, const FIntVector& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + + // For some reason, FIntVector doesn't have an InitFromString method, so + // copy the one from FVector. + int32 X = 0, Y = 0, Z = 0; + const bool bSuccessful = FParse::Value(*string, TEXT("X="), X) && + FParse::Value(*string, TEXT("Y="), Y) && + FParse::Value(*string, TEXT("Z="), Z); + return bSuccessful ? FIntVector(X, Y, Z) : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to float vec3 +/** + * Converts from a boolean to a single-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FVector3f. The boolean is converted to a float + * value of 1.0f for true or 0.0f for false. The returned vector is + * initialized with this value in all of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f convert(bool from, const FVector3f& defaultValue) { + float value = from ? 1.0f : 0.0f; + return FVector3f(value); + } +}; + +/** + * Converts from an integer type to a single-precision floating-point vec3. + */ +template +struct CesiumMetadataConversions< + FVector3f, + TFrom, + std::enable_if_t::value>> { + /** + * Converts an integer to a FVector3f. The returned vector is initialized with + * the value in all of its components. The value may lose precision during + * conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f convert(TFrom from, const FVector3f& defaultValue) { + return FVector3f(static_cast(from)); + } +}; + +/** + * Converts from a float to a single-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a float to a FVector3f. The returned vector is initialized with + * the value in all of its components. + * + * @param from The float to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f convert(float from, const FVector3f& defaultValue) { + return FVector3f(from); + } +}; + +/** + * Converts from a double to a single-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a double to a FVector3f. This attempts to convert the double to a + * float, then initialize a vector with the value in all of its components. If + * the double cannot be converted, the default value is returned. + * + * @param from The double to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f convert(double from, const FVector3f& defaultValue) { + if (from > double(std::numeric_limits::max()) || + from < double(std::numeric_limits::lowest())) { + return defaultValue; + } + return FVector3f(static_cast(from)); + } +}; + +/** + * Converts from a glm::vec2 of any type to a single-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec2 of any type to a FVector3f. Similar to how an + * FVector3f can be constructed from an FIntPoint, the vec2 becomes the first + * two components of the FVector3f, while the third component is set to zero. + * If the vec2 is of an integer type, its values may lose precision during + * conversion. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f + convert(const glm::vec<2, T>& from, const FVector3f& defaultValue) { + if constexpr (std::is_same_v) { + // Check if all double values can be converted to floats. + for (size_t i = 0; i < 2; i++) { + if (from[i] > double(std::numeric_limits::max()) || + from[i] < double(std::numeric_limits::lowest())) { + return defaultValue; + } + } + } + + return FVector3f( + static_cast(from[0]), + static_cast(from[1]), + 0.0f); + } +}; + +/** + * Converts from a glm::vec3 of any type to a single-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec3 of any type to a FVector3f. If any of the original + * vec3 values cannot be converted to a float, the default value is + * returned. + * + * @param from The glm::vecN to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f + convert(const glm::vec<3, T>& from, const FVector3f& defaultValue) { + if constexpr (std::is_same_v) { + // Check if all double values can be converted to floats. + for (size_t i = 0; i < 3; i++) { + if (from[i] > double(std::numeric_limits::max()) || + from[i] < double(std::numeric_limits::lowest())) { + return defaultValue; + } + } + } + + return FVector3f( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } +}; + +/** + * Converts from a glm::vec4 of any type to a single-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec4 of any type to a FVector3f. If any of the first three + * values cannot be converted to a float, the default value is returned. + * + * @param from The glm::vec4 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f + convert(const glm::vec<4, T>& from, const FVector3f& defaultValue) { + if constexpr (std::is_same_v) { + // Check if all double values can be converted to floats. + for (size_t i = 0; i < 3; i++) { + if (from[i] > std::numeric_limits::max() || + from[i] < std::numeric_limits::lowest()) { + return defaultValue; + } + } + } + return FVector3f( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } +}; + +/** + * Converts from a std::string_view to a single-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FVector3f. This uses + * FVector3f::InitFromString, which expects the values to be written in the + * "X=... Y=... Z=..." format. If this function fails to parse a FVector3f, + * the default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector3f + convert(const std::string_view& from, const FVector3f& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + FVector3f result; + return result.InitFromString(string) ? result : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to double vec3 +/** + * Converts from a boolean to a double-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FVector. The boolean is converted to a float + * value of 1.0 for true or 0.0 for false. The returned vector is + * initialized with this value in all of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector convert(bool from, const FVector& defaultValue) { + float value = from ? 1.0 : 0.0; + return FVector(value); + } +}; + +/** + * Converts from an integer type to a double-precision floating-point vec3. + */ +template +struct CesiumMetadataConversions< + FVector, + TFrom, + std::enable_if_t::value>> { + /** + * Converts an integer to a FVector. The returned vector is initialized with + * the value in all of its components. The value may lose precision during + * conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector convert(TFrom from, const FVector& defaultValue) { + return FVector(static_cast(from)); + } +}; + +/** + * Converts from a float to a double-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a float to a FVector. The returned vector is initialized with + * the value in all of its components. + * + * @param from The float to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector convert(float from, const FVector& defaultValue) { + return FVector(static_cast(from)); + } +}; + +/** + * Converts from a double to a single-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a double to a FVector. The returned vector is initialized with + * the value in all of its components. + * + * @param from The double to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector convert(double from, const FVector& defaultValue) { + return FVector(from); + } +}; + +/** + * Converts from a glm::vec2 of any type to a double-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec2 of any type to a FVector. Similar to how an + * FVector can be constructed from an FIntPoint, the vec2 becomes the first + * two components of the FVector, while the third component is set to zero. + * If the vec2 is of an integer type, its values may lose precision during + * conversion. + * + * @param from The glm::vec2 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector + convert(const glm::vec<2, T>& from, const FVector& defaultValue) { + return FVector( + static_cast(from[0]), + static_cast(from[1]), + 0.0); + } +}; + +/** + * Converts from a glm::vec3 of any type to a double-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec3 of any type to a FVector. If the vec3 is of an integer + * type, its values may lose precision during conversion. + * + * @param from The glm::vec3 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector + convert(const glm::vec<3, T>& from, const FVector& defaultValue) { + return FVector( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } +}; + +/** + * Converts from a glm::vec4 of any type to a double-precision floating-point + * vec3. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec4 of any type to a FVector. This only uses the first + * three components of the vec4, dropping the fourth. If the vec3 is of an + * integer type, its values may lose precision during conversion. + * + * @param from The glm::vec4 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector + convert(const glm::vec<4, T>& from, const FVector& defaultValue) { + return FVector( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2])); + } +}; + +/** + * Converts from a std::string_view to a double-precision floating-point vec3. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FVector. This uses + * FVector::InitFromString, which expects the values to be written in the + * "X=... Y=... Z=..." format. If this function fails to parse a FVector, + * the default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector + convert(const std::string_view& from, const FVector& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + FVector result; + return result.InitFromString(string) ? result : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to double vec4 + +/** + * Converts from a boolean to a double-precision floating-point vec4. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FVector4. The boolean is converted to a double + * value of 1.0 for true or 0.0 for false. The returned vector is + * initialized with this value in all of its components. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 convert(bool from, const FVector4& defaultValue) { + double value = from ? 1.0 : 0.0; + return FVector4(value, value, value, value); + } +}; + +/** + * Converts from an integer type to a double-precision floating-point vec4. + */ +template +struct CesiumMetadataConversions< + FVector4, + TFrom, + std::enable_if_t::value>> { + /** + * Converts an integer to a FVector4. The returned vector is initialized with + * the value in all of its components. The value may lose precision during + * conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 convert(TFrom from, const FVector4& defaultValue) { + double value = static_cast(from); + return FVector4(from, from, from, from); + } +}; + +/** + * Converts from a float to a double-precision floating-point vec4. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a float to a FVector4. The returned vector is initialized with + * the value in all of its components. + * + * @param from The float to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 convert(float from, const FVector& defaultValue) { + double value = static_cast(from); + return FVector4(from, from, from, from); + } +}; + +/** + * Converts from a double to a double-precision floating-point vec4. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a double to a FVector4. The returned vector is initialized with + * the value in all of its components. + * + * @param from The double to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 convert(double from, const FVector4& defaultValue) { + return FVector4(from, from, from, from); + } +}; + +/** + * Converts from a glm::vec2 of any type to a double-precision floating-point + * vec4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec2 of any type to a FVector4. The vec2 becomes the first + * two components of the FVector4, while the third and fourth components are + * set to zero. + * + * If the vec2 is of an integer type, its values may lose + * precision during conversion. + * + * @param from The glm::vec2 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 + convert(const glm::vec<2, T>& from, const FVector4& defaultValue) { + return FVector4( + static_cast(from[0]), + static_cast(from[1]), + 0.0, + 0.0); + } +}; + +/** + * Converts from a glm::vec3 of any type to a double-precision floating-point + * vec4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec3 of any type to a FVector4. The vec3 becomes the first + * three components of the FVector4, while the fourth component is set to + * zero. + * + * If the vec3 is of an integer type, its values may lose precision during + * conversion. + * + * @param from The glm::vec3 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 + convert(const glm::vec<3, T>& from, const FVector4& defaultValue) { + return FVector4( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2]), + 0.0); + } +}; + +/** + * Converts from a glm::vec4 of any type to a double-precision floating-point + * vec4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::vec4 of any type to a FVector4. If the vec4 is of an + * integer type, its values may lose precision during conversion. + * + * @param from The glm::vec4 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 + convert(const glm::vec<4, T>& from, const FVector4& defaultValue) { + return FVector4( + static_cast(from[0]), + static_cast(from[1]), + static_cast(from[2]), + static_cast(from[3])); + } +}; + +/** + * Converts from a std::string_view to a double-precision floating-point vec4. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a std::string_view to a FVector4. This uses + * FVector4::InitFromString, which expects the values to be written in the + * "X=... Y=... Z=..." format. It allows the "W=..." component is optional; if + * left out, the fourth component will be initialized as 1.0. + * + * If this function fails to parse a FVector, the default value is returned. + * + * @param from The std::string_view to be parsed. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FVector4 + convert(const std::string_view& from, const FVector4& defaultValue) { + FString string = + CesiumMetadataConversions::convert( + from, + FString("")); + FVector4 result; + return result.InitFromString(string) ? result : defaultValue; + } +}; + +#pragma endregion + +#pragma region Conversions to double mat4 + +static const FPlane4d ZeroPlane(0.0, 0.0, 0.0, 0.0); + +/** + * Converts from a glm::mat2 to a double-precision floating-point mat4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::mat2 of any type to a FMatrix. The mat2 is used to + * initialize the values of the FMatrix at the corresponding indices. + * The rest of the components are all set to zero. + * + * If the mat2 is of an integer type, its values may lose precision during + * conversion. + * + * @param from The mat2 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FMatrix + convert(const glm::mat<2, 2, T>& from, const FMatrix& defaultValue) { + // glm is column major, but Unreal is row major. + FPlane4d row1(ZeroPlane); + row1.X = static_cast(from[0][0]); + row1.Y = static_cast(from[1][0]); + + FPlane4d row2(ZeroPlane); + row2.X = static_cast(from[0][1]); + row2.Y = static_cast(from[1][1]); + + return FMatrix(row1, row2, ZeroPlane, ZeroPlane); + } +}; + +/** + * Converts from a glm::mat3 to a double-precision floating-point mat4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::mat3 of any type to a FMatrix. The mat3 is used to + * initialize the values of the FMatrix at the corresponding indices. + * The rest of the components are all set to zero. + * + * If the mat3 is of an integer type, its values may lose precision during + * conversion. + * + * @param from The mat3 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FMatrix + convert(const glm::mat<3, 3, T>& from, const FMatrix& defaultValue) { + // glm is column major, but Unreal is row major. + FPlane4d row1(ZeroPlane); + row1.X = static_cast(from[0][0]); + row1.Y = static_cast(from[1][0]); + row1.Z = static_cast(from[2][0]); + + FPlane4d row2(ZeroPlane); + row2.X = static_cast(from[0][1]); + row2.Y = static_cast(from[1][1]); + row2.Z = static_cast(from[2][1]); + + FPlane4d row3(ZeroPlane); + row3.X = static_cast(from[0][2]); + row3.Y = static_cast(from[1][2]); + row3.Z = static_cast(from[2][2]); + + return FMatrix(row1, row2, row3, ZeroPlane); + } +}; + +/** + * Converts from a glm::mat4 to a double-precision floating-point mat4. + */ +template +struct CesiumMetadataConversions> { + /** + * Converts a glm::mat4 of any type to a FMatrix. If the mat4 is of an integer + * type, its values may lose precision during conversion. + * + * @param from The mat4 to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FMatrix + convert(const glm::mat<4, 4, T>& from, const FMatrix& defaultValue) { + // glm is column major, but Unreal is row major. + FPlane4d row1( + static_cast(from[0][0]), + static_cast(from[1][0]), + static_cast(from[2][0]), + static_cast(from[3][0])); + + FPlane4d row2(ZeroPlane); + row2.X = static_cast(from[0][1]); + row2.Y = static_cast(from[1][1]); + row2.Z = static_cast(from[2][1]); + row2.W = static_cast(from[3][1]); + + FPlane4d row3(ZeroPlane); + row3.X = static_cast(from[0][2]); + row3.Y = static_cast(from[1][2]); + row3.Z = static_cast(from[2][2]); + row3.W = static_cast(from[3][2]); + + FPlane4d row4(ZeroPlane); + row4.X = static_cast(from[0][3]); + row4.Y = static_cast(from[1][3]); + row4.Z = static_cast(from[2][3]); + row4.W = static_cast(from[3][3]); + + return FMatrix(row1, row2, row3, row4); + } +}; + +/** + * Converts from a boolean to a double-precision floating-point mat4. + */ +template <> struct CesiumMetadataConversions { + /** + * Converts a boolean to a FMatrix. The boolean is converted to a double + * value of 1.0 for true or 0.0 for false. The returned matrix is + * initialized with this value along its diagonal. + * + * @param from The boolean to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FMatrix convert(bool from, const FMatrix& defaultValue) { + glm::dmat4 mat4(from ? 1.0 : 0.0); + return CesiumMetadataConversions::convert( + mat4, + defaultValue); + ; + } +}; + +/** + * Converts from a scalar type to a double-precision floating-point mat4. + */ +template +struct CesiumMetadataConversions< + FMatrix, + TFrom, + std::enable_if_t::value>> { + /** + * Converts a scalar to a FMatrix. The returned vector is initialized + * with the value along its diagonal. If the scalar is an integer, the value + * may lose precision during conversion. + * + * @param from The integer value to be converted. + * @param defaultValue The default value to be returned if conversion fails. + */ + static FMatrix convert(TFrom from, const FMatrix& defaultValue) { + glm::dmat4 mat4(static_cast(from)); + return CesiumMetadataConversions::convert( + mat4, + defaultValue); + } +}; + +#pragma endregion diff --git a/Source/CesiumRuntime/Public/CesiumMetadataValue.h b/Source/CesiumRuntime/Public/CesiumMetadataValue.h index 9105fbbde..d79c0f57e 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataValue.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataValue.h @@ -218,6 +218,12 @@ struct CESIUMRUNTIME_API FCesiumMetadataValue { _valueType = TypeToMetadataValueType(); } + FCesiumMetadataValue& operator=(const FCesiumMetadataValue& rhs) noexcept; + FCesiumMetadataValue& operator=(FCesiumMetadataValue&& rhs) noexcept; + FCesiumMetadataValue(const FCesiumMetadataValue& rhs) noexcept; + FCesiumMetadataValue(FCesiumMetadataValue&& rhs) noexcept; + ~FCesiumMetadataValue() noexcept; + private: ValueType _value; FCesiumMetadataValueType _valueType; diff --git a/extern/cesium-native b/extern/cesium-native index 0a296cf04..ce990d0ea 160000 --- a/extern/cesium-native +++ b/extern/cesium-native @@ -1 +1 @@ -Subproject commit 0a296cf044f77a7cb78a271578dbcb841460f1b6 +Subproject commit ce990d0ea5e755cb5a83d065bee6d4698b5775e6