3752 lines
109 KiB
C++
3752 lines
109 KiB
C++
#include <CesiumGltf/ClassProperty.h>
|
|
#include <CesiumGltf/PropertyArrayView.h>
|
|
#include <CesiumGltf/PropertyTableProperty.h>
|
|
#include <CesiumGltf/PropertyType.h>
|
|
#include <CesiumGltf/PropertyTypeTraits.h>
|
|
#include <CesiumUtility/JsonValue.h>
|
|
|
|
#include <glm/ext/matrix_double2x2.hpp>
|
|
#include <glm/ext/matrix_double3x3.hpp>
|
|
#include <glm/ext/matrix_double4x4.hpp>
|
|
#include <glm/ext/matrix_float2x2.hpp>
|
|
#include <glm/ext/vector_double2.hpp>
|
|
#include <glm/ext/vector_double3.hpp>
|
|
#include <glm/ext/vector_float2.hpp>
|
|
#include <glm/ext/vector_float3.hpp>
|
|
#include <glm/ext/vector_float4.hpp>
|
|
#include <glm/ext/vector_int2.hpp>
|
|
#include <glm/ext/vector_int2_sized.hpp>
|
|
#include <glm/ext/vector_int3.hpp>
|
|
#include <glm/ext/vector_int3_sized.hpp>
|
|
#include <glm/ext/vector_uint2_sized.hpp>
|
|
#include <glm/ext/vector_uint4_sized.hpp>
|
|
#include <glm/fwd.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string_view>
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
|
#endif
|
|
|
|
#include <CesiumGltf/PropertyTablePropertyView.h>
|
|
|
|
#include <doctest/doctest.h>
|
|
|
|
#include <bitset>
|
|
#include <climits>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <ostream>
|
|
#include <span>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace doctest;
|
|
using namespace CesiumGltf;
|
|
using namespace CesiumUtility;
|
|
|
|
namespace {
|
|
|
|
template <typename T>
|
|
static void
|
|
checkArrayEqual(PropertyArrayView<T> arrayView, std::vector<T> expected) {
|
|
REQUIRE(arrayView.size() == static_cast<int64_t>(expected.size()));
|
|
for (int64_t i = 0; i < arrayView.size(); i++) {
|
|
REQUIRE(arrayView[i] == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
|
|
template <typename T> static void checkNumeric(const std::vector<T>& expected) {
|
|
std::vector<std::byte> data;
|
|
data.resize(expected.size() * sizeof(T));
|
|
std::memcpy(data.data(), expected.data(), data.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
if (componentType != PropertyComponentType::None) {
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
}
|
|
|
|
PropertyTablePropertyView<T> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(expected.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
REQUIRE(property.size() == static_cast<int64_t>(expected.size()));
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == expected[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == property.getRaw(i));
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void checkNumeric(
|
|
const std::vector<T>& values,
|
|
const std::vector<std::optional<T>>& expected,
|
|
const std::optional<JsonValue>& offset = std::nullopt,
|
|
const std::optional<JsonValue>& scale = std::nullopt,
|
|
const std::optional<JsonValue>& noData = std::nullopt,
|
|
const std::optional<JsonValue>& defaultValue = std::nullopt) {
|
|
std::vector<std::byte> data;
|
|
data.resize(values.size() * sizeof(T));
|
|
std::memcpy(data.data(), values.data(), data.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
|
|
classProperty.offset = offset;
|
|
classProperty.scale = scale;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<T> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(expected.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
REQUIRE(property.size() == static_cast<int64_t>(expected.size()));
|
|
REQUIRE(!property.normalized());
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == values[static_cast<size_t>(i)]);
|
|
if constexpr (IsMetadataFloating<T>::value) {
|
|
REQUIRE(property.get(i) == Approx(*expected[static_cast<size_t>(i)]));
|
|
} else {
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename D = typename TypeToNormalizedType<T>::type>
|
|
static void checkNormalizedNumeric(
|
|
const std::vector<T>& values,
|
|
const std::vector<std::optional<D>>& expected,
|
|
const std::optional<JsonValue>& offset = std::nullopt,
|
|
const std::optional<JsonValue>& scale = std::nullopt,
|
|
const std::optional<JsonValue>& noData = std::nullopt,
|
|
const std::optional<JsonValue>& defaultValue = std::nullopt) {
|
|
std::vector<std::byte> data;
|
|
data.resize(values.size() * sizeof(T));
|
|
std::memcpy(data.data(), values.data(), data.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
|
|
classProperty.normalized = true;
|
|
|
|
classProperty.offset = offset;
|
|
classProperty.scale = scale;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<T, true> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(expected.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
REQUIRE(property.size() == static_cast<int64_t>(expected.size()));
|
|
REQUIRE(property.normalized());
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == values[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
|
|
template <typename DataType, typename OffsetType>
|
|
static void checkVariableLengthArray(
|
|
const std::vector<DataType>& data,
|
|
const std::vector<OffsetType>& offsets,
|
|
PropertyComponentType offsetType,
|
|
int64_t instanceCount) {
|
|
// copy data to buffer
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(DataType));
|
|
std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType));
|
|
|
|
// copy offset to buffer
|
|
std::vector<std::byte> offsetBuffer;
|
|
offsetBuffer.resize(offsets.size() * sizeof(OffsetType));
|
|
std::memcpy(
|
|
offsetBuffer.data(),
|
|
offsets.data(),
|
|
offsets.size() * sizeof(OffsetType));
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<DataType>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<DataType>::component;
|
|
if (componentType != PropertyComponentType::None) {
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
}
|
|
|
|
classProperty.array = true;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<DataType>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
std::span<const std::byte>(),
|
|
offsetType,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<DataType> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
|
|
auto maybeValues = property.get(i);
|
|
REQUIRE(maybeValues);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE((*maybeValues)[j] == values[j]);
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
}
|
|
|
|
template <typename DataType, typename OffsetType>
|
|
static void checkVariableLengthArray(
|
|
const std::vector<DataType>& data,
|
|
const std::vector<OffsetType>& offsets,
|
|
PropertyComponentType offsetType,
|
|
int64_t instanceCount,
|
|
const std::vector<std::optional<std::vector<DataType>>>& expected,
|
|
const std::optional<JsonValue::Array>& noData = std::nullopt,
|
|
const std::optional<JsonValue::Array>& defaultValue = std::nullopt) {
|
|
// copy data to buffer
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(DataType));
|
|
std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType));
|
|
|
|
// copy offset to buffer
|
|
std::vector<std::byte> offsetBuffer;
|
|
offsetBuffer.resize(offsets.size() * sizeof(OffsetType));
|
|
std::memcpy(
|
|
offsetBuffer.data(),
|
|
offsets.data(),
|
|
offsets.size() * sizeof(OffsetType));
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<DataType>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<DataType>::component;
|
|
if (componentType != PropertyComponentType::None) {
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
}
|
|
|
|
classProperty.array = true;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<DataType>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
std::span<const std::byte>(),
|
|
offsetType,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<DataType> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
|
|
// Check values with properties applied
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
std::optional<PropertyArrayCopy<DataType>> maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <
|
|
typename DataType,
|
|
typename OffsetType,
|
|
typename NormalizedType = typename TypeToNormalizedType<DataType>::type>
|
|
static void checkNormalizedVariableLengthArray(
|
|
const std::vector<DataType>& data,
|
|
const std::vector<OffsetType> offsets,
|
|
PropertyComponentType offsetType,
|
|
int64_t instanceCount,
|
|
const std::vector<std::optional<std::vector<NormalizedType>>>& expected,
|
|
const std::optional<JsonValue::Array>& noData = std::nullopt,
|
|
const std::optional<JsonValue::Array>& defaultValue = std::nullopt) {
|
|
// copy data to buffer
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(DataType));
|
|
std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType));
|
|
|
|
// copy offset to buffer
|
|
std::vector<std::byte> offsetBuffer;
|
|
offsetBuffer.resize(offsets.size() * sizeof(OffsetType));
|
|
std::memcpy(
|
|
offsetBuffer.data(),
|
|
offsets.data(),
|
|
offsets.size() * sizeof(OffsetType));
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<DataType>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<DataType>::component;
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
|
|
classProperty.array = true;
|
|
classProperty.normalized = true;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<DataType>, true> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
offsetType);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<DataType> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
|
|
// Check values with properties applied
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
std::optional<PropertyArrayCopy<NormalizedType>> maybeValues =
|
|
property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void checkFixedLengthArray(
|
|
const std::vector<T>& data,
|
|
int64_t fixedLengthArrayCount) {
|
|
int64_t instanceCount =
|
|
static_cast<int64_t>(data.size()) / fixedLengthArrayCount;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(T));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
if (componentType != PropertyComponentType::None) {
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
}
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = fixedLengthArrayCount;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<T>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == fixedLengthArrayCount);
|
|
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<T> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
|
|
auto maybeValues = property.get(i);
|
|
REQUIRE(maybeValues);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE((*maybeValues)[j] == values[j]);
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
}
|
|
|
|
template <typename T>
|
|
static void checkFixedLengthArray(
|
|
const std::vector<T>& data,
|
|
int64_t fixedLengthArrayCount,
|
|
const std::vector<std::optional<std::vector<T>>>& expected,
|
|
const std::optional<JsonValue::Array>& offset = std::nullopt,
|
|
const std::optional<JsonValue::Array>& scale = std::nullopt,
|
|
const std::optional<JsonValue::Array>& noData = std::nullopt,
|
|
const std::optional<JsonValue::Array>& defaultValue = std::nullopt) {
|
|
int64_t instanceCount =
|
|
static_cast<int64_t>(data.size()) / fixedLengthArrayCount;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(T));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
if (componentType != PropertyComponentType::None) {
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
}
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = fixedLengthArrayCount;
|
|
classProperty.offset = offset;
|
|
classProperty.scale = scale;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<T>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == fixedLengthArrayCount);
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<T> rawValues = property.getRaw(i);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
|
|
// Check values with properties applied
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
std::optional<PropertyArrayCopy<T>> maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename D = typename TypeToNormalizedType<T>::type>
|
|
static void checkNormalizedFixedLengthArray(
|
|
const std::vector<T>& data,
|
|
int64_t fixedLengthArrayCount,
|
|
const std::vector<std::optional<std::vector<D>>>& expected,
|
|
const std::optional<JsonValue::Array>& offset = std::nullopt,
|
|
const std::optional<JsonValue::Array>& scale = std::nullopt,
|
|
const std::optional<JsonValue::Array>& noData = std::nullopt,
|
|
const std::optional<JsonValue::Array>& defaultValue = std::nullopt) {
|
|
int64_t instanceCount =
|
|
static_cast<int64_t>(data.size()) / fixedLengthArrayCount;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(T));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type =
|
|
convertPropertyTypeToString(TypeToPropertyType<T>::value);
|
|
|
|
PropertyComponentType componentType = TypeToPropertyType<T>::component;
|
|
classProperty.componentType =
|
|
convertPropertyComponentTypeToString(componentType);
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = fixedLengthArrayCount;
|
|
classProperty.normalized = true;
|
|
|
|
classProperty.offset = offset;
|
|
classProperty.scale = scale;
|
|
classProperty.noData = noData;
|
|
classProperty.defaultProperty = defaultValue;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<T>, true> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == fixedLengthArrayCount);
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<T> rawValues = property.getRaw(i);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == data.size());
|
|
|
|
// Check values with properties applied
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
std::optional<PropertyArrayCopy<D>> maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
TEST_CASE("Check scalar PropertyTablePropertyView") {
|
|
SUBCASE("Uint8") {
|
|
std::vector<uint8_t> data{12, 33, 56, 67};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Int32") {
|
|
std::vector<int32_t> data{111222, -11133, -56000, 670000};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Float") {
|
|
std::vector<float> data{12.3333f, -12.44555f, -5.6111f, 6.7421f};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Double") {
|
|
std::vector<double> data{
|
|
12222.3302121,
|
|
-12000.44555,
|
|
-5000.6113111,
|
|
6.7421};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Float with Offset / Scale") {
|
|
std::vector<float> values{12.5f, -12.5f, -5.0f, 6.75f};
|
|
const float offset = 1.0f;
|
|
const float scale = 2.0f;
|
|
std::vector<std::optional<float>> expected{26.0f, -24.0f, -9.0f, 14.5f};
|
|
checkNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Int16 with NoData") {
|
|
std::vector<int16_t> values{-1, 3, 7, -1};
|
|
const int16_t noData = -1;
|
|
std::vector<std::optional<int16_t>> expected{
|
|
std::nullopt,
|
|
static_cast<int16_t>(3),
|
|
static_cast<int16_t>(7),
|
|
std::nullopt};
|
|
checkNumeric<int16_t>(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
};
|
|
|
|
SUBCASE("Int16 with NoData and Default") {
|
|
std::vector<int16_t> values{-1, 3, 7, -1};
|
|
const int16_t noData = -1;
|
|
const int16_t defaultValue = 0;
|
|
std::vector<std::optional<int16_t>> expected{
|
|
static_cast<int16_t>(0),
|
|
static_cast<int16_t>(3),
|
|
static_cast<int16_t>(7),
|
|
static_cast<int16_t>(0)};
|
|
checkNumeric<int16_t>(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
std::vector<float> values{1.0f, 3.0f, 2.0f, 4.0f};
|
|
std::vector<std::byte> data;
|
|
data.resize(values.size() * sizeof(float));
|
|
std::memcpy(data.data(), values.data(), data.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::SCALAR;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
classProperty.offset = 0.0f;
|
|
classProperty.scale = 1.0f;
|
|
classProperty.min = 1.0f;
|
|
classProperty.max = 4.0f;
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
propertyTableProperty.offset = 1.0f;
|
|
propertyTableProperty.scale = 2.0f;
|
|
propertyTableProperty.min = 3.0f;
|
|
propertyTableProperty.max = 9.0f;
|
|
|
|
PropertyTablePropertyView<float> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(values.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
REQUIRE(property.offset() == 1.0f);
|
|
REQUIRE(property.scale() == 2.0f);
|
|
REQUIRE(property.min() == 3.0f);
|
|
REQUIRE(property.max() == 9.0f);
|
|
|
|
std::vector<float> expected{3.0, 7.0f, 5.0f, 9.0f};
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == values[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == Approx(expected[static_cast<size_t>(i)]));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check scalar PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Uint8") {
|
|
std::vector<uint8_t> values{0, 64, 128, 255};
|
|
std::vector<std::optional<double>> expected{
|
|
0.0,
|
|
64.0 / 255.0,
|
|
128.0 / 255.0,
|
|
1.0};
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Int16") {
|
|
std::vector<int16_t> values{-32768, 0, 16384, 32767};
|
|
std::vector<std::optional<double>> expected{
|
|
-1.0,
|
|
0.0,
|
|
16384.0 / 32767.0,
|
|
1.0};
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Uint8 with Offset and Scale") {
|
|
std::vector<uint8_t> values{0, 64, 128, 255};
|
|
const double offset = 1.0;
|
|
const double scale = 2.0;
|
|
std::vector<std::optional<double>> expected{
|
|
1.0,
|
|
1 + 2 * (64.0 / 255.0),
|
|
1 + 2 * (128.0 / 255.0),
|
|
3.0};
|
|
checkNormalizedNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Uint8 with all properties") {
|
|
std::vector<uint8_t> values{0, 64, 128, 255};
|
|
const double offset = 1.0;
|
|
const double scale = 2.0;
|
|
const uint8_t noData = 0;
|
|
const double defaultValue = 10.0;
|
|
std::vector<std::optional<double>> expected{
|
|
10.0,
|
|
1 + 2 * (64.0 / 255.0),
|
|
1 + 2 * (128.0 / 255.0),
|
|
3.0};
|
|
checkNormalizedNumeric(
|
|
values,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check vecN PropertyTablePropertyView") {
|
|
SUBCASE("Float Vec2") {
|
|
std::vector<glm::vec2> data{
|
|
glm::vec2(10.001f, 0.005f),
|
|
glm::vec2(-20.8f, 50.0f),
|
|
glm::vec2(99.9f, -9.9f),
|
|
glm::vec2(-64.456f, 12.01f)};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Int32 Vec3") {
|
|
std::vector<glm::ivec3> data{
|
|
glm::ivec3(10, 0, -3),
|
|
glm::ivec3(-20, 10, 52),
|
|
glm::ivec3(9, 9, -9),
|
|
glm::ivec3(8, -40, 2)};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Uint8 Vec4") {
|
|
std::vector<glm::u8vec4> data{
|
|
glm::u8vec4(1, 2, 3, 0),
|
|
glm::u8vec4(4, 5, 6, 1),
|
|
glm::u8vec4(7, 8, 9, 0),
|
|
glm::u8vec4(0, 0, 0, 1)};
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Float Vec3 with Offset / Scale") {
|
|
std::vector<glm::vec3> values{
|
|
glm::vec3(0.0f, -1.5f, -5.0f),
|
|
glm::vec3(6.5f, 2.0f, 4.0f),
|
|
glm::vec3(8.0f, -3.0f, 1.0f),
|
|
};
|
|
JsonValue::Array offset{1.0f, 2.0f, 3.0f};
|
|
JsonValue::Array scale{2.0f, 1.0f, 2.0f};
|
|
std::vector<std::optional<glm::vec3>> expected{
|
|
glm::vec3(1.0f, 0.5f, -7.0f),
|
|
glm::vec3(14.0f, 4.0f, 11.0f),
|
|
glm::vec3(17.0f, -1.0f, 5.0f),
|
|
};
|
|
checkNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Int16 Vec2 with NoData") {
|
|
std::vector<glm::i16vec2> values{
|
|
glm::i16vec2(-1, 3),
|
|
glm::i16vec2(-1, -1),
|
|
glm::i16vec2(7, 0)};
|
|
JsonValue::Array noData{-1, -1};
|
|
std::vector<std::optional<glm::i16vec2>> expected{
|
|
glm::i16vec2(-1, 3),
|
|
std::nullopt,
|
|
glm::i16vec2(7, 0)};
|
|
checkNumeric(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
};
|
|
|
|
SUBCASE("Int16 Vec2 with NoData and Default") {
|
|
std::vector<glm::i16vec2> values{
|
|
glm::i16vec2(-1, 3),
|
|
glm::i16vec2(-1, -1),
|
|
glm::i16vec2(7, 0)};
|
|
JsonValue::Array noData{-1, -1};
|
|
JsonValue::Array defaultValue{0, 1};
|
|
std::vector<std::optional<glm::i16vec2>> expected{
|
|
glm::i16vec2(-1, 3),
|
|
glm::i16vec2(0, 1),
|
|
glm::i16vec2(7, 0)};
|
|
checkNumeric(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
};
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
std::vector<glm::vec2> values{
|
|
glm::vec2(1.0f, 3.0f),
|
|
glm::vec2(2.5f, 2.5f),
|
|
glm::vec2(2.0f, 4.0f)};
|
|
std::vector<std::byte> data;
|
|
data.resize(values.size() * sizeof(glm::vec2));
|
|
std::memcpy(data.data(), values.data(), data.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::VEC2;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
classProperty.offset = {0.0f, 0.0f};
|
|
classProperty.scale = {1.0f, 1.0f};
|
|
classProperty.min = {1.0f, 2.5f};
|
|
classProperty.max = {2.5f, 4.0f};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
propertyTableProperty.offset = {1.0f, 0.5f};
|
|
propertyTableProperty.scale = {2.0f, 1.0f};
|
|
propertyTableProperty.min = {3.0f, 3.0f};
|
|
propertyTableProperty.max = {6.0f, 4.5f};
|
|
|
|
PropertyTablePropertyView<glm::vec2> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(values.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
REQUIRE(property.offset() == glm::vec2(1.0f, 0.5f));
|
|
REQUIRE(property.scale() == glm::vec2(2.0f, 1.0f));
|
|
REQUIRE(property.min() == glm::vec2(3.0f, 3.0f));
|
|
REQUIRE(property.max() == glm::vec2(6.0f, 4.5f));
|
|
|
|
std::vector<glm::vec2> expected{
|
|
glm::vec2(3.0f, 3.5f),
|
|
glm::vec2(6.0f, 3.0f),
|
|
glm::vec2(5.0f, 4.5f)};
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == values[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check vecN PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Uint8 Vec2") {
|
|
std::vector<glm::u8vec2> values{
|
|
glm::u8vec2(0, 64),
|
|
glm::u8vec2(128, 255),
|
|
glm::u8vec2(255, 0)};
|
|
std::vector<std::optional<glm::dvec2>> expected{
|
|
glm::dvec2(0.0, 64.0 / 255.0),
|
|
glm::dvec2(128.0 / 255.0, 1.0),
|
|
glm::dvec2(1.0, 0.0)};
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Int16 Vec2") {
|
|
std::vector<glm::i16vec2> values{
|
|
glm::i16vec2(-32768, 0),
|
|
glm::i16vec2(16384, 32767),
|
|
glm::i16vec2(32767, -32768)};
|
|
std::vector<std::optional<glm::dvec2>> expected{
|
|
glm::dvec2(-1.0, 0.0),
|
|
glm::dvec2(16384.0 / 32767.0, 1.0),
|
|
glm::dvec2(1.0, -1.0),
|
|
};
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Uint8 Vec2 with Offset and Scale") {
|
|
std::vector<glm::u8vec2> values{
|
|
glm::u8vec2(0, 64),
|
|
glm::u8vec2(128, 255),
|
|
glm::u8vec2(255, 0)};
|
|
JsonValue::Array offset{0.0, 1.0};
|
|
JsonValue::Array scale{2.0, 1.0};
|
|
std::vector<std::optional<glm::dvec2>> expected{
|
|
glm::dvec2(0.0, 1 + (64.0 / 255.0)),
|
|
glm::dvec2(2 * (128.0 / 255.0), 2.0),
|
|
glm::dvec2(2.0, 1.0)};
|
|
checkNormalizedNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Uint8 Vec2 with all properties") {
|
|
std::vector<glm::u8vec2> values{
|
|
glm::u8vec2(0, 64),
|
|
glm::u8vec2(128, 255),
|
|
glm::u8vec2(255, 0),
|
|
glm::u8vec2(0, 0)};
|
|
JsonValue::Array offset{0.0, 1.0};
|
|
JsonValue::Array scale{2.0, 1.0};
|
|
JsonValue::Array noData{0, 0};
|
|
JsonValue::Array defaultValue{5.0, 15.0};
|
|
std::vector<std::optional<glm::dvec2>> expected{
|
|
glm::dvec2(0.0, 1 + (64.0 / 255.0)),
|
|
glm::dvec2(2 * (128.0 / 255.0), 2.0),
|
|
glm::dvec2(2.0, 1.0),
|
|
glm::dvec2(5.0, 15.0)};
|
|
checkNormalizedNumeric(
|
|
values,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check matN PropertyTablePropertyView") {
|
|
SUBCASE("Float Mat2") {
|
|
// clang-format off
|
|
std::vector<glm::mat2> data{
|
|
glm::mat2(
|
|
1.0f, 2.0f,
|
|
3.0f, 4.0f),
|
|
glm::mat2(
|
|
-10.0f, 40.0f,
|
|
0.08f, 5.4f),
|
|
glm::mat2(
|
|
9.99f, -2.0f,
|
|
-0.4f, 0.23f)
|
|
};
|
|
// clang-format on
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Int16 Mat3") {
|
|
// clang-format off
|
|
std::vector<glm::i16mat3x3> data{
|
|
glm::i16mat3x3(
|
|
1, 2, 3,
|
|
4, 5, 6,
|
|
7, 8, 9),
|
|
glm::i16mat3x3(
|
|
10, 0, 5,
|
|
-14, 35, 16,
|
|
-2, 3, 4),
|
|
glm::i16mat3x3(
|
|
-6, 5, 2,
|
|
14, 4, -33,
|
|
2, 1, 0)
|
|
};
|
|
// clang-format on
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Double Mat4") {
|
|
// clang-format off
|
|
std::vector<glm::dmat4> data{
|
|
glm::dmat4(
|
|
1.0, 2.0, 3.0, 4.0,
|
|
5.0, 6.0, 7.0, 8.0,
|
|
9.0, 10.0, 11.0, 12.0,
|
|
13.0, 14.0, 15.0, 16.0),
|
|
glm::dmat4(
|
|
0.1, 0.2, 0.3, 0.4,
|
|
0.5, 0.6, 0.7, 0.8,
|
|
-9.0, -10.0, -11.0, -12.0,
|
|
13.0, 14.0, 15.0, 16.0),
|
|
glm::dmat4(
|
|
1.0, 0.0, 0.0, 10.0,
|
|
0.0, 0.0, -1.0, -3.5,
|
|
0.0, 1.0, 0.0, 20.4,
|
|
0.0, 0.0, 0.0, 1.0)
|
|
};
|
|
// clang-format on
|
|
checkNumeric(data);
|
|
}
|
|
|
|
SUBCASE("Float Mat2 with Offset / Scale") {
|
|
// clang-format off
|
|
std::vector<glm::mat2> values{
|
|
glm::mat2(
|
|
1.0f, 3.0f,
|
|
4.0f, 2.0f),
|
|
glm::mat2(
|
|
6.5f, 2.0f,
|
|
-2.0f, 0.0f),
|
|
glm::mat2(
|
|
8.0f, -1.0f,
|
|
-3.0f, 1.0f),
|
|
};
|
|
JsonValue::Array offset{
|
|
1.0f, 2.0f,
|
|
3.0f, 1.0f};
|
|
JsonValue::Array scale {
|
|
2.0f, 0.0f,
|
|
0.0f, 2.0f};
|
|
std::vector<std::optional<glm::mat2>> expected{
|
|
glm::mat2(
|
|
3.0f, 2.0f,
|
|
3.0f, 5.0f),
|
|
glm::mat2(
|
|
14.0f, 2.0f,
|
|
3.0f, 1.0f),
|
|
glm::mat2(
|
|
17.0f, 2.0f,
|
|
3.0f, 3.0f),
|
|
};
|
|
// clang-format on
|
|
checkNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Int16 Mat3 with NoData") {
|
|
// clang-format off
|
|
std::vector<glm::i16mat3x3> values{
|
|
glm::i16mat3x3(
|
|
1, 2, 3,
|
|
-1, -2, -3,
|
|
0, 1, 0),
|
|
glm::i16mat3x3(
|
|
1, -1, 0,
|
|
0, 1, 2,
|
|
0, 4, 5),
|
|
glm::i16mat3x3(
|
|
-1, -1, -1,
|
|
0, 0, 0,
|
|
1, 1, 1)};
|
|
JsonValue::Array noData{
|
|
-1, -1, -1,
|
|
0, 0, 0,
|
|
1, 1, 1};
|
|
// clang-format on
|
|
std::vector<std::optional<glm::i16mat3x3>> expected{
|
|
values[0],
|
|
values[1],
|
|
std::nullopt};
|
|
checkNumeric(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
};
|
|
|
|
SUBCASE("Int16 Mat3 with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<glm::i16mat3x3> values{
|
|
glm::i16mat3x3(
|
|
1, 2, 3,
|
|
-1, -2, -3,
|
|
0, 1, 0),
|
|
glm::i16mat3x3(
|
|
1, -1, 0,
|
|
0, 1, 2,
|
|
0, 4, 5),
|
|
glm::i16mat3x3(
|
|
-1, -1, -1,
|
|
0, 0, 0,
|
|
1, 1, 1)};
|
|
JsonValue::Array noData{
|
|
-1, -1, -1,
|
|
0, 0, 0,
|
|
1, 1, 1};
|
|
JsonValue::Array defaultValue{
|
|
1, 0, 0,
|
|
0, 1, 0,
|
|
0, 0, 1};
|
|
// clang-format on
|
|
std::vector<std::optional<glm::i16mat3x3>> expected{
|
|
values[0],
|
|
values[1],
|
|
glm::i16mat3x3(1)};
|
|
checkNumeric(
|
|
values,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
};
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
// clang-fomrat off
|
|
std::vector<glm::mat2> values{
|
|
glm::mat2(1.0f),
|
|
glm::mat2(2.5f, 1.0f, 1.0f, 2.5f),
|
|
glm::mat2(3.0f)};
|
|
// clang-format on
|
|
std::vector<std::byte> data;
|
|
data.resize(values.size() * sizeof(glm::mat2));
|
|
std::memcpy(data.data(), values.data(), data.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::MAT2;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
// clang-format off
|
|
classProperty.offset = {
|
|
0.0f, 0.0f,
|
|
0.0f, 0.0f};
|
|
classProperty.scale = {
|
|
1.0f, 1.0f,
|
|
1.0f, 1.0f};
|
|
classProperty.min = {
|
|
1.0f, 0.0f,
|
|
0.0f, 1.0f};
|
|
classProperty.max = {
|
|
3.0f, 0.0f,
|
|
0.0f, 3.0f};
|
|
// clang-format on
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
// clang-format off
|
|
propertyTableProperty.offset = {
|
|
1.0f, 0.5f,
|
|
0.5f, 1.0f};
|
|
propertyTableProperty.scale = {
|
|
2.0f, 1.0f,
|
|
0.0f, 1.0f};
|
|
propertyTableProperty.min = {
|
|
3.0f, 0.5f,
|
|
0.5f, 2.0f};
|
|
propertyTableProperty.max = {
|
|
7.0f, 1.5f,
|
|
0.5f, 4.0f};
|
|
// clang-format on
|
|
|
|
PropertyTablePropertyView<glm::mat2> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(values.size()),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
// clang-format off
|
|
REQUIRE(property.offset() == glm::mat2(
|
|
1.0f, 0.5f,
|
|
0.5f, 1.0f));
|
|
REQUIRE(property.scale() == glm::mat2(
|
|
2.0f, 1.0f,
|
|
0.0f, 1.0f));
|
|
REQUIRE(property.min() == glm::mat2(
|
|
3.0f, 0.5f,
|
|
0.5f, 2.0f));
|
|
REQUIRE(property.max() == glm::mat2(
|
|
7.0f, 1.5f,
|
|
0.5f, 4.0f));
|
|
|
|
std::vector<glm::mat2> expected{
|
|
glm::mat2(
|
|
3.0f, 0.5f,
|
|
0.5f, 2.0f),
|
|
glm::mat2(
|
|
6.0f, 1.5f,
|
|
0.5f, 3.5f),
|
|
glm::mat2(
|
|
7.0f, 0.5f,
|
|
0.5f, 4.0f)};
|
|
// clang-format on
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == values[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check matN PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Uint8 Mat2") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> values{
|
|
glm::u8mat2x2(
|
|
0, 64,
|
|
255, 255),
|
|
glm::u8mat2x2(
|
|
255, 0,
|
|
128, 0)};
|
|
std::vector<std::optional<glm::dmat2>> expected{
|
|
glm::dmat2(
|
|
0.0, 64.0 / 255.0,
|
|
1.0, 1.0),
|
|
glm::dmat2(
|
|
1.0, 0.0,
|
|
128.0 / 255.0, 0.0)};
|
|
// clang-format on
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Int16 Mat2") {
|
|
// clang-format off
|
|
std::vector<glm::i16mat2x2> values{
|
|
glm::i16mat2x2(
|
|
-32768, 0,
|
|
16384, 32767),
|
|
glm::i16mat2x2(
|
|
0, 32767,
|
|
32767, -32768)};
|
|
std::vector<std::optional<glm::dmat2>> expected{
|
|
glm::dmat2(
|
|
-1.0, 0.0,
|
|
16384.0 / 32767.0, 1.0),
|
|
glm::dmat2(
|
|
0.0, 1.0,
|
|
1.0, -1.0),
|
|
};
|
|
// clang-format on
|
|
checkNormalizedNumeric(values, expected);
|
|
}
|
|
|
|
SUBCASE("Uint8 Mat2 with Offset and Scale") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> values{
|
|
glm::u8mat2x2(
|
|
0, 64,
|
|
255, 255),
|
|
glm::u8mat2x2(
|
|
255, 0,
|
|
128, 0)};
|
|
JsonValue::Array offset{
|
|
0.0, 1.0,
|
|
1.0, 0.0};
|
|
JsonValue::Array scale{
|
|
2.0, 1.0,
|
|
0.0, 2.0};
|
|
std::vector<std::optional<glm::dmat2>> expected{
|
|
glm::dmat2(
|
|
0.0, 1 + 64.0 / 255.0,
|
|
1.0, 2.0),
|
|
glm::dmat2(
|
|
2.0, 1.0,
|
|
1.0, 0.0)};
|
|
// clang-format on
|
|
checkNormalizedNumeric(values, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Normalized Uint8 Mat2 with all properties") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> values{
|
|
glm::u8mat2x2(
|
|
0, 64,
|
|
255, 255),
|
|
glm::u8mat2x2(0),
|
|
glm::u8mat2x2(
|
|
255, 0,
|
|
128, 0)};
|
|
JsonValue::Array offset{
|
|
0.0, 1.0,
|
|
1.0, 0.0};
|
|
JsonValue::Array scale{
|
|
2.0, 1.0,
|
|
0.0, 2.0};
|
|
JsonValue::Array noData{
|
|
0, 0,
|
|
0, 0};
|
|
JsonValue::Array defaultValue{
|
|
1.0, 0.0,
|
|
0.0, 1.0};
|
|
|
|
std::vector<std::optional<glm::dmat2>> expected{
|
|
glm::dmat2(
|
|
0.0, 1 + 64.0 / 255.0,
|
|
1.0, 2.0),
|
|
glm::dmat2(1.0),
|
|
glm::dmat2(
|
|
2.0, 1.0,
|
|
1.0, 0.0)};
|
|
// clang-format on
|
|
checkNormalizedNumeric(
|
|
values,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check boolean PropertyTablePropertyView") {
|
|
std::bitset<sizeof(unsigned long)* CHAR_BIT> bits = 0b11110101;
|
|
unsigned long val = bits.to_ulong();
|
|
std::vector<std::byte> data(sizeof(val));
|
|
std::memcpy(data.data(), &val, sizeof(val));
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::BOOLEAN;
|
|
|
|
size_t instanceCount = sizeof(unsigned long) * CHAR_BIT;
|
|
PropertyTablePropertyView<bool> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(instanceCount),
|
|
std::span<const std::byte>(data.data(), data.size()));
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == bits[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == property.getRaw(i));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check string PropertyTablePropertyView") {
|
|
std::vector<std::string> strings{
|
|
"This is a fine test",
|
|
"What's going on",
|
|
"Good morning"};
|
|
size_t totalSize = 0;
|
|
for (const auto& s : strings) {
|
|
totalSize += s.size();
|
|
}
|
|
|
|
uint32_t currentOffset = 0;
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(totalSize);
|
|
for (size_t i = 0; i < strings.size(); ++i) {
|
|
std::memcpy(
|
|
buffer.data() + currentOffset,
|
|
strings[i].data(),
|
|
strings[i].size());
|
|
currentOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
|
|
// copy offset to buffer
|
|
std::vector<std::byte> offsetBuffer;
|
|
offsetBuffer.resize((strings.size() + 1) * sizeof(uint32_t));
|
|
currentOffset = 0;
|
|
for (size_t i = 0; i < strings.size(); ++i) {
|
|
std::memcpy(
|
|
offsetBuffer.data() + i * sizeof(uint32_t),
|
|
¤tOffset,
|
|
sizeof(uint32_t));
|
|
currentOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
std::memcpy(
|
|
offsetBuffer.data() + strings.size() * sizeof(uint32_t),
|
|
¤tOffset,
|
|
sizeof(uint32_t));
|
|
|
|
SUBCASE("Returns correct values") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
|
|
PropertyTablePropertyView<std::string_view> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(strings.size()),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == strings[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == strings[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Uses NoData value") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.noData = "What's going on";
|
|
|
|
PropertyTablePropertyView<std::string_view> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(strings.size()),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
std::vector<std::optional<std::string_view>> expected{
|
|
strings[0],
|
|
std::nullopt,
|
|
strings[2]};
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == strings[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
|
|
SUBCASE("Uses NoData and Default value") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.noData = "What's going on";
|
|
classProperty.defaultProperty = "Hello";
|
|
|
|
PropertyTablePropertyView<std::string_view> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(strings.size()),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(offsetBuffer.data(), offsetBuffer.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
std::vector<std::optional<std::string_view>> expected{
|
|
strings[0],
|
|
"Hello",
|
|
strings[2]};
|
|
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
REQUIRE(property.getRaw(i) == strings[static_cast<size_t>(i)]);
|
|
REQUIRE(property.get(i) == expected[static_cast<size_t>(i)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") {
|
|
SUBCASE("Array of 4 uint8_ts") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
210, 211, 3, 42,
|
|
122, 22, 1, 45};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 3 int8_ts") {
|
|
// clang-format off
|
|
std::vector<int8_t> data{
|
|
122, -12, 3,
|
|
44, 11, -2,
|
|
5, 6, -22,
|
|
5, 6, 1};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 3);
|
|
}
|
|
|
|
SUBCASE("Array of 4 int16_ts") {
|
|
// clang-format off
|
|
std::vector<int16_t> data{
|
|
-122, 12, 3, 44,
|
|
11, 2, 5, -6000,
|
|
119, 30, 51, 200,
|
|
22000, -500, 6000, 1};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 6 uint32_ts") {
|
|
// clang-format off
|
|
std::vector<uint32_t> data{
|
|
122, 12, 3, 44, 34444, 2222,
|
|
11, 2, 5, 6000, 1111, 2222,
|
|
119, 30, 51, 200, 12534, 11,
|
|
22000, 500, 6000, 1, 3, 7};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 6);
|
|
}
|
|
|
|
SUBCASE("Array of 2 int32_ts") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
122, 12,
|
|
-3, 44};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 2);
|
|
}
|
|
|
|
SUBCASE("Array of 4 uint64_ts") {
|
|
// clang-format off
|
|
std::vector<uint64_t> data{
|
|
10022, 120000, 2422, 1111,
|
|
3, 440000, 333, 1455};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 4 int64_ts") {
|
|
// clang-format off
|
|
std::vector<int64_t> data{
|
|
10022, -120000, 2422, 1111,
|
|
3, 440000, -333, 1455};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 4 floats") {
|
|
// clang-format off
|
|
std::vector<float> data{
|
|
10.022f, -12.43f, 242.2f, 1.111f,
|
|
3.333f, 440000.1f, -33.3f, 14.55f};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 4 double") {
|
|
// clang-format off
|
|
std::vector<double> data{
|
|
10.022, -12.43, 242.2, 1.111,
|
|
3.333, 440000.1, -33.3, 14.55};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 4 uint8_ts") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
210, 211, 3, 42,
|
|
122, 22, 1, 45};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 4 floats with offset / scale") {
|
|
// clang-format off
|
|
std::vector<float> data{
|
|
1.0f, 2.0f, 3.0f, 4.0f,
|
|
5.0f, -1.0f, 0.0f, 2.0f
|
|
};
|
|
// clang-format on
|
|
|
|
JsonValue::Array offset{1.0f, 0.0f, -1.0f, 0.0f};
|
|
JsonValue::Array scale{1.0f, 2.0f, 1.0f, 2.0f};
|
|
|
|
std::vector<std::optional<std::vector<float>>> expected{
|
|
std::vector<float>{2.0f, 4.0f, 2.0f, 8.0f},
|
|
std::vector<float>{6.0f, -2.0f, -1.0f, 4.0f}};
|
|
checkFixedLengthArray(data, 4, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Array of 2 int32_ts with noData value") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
122, 12,
|
|
-1, -1,
|
|
-3, 44};
|
|
// clang-format on
|
|
JsonValue::Array noData{-1, -1};
|
|
std::vector<std::optional<std::vector<int32_t>>> expected{
|
|
std::vector<int32_t>{122, 12},
|
|
std::nullopt,
|
|
std::vector<int32_t>{-3, 44}};
|
|
checkFixedLengthArray<int32_t>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
}
|
|
|
|
SUBCASE("Array of 2 int32_ts with noData and default value") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
122, 12,
|
|
-1, -1,
|
|
-3, 44};
|
|
// clang-format on
|
|
JsonValue::Array noData{-1, -1};
|
|
JsonValue::Array defaultValue{0, 1};
|
|
std::vector<std::optional<std::vector<int32_t>>> expected{
|
|
std::vector<int32_t>{122, 12},
|
|
std::vector<int32_t>{0, 1},
|
|
std::vector<int32_t>{-3, 44}};
|
|
checkFixedLengthArray<int32_t>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
// clang-format off
|
|
std::vector<float> data{
|
|
1.0f, 2.0f, 3.0f, 4.0f,
|
|
0.0f, -1.0f, 1.0f, -2.0f};
|
|
// clang-format on
|
|
const int64_t count = 4;
|
|
const int64_t instanceCount = 2;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(float));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::SCALAR;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = count;
|
|
classProperty.offset = {0, 0, 0, 0};
|
|
classProperty.scale = {1, 1, 1, 1};
|
|
classProperty.min = {0.0f, -1.0f, 1.0f, -2.0f};
|
|
classProperty.max = {1.0f, 2.0f, 3.0f, 4.0f};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
propertyTableProperty.offset = {2, 1, 0, -1};
|
|
propertyTableProperty.scale = {1, 0, 1, -1};
|
|
propertyTableProperty.min = {0.0f, 1.0f, 1.0f, -2.0f};
|
|
propertyTableProperty.max = {1.0f, 1.0f, 3.0f, 4.0f};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<float>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == count);
|
|
REQUIRE(property.size() == instanceCount);
|
|
|
|
REQUIRE(property.offset());
|
|
checkArrayEqual(*property.offset(), {2, 1, 0, -1});
|
|
|
|
REQUIRE(property.scale());
|
|
checkArrayEqual(*property.scale(), {1, 0, 1, -1});
|
|
|
|
REQUIRE(property.min());
|
|
checkArrayEqual(*property.min(), {0.0f, 1.0f, 1.0f, -2.0f});
|
|
|
|
REQUIRE(property.max());
|
|
checkArrayEqual(*property.max(), {1.0f, 1.0f, 3.0f, 4.0f});
|
|
|
|
std::vector<std::vector<float>> expected{
|
|
{3.0f, 1.0, 3.0f, -5.0f},
|
|
{2.0f, 1.0f, 1.0f, 1.0f}};
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<float> rawValues = property.getRaw(i);
|
|
auto values = property.get(i);
|
|
REQUIRE(values);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
REQUIRE(
|
|
(*values)[j] ==
|
|
expected[static_cast<size_t>(i)][static_cast<size_t>(j)]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Check fixed-length scalar array PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Array of 4 uint8_ts") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
255, 64, 0, 255,
|
|
128, 0, 255, 0};
|
|
// clang-format on
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{1.0, 64.0 / 255.0, 0.0, 1.0},
|
|
std::vector<double>{128.0 / 255.0, 0.0, 1.0, 0.0}};
|
|
checkNormalizedFixedLengthArray(data, 4, expected);
|
|
}
|
|
|
|
SUBCASE("Array of 3 normalized int8_ts with all properties") {
|
|
// clang-format off
|
|
std::vector<int8_t> data{
|
|
-128, 0, 64,
|
|
-64, 127, -128,
|
|
0, 0, 0};
|
|
// clang-format on
|
|
JsonValue::Array offset{0, 1, 1};
|
|
JsonValue::Array scale{1, -1, 2};
|
|
JsonValue::Array noData{0, 0, 0};
|
|
JsonValue::Array defaultValue{10, 8, 2};
|
|
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)},
|
|
std::vector<double>{-64.0 / 127.0, 0.0, -1.0},
|
|
std::vector<double>{10.0, 8.0, 2.0},
|
|
};
|
|
checkNormalizedFixedLengthArray(
|
|
data,
|
|
3,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") {
|
|
SUBCASE("Array of 4 u8vec2s") {
|
|
std::vector<glm::u8vec2> data{
|
|
glm::u8vec2(10, 21),
|
|
glm::u8vec2(3, 42),
|
|
glm::u8vec2(122, 22),
|
|
glm::u8vec2(1, 45),
|
|
glm::u8vec2(0, 0),
|
|
glm::u8vec2(32, 12),
|
|
glm::u8vec2(8, 19),
|
|
glm::u8vec2(6, 5)};
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 2 i8vec3s") {
|
|
std::vector<glm::i8vec3> data{
|
|
glm::i8vec3(122, -12, 3),
|
|
glm::i8vec3(44, 11, -2),
|
|
glm::i8vec3(5, 6, -22),
|
|
glm::i8vec3(5, 6, 1),
|
|
glm::i8vec3(8, -7, 7),
|
|
glm::i8vec3(-4, 36, 17)};
|
|
checkFixedLengthArray(data, 2);
|
|
}
|
|
|
|
SUBCASE("Array of 3 vec4s") {
|
|
std::vector<glm::vec4> data{
|
|
glm::vec4(40.2f, -1.2f, 8.8f, 1.0f),
|
|
glm::vec4(1.4f, 0.11, 34.0f, 0.0f),
|
|
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f),
|
|
glm::vec4(1.0f, 2.0f, 3.0f, 6.0f),
|
|
glm::vec4(1.08f, -3.71f, 18.0f, -7.0f),
|
|
glm::vec4(-17.0f, 33.0f, 8.0f, -3.0f)};
|
|
checkFixedLengthArray(data, 3);
|
|
}
|
|
|
|
SUBCASE("Array of 2 vec2s with offset / scale") {
|
|
// clang-format off
|
|
std::vector<glm::vec2> data{
|
|
glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f),
|
|
glm::vec2(5.0f, -1.0f), glm::vec2(0.0f, 2.0f)
|
|
};
|
|
// clang-format on
|
|
|
|
JsonValue::Array offset{{1.0f, 0.0f}, {-1.0f, 0.0f}};
|
|
JsonValue::Array scale{{1.0f, 2.0f}, {1.0f, 2.0f}};
|
|
|
|
std::vector<std::optional<std::vector<glm::vec2>>> expected{
|
|
std::vector<glm::vec2>{glm::vec2(2.0f, 4.0f), glm::vec2(2.0f, 8.0f)},
|
|
std::vector<glm::vec2>{glm::vec2(6.0f, -2.0f), glm::vec2(-1.0f, 4.0f)}};
|
|
checkFixedLengthArray(data, 2, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Array of 2 ivec2 with noData value") {
|
|
// clang-format off
|
|
std::vector<glm::ivec2> data{
|
|
glm::ivec2(122, 12), glm::ivec2(-1, -1),
|
|
glm::ivec2( -3, 44), glm::ivec2(0, 7),
|
|
glm::ivec2(-1, -1), glm::ivec2(0, 0)};
|
|
// clang-format on
|
|
JsonValue::Array noData{{-1, -1}, {0, 0}};
|
|
std::vector<std::optional<std::vector<glm::ivec2>>> expected{
|
|
std::vector<glm::ivec2>{glm::ivec2(122, 12), glm::ivec2(-1, -1)},
|
|
std::vector<glm::ivec2>{glm::ivec2(-3, 44), glm::ivec2(0, 7)},
|
|
std::nullopt};
|
|
checkFixedLengthArray<glm::ivec2>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
}
|
|
|
|
SUBCASE("Array of 2 ivec2 with noData and default value") {
|
|
// clang-format off
|
|
std::vector<glm::ivec2> data{
|
|
glm::ivec2(122, 12), glm::ivec2(-1, -1),
|
|
glm::ivec2( -3, 44), glm::ivec2(0, 7),
|
|
glm::ivec2(-1, -1), glm::ivec2(0, 0)};
|
|
// clang-format on
|
|
JsonValue::Array noData{{-1, -1}, {0, 0}};
|
|
JsonValue::Array defaultValue{{1, 1}, {1, 2}};
|
|
std::vector<std::optional<std::vector<glm::ivec2>>> expected{
|
|
std::vector<glm::ivec2>{glm::ivec2(122, 12), glm::ivec2(-1, -1)},
|
|
std::vector<glm::ivec2>{glm::ivec2(-3, 44), glm::ivec2(0, 7)},
|
|
std::vector<glm::ivec2>{glm::ivec2(1, 1), glm::ivec2(1, 2)}};
|
|
checkFixedLengthArray<glm::ivec2>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
// clang-format off
|
|
std::vector<glm::vec2> data{
|
|
glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f),
|
|
glm::vec2(0.0f, -1.0f), glm::vec2(1.0f, -2.0f)};
|
|
// clang-format on
|
|
const int64_t count = 2;
|
|
const int64_t instanceCount = 2;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(glm::vec2));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::VEC2;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = count;
|
|
classProperty.offset = JsonValue::Array{{0, 0}, {0, 0}};
|
|
classProperty.scale = JsonValue::Array{{1, 1}, {1, 1}};
|
|
classProperty.min = JsonValue::Array{{0.0f, -1.0f}, {1.0f, -2.0f}};
|
|
classProperty.max = JsonValue::Array{{1.0f, 2.0f}, {3.0f, 4.0f}};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
propertyTableProperty.offset = JsonValue::Array{{2, 1}, {0, -1}};
|
|
propertyTableProperty.scale = JsonValue::Array{{1, 0}, {1, -1}};
|
|
propertyTableProperty.min = JsonValue::Array{{0.0f, 1.0f}, {1.0f, -2.0f}};
|
|
propertyTableProperty.max = JsonValue::Array{{1.0f, 1.0f}, {3.0f, 4.0f}};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<glm::vec2>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == count);
|
|
REQUIRE(property.size() == instanceCount);
|
|
|
|
REQUIRE(property.offset());
|
|
checkArrayEqual(*property.offset(), {glm::vec2{2, 1}, glm::vec2{0, -1}});
|
|
|
|
REQUIRE(property.scale());
|
|
checkArrayEqual(*property.scale(), {glm::vec2{1, 0}, glm::vec2{1, -1}});
|
|
|
|
REQUIRE(property.min());
|
|
checkArrayEqual(
|
|
*property.min(),
|
|
{glm::vec2{0.0f, 1.0f}, glm::vec2{1.0f, -2.0f}});
|
|
|
|
REQUIRE(property.max());
|
|
checkArrayEqual(
|
|
*property.max(),
|
|
{glm::vec2(1.0f, 1.0f), glm::vec2(3.0f, 4.0f)});
|
|
|
|
std::vector<std::vector<glm::vec2>> expected{
|
|
{glm::vec2(3.0f, 1.0f), glm::vec2(3.0f, -5.0f)},
|
|
{glm::vec2(2.0f, 1.0f), glm::vec2(1.0f, 1.0f)}};
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<glm::vec2> rawValues = property.getRaw(i);
|
|
auto values = property.get(i);
|
|
REQUIRE(values);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
REQUIRE(
|
|
(*values)[j] ==
|
|
expected[static_cast<size_t>(i)][static_cast<size_t>(j)]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Check fixed-length vecN array PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Array of 2 u8vec2s") {
|
|
std::vector<glm::u8vec2> data{
|
|
glm::u8vec2(255, 64),
|
|
glm::u8vec2(0, 255),
|
|
glm::u8vec2(128, 0),
|
|
glm::u8vec2(255, 0)};
|
|
std::vector<std::optional<std::vector<glm::dvec2>>> expected{
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(1.0, 64.0 / 255.0),
|
|
glm::dvec2(0.0, 1.0)},
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(128.0 / 255.0, 0.0),
|
|
glm::dvec2(1.0, 0.0)}};
|
|
checkNormalizedFixedLengthArray(data, 2, expected);
|
|
}
|
|
|
|
SUBCASE("Array of 2 i8vec2 with all properties") {
|
|
// clang-format off
|
|
std::vector<glm::i8vec2> data{
|
|
glm::i8vec2(-128, 0), glm::i8vec2(64, -64),
|
|
glm::i8vec2(127, -128), glm::i8vec2(0, 0),
|
|
glm::i8vec2(0), glm::i8vec2(0)};
|
|
// clang-format on
|
|
JsonValue::Array offset{{0, 1}, {1, 2}};
|
|
JsonValue::Array scale{{1, -1}, {2, 1}};
|
|
JsonValue::Array noData{{0, 0}, {0, 0}};
|
|
JsonValue::Array defaultValue{{10, 2}, {4, 8}};
|
|
|
|
std::vector<std::optional<std::vector<glm::dvec2>>> expected{
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(-1.0, 1.0),
|
|
glm::dvec2(1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0))},
|
|
std::vector<glm::dvec2>{glm::dvec2(1, 2), glm::dvec2(1, 2)},
|
|
std::vector<glm::dvec2>{glm::dvec2(10, 2), glm::dvec2(4, 8)},
|
|
};
|
|
checkNormalizedFixedLengthArray(
|
|
data,
|
|
2,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
// clang-format off
|
|
std::vector<glm::vec2> data{
|
|
glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f),
|
|
glm::vec2(0.0f, -1.0f), glm::vec2(1.0f, -2.0f)};
|
|
// clang-format on
|
|
const int64_t count = 2;
|
|
const int64_t instanceCount = 2;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(glm::vec2));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::VEC2;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = count;
|
|
classProperty.offset = JsonValue::Array{{0, 0}, {0, 0}};
|
|
classProperty.scale = JsonValue::Array{{1, 1}, {1, 1}};
|
|
classProperty.min = JsonValue::Array{{0.0f, -1.0f}, {1.0f, -2.0f}};
|
|
classProperty.max = JsonValue::Array{{1.0f, 2.0f}, {3.0f, 4.0f}};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
propertyTableProperty.offset = JsonValue::Array{{2, 1}, {0, -1}};
|
|
propertyTableProperty.scale = JsonValue::Array{{1, 0}, {1, -1}};
|
|
propertyTableProperty.min = JsonValue::Array{{0.0f, 1.0f}, {1.0f, -2.0f}};
|
|
propertyTableProperty.max = JsonValue::Array{{1.0f, 1.0f}, {3.0f, 4.0f}};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<glm::vec2>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == count);
|
|
REQUIRE(property.size() == instanceCount);
|
|
|
|
REQUIRE(property.offset());
|
|
checkArrayEqual(*property.offset(), {glm::vec2{2, 1}, glm::vec2{0, -1}});
|
|
|
|
REQUIRE(property.scale());
|
|
checkArrayEqual(*property.scale(), {glm::vec2{1, 0}, glm::vec2{1, -1}});
|
|
|
|
REQUIRE(property.min());
|
|
checkArrayEqual(
|
|
*property.min(),
|
|
{glm::vec2{0.0f, 1.0f}, glm::vec2{1.0f, -2.0f}});
|
|
|
|
REQUIRE(property.max());
|
|
checkArrayEqual(
|
|
*property.max(),
|
|
{glm::vec2(1.0f, 1.0f), glm::vec2(3.0f, 4.0f)});
|
|
|
|
std::vector<std::vector<glm::vec2>> expected{
|
|
{glm::vec2(3.0f, 1.0f), glm::vec2(3.0f, -5.0f)},
|
|
{glm::vec2(2.0f, 1.0f), glm::vec2(1.0f, 1.0f)}};
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<glm::vec2> rawValues = property.getRaw(i);
|
|
auto values = property.get(i);
|
|
REQUIRE(values);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
REQUIRE(
|
|
(*values)[j] ==
|
|
expected[static_cast<size_t>(i)][static_cast<size_t>(j)]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") {
|
|
SUBCASE("Array of 4 i8mat2x2") {
|
|
// clang-format off
|
|
std::vector<glm::i8mat2x2> data{
|
|
glm::i8mat2x2(
|
|
10, 21,
|
|
1, -2),
|
|
glm::i8mat2x2(
|
|
3, 42,
|
|
-10, 12),
|
|
glm::i8mat2x2(
|
|
122, 22,
|
|
80, -4),
|
|
glm::i8mat2x2(
|
|
15, -2,
|
|
17, 6),
|
|
glm::i8mat2x2(
|
|
0, 0,
|
|
-1, 1),
|
|
glm::i8mat2x2(
|
|
32, -12,
|
|
20, 4),
|
|
glm::i8mat2x2(
|
|
8, 19,
|
|
-7, 1),
|
|
glm::i8mat2x2(
|
|
6, 16,
|
|
2, 5)};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 4);
|
|
}
|
|
|
|
SUBCASE("Array of 2 dmat3s") {
|
|
// clang-format off
|
|
std::vector<glm::dmat3> data{
|
|
glm::dmat3(
|
|
1.0, 2.0, 3.0,
|
|
0.01, 0.02, 0.03,
|
|
4.0, 5.0, 6.0),
|
|
glm::dmat3(
|
|
0.2, -1.0, 8.0,
|
|
40.0, -8.0, 9.0,
|
|
10.0, 0.2, 0.34),
|
|
glm::dmat3(
|
|
7.2, 16.5, 4.2,
|
|
33.0, 3.5, -20.0,
|
|
1.22, 1.02, 30.34),
|
|
glm::dmat3(
|
|
1.2, 0.5, 0.0,
|
|
0.0, 3.5, 0.0,
|
|
0.76, 0.9, 1.1),
|
|
glm::dmat3(
|
|
25.0, 50.4, 8.8,
|
|
16.1, 23.0, 40.0,
|
|
0.8, 8.9, 5.0),
|
|
glm::dmat3(
|
|
-4.0, 9.4, 11.2,
|
|
5.5, 3.09, 0.301,
|
|
4.5, 52.4, 1.05)};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 2);
|
|
}
|
|
|
|
SUBCASE("Array of 3 u8mat4x4") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat4x4> data{
|
|
glm::u8mat4x4(
|
|
1, 2, 3, 4,
|
|
5, 6, 7, 8,
|
|
9, 10, 11, 12,
|
|
13, 14, 15, 16),
|
|
glm::u8mat4x4(
|
|
0, 4, 2, 19,
|
|
8, 7, 3, 5,
|
|
43, 21, 10, 9,
|
|
3, 10, 8, 6),
|
|
glm::u8mat4x4(
|
|
1, 0, 0, 19,
|
|
0, 1, 0, 2,
|
|
0, 0, 4, 0,
|
|
0, 0, 0, 1),
|
|
glm::u8mat4x4(
|
|
6, 2, 7, 8,
|
|
50, 11, 18, 2,
|
|
3, 12, 6, 9,
|
|
4, 20, 10, 4),
|
|
glm::u8mat4x4(
|
|
10, 2, 46, 5,
|
|
8, 7, 20, 13,
|
|
24, 8, 6, 9,
|
|
2, 15, 4, 3),
|
|
glm::u8mat4x4(
|
|
3, 2, 1, 0,
|
|
0, 1, 2, 3,
|
|
8, 7, 6, 5,
|
|
4, 3, 2, 1),};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 3);
|
|
}
|
|
|
|
SUBCASE("Array of 2 mat2s with offset / scale") {
|
|
// clang-format off
|
|
std::vector<glm::mat2> data{
|
|
glm::mat2(
|
|
1.0f, 2.0f,
|
|
3.0f, 4.0f),
|
|
glm::mat2(
|
|
5.0f, -1.0f,
|
|
0.0f, 2.0f),
|
|
glm::mat2(
|
|
-1.0f, -1.0f,
|
|
0.0f, -2.0f),
|
|
glm::mat2(
|
|
0.0f, -2.0f,
|
|
4.0f, 3.0f)};
|
|
|
|
JsonValue::Array offset{
|
|
{1.0f, 0.0f,
|
|
2.0f, 3.0f},
|
|
{-1.0f, 0.0f,
|
|
0.0f, 2.0f}};
|
|
JsonValue::Array scale{
|
|
{1.0f, 2.0f,
|
|
1.0f, 0.0f},
|
|
{1.0f, -1.0f,
|
|
-1.0f, 2.0f}};
|
|
|
|
std::vector<std::optional<std::vector<glm::mat2>>> expected{
|
|
std::vector<glm::mat2>{
|
|
glm::mat2(
|
|
2.0f, 4.0f,
|
|
5.0f, 3.0f),
|
|
glm::mat2(
|
|
4.0f, 1.0f,
|
|
0.0f, 6.0f)},
|
|
std::vector<glm::mat2>{
|
|
glm::mat2(
|
|
0.0f, -2.0f,
|
|
2.0f, 3.0f),
|
|
glm::mat2(
|
|
-1.0f, 2.0f,
|
|
-4.0f, 8.0f)}};
|
|
// clang-format on
|
|
checkFixedLengthArray(data, 2, expected, offset, scale);
|
|
}
|
|
|
|
SUBCASE("Array of 2 imat2x2 with noData value") {
|
|
// clang-format off
|
|
std::vector<glm::imat2x2> data{
|
|
glm::imat2x2(
|
|
122, 12,
|
|
4, 6),
|
|
glm::imat2x2(-1),
|
|
glm::imat2x2(
|
|
-3, 44,
|
|
7, 8),
|
|
glm::imat2x2(
|
|
0, 7,
|
|
-1, 0),
|
|
glm::imat2x2(-1),
|
|
glm::imat2x2(0)};
|
|
JsonValue::Array noData{
|
|
{-1, 0,
|
|
0, -1},
|
|
{0, 0,
|
|
0, 0}};
|
|
std::vector<std::optional<std::vector<glm::imat2x2>>> expected{
|
|
std::vector<glm::imat2x2>{
|
|
glm::imat2x2(
|
|
122, 12,
|
|
4, 6),
|
|
glm::imat2x2(-1)},
|
|
std::vector<glm::imat2x2>{
|
|
glm::imat2x2(
|
|
-3, 44,
|
|
7, 8),
|
|
glm::imat2x2(
|
|
0, 7,
|
|
-1, 0)},
|
|
std::nullopt};
|
|
// clang-format on
|
|
checkFixedLengthArray<glm::imat2x2>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
std::nullopt);
|
|
}
|
|
|
|
SUBCASE("Array of 2 imat2x2 with noData and default value") {
|
|
// clang-format off
|
|
std::vector<glm::imat2x2> data{
|
|
glm::imat2x2(
|
|
122, 12,
|
|
4, 6),
|
|
glm::imat2x2(-1),
|
|
glm::imat2x2(
|
|
-3, 44,
|
|
7, 8),
|
|
glm::imat2x2(
|
|
0, 7,
|
|
-1, 0),
|
|
glm::imat2x2(-1),
|
|
glm::imat2x2(0)};
|
|
JsonValue::Array noData{
|
|
{-1, 0,
|
|
0, -1},
|
|
{0, 0,
|
|
0, 0}};
|
|
JsonValue::Array defaultValue{
|
|
{2, 0,
|
|
0, 2},
|
|
{1, 0,
|
|
0, 1}
|
|
};
|
|
std::vector<std::optional<std::vector<glm::imat2x2>>> expected{
|
|
std::vector<glm::imat2x2>{
|
|
glm::imat2x2(
|
|
122, 12,
|
|
4, 6),
|
|
glm::imat2x2(-1)},
|
|
std::vector<glm::imat2x2>{
|
|
glm::imat2x2(
|
|
-3, 44,
|
|
7, 8),
|
|
glm::imat2x2(
|
|
0, 7,
|
|
-1, 0)},
|
|
std::vector<glm::imat2x2>{
|
|
glm::imat2x2(2),
|
|
glm::imat2x2(1)
|
|
}};
|
|
// clang-format on
|
|
checkFixedLengthArray<glm::imat2x2>(
|
|
data,
|
|
2,
|
|
expected,
|
|
std::nullopt,
|
|
std::nullopt,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Overrides class property values") {
|
|
// clang-format off
|
|
std::vector<glm::mat2> data{
|
|
glm::mat2(1.0f),
|
|
glm::mat2(2.0f),
|
|
glm::mat2(3.0f),
|
|
glm::mat2(4.0f)};
|
|
// clang-format on
|
|
const int64_t count = 2;
|
|
const int64_t instanceCount = 2;
|
|
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(data.size() * sizeof(glm::mat2));
|
|
std::memcpy(buffer.data(), data.data(), buffer.size());
|
|
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::MAT2;
|
|
classProperty.componentType = ClassProperty::ComponentType::FLOAT32;
|
|
|
|
classProperty.array = true;
|
|
classProperty.count = count;
|
|
// clang-format off
|
|
classProperty.offset = JsonValue::Array{
|
|
{0, 0,
|
|
0, 0},
|
|
{0, 0,
|
|
0, 0}};
|
|
classProperty.scale = JsonValue::Array{
|
|
{1, 1,
|
|
1, 1},
|
|
{1, 1,
|
|
1, 1}};
|
|
classProperty.min = JsonValue::Array{
|
|
{1.0f, 0.0f,
|
|
0.0f, 1.0f},
|
|
{2.0f, 0.0f,
|
|
0.0f, 2.0f}};
|
|
classProperty.max = JsonValue::Array{
|
|
{3.0f, 0.0f,
|
|
0.0f, 3.0f},
|
|
{4.0f, 0.0f,
|
|
0.0f, 4.0f}};
|
|
// clang-format on
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
// clang-format off
|
|
propertyTableProperty.offset = JsonValue::Array{
|
|
{2, 1,
|
|
-1, -2},
|
|
{0, -1,
|
|
4, 0}};
|
|
propertyTableProperty.scale = JsonValue::Array{
|
|
{1, 0,
|
|
1, 2},
|
|
{1, -1,
|
|
3, 2}};
|
|
propertyTableProperty.min = JsonValue::Array{
|
|
{2.0f, 1.0f,
|
|
-1.0f, 0.0f},
|
|
{2.0f, -1.0f,
|
|
-4.0f, 4.0f}};
|
|
propertyTableProperty.max = JsonValue::Array{
|
|
{5.0f, 1.0f,
|
|
-1.0f, 4.0f},
|
|
{4.0f, -1.0f,
|
|
4.0f, 8.0f}};
|
|
// clang-format on
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<glm::mat2>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
instanceCount,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.arrayCount() == count);
|
|
REQUIRE(property.size() == instanceCount);
|
|
|
|
// clang-format off
|
|
REQUIRE(property.offset());
|
|
checkArrayEqual(*property.offset(), {
|
|
glm::mat2(
|
|
2, 1,
|
|
-1, -2),
|
|
glm::mat2(
|
|
0, -1,
|
|
4, 0)});
|
|
|
|
REQUIRE(property.scale());
|
|
checkArrayEqual(*property.scale(), {
|
|
glm::mat2(
|
|
1, 0,
|
|
1, 2),
|
|
glm::mat2(
|
|
1, -1,
|
|
3, 2)});
|
|
|
|
REQUIRE(property.min());
|
|
checkArrayEqual(*property.min(), {
|
|
glm::mat2{
|
|
2.0f, 1.0f,
|
|
-1.0f, 0.0f},
|
|
glm::mat2{
|
|
2.0f, -1.0f,
|
|
-4.0f, 4.0f}});
|
|
|
|
REQUIRE(property.max());
|
|
checkArrayEqual( *property.max(), {
|
|
glm::mat2(
|
|
5.0f, 1.0f,
|
|
-1.0f, 4.0f),
|
|
glm::mat2(
|
|
4.0f, -1.0f,
|
|
4.0f, 8.0f)});
|
|
|
|
std::vector<std::vector<glm::mat2>> expected{
|
|
{glm::mat2(
|
|
3.0f, 1.0f,
|
|
-1.0f, 0.0f),
|
|
glm::mat2(
|
|
2.0f, -1.0f,
|
|
4.0f, 4.0f)},
|
|
{glm::mat2(
|
|
5.0f, 1.0f,
|
|
-1.0f, 4.0f),
|
|
glm::mat2(
|
|
4.0f, -1.0f,
|
|
4.0f, 8.0f)}};
|
|
// clang-format on
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<glm::mat2> rawValues = property.getRaw(i);
|
|
auto values = property.get(i);
|
|
REQUIRE(values);
|
|
for (int64_t j = 0; j < rawValues.size(); ++j) {
|
|
REQUIRE(rawValues[j] == data[expectedIdx]);
|
|
REQUIRE(
|
|
(*values)[j] ==
|
|
expected[static_cast<size_t>(i)][static_cast<size_t>(j)]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Check fixed-length matN array PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Array of 2 u8mat2x2s") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> data{
|
|
glm::u8mat2x2(
|
|
255, 64,
|
|
0, 255),
|
|
glm::u8mat2x2(
|
|
0, 255,
|
|
64, 128),
|
|
glm::u8mat2x2(
|
|
128, 0,
|
|
0, 255),
|
|
glm::u8mat2x2(
|
|
255, 32,
|
|
255, 0)};
|
|
|
|
std::vector<std::optional<std::vector<glm::dmat2>>> expected{
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(
|
|
1.0, 64.0 / 255.0,
|
|
0.0, 1.0),
|
|
glm::dmat2(
|
|
0.0, 1.0,
|
|
64.0 / 255.0, 128.0 / 255.0),
|
|
},
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(
|
|
128.0 / 255.0, 0.0,
|
|
0.0, 1.0),
|
|
glm::dmat2(
|
|
1.0, 32.0 / 255.0,
|
|
1.0, 0.0),
|
|
}};
|
|
// clang-format on
|
|
|
|
checkNormalizedFixedLengthArray(data, 2, expected);
|
|
}
|
|
|
|
SUBCASE("Array of 2 i8mat2x2 with all properties") {
|
|
// clang-format off
|
|
std::vector<glm::i8mat2x2> data{
|
|
glm::i8mat2x2(-128),
|
|
glm::i8mat2x2(
|
|
64, -64,
|
|
0, 255),
|
|
glm::i8mat2x2(
|
|
127, -128,
|
|
-128, 0),
|
|
glm::i8mat2x2(0),
|
|
glm::i8mat2x2(0),
|
|
glm::i8mat2x2(
|
|
-128, -128,
|
|
-128, -128)};
|
|
JsonValue::Array offset{
|
|
{0, 1,
|
|
2, 3},
|
|
{1, 2,
|
|
0, -2}};
|
|
JsonValue::Array scale{
|
|
{1, -1,
|
|
0, 1},
|
|
{2, 1,
|
|
-1, 0}};
|
|
JsonValue::Array noData{
|
|
{0, 0,
|
|
0, 0},
|
|
{-128, -128,
|
|
-128, -128}};
|
|
JsonValue::Array defaultValue{
|
|
{1, 0,
|
|
0, 1},
|
|
{2, 0,
|
|
0, 2}};
|
|
|
|
std::vector<std::optional<std::vector<glm::dmat2>>> expected{
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(
|
|
-1.0, 1.0,
|
|
2.0, 2.0),
|
|
glm::dmat2(
|
|
1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0),
|
|
0, -2)},
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(
|
|
1.0, 2.0,
|
|
2.0, 3.0),
|
|
glm::dmat2(
|
|
1.0, 2.0,
|
|
0.0, -2.0)},
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(1),
|
|
glm::dmat2(2)},
|
|
};
|
|
// clang-format on
|
|
checkNormalizedFixedLengthArray(
|
|
data,
|
|
2,
|
|
expected,
|
|
offset,
|
|
scale,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") {
|
|
SUBCASE("Array of uint8_t") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
3, 2,
|
|
0, 45, 2, 1, 4,
|
|
1, 3, 2,
|
|
1, 3, 4, 1
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 7, 10, 14};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4);
|
|
}
|
|
|
|
SUBCASE("Array of int32_t") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
3, 200,
|
|
0, 450, 200, 1, 4,
|
|
1, 3, 2,
|
|
1, 3, 4, 1
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 7, 10, 14};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4);
|
|
}
|
|
|
|
SUBCASE("Array of double") {
|
|
// clang-format off
|
|
std::vector<double> data{
|
|
3.333, 200.2,
|
|
0.1122, 4.50, 2.30, 1.22, 4.444,
|
|
1.4, 3.3, 2.2,
|
|
1.11, 3.2, 4.111, 1.44
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 7, 10, 14};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4);
|
|
}
|
|
|
|
SUBCASE("Array of normalized uint8_t") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
255, 0,
|
|
0, 255, 128,
|
|
64,
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 5, 6};
|
|
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{1.0, 0.0},
|
|
std::vector<double>{0.0, 1.0, 128.0 / 255.0},
|
|
std::vector<double>{64.0 / 255.0},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected);
|
|
}
|
|
|
|
SUBCASE("Array of int32_t with NoData") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
3, 200,
|
|
0, 450, 200, 1, 4,
|
|
1, 3, 2,
|
|
0,
|
|
1, 3, 4, 1
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 7, 10, 11, 15};
|
|
|
|
JsonValue::Array noData{0};
|
|
|
|
std::vector<std::optional<std::vector<int32_t>>> expected{
|
|
std::vector<int32_t>{3, 200},
|
|
std::vector<int32_t>{0, 450, 200, 1, 4},
|
|
std::vector<int32_t>{1, 3, 2},
|
|
std::nullopt,
|
|
std::vector<int32_t>{1, 3, 4, 1}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData);
|
|
}
|
|
|
|
SUBCASE("Array of int32_t with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<int32_t> data{
|
|
3, 200,
|
|
0, 450, 200, 1, 4,
|
|
1, 3, 2,
|
|
0,
|
|
1, 3, 4, 1
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 7, 10, 11, 15};
|
|
|
|
JsonValue::Array noData{0};
|
|
JsonValue::Array defaultValue{1};
|
|
|
|
std::vector<std::optional<std::vector<int32_t>>> expected{
|
|
std::vector<int32_t>{3, 200},
|
|
std::vector<int32_t>{0, 450, 200, 1, 4},
|
|
std::vector<int32_t>{1, 3, 2},
|
|
std::vector<int32_t>{1},
|
|
std::vector<int32_t>{1, 3, 4, 1}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
|
|
SUBCASE("Array of normalized uint8_t with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
255, 0,
|
|
0, 255, 128,
|
|
64,
|
|
255, 255
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 5, 6, 8};
|
|
|
|
JsonValue::Array noData{255, 255};
|
|
JsonValue::Array defaultValue{-1.0};
|
|
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{1.0, 0.0},
|
|
std::vector<double>{0.0, 1.0, 128.0 / 255.0},
|
|
std::vector<double>{64.0 / 255},
|
|
std::vector<double>{-1.0},
|
|
};
|
|
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
4,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length scalar array PropertyTablePropertyView "
|
|
"(normalized)") {
|
|
SUBCASE("Array of uint8_t") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
255, 0,
|
|
0, 255, 128,
|
|
64,
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 5, 6};
|
|
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{1.0, 0.0},
|
|
std::vector<double>{0.0, 1.0, 128.0 / 255.0},
|
|
std::vector<double>{64.0 / 255.0},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected);
|
|
}
|
|
|
|
SUBCASE("Array of uint8_t with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<uint8_t> data{
|
|
255, 0,
|
|
0, 255, 128,
|
|
64,
|
|
255, 255
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 5, 6, 8};
|
|
|
|
JsonValue::Array noData{255, 255};
|
|
JsonValue::Array defaultValue{-1.0};
|
|
|
|
std::vector<std::optional<std::vector<double>>> expected{
|
|
std::vector<double>{1.0, 0.0},
|
|
std::vector<double>{0.0, 1.0, 128.0 / 255.0},
|
|
std::vector<double>{64.0 / 255},
|
|
std::vector<double>{-1.0},
|
|
};
|
|
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
4,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") {
|
|
SUBCASE("Array of ivec2") {
|
|
// clang-format off
|
|
std::vector<glm::ivec2> data{
|
|
glm::ivec2(3, -2), glm::ivec2(20, 3),
|
|
glm::ivec2(0, 45), glm::ivec2(-10, 2), glm::ivec2(4, 4), glm::ivec2(1, -1),
|
|
glm::ivec2(3, 1), glm::ivec2(3, 2), glm::ivec2(0, -5),
|
|
glm::ivec2(-9, 10), glm::ivec2(8, -2)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 6, 9, 11};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4);
|
|
}
|
|
|
|
SUBCASE("Array of dvec3") {
|
|
// clang-format off
|
|
std::vector<glm::dvec3> data{
|
|
glm::dvec3(-0.02, 2.0, 1.0), glm::dvec3(9.92, 9.0, -8.0),
|
|
glm::dvec3(22.0, 5.5, -3.7), glm::dvec3(1.02, 9.0, -8.0), glm::dvec3(0.0, 0.5, 1.0),
|
|
glm::dvec3(-1.3, -5.0, -90.0),
|
|
glm::dvec3(4.4, 1.0, 2.3), glm::dvec3(5.8, 7.07, -4.0),
|
|
glm::dvec3(-2.0, 0.85, 0.22), glm::dvec3(-8.8, 5.1, 0.0), glm::dvec3(12.0, 8.0, -2.2),
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 5, 6, 8, 11};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5);
|
|
}
|
|
|
|
SUBCASE("Array of u8vec4") {
|
|
// clang-format off
|
|
std::vector<glm::u8vec4> data{
|
|
glm::u8vec4(1, 2, 3, 4), glm::u8vec4(5, 6, 7, 8),
|
|
glm::u8vec4(9, 2, 1, 0),
|
|
glm::u8vec4(8, 7, 10, 21), glm::u8vec4(3, 6, 8, 0), glm::u8vec4(0, 0, 0, 1),
|
|
glm::u8vec4(64, 8, 17, 5), glm::u8vec4(35, 23, 10, 0),
|
|
glm::u8vec4(99, 8, 1, 2)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6, 8, 9};
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5);
|
|
}
|
|
|
|
SUBCASE("Array of ivec3 with NoData") {
|
|
// clang-format off
|
|
std::vector<glm::ivec3> data{
|
|
glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6),
|
|
glm::ivec3(-1, 0, -450),
|
|
glm::ivec3(200, 1, 4), glm::ivec3(1, 3, 2), glm::ivec3(0),
|
|
glm::ivec3(-1),
|
|
glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6, 7, 9};
|
|
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{-1, -1, -1});
|
|
|
|
std::vector<std::optional<std::vector<glm::ivec3>>> expected{
|
|
std::vector<glm::ivec3>{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)},
|
|
std::vector<glm::ivec3>{glm::ivec3(-1, 0, -450)},
|
|
std::vector<glm::ivec3>{
|
|
glm::ivec3(200, 1, 4),
|
|
glm::ivec3(1, 3, 2),
|
|
glm::ivec3(0)},
|
|
std::nullopt,
|
|
std::vector<glm::ivec3>{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData);
|
|
}
|
|
|
|
SUBCASE("Array of ivec3 with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<glm::ivec3> data{
|
|
glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6),
|
|
glm::ivec3(-1, 0, -450),
|
|
glm::ivec3(200, 1, 4), glm::ivec3(1, 3, 2), glm::ivec3(0),
|
|
glm::ivec3(-1),
|
|
glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6, 7, 9};
|
|
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{-1, -1, -1});
|
|
JsonValue::Array defaultValue{};
|
|
defaultValue.push_back(JsonValue::Array{0, 0, 0});
|
|
|
|
std::vector<std::optional<std::vector<glm::ivec3>>> expected{
|
|
std::vector<glm::ivec3>{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)},
|
|
std::vector<glm::ivec3>{glm::ivec3(-1, 0, -450)},
|
|
std::vector<glm::ivec3>{
|
|
glm::ivec3(200, 1, 4),
|
|
glm::ivec3(1, 3, 2),
|
|
glm::ivec3(0)},
|
|
std::vector<glm::ivec3>{glm::ivec3(0)},
|
|
std::vector<glm::ivec3>{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Check variable-length vecN array PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Array of u8vec2") {
|
|
// clang-format off
|
|
std::vector<glm::u8vec2> data{
|
|
glm::u8vec2(255, 0), glm::u8vec2(0, 64),
|
|
glm::u8vec2(0, 0),
|
|
glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6};
|
|
|
|
std::vector<std::optional<std::vector<glm::dvec2>>> expected{
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(1.0, 0.0),
|
|
glm::dvec2(0.0, 64.0 / 255.0)},
|
|
std::vector<glm::dvec2>{glm::dvec2(0.0, 0.0)},
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(128.0 / 255.0, 1.0),
|
|
glm::dvec2(1.0, 1.0),
|
|
glm::dvec2(32.0 / 255.0, 64.0 / 255.0)},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected);
|
|
}
|
|
|
|
SUBCASE("Array of normalized u8vec2 with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<glm::u8vec2> data{
|
|
glm::u8vec2(255, 0), glm::u8vec2(0, 64),
|
|
glm::u8vec2(0, 0),
|
|
glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6};
|
|
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{0, 0});
|
|
JsonValue::Array defaultValue{};
|
|
defaultValue.push_back(JsonValue::Array{-1.0, -1.0});
|
|
|
|
std::vector<std::optional<std::vector<glm::dvec2>>> expected{
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(1.0, 0.0),
|
|
glm::dvec2(0.0, 64.0 / 255.0)},
|
|
std::vector<glm::dvec2>{glm::dvec2(-1.0)},
|
|
std::vector<glm::dvec2>{
|
|
glm::dvec2(128.0 / 255.0, 1.0),
|
|
glm::dvec2(1.0, 1.0),
|
|
glm::dvec2(32.0 / 255.0, 64.0 / 255.0)},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length matN array PropertyTablePropertyView") {
|
|
SUBCASE("Array of dmat2") {
|
|
// clang-format off
|
|
std::vector<glm::dmat2> data0{
|
|
glm::dmat2(
|
|
3.23, -2.456,
|
|
1.0, 0.003),
|
|
glm::dmat2(
|
|
40.0, 3.66,
|
|
8.567, -9.8)
|
|
};
|
|
std::vector<glm::dmat2> data1{
|
|
glm::dmat2(
|
|
1.1, 10.02,
|
|
7.0, 0.0),
|
|
};
|
|
std::vector<glm::dmat2> data2{
|
|
glm::dmat2(
|
|
18.8, 0.0,
|
|
1.0, 17.2),
|
|
glm::dmat2(
|
|
-4.0, -0.053,
|
|
-9.0, 1.0),
|
|
glm::dmat2(
|
|
1.1, 8.88,
|
|
-99.0, 1.905),
|
|
};
|
|
// clang-format on
|
|
|
|
std::vector<glm::dmat2> data;
|
|
data.reserve(data0.size() + data1.size() + data2.size());
|
|
data.insert(data.end(), data0.begin(), data0.end());
|
|
data.insert(data.end(), data1.begin(), data1.end());
|
|
data.insert(data.end(), data2.begin(), data2.end());
|
|
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6};
|
|
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3);
|
|
}
|
|
|
|
SUBCASE("Array of i16mat3x3") {
|
|
// clang-format off
|
|
std::vector<glm::i16mat3x3> data0{
|
|
glm::i16mat3x3(
|
|
1, 0, 0,
|
|
0, -1, 0,
|
|
0, 0, 1),
|
|
};
|
|
std::vector<glm::i16mat3x3> data1{
|
|
glm::i16mat3x3(
|
|
2, 3, 0,
|
|
-9, 14, 4,
|
|
-2, -5, 10),
|
|
glm::i16mat3x3(
|
|
0, 5, 10,
|
|
-8, 33, 2,
|
|
-9, 8, 41),
|
|
glm::i16mat3x3(
|
|
10, -7, 8,
|
|
21, -9, 2,
|
|
3, 4, 5)
|
|
};
|
|
std::vector<glm::i16mat3x3> data2{
|
|
glm::i16mat3x3(
|
|
-10, 50, 30,
|
|
8, 17, 2,
|
|
16, 40, 3),
|
|
glm::i16mat3x3(
|
|
-9, 18, 8,
|
|
20, 3, 4,
|
|
16, 7, -9),
|
|
};
|
|
// clang-format on
|
|
|
|
std::vector<glm::i16mat3x3> data;
|
|
data.reserve(data0.size() + data1.size() + data2.size());
|
|
data.insert(data.end(), data0.begin(), data0.end());
|
|
data.insert(data.end(), data1.begin(), data1.end());
|
|
data.insert(data.end(), data2.begin(), data2.end());
|
|
|
|
std::vector<uint32_t> offsets{0, 1, 4, 6};
|
|
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3);
|
|
}
|
|
|
|
SUBCASE("Array of u8mat4x4") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat4x4> data0{
|
|
glm::u8mat4x4(
|
|
1, 0, 0, 0,
|
|
0, 4, 0, 0,
|
|
0, 0, 1, 10,
|
|
0, 0, 0, 1),
|
|
glm::u8mat4x4(
|
|
10, 0, 0, 8,
|
|
0, 5, 0, 4,
|
|
0, 0, 1, 3,
|
|
0, 0, 0, 1),
|
|
glm::u8mat4x4(
|
|
8, 0, 0, 9,
|
|
0, 3, 0, 11,
|
|
0, 0, 20, 0,
|
|
0, 0, 0, 1),
|
|
};
|
|
std::vector<glm::u8mat4x4> data1{
|
|
glm::u8mat4x4(
|
|
1, 2, 3, 4,
|
|
4, 3, 2, 1,
|
|
0, 9, 8, 7,
|
|
6, 5, 5, 6),
|
|
};
|
|
std::vector<glm::u8mat4x4> data2{
|
|
glm::u8mat4x4(
|
|
4, 1, 8, 9,
|
|
2, 6, 50, 1,
|
|
10, 20, 30, 9,
|
|
8, 7, 20, 4),
|
|
glm::u8mat4x4(
|
|
0, 2, 1, 0,
|
|
25, 19, 8, 2,
|
|
3, 6, 40, 50,
|
|
15, 9, 0, 3),
|
|
};
|
|
// clang-format on
|
|
|
|
std::vector<glm::u8mat4x4> data;
|
|
data.reserve(data0.size() + data1.size() + data2.size());
|
|
data.insert(data.end(), data0.begin(), data0.end());
|
|
data.insert(data.end(), data1.begin(), data1.end());
|
|
data.insert(data.end(), data2.begin(), data2.end());
|
|
|
|
std::vector<uint32_t> offsets{0, 3, 4, 6};
|
|
|
|
checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3);
|
|
}
|
|
|
|
SUBCASE("Array of imat3x3 with NoData") {
|
|
// clang-format off
|
|
std::vector<glm::imat3x3> data{
|
|
glm::imat3x3(3), glm::imat3x3(2),
|
|
glm::imat3x3(-1),
|
|
glm::imat3x3(200), glm::imat3x3(1), glm::imat3x3(0),
|
|
glm::imat3x3(-1),
|
|
glm::imat3x3(1), glm::imat3x3(24)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6, 7, 9};
|
|
|
|
// clang-format off
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{
|
|
-1, 0, 0,
|
|
0, -1, 0,
|
|
0, 0, -1});
|
|
// clang-format on
|
|
|
|
std::vector<std::optional<std::vector<glm::imat3x3>>> expected{
|
|
std::vector<glm::imat3x3>{glm::imat3x3(3), glm::imat3x3(2)},
|
|
std::nullopt,
|
|
std::vector<glm::imat3x3>{
|
|
glm::imat3x3(200),
|
|
glm::imat3x3(1),
|
|
glm::imat3x3(0)},
|
|
std::nullopt,
|
|
std::vector<glm::imat3x3>{glm::imat3x3(1), glm::imat3x3(24)}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData);
|
|
}
|
|
|
|
SUBCASE("Array of imat3x3 with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<glm::imat3x3> data{
|
|
glm::imat3x3(3), glm::imat3x3(2),
|
|
glm::imat3x3(-1),
|
|
glm::imat3x3(200), glm::imat3x3(1), glm::imat3x3(0),
|
|
glm::imat3x3(-1),
|
|
glm::imat3x3(1), glm::imat3x3(24)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6, 7, 9};
|
|
|
|
// clang-format off
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{
|
|
-1, 0, 0,
|
|
0, -1, 0,
|
|
0, 0, -1});
|
|
JsonValue::Array defaultValue{};
|
|
defaultValue.push_back(JsonValue::Array{
|
|
99, 0, 0,
|
|
0, 99, 0,
|
|
0, 0, 99});
|
|
// clang-format on
|
|
|
|
std::vector<std::optional<std::vector<glm::imat3x3>>> expected{
|
|
std::vector<glm::imat3x3>{glm::imat3x3(3), glm::imat3x3(2)},
|
|
std::vector<glm::imat3x3>{glm::imat3x3(99)},
|
|
std::vector<glm::imat3x3>{
|
|
glm::imat3x3(200),
|
|
glm::imat3x3(1),
|
|
glm::imat3x3(0)},
|
|
std::vector<glm::imat3x3>{glm::imat3x3(99)},
|
|
std::vector<glm::imat3x3>{glm::imat3x3(1), glm::imat3x3(24)}};
|
|
checkVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
5,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Check variable-length matN array PropertyTablePropertyView (normalized)") {
|
|
SUBCASE("Array of u8mat2x2") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> data{
|
|
glm::u8mat2x2(255), glm::u8mat2x2(64),
|
|
glm::u8mat2x2(0),
|
|
glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6};
|
|
|
|
std::vector<std::optional<std::vector<glm::dmat2>>> expected{
|
|
std::vector<glm::dmat2>{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)},
|
|
std::vector<glm::dmat2>{glm::dmat2(0.0)},
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(128.0 / 255.0),
|
|
glm::dmat2(1.0),
|
|
glm::dmat2(32.0 / 255.0)},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected);
|
|
}
|
|
|
|
SUBCASE("Array of u8mat2x2 with NoData and DefaultValue") {
|
|
// clang-format off
|
|
std::vector<glm::u8mat2x2> data{
|
|
glm::u8mat2x2(255), glm::u8mat2x2(64),
|
|
glm::u8mat2x2(0),
|
|
glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32)
|
|
};
|
|
// clang-format on
|
|
std::vector<uint32_t> offsets{0, 2, 3, 6};
|
|
|
|
// clang-format off
|
|
JsonValue::Array noData{};
|
|
noData.push_back(JsonValue::Array{
|
|
0, 0,
|
|
0, 0});
|
|
JsonValue::Array defaultValue{};
|
|
defaultValue.push_back(JsonValue::Array{
|
|
-1.0, 0.0,
|
|
0.0, -1.0});
|
|
// clang-format on
|
|
std::vector<std::optional<std::vector<glm::dmat2>>> expected{
|
|
std::vector<glm::dmat2>{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)},
|
|
std::vector<glm::dmat2>{glm::dmat2(-1.0)},
|
|
std::vector<glm::dmat2>{
|
|
glm::dmat2(128.0 / 255.0),
|
|
glm::dmat2(1.0),
|
|
glm::dmat2(32.0 / 255.0)},
|
|
};
|
|
checkNormalizedVariableLengthArray(
|
|
data,
|
|
offsets,
|
|
PropertyComponentType::Uint32,
|
|
3,
|
|
expected,
|
|
noData,
|
|
defaultValue);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check fixed-length array of string") {
|
|
std::vector<std::string> strings{
|
|
"Test 1",
|
|
"Test 2",
|
|
"Test 3",
|
|
"Test 4",
|
|
"Test 5",
|
|
"Test 6",
|
|
"This is a fine test",
|
|
"What's going on",
|
|
"Good morning"};
|
|
size_t totalSize = 0;
|
|
for (const auto& str : strings) {
|
|
totalSize += str.size();
|
|
}
|
|
|
|
const size_t stringCount = strings.size();
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(totalSize);
|
|
uint32_t currentStringOffset = 0;
|
|
for (size_t i = 0; i < stringCount; ++i) {
|
|
std::memcpy(
|
|
buffer.data() + currentStringOffset,
|
|
strings[i].data(),
|
|
strings[i].size());
|
|
currentStringOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
|
|
// Create string offset buffer
|
|
std::vector<std::byte> stringOffsets;
|
|
stringOffsets.resize((stringCount + 1) * sizeof(uint32_t));
|
|
currentStringOffset = 0;
|
|
for (size_t i = 0; i < stringCount; ++i) {
|
|
std::memcpy(
|
|
stringOffsets.data() + i * sizeof(uint32_t),
|
|
¤tStringOffset,
|
|
sizeof(uint32_t));
|
|
currentStringOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
|
|
std::memcpy(
|
|
stringOffsets.data() + stringCount * sizeof(uint32_t),
|
|
¤tStringOffset,
|
|
sizeof(uint32_t));
|
|
|
|
SUBCASE("Returns correct values") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
classProperty.count = 3;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(stringCount / 3),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == classProperty.count);
|
|
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
auto maybeValues = property.get(i);
|
|
REQUIRE(maybeValues);
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == strings[expectedIdx]);
|
|
REQUIRE((*maybeValues)[j] == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
}
|
|
|
|
SUBCASE("Uses NoData value") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
classProperty.count = 3;
|
|
classProperty.noData = {"Test 1", "Test 2", "Test 3"};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(stringCount / 3),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == classProperty.count);
|
|
|
|
std::vector<std::optional<std::vector<std::string_view>>> expected{
|
|
std::nullopt,
|
|
std::vector<std::string_view>{"Test 4", "Test 5", "Test 6"},
|
|
std::vector<std::string_view>{
|
|
"This is a fine test",
|
|
"What's going on",
|
|
"Good morning"}};
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
std::string_view v = values[j];
|
|
REQUIRE(v == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
|
|
// Check values with properties
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
auto maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
SUBCASE("Uses NoData and DefaultValue") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
classProperty.count = 3;
|
|
classProperty.noData = {"Test 1", "Test 2", "Test 3"};
|
|
classProperty.defaultProperty = {"Default 1", "Default 2", "Default 3"};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
static_cast<int64_t>(stringCount / 3),
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::None,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == classProperty.count);
|
|
|
|
std::vector<std::optional<std::vector<std::string_view>>> expected{
|
|
std::vector<std::string_view>{"Default 1", "Default 2", "Default 3"},
|
|
std::vector<std::string_view>{"Test 4", "Test 5", "Test 6"},
|
|
std::vector<std::string_view>{
|
|
"This is a fine test",
|
|
"What's going on",
|
|
"Good morning"}};
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
std::string_view v = values[j];
|
|
REQUIRE(v == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
|
|
// Check values with properties
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
auto maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length string array PropertyTablePropertyView") {
|
|
// clang-format off
|
|
std::vector<uint32_t> arrayOffsets{
|
|
0,
|
|
4,
|
|
7,
|
|
8,
|
|
12
|
|
};
|
|
|
|
std::vector<std::string> strings{
|
|
"Test 1", "Test 2", "Test 3", "Test 4",
|
|
"Test 5", "Test 6", "Test 7",
|
|
"Null",
|
|
"Test 8", "Test 9", "Test 10", "Test 11"
|
|
};
|
|
// clang-format on
|
|
|
|
size_t totalSize = 0;
|
|
for (const auto& str : strings) {
|
|
totalSize += str.size();
|
|
}
|
|
|
|
const size_t stringCount = strings.size();
|
|
uint32_t currentOffset = 0;
|
|
std::vector<std::byte> buffer;
|
|
buffer.resize(totalSize);
|
|
for (size_t i = 0; i < stringCount; ++i) {
|
|
std::memcpy(
|
|
buffer.data() + currentOffset,
|
|
strings[i].data(),
|
|
strings[i].size());
|
|
currentOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
|
|
std::vector<std::byte> stringOffsets;
|
|
stringOffsets.resize((stringCount + 1) * sizeof(uint32_t));
|
|
currentOffset = 0;
|
|
for (size_t i = 0; i < stringCount; ++i) {
|
|
std::memcpy(
|
|
stringOffsets.data() + i * sizeof(uint32_t),
|
|
¤tOffset,
|
|
sizeof(uint32_t));
|
|
currentOffset += static_cast<uint32_t>(strings[i].size());
|
|
}
|
|
std::memcpy(
|
|
stringOffsets.data() + stringCount * sizeof(uint32_t),
|
|
¤tOffset,
|
|
sizeof(uint32_t));
|
|
|
|
SUBCASE("Returns correct values") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
4,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(
|
|
reinterpret_cast<const std::byte*>(arrayOffsets.data()),
|
|
arrayOffsets.size() * sizeof(uint32_t)),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::Uint32,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
auto maybeValues = property.get(i);
|
|
REQUIRE(maybeValues);
|
|
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == strings[expectedIdx]);
|
|
REQUIRE((*maybeValues)[j] == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
}
|
|
|
|
SUBCASE("Uses NoData Value") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
classProperty.noData = JsonValue::Array{"Null"};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
4,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(
|
|
reinterpret_cast<const std::byte*>(arrayOffsets.data()),
|
|
arrayOffsets.size() * sizeof(uint32_t)),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::Uint32,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
std::vector<std::optional<std::vector<std::string_view>>> expected{
|
|
std::vector<std::string_view>{"Test 1", "Test 2", "Test 3", "Test 4"},
|
|
std::vector<std::string_view>{"Test 5", "Test 6", "Test 7"},
|
|
std::nullopt,
|
|
std::vector<std::string_view>{
|
|
"Test 8",
|
|
"Test 9",
|
|
"Test 10",
|
|
"Test 11"}};
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
std::string_view v = values[j];
|
|
REQUIRE(v == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
|
|
// Check values with properties
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
auto maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
|
|
SUBCASE("Uses NoData and DefaultValue") {
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::STRING;
|
|
classProperty.array = true;
|
|
classProperty.noData = JsonValue::Array{"Null"};
|
|
classProperty.defaultProperty = JsonValue::Array{"Default"};
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<std::string_view>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
4,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(
|
|
reinterpret_cast<const std::byte*>(arrayOffsets.data()),
|
|
arrayOffsets.size() * sizeof(uint32_t)),
|
|
std::span<const std::byte>(stringOffsets.data(), stringOffsets.size()),
|
|
PropertyComponentType::Uint32,
|
|
PropertyComponentType::Uint32);
|
|
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
std::vector<std::optional<std::vector<std::string_view>>> expected{
|
|
std::vector<std::string_view>{"Test 1", "Test 2", "Test 3", "Test 4"},
|
|
std::vector<std::string_view>{"Test 5", "Test 6", "Test 7"},
|
|
std::vector<std::string_view>{"Default"},
|
|
std::vector<std::string_view>{
|
|
"Test 8",
|
|
"Test 9",
|
|
"Test 10",
|
|
"Test 11"}};
|
|
|
|
// Check raw values first
|
|
size_t expectedIdx = 0;
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
PropertyArrayView<std::string_view> values = property.getRaw(i);
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
std::string_view v = values[j];
|
|
REQUIRE(v == strings[expectedIdx]);
|
|
++expectedIdx;
|
|
}
|
|
}
|
|
|
|
REQUIRE(expectedIdx == stringCount);
|
|
|
|
// Check values with properties
|
|
for (int64_t i = 0; i < property.size(); ++i) {
|
|
auto maybeValues = property.get(i);
|
|
if (!maybeValues) {
|
|
REQUIRE(!expected[static_cast<size_t>(i)]);
|
|
continue;
|
|
}
|
|
|
|
auto values = *maybeValues;
|
|
auto expectedValues = *expected[static_cast<size_t>(i)];
|
|
for (int64_t j = 0; j < values.size(); ++j) {
|
|
REQUIRE(values[j] == expectedValues[static_cast<size_t>(j)]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") {
|
|
std::vector<std::byte> buffer{
|
|
static_cast<std::byte>(0b10101111),
|
|
static_cast<std::byte>(0b11111010),
|
|
static_cast<std::byte>(0b11100111)};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::BOOLEAN;
|
|
classProperty.array = true;
|
|
classProperty.count = 12;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<bool>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
2,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::Uint32,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.size() == 2);
|
|
REQUIRE(property.arrayCount() == classProperty.count);
|
|
|
|
PropertyArrayView<bool> val0 = property.getRaw(0);
|
|
REQUIRE(val0.size() == 12);
|
|
REQUIRE(static_cast<int>(val0[0]) == 1);
|
|
REQUIRE(static_cast<int>(val0[1]) == 1);
|
|
REQUIRE(static_cast<int>(val0[2]) == 1);
|
|
REQUIRE(static_cast<int>(val0[3]) == 1);
|
|
REQUIRE(static_cast<int>(val0[4]) == 0);
|
|
REQUIRE(static_cast<int>(val0[5]) == 1);
|
|
REQUIRE(static_cast<int>(val0[6]) == 0);
|
|
REQUIRE(static_cast<int>(val0[7]) == 1);
|
|
REQUIRE(static_cast<int>(val0[8]) == 0);
|
|
REQUIRE(static_cast<int>(val0[9]) == 1);
|
|
REQUIRE(static_cast<int>(val0[10]) == 0);
|
|
REQUIRE(static_cast<int>(val0[11]) == 1);
|
|
|
|
PropertyArrayView<bool> val1 = property.getRaw(1);
|
|
REQUIRE(static_cast<int>(val1[0]) == 1);
|
|
REQUIRE(static_cast<int>(val1[1]) == 1);
|
|
REQUIRE(static_cast<int>(val1[2]) == 1);
|
|
REQUIRE(static_cast<int>(val1[3]) == 1);
|
|
REQUIRE(static_cast<int>(val1[4]) == 1);
|
|
REQUIRE(static_cast<int>(val1[5]) == 1);
|
|
REQUIRE(static_cast<int>(val1[6]) == 1);
|
|
REQUIRE(static_cast<int>(val1[7]) == 0);
|
|
REQUIRE(static_cast<int>(val1[8]) == 0);
|
|
REQUIRE(static_cast<int>(val1[9]) == 1);
|
|
REQUIRE(static_cast<int>(val1[10]) == 1);
|
|
REQUIRE(static_cast<int>(val1[11]) == 1);
|
|
|
|
for (int64_t i = 0; i < property.size(); i++) {
|
|
auto value = property.getRaw(i);
|
|
auto maybeValue = property.get(i);
|
|
REQUIRE(maybeValue);
|
|
REQUIRE(maybeValue->size() == value.size());
|
|
for (int64_t j = 0; j < maybeValue->size(); j++) {
|
|
REQUIRE((*maybeValue)[j] == value[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") {
|
|
std::vector<std::byte> buffer{
|
|
static_cast<std::byte>(0b10101111),
|
|
static_cast<std::byte>(0b11111010),
|
|
static_cast<std::byte>(0b11100111),
|
|
static_cast<std::byte>(0b11110110)};
|
|
|
|
std::vector<uint32_t> offsetBuffer{0, 3, 12, 28};
|
|
|
|
PropertyTableProperty propertyTableProperty;
|
|
ClassProperty classProperty;
|
|
classProperty.type = ClassProperty::Type::BOOLEAN;
|
|
classProperty.array = true;
|
|
|
|
PropertyTablePropertyView<PropertyArrayView<bool>> property(
|
|
propertyTableProperty,
|
|
classProperty,
|
|
3,
|
|
std::span<const std::byte>(buffer.data(), buffer.size()),
|
|
std::span<const std::byte>(
|
|
reinterpret_cast<const std::byte*>(offsetBuffer.data()),
|
|
offsetBuffer.size() * sizeof(uint32_t)),
|
|
std::span<const std::byte>(),
|
|
PropertyComponentType::Uint32,
|
|
PropertyComponentType::None);
|
|
|
|
REQUIRE(property.size() == 3);
|
|
REQUIRE(property.arrayCount() == 0);
|
|
|
|
PropertyArrayView<bool> val0 = property.getRaw(0);
|
|
REQUIRE(val0.size() == 3);
|
|
REQUIRE(static_cast<int>(val0[0]) == 1);
|
|
REQUIRE(static_cast<int>(val0[1]) == 1);
|
|
REQUIRE(static_cast<int>(val0[2]) == 1);
|
|
|
|
PropertyArrayView<bool> val1 = property.getRaw(1);
|
|
REQUIRE(val1.size() == 9);
|
|
REQUIRE(static_cast<int>(val1[0]) == 1);
|
|
REQUIRE(static_cast<int>(val1[1]) == 0);
|
|
REQUIRE(static_cast<int>(val1[2]) == 1);
|
|
REQUIRE(static_cast<int>(val1[3]) == 0);
|
|
REQUIRE(static_cast<int>(val1[4]) == 1);
|
|
REQUIRE(static_cast<int>(val1[5]) == 0);
|
|
REQUIRE(static_cast<int>(val1[6]) == 1);
|
|
REQUIRE(static_cast<int>(val1[7]) == 0);
|
|
REQUIRE(static_cast<int>(val1[8]) == 1);
|
|
|
|
PropertyArrayView<bool> val2 = property.getRaw(2);
|
|
REQUIRE(val2.size() == 16);
|
|
REQUIRE(static_cast<int>(val2[0]) == 1);
|
|
REQUIRE(static_cast<int>(val2[1]) == 1);
|
|
REQUIRE(static_cast<int>(val2[2]) == 1);
|
|
REQUIRE(static_cast<int>(val2[3]) == 1);
|
|
REQUIRE(static_cast<int>(val2[4]) == 1);
|
|
REQUIRE(static_cast<int>(val2[5]) == 1);
|
|
REQUIRE(static_cast<int>(val2[6]) == 1);
|
|
REQUIRE(static_cast<int>(val2[7]) == 0);
|
|
REQUIRE(static_cast<int>(val2[8]) == 0);
|
|
REQUIRE(static_cast<int>(val2[9]) == 1);
|
|
REQUIRE(static_cast<int>(val2[10]) == 1);
|
|
REQUIRE(static_cast<int>(val2[11]) == 1);
|
|
REQUIRE(static_cast<int>(val2[12]) == 0);
|
|
REQUIRE(static_cast<int>(val2[13]) == 1);
|
|
REQUIRE(static_cast<int>(val2[14]) == 1);
|
|
REQUIRE(static_cast<int>(val2[15]) == 0);
|
|
|
|
for (int64_t i = 0; i < property.size(); i++) {
|
|
auto value = property.getRaw(i);
|
|
auto maybeValue = property.get(i);
|
|
REQUIRE(maybeValue);
|
|
REQUIRE(maybeValue->size() == value.size());
|
|
for (int64_t j = 0; j < maybeValue->size(); j++) {
|
|
REQUIRE((*maybeValue)[j] == value[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
#pragma GCC diagnostic pop
|
|
#endif
|