3 #include "PropertyTypeTraits.h"
5 #include <CesiumUtility/JsonValue.h>
7 #include <glm/common.hpp>
13 #include <string_view>
15 #ifndef GLM_ENABLE_EXPERIMENTAL
18 #define GLM_ENABLE_EXPERIMENTAL
19 #define GLM_ENABLE_EXPERIMENTAL_defined_locally
21 #include <glm/gtx/string_cast.hpp>
28 template <
typename TTo,
typename TFrom,
typename Enable =
void>
30 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
44 template <
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
132 template <
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) {
148 return CesiumUtility::losslessNarrow<TTo, TFrom>(from);
155 template <
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);
185 template <
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()) {
213 return CesiumUtility::losslessNarrow<TTo, int64_t>(parsedValue);
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) {
229 return CesiumUtility::losslessNarrow<TTo, int64_t>(asInteger);
240 template <
typename TTo>
245 CesiumGltf::IsMetadataInteger<TTo>::value && !std::is_signed_v<TTo>>> {
256 static std::optional<TTo>
convert(
const std::string& from) {
257 if (from.size() == 0) {
263 if (from.find(
'-') != std::string::npos) {
273 uint64_t parsedValue = std::strtoull(from.c_str(), &pLastUsed, 10);
274 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
276 return CesiumUtility::losslessNarrow<TTo, uint64_t>(parsedValue);
283 double parsedDouble = std::strtod(from.c_str(), &pLastUsed);
284 if (errno == 0 && pLastUsed == from.c_str() + from.size()) {
287 double truncated = glm::trunc(parsedDouble);
289 uint64_t asInteger =
static_cast<uint64_t
>(truncated);
290 double roundTrip =
static_cast<double>(asInteger);
291 if (roundTrip == truncated) {
292 return CesiumUtility::losslessNarrow<TTo, uint64_t>(asInteger);
303 template <
typename TTo>
307 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
317 static std::optional<TTo>
convert(
const std::string_view& from) {
318 if (from.size() == 0) {
336 template <
typename TTo>
340 std::enable_if_t<CesiumGltf::IsMetadataInteger<TTo>::value>> {
347 static std::optional<TTo>
convert(
bool from) {
return from ? 1 : 0; }
351 #pragma region Conversions to float
362 static std::optional<float>
convert(
bool from) {
return from ? 1.0f : 0.0f; }
368 template <
typename TFrom>
372 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
379 static std::optional<float>
convert(TFrom from) {
380 return static_cast<float>(from);
396 static std::optional<float>
convert(
double from) {
397 if (from > std::numeric_limits<float>::max() ||
398 from < std::numeric_limits<float>::lowest()) {
401 return static_cast<float>(from);
417 static std::optional<float>
convert(
const std::string& from) {
418 if (from.size() == 0) {
427 float parsedValue = std::strtof(from.c_str(), &pLastUsed);
428 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
429 !std::isinf(parsedValue)) {
449 static std::optional<float>
convert(
const std::string_view& from) {
450 if (from.size() == 0) {
461 std::string(from.data(), from.size()));
466 #pragma region Conversions to double
477 static std::optional<double>
convert(
bool from) {
return from ? 1.0 : 0.0; }
483 template <
typename TFrom>
487 std::enable_if_t<CesiumGltf::IsMetadataInteger<TFrom>::value>> {
494 static std::optional<double>
convert(TFrom from) {
495 return static_cast<double>(from);
508 static std::optional<double>
convert(
float from) {
509 return static_cast<double>(from);
525 static std::optional<double>
convert(
const std::string& from) {
526 if (from.size() == 0) {
535 double parsedValue = std::strtod(from.c_str(), &pLastUsed);
536 if (errno == 0 && pLastUsed == from.c_str() + from.size() &&
537 !std::isinf(parsedValue)) {
557 static std::optional<double>
convert(
const std::string_view& from) {
558 if (from.size() == 0) {
574 #pragma region Conversions to string
585 static std::optional<std::string>
convert(
bool from) {
586 return from ?
"true" :
"false";
593 template <
typename TFrom>
597 std::enable_if_t<IsMetadataScalar<TFrom>::value>> {
604 static std::optional<std::string>
convert(TFrom from) {
605 return std::to_string(from);
612 template <
typename TFrom>
617 IsMetadataVecN<TFrom>::value || IsMetadataMatN<TFrom>::value>> {
624 static std::optional<std::string>
convert(
const TFrom& from) {
625 return glm::to_string(from);
636 static std::optional<std::string>
convert(
const std::string_view& from) {
637 return std::string(from.data(), from.size());
643 #pragma region Conversions to glm::vecN
647 template <
typename TTo>
651 std::enable_if_t<IsMetadataVecN<TTo>::value>> {
659 static std::optional<TTo>
convert(
bool from) {
660 return from ? TTo(1) : TTo(0);
667 template <
typename TTo,
typename TFrom>
672 CesiumGltf::IsMetadataVecN<TTo>::value &&
673 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
685 static std::optional<TTo>
convert(TFrom from) {
686 using ToValueType =
typename TTo::value_type;
688 std::optional<ToValueType> maybeValue =
691 ToValueType value = *maybeValue;
702 template <
typename TTo,
typename TFrom>
707 CesiumGltf::IsMetadataVecN<TTo>::value &&
708 CesiumGltf::IsMetadataVecN<TFrom>::value &&
709 !std::is_same_v<TTo, TFrom>>> {
723 static std::optional<TTo>
convert(TFrom from) {
726 constexpr glm::length_t validLength =
727 glm::min(TTo::length(), TFrom::length());
729 using ToValueType =
typename TTo::value_type;
730 using FromValueType =
typename TFrom::value_type;
732 for (glm::length_t i = 0; i < validLength; i++) {
739 result[i] = *maybeValue;
747 #pragma region Conversions to glm::matN
751 template <
typename TTo>
755 std::enable_if_t<IsMetadataMatN<TTo>::value>> {
763 static std::optional<TTo>
convert(
bool from) {
764 return from ? TTo(1) : TTo(0);
771 template <
typename TTo,
typename TFrom>
776 CesiumGltf::IsMetadataMatN<TTo>::value &&
777 CesiumGltf::IsMetadataScalar<TFrom>::value>> {
789 static std::optional<TTo>
convert(TFrom from) {
790 using ToValueType =
typename TTo::value_type;
792 std::optional<ToValueType> maybeValue =
798 ToValueType value = *maybeValue;
806 template <
typename TTo,
typename TFrom>
811 CesiumGltf::IsMetadataMatN<TTo>::value &&
812 CesiumGltf::IsMetadataMatN<TFrom>::value &&
813 !std::is_same_v<TTo, TFrom>>> {
827 static std::optional<TTo>
convert(TFrom from) {
830 constexpr glm::length_t validLength =
831 glm::min(TTo::length(), TFrom::length());
833 using ToValueType =
typename TTo::value_type;
834 using FromValueType =
typename TFrom::value_type;
836 for (glm::length_t c = 0; c < validLength; c++) {
837 for (glm::length_t r = 0; r < validLength; r++) {
845 result[c][r] = *maybeValue;
856 #ifdef GLM_ENABLE_EXPERIMENTAL_defined_locally
857 #undef GLM_ENABLE_EXPERIMENTAL
858 #undef GLM_ENABLE_EXPERIMENTAL_defined_locally
Classes for working with glTF models.