3#include "PropertyTypeTraits.h"
5#include <CesiumUtility/JsonValue.h>
7#include <glm/common.hpp>
15#ifndef GLM_ENABLE_EXPERIMENTAL
18#define GLM_ENABLE_EXPERIMENTAL
19#define GLM_ENABLE_EXPERIMENTAL_defined_locally
21#include <glm/gtx/string_cast.hpp>
28template <
typename TTo,
typename TFrom,
typename Enable =
void>
34 static std::optional<TTo>
convert(TFrom ) {
return std::nullopt; }
45 static std::optional<T>
convert(T from) {
return from; }
48#pragma region Conversions to boolean
52template <
typename TFrom>
56 std::enable_if_t<CesiumGltf::IsMetadataScalar<TFrom>::value>> {
63 static std::optional<bool>
convert(TFrom from) {
64 return from !=
static_cast<TFrom
>(0);
74 isEqualCaseInsensitive(
const std::string_view& a,
const std::string_view& b) {
75 if (a.size() != b.size()) {
79 for (
size_t i = 0; i < a.size(); i++) {
80 if (std::tolower(a[i]) != std::tolower(b[i])) {
97 static std::optional<bool>
convert(
const std::string_view& from) {
98 if (isEqualCaseInsensitive(from,
"1") ||
99 isEqualCaseInsensitive(from,
"true") ||
100 isEqualCaseInsensitive(from,
"yes")) {
104 if (isEqualCaseInsensitive(from,
"0") ||
105 isEqualCaseInsensitive(from,
"false") ||
106 isEqualCaseInsensitive(from,
"no")) {
128 static std::optional<bool>
convert(
const std::string& from) {
130 std::string_view(from.data(), from.size()));
136#pragma region Conversions to integer
140template <
typename TTo,
typename TFrom>
145 CesiumGltf::IsMetadataInteger<TTo>::value &&
146 CesiumGltf::IsMetadataInteger<TFrom>::value &&
147 !std::is_same_v<TTo, TFrom>>> {
155 static std::optional<TTo>
convert(TFrom from) {
163template <
typename TTo,
typename TFrom>
168 CesiumGltf::IsMetadataInteger<TTo>::value &&
169 CesiumGltf::IsMetadataFloating<TFrom>::value>> {
179 static std::optional<TTo>
convert(TFrom from) {
180 if (
double(std::numeric_limits<TTo>::max()) < from ||
181 double(std::numeric_limits<TTo>::lowest()) > from) {
186 return static_cast<TTo
>(from);
193template <
typename TTo>
198 CesiumGltf::IsMetadataInteger<TTo>::value && std::is_signed_v<TTo>>> {
208 static std::optional<TTo>
convert(
const std::string& from) {
209 if (from.size() == 0) {
218 int64_t parsedValue = std::strtoll(from.c_str(), &pLastUsed, 10);
219 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
228 double parsedDouble = std::strtod(from.c_str(), &pLastUsed);
229 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
232 double truncated = glm::trunc(parsedDouble);
234 int64_t asInteger =
static_cast<int64_t
>(truncated);
235 double roundTrip =
static_cast<double>(asInteger);
236 if (roundTrip == truncated) {
248template <
typename TTo>
253 CesiumGltf::IsMetadataInteger<TTo>::value && !std::is_signed_v<TTo>>> {
263 static std::optional<TTo>
convert(
const std::string& from) {
264 if (from.size() == 0) {
270 if (from.find(
'-') != std::string::npos) {
280 uint64_t parsedValue = std::strtoull(from.c_str(), &pLastUsed, 10);
281 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
290 double parsedDouble = std::strtod(from.c_str(), &pLastUsed);
291 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
294 double truncated = glm::trunc(parsedDouble);
296 uint64_t asInteger =
static_cast<uint64_t
>(truncated);
297 double roundTrip =
static_cast<double>(asInteger);
298 if (roundTrip == truncated) {
310template <
typename TTo>
314 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
324 static std::optional<TTo>
convert(
const std::string_view& from) {
325 if (from.size() == 0) {
343template <
typename TTo>
347 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
354 static std::optional<TTo>
convert(
bool from) {
return from ? 1 : 0; }
358#pragma region Conversions to float
369 static std::optional<float>
convert(
bool from) {
return from ? 1.0f : 0.0f; }
375template <
typename TFrom>
379 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
386 static std::optional<float>
convert(TFrom from) {
387 return static_cast<float>(from);
403 static std::optional<float>
convert(
double from) {
404 if (from > std::numeric_limits<float>::max() ||
405 from < std::numeric_limits<float>::lowest()) {
408 return static_cast<float>(from);
424 static std::optional<float>
convert(
const std::string& from) {
425 if (from.size() == 0) {
434 float parsedValue = std::strtof(from.c_str(), &pLastUsed);
435 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
436 !std::isinf(parsedValue)) {
456 static std::optional<float>
convert(
const std::string_view& from) {
457 if (from.size() == 0) {
468 std::string(from.data(), from.size()));
473#pragma region Conversions to double
484 static std::optional<double>
convert(
bool from) {
return from ? 1.0 : 0.0; }
490template <
typename TFrom>
494 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
501 static std::optional<double>
convert(TFrom from) {
502 return static_cast<double>(from);
515 static std::optional<double>
convert(
float from) {
516 return static_cast<double>(from);
532 static std::optional<double>
convert(
const std::string& from) {
533 if (from.size() == 0) {
542 double parsedValue = std::strtod(from.c_str(), &pLastUsed);
543 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
544 !std::isinf(parsedValue)) {
564 static std::optional<double>
convert(
const std::string_view& from) {
565 if (from.size() == 0) {
581#pragma region Conversions to string
592 static std::optional<std::string>
convert(
bool from) {
593 return from ?
"true" :
"false";
600template <
typename TFrom>
604 std::enable_if_t<IsMetadataScalar<TFrom>::value>> {
610 static std::optional<std::string>
convert(TFrom from) {
611 return std::to_string(from);
618template <
typename TFrom>
623 IsMetadataVecN<TFrom>::value || IsMetadataMatN<TFrom>::value>> {
630 static std::optional<std::string>
convert(
const TFrom& from) {
631 return glm::to_string(from);
642 static std::optional<std::string>
convert(
const std::string_view& from) {
643 return std::string(from.data(), from.size());
649#pragma region Conversions to glm::vecN
653template <
typename TTo>
657 std::enable_if_t<IsMetadataVecN<TTo>::value>> {
665 static std::optional<TTo>
convert(
bool from) {
666 return from ? TTo(1) : TTo(0);
673template <
typename TTo,
typename TFrom>
678 CesiumGltf::IsMetadataVecN<TTo>::value &&
679 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
691 static std::optional<TTo>
convert(TFrom from) {
692 using ToValueType =
typename TTo::value_type;
694 std::optional<ToValueType> maybeValue =
697 ToValueType value = *maybeValue;
708template <
typename TTo,
typename TFrom>
713 CesiumGltf::IsMetadataVecN<TTo>::value &&
714 CesiumGltf::IsMetadataVecN<TFrom>::value &&
715 !std::is_same_v<TTo, TFrom>>> {
729 static std::optional<TTo>
convert(TFrom from) {
732 constexpr glm::length_t validLength =
733 glm::min(TTo::length(), TFrom::length());
735 using ToValueType =
typename TTo::value_type;
736 using FromValueType =
typename TFrom::value_type;
738 for (glm::length_t i = 0; i < validLength; i++) {
745 result[i] = *maybeValue;
753#pragma region Conversions to glm::matN
757template <
typename TTo>
761 std::enable_if_t<IsMetadataMatN<TTo>::value>> {
769 static std::optional<TTo>
convert(
bool from) {
770 return from ? TTo(1) : TTo(0);
777template <
typename TTo,
typename TFrom>
782 CesiumGltf::IsMetadataMatN<TTo>::value &&
783 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
795 static std::optional<TTo>
convert(TFrom from) {
796 using ToValueType =
typename TTo::value_type;
798 std::optional<ToValueType> maybeValue =
804 ToValueType value = *maybeValue;
812template <
typename TTo,
typename TFrom>
817 CesiumGltf::IsMetadataMatN<TTo>::value &&
818 CesiumGltf::IsMetadataMatN<TFrom>::value &&
819 !std::is_same_v<TTo, TFrom>>> {
833 static std::optional<TTo>
convert(TFrom from) {
836 constexpr glm::length_t validLength =
837 glm::min(TTo::length(), TFrom::length());
839 using ToValueType =
typename TTo::value_type;
840 using FromValueType =
typename TFrom::value_type;
842 for (glm::length_t c = 0; c < validLength; c++) {
843 for (glm::length_t r = 0; r < validLength; r++) {
851 result[c][r] = *maybeValue;
862#ifdef GLM_ENABLE_EXPERIMENTAL_defined_locally
863#undef GLM_ENABLE_EXPERIMENTAL
864#undef GLM_ENABLE_EXPERIMENTAL_defined_locally
Classes for working with glTF models.
constexpr std::optional< T > losslessNarrow(U u) noexcept
Attempts a narrowing conversion of U into T without losing information. If a lossless conversion can'...