3#include <CesiumGltf/PropertyTypeTraits.h>
4#include <CesiumUtility/JsonValue.h>
6#include <glm/common.hpp>
7#include <glm/gtx/string_cast.hpp>
20template <
typename TTo,
typename TFrom,
typename Enable =
void>
26 static std::optional<TTo>
convert(TFrom ) {
return std::nullopt; }
37 static std::optional<T>
convert(T from) {
return from; }
40#pragma region Conversions to boolean
44template <
typename TFrom>
48 std::enable_if_t<CesiumGltf::IsMetadataScalar<TFrom>::value>> {
55 static std::optional<bool>
convert(TFrom from) {
56 return from !=
static_cast<TFrom
>(0);
66 isEqualCaseInsensitive(
const std::string_view& a,
const std::string_view& b) {
67 if (a.size() != b.size()) {
71 for (
size_t i = 0; i < a.size(); i++) {
72 if (std::tolower(a[i]) != std::tolower(b[i])) {
89 static std::optional<bool>
convert(
const std::string_view& from) {
90 if (isEqualCaseInsensitive(from,
"1") ||
91 isEqualCaseInsensitive(from,
"true") ||
92 isEqualCaseInsensitive(from,
"yes")) {
96 if (isEqualCaseInsensitive(from,
"0") ||
97 isEqualCaseInsensitive(from,
"false") ||
98 isEqualCaseInsensitive(from,
"no")) {
120 static std::optional<bool>
convert(
const std::string& from) {
122 std::string_view(from.data(), from.size()));
128#pragma region Conversions to integer
132template <
typename TTo,
typename TFrom>
137 CesiumGltf::IsMetadataInteger<TTo>::value &&
138 CesiumGltf::IsMetadataInteger<TFrom>::value &&
139 !std::is_same_v<TTo, TFrom>>> {
147 static std::optional<TTo>
convert(TFrom from) {
155template <
typename TTo,
typename TFrom>
160 CesiumGltf::IsMetadataInteger<TTo>::value &&
161 CesiumGltf::IsMetadataFloating<TFrom>::value>> {
171 static std::optional<TTo>
convert(TFrom from) {
172 if (
double(std::numeric_limits<TTo>::max()) < from ||
173 double(std::numeric_limits<TTo>::lowest()) > from) {
178 return static_cast<TTo
>(from);
185template <
typename TTo>
190 CesiumGltf::IsMetadataInteger<TTo>::value && std::is_signed_v<TTo>>> {
200 static std::optional<TTo>
convert(
const std::string& from) {
201 if (from.size() == 0) {
210 int64_t parsedValue = std::strtoll(from.c_str(), &pLastUsed, 10);
211 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
220 double parsedDouble = std::strtod(from.c_str(), &pLastUsed);
221 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
224 double truncated = glm::trunc(parsedDouble);
226 int64_t asInteger =
static_cast<int64_t
>(truncated);
227 double roundTrip =
static_cast<double>(asInteger);
228 if (roundTrip == truncated) {
240template <
typename TTo>
245 CesiumGltf::IsMetadataInteger<TTo>::value && !std::is_signed_v<TTo>>> {
255 static std::optional<TTo>
convert(
const std::string& from) {
256 if (from.size() == 0) {
262 if (from.find(
'-') != std::string::npos) {
272 uint64_t parsedValue = std::strtoull(from.c_str(), &pLastUsed, 10);
273 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
282 double parsedDouble = std::strtod(from.c_str(), &pLastUsed);
283 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
286 double truncated = glm::trunc(parsedDouble);
288 uint64_t asInteger =
static_cast<uint64_t
>(truncated);
289 double roundTrip =
static_cast<double>(asInteger);
290 if (roundTrip == truncated) {
302template <
typename TTo>
306 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
316 static std::optional<TTo>
convert(
const std::string_view& from) {
317 if (from.size() == 0) {
335template <
typename TTo>
339 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
346 static std::optional<TTo>
convert(
bool from) {
return from ? 1 : 0; }
350#pragma region Conversions to float
361 static std::optional<float>
convert(
bool from) {
return from ? 1.0f : 0.0f; }
367template <
typename TFrom>
371 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
378 static std::optional<float>
convert(TFrom from) {
379 return static_cast<float>(from);
395 static std::optional<float>
convert(
double from) {
396 if (from > std::numeric_limits<float>::max() ||
397 from < std::numeric_limits<float>::lowest()) {
400 return static_cast<float>(from);
416 static std::optional<float>
convert(
const std::string& from) {
417 if (from.size() == 0) {
426 float parsedValue = std::strtof(from.c_str(), &pLastUsed);
427 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
428 !std::isinf(parsedValue)) {
448 static std::optional<float>
convert(
const std::string_view& from) {
449 if (from.size() == 0) {
460 std::string(from.data(), from.size()));
465#pragma region Conversions to double
476 static std::optional<double>
convert(
bool from) {
return from ? 1.0 : 0.0; }
482template <
typename TFrom>
486 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
493 static std::optional<double>
convert(TFrom from) {
494 return static_cast<double>(from);
507 static std::optional<double>
convert(
float from) {
508 return static_cast<double>(from);
524 static std::optional<double>
convert(
const std::string& from) {
525 if (from.size() == 0) {
534 double parsedValue = std::strtod(from.c_str(), &pLastUsed);
535 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
536 !std::isinf(parsedValue)) {
556 static std::optional<double>
convert(
const std::string_view& from) {
557 if (from.size() == 0) {
573#pragma region Conversions to string
584 static std::optional<std::string>
convert(
bool from) {
585 return from ?
"true" :
"false";
592template <
typename TFrom>
596 std::enable_if_t<IsMetadataScalar<TFrom>::value>> {
602 static std::optional<std::string>
convert(TFrom from) {
603 return std::to_string(from);
610template <
typename TFrom>
615 IsMetadataVecN<TFrom>::value || IsMetadataMatN<TFrom>::value>> {
622 static std::optional<std::string>
convert(
const TFrom& from) {
623 return glm::to_string(from);
634 static std::optional<std::string>
convert(
const std::string_view& from) {
635 return std::string(from.data(), from.size());
641#pragma region Conversions to glm::vecN
645template <
typename TTo>
649 std::enable_if_t<IsMetadataVecN<TTo>::value>> {
657 static std::optional<TTo>
convert(
bool from) {
658 return from ? TTo(1) : TTo(0);
665template <
typename TTo,
typename TFrom>
670 CesiumGltf::IsMetadataVecN<TTo>::value &&
671 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
683 static std::optional<TTo>
convert(TFrom from) {
684 using ToValueType =
typename TTo::value_type;
686 std::optional<ToValueType> maybeValue =
689 ToValueType value = *maybeValue;
700template <
typename TTo,
typename TFrom>
705 CesiumGltf::IsMetadataVecN<TTo>::value &&
706 CesiumGltf::IsMetadataVecN<TFrom>::value &&
707 !std::is_same_v<TTo, TFrom>>> {
721 static std::optional<TTo>
convert(TFrom from) {
724 constexpr glm::length_t validLength =
725 glm::min(TTo::length(), TFrom::length());
727 using ToValueType =
typename TTo::value_type;
728 using FromValueType =
typename TFrom::value_type;
730 for (glm::length_t i = 0; i < validLength; i++) {
737 result[i] = *maybeValue;
745#pragma region Conversions to glm::matN
749template <
typename TTo>
753 std::enable_if_t<IsMetadataMatN<TTo>::value>> {
761 static std::optional<TTo>
convert(
bool from) {
762 return from ? TTo(1) : TTo(0);
769template <
typename TTo,
typename TFrom>
774 CesiumGltf::IsMetadataMatN<TTo>::value &&
775 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
787 static std::optional<TTo>
convert(TFrom from) {
788 using ToValueType =
typename TTo::value_type;
790 std::optional<ToValueType> maybeValue =
796 ToValueType value = *maybeValue;
804template <
typename TTo,
typename TFrom>
809 CesiumGltf::IsMetadataMatN<TTo>::value &&
810 CesiumGltf::IsMetadataMatN<TFrom>::value &&
811 !std::is_same_v<TTo, TFrom>>> {
825 static std::optional<TTo>
convert(TFrom from) {
828 constexpr glm::length_t validLength =
829 glm::min(TTo::length(), TFrom::length());
831 using ToValueType =
typename TTo::value_type;
832 using FromValueType =
typename TFrom::value_type;
834 for (glm::length_t c = 0; c < validLength; c++) {
835 for (glm::length_t r = 0; r < validLength; r++) {
843 result[c][r] = *maybeValue;
Classes for working with glTF models.
std::optional< TTo > losslessNarrow(TFrom from) noexcept
Attempts a narrowing conversion of TFrom into TTo without losing information. If a lossless conversio...