-
Giovanni Vindiola authoredGiovanni Vindiola authored
PropertyTransformations.h 4.74 KiB
#pragma once
#include "CesiumGltf/PropertyArrayView.h"
#include "CesiumGltf/PropertyTypeTraits.h"
#include <glm/common.hpp>
#include <algorithm>
#include <cstdint>
#include <optional>
namespace CesiumGltf {
template <typename T> double normalize(T value) {
constexpr double max = static_cast<double>(std::numeric_limits<T>::max());
if constexpr (std::is_signed_v<T>) {
return std::max(static_cast<double>(value) / max, -1.0);
} else {
return static_cast<double>(value) / max;
}
}
template <glm::length_t N, typename T>
glm::vec<N, double> normalize(glm::vec<N, T> value) {
constexpr double max = static_cast<double>(std::numeric_limits<T>::max());
if constexpr (std::is_signed_v<T>) {
return glm::max(static_cast<glm::vec<N, double>>(value) / max, -1.0);
} else {
return static_cast<glm::vec<N, double>>(value) / max;
}
}
template <glm::length_t N, typename T>
glm::mat<N, N, double> normalize(glm::mat<N, N, T> value) {
constexpr double max = static_cast<double>(std::numeric_limits<T>::max());
// No max() implementation for matrices, so we have to write our own.
glm::mat<N, N, double> result;
for (glm::length_t i = 0; i < N; i++) {
for (glm::length_t j = 0; j < N; j++) {
if constexpr (std::is_signed_v<T>) {
result[i][j] = glm::max(static_cast<double>(value[i][j]) / max, -1.0);
} else {
result[i][j] = static_cast<double>(value[i][j]) / max;
}
}
}
return result;
}
template <typename T> T applyScale(const T& value, const T& scale) {
if constexpr (IsMetadataMatN<T>::value) {
// Do component-wise multiplication instead of actual matrix
// multiplication.
T matN;
constexpr glm::length_t N = T::length();
for (glm::length_t i = 0; i < N; i++) {
matN[i] = value[i] * scale[i];
}
return matN;
} else {
return value * scale;
}
}
template <typename T>
T transformValue(
const T& value,
const std::optional<T>& offset,
const std::optional<T>& scale) {
T result = value;
if (scale) {
result = applyScale<T>(result, *scale);
}
if (offset) {
result += *offset;
}
return result;
}
template <typename T>
PropertyArrayView<T> transformArray(
const PropertyArrayView<T>& value,
const std::optional<PropertyArrayView<T>>& offset,
const std::optional<PropertyArrayView<T>>& scale) {
std::vector<T> result(static_cast<size_t>(value.size()));
for (int64_t i = 0; i < value.size(); i++) {
result[i] = value[i];
if (scale) {
result[i] = applyScale<T>(result[i], (*scale)[i]);
}
if (offset) {
result[i] = result[i] + (*offset)[i];
}
}
return PropertyArrayView<T>(std::move(result));
}
template <
typename T,
typename NormalizedType = typename TypeToNormalizedType<T>::type>
PropertyArrayView<NormalizedType> transformNormalizedArray(
const PropertyArrayView<T>& value,
const std::optional<PropertyArrayView<NormalizedType>>& offset,
const std::optional<PropertyArrayView<NormalizedType>>& scale) {
std::vector<NormalizedType> result(static_cast<size_t>(value.size()));
for (int64_t i = 0; i < value.size(); i++) {
result[i] = normalize<T>(value[i]);
if (scale) {
result[i] = result[i] * (*scale)[i];
}
if (offset) {
result[i] = result[i] + (*offset)[i];
}
}
return PropertyArrayView<NormalizedType>(std::move(result));
}
template <glm::length_t N, typename T>
PropertyArrayView<glm::vec<N, double>> transformNormalizedVecNArray(
const PropertyArrayView<glm::vec<N, T>>& value,
const std::optional<PropertyArrayView<glm::vec<N, double>>>& offset,
const std::optional<PropertyArrayView<glm::vec<N, double>>>& scale) {
std::vector<glm::vec<N, double>> result(static_cast<size_t>(value.size()));
for (int64_t i = 0; i < value.size(); i++) {
result[i] = normalize<N, T>(value[i]);
if (scale) {
result[i] = result[i] * (*scale)[i];
}
if (offset) {
result[i] = result[i] + (*offset)[i];
}
}
return PropertyArrayView<glm::vec<N, double>>(std::move(result));
}
template <glm::length_t N, typename T>
PropertyArrayView<glm::mat<N, N, double>> transformNormalizedMatNArray(
const PropertyArrayView<glm::mat<N, N, T>>& value,
const std::optional<PropertyArrayView<glm::mat<N, N, double>>>& offset,
const std::optional<PropertyArrayView<glm::mat<N, N, double>>>& scale) {
std::vector<glm::mat<N, N, double>> result(static_cast<size_t>(value.size()));
for (int64_t i = 0; i < value.size(); i++) {
result[i] = normalize<N, T>(value[i]);
if (scale) {
result[i] = applyScale<glm::mat<N, N, double>>(result[i], (*scale)[i]);
}
if (offset) {
result[i] = result[i] + (*offset)[i];
}
}
return PropertyArrayView<glm::mat<N, N, double>>(std::move(result));
}
} // namespace CesiumGltf