Use a utility Optional type for class member variables that are not required and have no default value specified. The following classes have been modified:

- BufferView: byteStride & target members
- Perspective: zfar & aspectRatio members
- Sampler: magFilter & minFilter members
- TextureTransform: texCoord member
This commit is contained in:
Chris Chenery 2019-04-16 00:03:46 +01:00 коммит произвёл GitHub
Родитель fc96348a60
Коммит bf524fe3e9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 955 добавлений и 147 удалений

Просмотреть файл

@ -60,6 +60,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Math.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\MeshPrimitiveUtils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\MicrosoftGeneratorVersion.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Optional.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\PBRUtils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\RapidJsonUtils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\ResourceReaderUtils.h" />

Просмотреть файл

@ -197,6 +197,9 @@
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\SchemaValidation.h">
<Filter>Header Files\GLTFSDK</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Optional.h">
<Filter>Header Files\GLTFSDK</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)..\GLTFSDK\schema\accessor.schema.json">

Просмотреть файл

@ -105,6 +105,7 @@
<ClCompile Include="Source\IndexedContainerTests.cpp" />
<ClCompile Include="Source\MeshPrimitiveUtilsTests.cpp" />
<ClCompile Include="Source\MicrosoftGeneratorVersionTests.cpp" />
<ClCompile Include="Source\OptionalTests.cpp" />
<ClCompile Include="Source\PBRUtilsTests.cpp" />
<ClCompile Include="Source\ResourceReaderUtilsTests.cpp" />
<ClCompile Include="Source\SerializeTests.cpp" />

Просмотреть файл

@ -92,6 +92,9 @@
<ClCompile Include="Source\GLBResourceWriterTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Source\OptionalTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\gltf\ReciprocatingSaw.gltf">
@ -255,5 +258,8 @@
<None Include="Resources\glTF-Asset-Generator\Mesh_PrimitiveMode\Mesh_PrimitiveMode_15.bin">
<Filter>Resource Files</Filter>
</None>
<None Include="Resources\gltf\TextureTransformTest.gltf">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -429,7 +429,7 @@ namespace Microsoft
auto checkTextureInfo = [](
const Material& material,
const Vector2& offset, float rotation, const Vector2& scale, std::unique_ptr<size_t> texCoord)
const Vector2& offset, float rotation, const Vector2& scale, Optional<size_t> texCoord = {})
{
auto& textureInfo = material.metallicRoughness.baseColorTexture;
@ -441,19 +441,19 @@ namespace Microsoft
expectedTextureTransform.offset = offset;
expectedTextureTransform.scale = scale;
expectedTextureTransform.rotation = rotation;
expectedTextureTransform.texCoord = std::move(texCoord);
expectedTextureTransform.texCoord = texCoord;
Assert::IsTrue(textureTransform == expectedTextureTransform);
};
Assert::IsTrue(doc.materials.Size() == 9);
checkTextureInfo(doc.materials[0], Vector2(0.5f, 0.0f), 0.0f, Vector2(1.0f, 1.0f), {}); // Note: texCoord not specified
checkTextureInfo(doc.materials[1], Vector2(0.0f, 0.5f), 0.0f, Vector2(1.0f, 1.0f), {});
checkTextureInfo(doc.materials[2], Vector2(0.5f, 0.5f), 0.0f, Vector2(1.0f, 1.0f), {});
checkTextureInfo(doc.materials[3], Vector2(0.0f, 0.0f), 0.39269908169872415480783042290994f, Vector2(1.0f, 1.0f), {});
checkTextureInfo(doc.materials[4], Vector2(0.0f, 0.0f), 0.0f, Vector2(1.5f, 1.5f), {});
checkTextureInfo(doc.materials[5], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f), {});
checkTextureInfo(doc.materials[0], Vector2(0.5f, 0.0f), 0.0f, Vector2(1.0f, 1.0f)); // Note: texCoord not specified
checkTextureInfo(doc.materials[1], Vector2(0.0f, 0.5f), 0.0f, Vector2(1.0f, 1.0f));
checkTextureInfo(doc.materials[2], Vector2(0.5f, 0.5f), 0.0f, Vector2(1.0f, 1.0f));
checkTextureInfo(doc.materials[3], Vector2(0.0f, 0.0f), 0.39269908169872415480783042290994f, Vector2(1.0f, 1.0f));
checkTextureInfo(doc.materials[4], Vector2(0.0f, 0.0f), 0.0f, Vector2(1.5f, 1.5f));
checkTextureInfo(doc.materials[5], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f));
}
GLTFSDK_TEST_METHOD(ExtensionsTests, Extensions_Test_HasTextureTransformExtension_TexCoord)
@ -464,7 +464,7 @@ namespace Microsoft
auto checkTextureInfo = [](
const Material& material,
const Vector2& offset, float rotation, const Vector2& scale, std::unique_ptr<size_t> texCoord)
const Vector2& offset, float rotation, const Vector2& scale, Optional<size_t> texCoord = {})
{
auto& textureInfo = material.metallicRoughness.baseColorTexture;
@ -476,15 +476,15 @@ namespace Microsoft
expectedTextureTransform.offset = offset;
expectedTextureTransform.scale = scale;
expectedTextureTransform.rotation = rotation;
expectedTextureTransform.texCoord = std::move(texCoord);
expectedTextureTransform.texCoord = texCoord;
Assert::IsTrue(textureTransform == expectedTextureTransform);
};
Assert::IsTrue(doc.materials.Size() == 2);
checkTextureInfo(doc.materials[0], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f), std::make_unique<size_t>(1234));
checkTextureInfo(doc.materials[1], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f), {});
checkTextureInfo(doc.materials[0], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f), 1234);
checkTextureInfo(doc.materials[1], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f));
const auto extensionSerializer = KHR::GetKHRExtensionSerializer();
auto tt = Serialize(doc, extensionSerializer);

Просмотреть файл

@ -254,7 +254,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(uint32_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
writer.Write(bufferView, data.data());
@ -280,7 +279,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(uint32_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
writer.Write(bufferView, data.data());
@ -306,7 +304,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(uint32_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
writer.Write(bufferView, data.data());
@ -332,7 +329,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data1.size() * sizeof(uint32_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
writer.Write(bufferView, data1.data());
@ -361,7 +357,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(float);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";
@ -399,7 +394,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(float);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";
@ -435,7 +429,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data1.size() * sizeof(uint8_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";
@ -488,7 +481,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data1.size() * sizeof(uint8_t);
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";
@ -535,7 +527,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 0;
bufferView.byteLength = data.size() * sizeof(uint32_t) + 1U;// Add an additional byte as the accessor's byteOffset is 1;
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";
@ -563,7 +554,6 @@ namespace Microsoft
bufferView.bufferId = "0";
bufferView.byteOffset = 1U;
bufferView.byteLength = data.size() * sizeof(uint32_t) + 5U;// Add an additional 5 bytes as the bufferView and accessor's byteOffsets are 1 and 4 respectively;
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
Accessor accessor;
accessor.id = "0";

Просмотреть файл

@ -18,26 +18,26 @@ namespace
void TestBadGLTFSerializeToJson(const Document& doc)
{
Assert::ExpectException<GLTFException>([&doc]
{
Serialize(doc);
}, L"Expected exception was not thrown");
{
Serialize(doc);
}, L"Expected exception was not thrown");
}
void TestBadGLTFDeserializeToDocument(const char* data)
{
Assert::ExpectException<GLTFException>([&data]
{
Deserialize(data);
}, L"Expected exception was not thrown");
{
Deserialize(data);
}, L"Expected exception was not thrown");
}
void TestDocumentValidationFail(const char* data)
{
Assert::ExpectException<ValidationException>([&data]
{
auto doc = Deserialize(data);
Validation::Validate(doc);
}, L"Expected exception was not thrown");
{
auto doc = Deserialize(data);
Validation::Validate(doc);
}, L"Expected exception was not thrown");
}
const char* c_invalidPrimitiveAccessorComponentType = R"({
@ -294,12 +294,77 @@ namespace
],
"scene": 0
})";
const char* c_validSamplerDocument = R"({
"asset": {
"version": "2.0"
},
"samplers": [
{
"minFilter": 9728,
"magFilter": 9729
},
{
"wrapS": 33648,
"wrapT": 33071
}
]
})";
}
namespace Microsoft
{
namespace glTF
{
std::wstring ToString(WrapMode wrapMode)
{
switch (wrapMode)
{
case Wrap_REPEAT:
return L"REPEAT";
case Wrap_CLAMP_TO_EDGE:
return L"CLAMP_TO_EDGE";
case Wrap_MIRRORED_REPEAT:
return L"MIRRORED_REPEAT";
}
return {};
}
std::wstring ToString(MinFilterMode minFilterMode)
{
switch (minFilterMode)
{
case MinFilter_NEAREST:
return L"NEAREST";
case MinFilter_NEAREST_MIPMAP_LINEAR:
return L"NEAREST_MIPMAP_LINEAR";
case MinFilter_NEAREST_MIPMAP_NEAREST:
return L"NEAREST_MIPMAP_NEAREST";
case MinFilter_LINEAR:
return L"LINEAR";
case MinFilter_LINEAR_MIPMAP_LINEAR:
return L"LINEAR_MIPMAP_LINEAR";
case MinFilter_LINEAR_MIPMAP_NEAREST:
return L"LINEAR_MIPMAP_NEAREST";
}
return {};
}
std::wstring ToString(MagFilterMode magFilterMode)
{
switch (magFilterMode)
{
case MagFilter_NEAREST:
return L"NEAREST";
case MagFilter_LINEAR:
return L"LINEAR";
}
return {};
}
namespace Test
{
GLTFSDK_TEST_CLASS(SerializerGLTFTests)
@ -423,6 +488,25 @@ namespace Microsoft
TestBadGLTFSerializeToJson(doc);
}
GLTFSDK_TEST_METHOD(SerializerGLTFTests, SerializerGLTFTests_DeserializeSampler)
{
auto doc = Deserialize(c_validSamplerDocument);
Assert::AreEqual(doc.samplers.Size(), size_t(2U), L"Unexpected number of samplers after deserializing manifest");
Assert::AreEqual(doc.samplers[0].minFilter.Get(), MinFilter_NEAREST, L"Sampler minification filter was not deserialized correctly");
Assert::AreEqual(doc.samplers[0].magFilter.Get(), MagFilter_LINEAR, L"Sampler magnification filter was not deserialized correctly");
Assert::AreEqual(doc.samplers[0].wrapS, Wrap_REPEAT, L"Sampler default wrapS property was not deserialized correctly");
Assert::AreEqual(doc.samplers[0].wrapT, Wrap_REPEAT, L"Sampler default wrapT property was not deserialized correctly");
Assert::IsFalse(doc.samplers[1].minFilter.HasValue(), L"Sampler default minification filter was not unspecified");
Assert::IsFalse(doc.samplers[1].magFilter.HasValue(), L"Sampler default magnification filter was not unspecified");
Assert::AreEqual(doc.samplers[1].wrapS, Wrap_MIRRORED_REPEAT, L"Sampler wrapS property was not deserialized correctly");
Assert::AreEqual(doc.samplers[1].wrapT, Wrap_CLAMP_TO_EDGE, L"Sampler wrapT property was not deserialized correctly");
}
};
}
}

Просмотреть файл

@ -0,0 +1,480 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "stdafx.h"
#include <GLTFSDK/Optional.h>
using namespace glTF::UnitTest;
namespace Microsoft
{
namespace glTF
{
namespace Test
{
GLTFSDK_TEST_CLASS(OptionalTests)
{
GLTFSDK_TEST_METHOD(OptionalTests, ConstructorDefault)
{
Optional<int> optional;
Assert::IsFalse(static_cast<bool>(optional));
Assert::IsFalse(optional.HasValue());
Assert::ExpectException<GLTFException>([&optional]{ optional.Get(); });
}
GLTFSDK_TEST_METHOD(OptionalTests, ConstructorValueCopy)
{
Optional<double> optional(1.0);
Assert::IsTrue(static_cast<bool>(optional));
Assert::IsTrue(optional.HasValue());
Assert::AreEqual(1.0, optional.Get());
}
GLTFSDK_TEST_METHOD(OptionalTests, ConstructorValueMove)
{
Optional<std::unique_ptr<int>> optional(std::make_unique<int>(1));
Assert::IsTrue(static_cast<bool>(optional));
Assert::IsTrue(optional.HasValue());
Assert::AreEqual(1, *optional.Get().get());
}
GLTFSDK_TEST_METHOD(OptionalTests, ConstructorOptionalCopy)
{
Optional<unsigned int> opt1;
Optional<unsigned int> opt2(opt1);
Optional<unsigned int> opt3(3U);
Optional<unsigned int> opt4(opt3);
Assert::IsFalse(static_cast<bool>(opt1));
Assert::IsFalse(opt1.HasValue());
Assert::IsFalse(static_cast<bool>(opt2));
Assert::IsFalse(opt2.HasValue());
Assert::IsTrue(static_cast<bool>(opt3));
Assert::IsTrue(opt3.HasValue());
Assert::IsTrue(static_cast<bool>(opt4));
Assert::IsTrue(opt4.HasValue());
Assert::ExpectException<GLTFException>([&opt1] { opt1.Get(); });
Assert::ExpectException<GLTFException>([&opt2] { opt2.Get(); });
Assert::AreEqual(3U, opt3.Get());
Assert::AreEqual(3U, opt4.Get());
}
GLTFSDK_TEST_METHOD(OptionalTests, ConstructorOptionalMove)
{
Optional<std::unique_ptr<int>> opt1;
Optional<std::unique_ptr<int>> opt2(std::move(opt1));
Optional<std::unique_ptr<int>> opt3(std::make_unique<int>(3));
Optional<std::unique_ptr<int>> opt4(std::move(opt3));
Assert::IsFalse(static_cast<bool>(opt1));
Assert::IsFalse(opt1.HasValue());
Assert::IsFalse(static_cast<bool>(opt2));
Assert::IsFalse(opt2.HasValue());
Assert::IsFalse(static_cast<bool>(opt3));
Assert::IsFalse(opt3.HasValue());
Assert::IsTrue(static_cast<bool>(opt4));
Assert::IsTrue(opt4.HasValue());
Assert::ExpectException<GLTFException>([&opt1] { opt1.Get(); });
Assert::ExpectException<GLTFException>([&opt2] { opt2.Get(); });
Assert::ExpectException<GLTFException>([&opt3] { opt3.Get(); });
Assert::AreEqual(3, *opt4.Get().get());
}
GLTFSDK_TEST_METHOD(OptionalTests, DestructorReset)
{
unsigned int count = 0U;
struct Counter
{
Counter(unsigned int* count_ptr) : count_ptr(count_ptr)
{
++(*count_ptr);
}
Counter(Counter&& other) : count_ptr(other.count_ptr)
{
++(*count_ptr);
}
Counter(const Counter& other) : count_ptr(other.count_ptr)
{
++(*count_ptr);
}
~Counter()
{
--(*count_ptr);
}
unsigned int* count_ptr;
};
{
Optional<Counter> opt1(&count);
{
Assert::AreEqual(1U, count);
Optional<Counter> opt2(&count);
Assert::AreEqual(2U, count);
}
Assert::AreEqual(1U, count);
opt1.Reset();
Assert::AreEqual(0U, count);
}
Assert::AreEqual(0U, count);
}
GLTFSDK_TEST_METHOD(OptionalTests, Swap)
{
// Both lhs and rhs Optionals have values
{
Optional<char> optA('A');
Optional<char> optB('B');
Assert::AreEqual('A', optA.Get());
Assert::AreEqual('B', optB.Get());
Optional<char>::Swap(optA, optB); // After swapping optA should contain 'B' and optB should contain 'A'
Assert::AreEqual('B', optA.Get());
Assert::AreEqual('A', optB.Get());
}
// Only lhs Optional has a value
{
Optional<char> optA('A');
Optional<char> optB;
Assert::AreEqual('A', optA.Get());
Assert::IsFalse(optB.HasValue());
Optional<char>::Swap(optA, optB); // After swapping optA should be empty and optB should contain 'A'
Assert::IsFalse(optA.HasValue());
Assert::AreEqual('A', optB.Get());
}
// Only rhs Optional has a value
{
Optional<char> optA;
Optional<char> optB('B');
Assert::IsFalse(optA.HasValue());
Assert::AreEqual('B', optB.Get());
Optional<char>::Swap(optA, optB); // After swapping optA should contain 'B' and optB should be empty
Assert::AreEqual('B', optA.Get());
Assert::IsFalse(optB.HasValue());
}
}
GLTFSDK_TEST_METHOD(OptionalTests, AssignmentValueCopy)
{
const std::string assignValue("Assign");
// Test assignment when Optional has no existing value
{
Optional<std::string> opt;
Assert::IsFalse(opt.HasValue());
opt = assignValue;
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Assign", opt.Get().c_str());
}
// Test assignment when Optional has an existing value
{
Optional<std::string> opt("Init");
Assert::IsTrue(opt.HasValue());
opt = assignValue;
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Assign", opt.Get().c_str());
}
}
GLTFSDK_TEST_METHOD(OptionalTests, AssignmentValueMove)
{
// Test assignment when Optional has no existing value
{
Optional<std::string> opt;
Assert::IsFalse(opt.HasValue());
opt = std::string("Assign");
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Assign", opt.Get().c_str());
}
// Test assignment when Optional has an existing value
{
Optional<std::string> opt("Init");
Assert::IsTrue(opt.HasValue());
opt = std::string("Assign");
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Assign", opt.Get().c_str());
}
}
GLTFSDK_TEST_METHOD(OptionalTests, AssignmentOptionalCopy)
{
// Test assignment when Optional has no existing value
{
Optional<std::string> opt1;
Optional<std::string> opt2("Assign");
Assert::IsFalse(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
opt1 = opt2;
Assert::IsTrue(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
Assert::AreEqual("Assign", opt1.Get().c_str());
Assert::AreEqual("Assign", opt2.Get().c_str());
}
// Test assignment when Optional has an existing value - assign no value
{
Optional<std::string> opt1("Init");
Optional<std::string> opt2;
Assert::IsTrue(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
opt1 = opt2;
Assert::IsFalse(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
}
// Test assignment when Optional has an existing value
{
Optional<std::string> opt1("Init");
Optional<std::string> opt2("Assign");
Assert::IsTrue(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
opt1 = opt2;
Assert::IsTrue(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
Assert::AreEqual("Assign", opt1.Get().c_str());
Assert::AreEqual("Assign", opt2.Get().c_str());
}
// Test self-assignment with no existing value
{
Optional<std::string> opt;
Assert::IsFalse(opt.HasValue());
opt = opt;
Assert::IsFalse(opt.HasValue());
}
// Test self-assignment with an existing value
{
Optional<std::string> opt("Init");
Assert::IsTrue(opt.HasValue());
opt = opt;
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Init", opt.Get().c_str());
}
}
GLTFSDK_TEST_METHOD(OptionalTests, AssignmentOptionalMove)
{
// Test assignment when Optional has no existing value
{
Optional<std::string> opt1;
Optional<std::string> opt2("Assign");
Assert::IsFalse(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
opt1 = std::move(opt2);
Assert::IsTrue(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
Assert::AreEqual("Assign", opt1.Get().c_str());
}
// Test assignment when Optional has an existing value - assign no value
{
Optional<std::string> opt1("Init");
Optional<std::string> opt2;
Assert::IsTrue(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
opt1 = std::move(opt2);
Assert::IsFalse(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
}
// Test assignment when Optional has an existing value
{
Optional<std::string> opt1("Init");
Optional<std::string> opt2("Assign");
Assert::IsTrue(opt1.HasValue());
Assert::IsTrue(opt2.HasValue());
opt1 = std::move(opt2);
Assert::IsTrue(opt1.HasValue());
Assert::IsFalse(opt2.HasValue());
Assert::AreEqual("Assign", opt1.Get().c_str());
}
// Disable warnings (clang only) about self move-assignment so it is possible to test that the Optional type works as expected in this situation
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wself-move"
#endif
// Test self-assignment with no existing value
{
Optional<std::string> opt;
Assert::IsFalse(opt.HasValue());
opt = std::move(opt);
Assert::IsFalse(opt.HasValue());
}
// Test self-assignment with an existing value
{
Optional<std::string> opt("Init");
Assert::IsTrue(opt.HasValue());
opt = std::move(opt);
Assert::IsTrue(opt.HasValue());
Assert::AreEqual("Init", opt.Get().c_str());
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
}
GLTFSDK_TEST_METHOD(OptionalTests, EqualTo)
{
// lhs and rhs have no value
{
Optional<long> opt1;
Optional<long> opt2;
Assert::IsTrue(opt1 == opt2);
}
// only lhs has a value
{
Optional<long> opt1(1L);
Optional<long> opt2;
Assert::IsFalse(opt1 == opt2);
}
// only rhs has a value
{
Optional<long> opt1;
Optional<long> opt2(1L);
Assert::IsFalse(opt1 == opt2);
}
// lhs and rhs have the same value
{
Optional<long> opt1(1L);
Optional<long> opt2(1L);
Assert::IsTrue(opt1 == opt2);
}
// lhs and rhs have different values
{
Optional<long> opt1(1L);
Optional<long> opt2(2L);
Assert::IsFalse(opt1 == opt2);
}
}
GLTFSDK_TEST_METHOD(OptionalTests, NotEqualTo)
{
// lhs and rhs have no value
{
Optional<long> opt1;
Optional<long> opt2;
Assert::IsFalse(opt1 != opt2);
}
// only lhs has a value
{
Optional<long> opt1(1L);
Optional<long> opt2;
Assert::IsTrue(opt1 != opt2);
}
// only rhs has a value
{
Optional<long> opt1;
Optional<long> opt2(1L);
Assert::IsTrue(opt1 != opt2);
}
// lhs and rhs have the same value
{
Optional<long> opt1(1L);
Optional<long> opt2(1L);
Assert::IsFalse(opt1 != opt2);
}
// lhs and rhs have different values
{
Optional<long> opt1(1L);
Optional<long> opt2(2L);
Assert::IsTrue(opt1 != opt2);
}
}
};
}
}
}

Просмотреть файл

@ -46,11 +46,11 @@ namespace Microsoft
const Buffer& AddBuffer(const char* bufferId = nullptr);
const BufferView& AddBufferView(BufferViewTarget target);
const BufferView& AddBufferView(const void* data, size_t byteLength, size_t byteStride = 0, BufferViewTarget target = BufferViewTarget::UNKNOWN_BUFFER);
const BufferView& AddBufferView(Optional<BufferViewTarget> target);
const BufferView& AddBufferView(const void* data, size_t byteLength, Optional<size_t> byteStride = {}, Optional<BufferViewTarget> target = {});
template<typename T>
const BufferView& AddBufferView(const std::vector<T>& data, size_t byteStride = 0, BufferViewTarget target = BufferViewTarget::UNKNOWN_BUFFER)
const BufferView& AddBufferView(const std::vector<T>& data, Optional<size_t> byteStride = {}, Optional<BufferViewTarget> target = {})
{
return AddBufferView(data.data(), data.size() * sizeof(T), byteStride, target);
}

Просмотреть файл

@ -4,6 +4,7 @@
#pragma once
#include <GLTFSDK/ExtensionHandlers.h>
#include <GLTFSDK/Optional.h>
#include <memory>
#include <string>
@ -84,8 +85,7 @@ namespace Microsoft
Vector2 offset;
float rotation;
Vector2 scale;
// TexCoord is optional
std::unique_ptr<size_t> texCoord;
Optional<size_t> texCoord; // TexCoord is an optional property
std::unique_ptr<Extension> Clone() const override;
bool IsEqual(const Extension& rhs) const override;

Просмотреть файл

@ -9,6 +9,7 @@
#include <GLTFSDK/Extension.h>
#include <GLTFSDK/IndexedContainer.h>
#include <GLTFSDK/Math.h>
#include <GLTFSDK/Optional.h>
#include <memory>
#include <string>
@ -23,7 +24,6 @@ namespace Microsoft
{
enum BufferViewTarget
{
UNKNOWN_BUFFER = 0,
ARRAY_BUFFER = 34962,
ELEMENT_ARRAY_BUFFER = 34963
};
@ -332,8 +332,8 @@ namespace Microsoft
std::string bufferId;
size_t byteOffset = 0U;
size_t byteLength = 0U;
size_t byteStride = 0U; // 0 = tight packing
BufferViewTarget target = UNKNOWN_BUFFER;
Optional<size_t> byteStride;
Optional<BufferViewTarget> target;
bool operator==(const BufferView& rhs) const
{
@ -880,16 +880,12 @@ namespace Microsoft
struct Projection : glTFProperty
{
float zfar;
float znear;
virtual ProjectionType GetProjectionType() const = 0;
virtual std::unique_ptr<Projection> Clone() const = 0;
virtual bool IsValid() const
{
return zfar > znear;
}
virtual bool IsValid() const = 0;
bool operator==(const Projection& rhs) const
{
@ -902,16 +898,13 @@ namespace Microsoft
}
protected:
Projection(float zfar, float znear) :
zfar(zfar),
znear(znear)
Projection(float znear) : znear(znear)
{
}
virtual bool IsEqual(const Projection& rhs) const
{
return glTFProperty::Equals(*this, rhs)
&& this->zfar == rhs.zfar
&& this->znear == rhs.znear;
}
};
@ -920,37 +913,41 @@ namespace Microsoft
{
float xmag;
float ymag;
float zfar;
Orthographic(float zfar, float znear, float xmag, float ymag) :
Projection(zfar, znear),
Projection(znear),
xmag(xmag),
ymag(ymag)
ymag(ymag),
zfar(zfar)
{
}
virtual bool IsValid() const
bool IsValid() const override
{
return Projection::IsValid()
&& ymag != 0.0
&& xmag != 0.0;
return (zfar > znear)
&& (ymag != 0.0)
&& (xmag != 0.0);
}
virtual ProjectionType GetProjectionType() const
ProjectionType GetProjectionType() const override
{
return ProjectionType::ORTHOGRAPHIC;
}
virtual std::unique_ptr<Projection> Clone() const
std::unique_ptr<Projection> Clone() const override
{
return std::make_unique<Orthographic>(*this);
}
virtual bool IsEqual(const Projection& rhs) const
bool IsEqual(const Projection& rhs) const override
{
if (const auto other = dynamic_cast<const Orthographic*>(&rhs))
{
return Projection::IsEqual(rhs)
&& xmag == other->xmag
&& ymag == other->ymag;
&& ymag == other->ymag
&& zfar == other->zfar;
}
return false;
@ -959,43 +956,59 @@ namespace Microsoft
struct Perspective : Projection
{
float aspectRatio;
Optional<float> aspectRatio;
float yfov;
Optional<float> zfar;
Perspective(float znear, float yfov) :
Projection(znear),
aspectRatio(),
yfov(yfov),
zfar()
{
}
Perspective(float zfar, float znear, float aspectRatio, float yfov) :
Projection(zfar, znear),
Projection(znear),
aspectRatio(aspectRatio),
yfov(yfov)
yfov(yfov),
zfar(zfar)
{
}
bool IsValid() const override
{
return !zfar.HasValue() || (zfar.Get() > znear);
}
bool IsFinite() const
{
return zfar != std::numeric_limits<float>::infinity();
return zfar.HasValue(); // If zfar is undefined the runtime must use an infinite projection matrix
}
bool HasCustomAspectRatio() const
{
return aspectRatio != 0.0f;
return aspectRatio.HasValue(); // When aspectRatio is undefined the aspect ratio of the 'canvas' should be used
}
virtual ProjectionType GetProjectionType() const
ProjectionType GetProjectionType() const override
{
return ProjectionType::PERSPECTIVE;
}
virtual std::unique_ptr<Projection> Clone() const
std::unique_ptr<Projection> Clone() const override
{
return std::make_unique<Perspective>(*this);
}
virtual bool IsEqual(const Projection& rhs) const
bool IsEqual(const Projection& rhs) const override
{
if (const auto other = dynamic_cast<const Perspective*>(&rhs))
{
return Projection::IsEqual(rhs)
&& aspectRatio == other->aspectRatio
&& yfov == other->yfov;
&& yfov == other->yfov
&& zfar == other->zfar;
}
return false;
@ -1038,6 +1051,7 @@ namespace Microsoft
{
return *ret;
}
throw GLTFException("Failed to cast projection to orthographic");
}
@ -1047,6 +1061,7 @@ namespace Microsoft
{
return *ret;
}
throw GLTFException("Failed to cast projection to orthographic");
}
@ -1061,6 +1076,7 @@ namespace Microsoft
{
return !projection && !rhs.projection;
}
return *projection == *(rhs.projection);
}
@ -1178,15 +1194,12 @@ namespace Microsoft
struct Sampler : glTFChildOfRootProperty
{
static const MagFilterMode kMagFilterDefault = MagFilter_LINEAR;
static const MinFilterMode kMinFilterDefault = MinFilter_NEAREST_MIPMAP_LINEAR;
static const WrapMode kWrapSDefault = Wrap_REPEAT;
static const WrapMode kWrapTDefault = Wrap_REPEAT;
MagFilterMode magFilter = kMagFilterDefault;
MinFilterMode minFilter = kMinFilterDefault;
WrapMode wrapS = kWrapSDefault;
WrapMode wrapT = kWrapTDefault;
// The glTF spec doesn't define default values for magFilter and minFilter members. When
// filtering options are not defined implementations are free to select a suitable value
Optional<MagFilterMode> magFilter;
Optional<MinFilterMode> minFilter;
WrapMode wrapS = Wrap_REPEAT;
WrapMode wrapT = Wrap_REPEAT;
static MinFilterMode GetSamplerMinFilterMode(size_t readValue)
{

Просмотреть файл

@ -137,14 +137,13 @@ namespace Microsoft
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
if (bufferView.byteStride == 0U ||
bufferView.byteStride == elementSize)
if (!bufferView.byteStride || bufferView.byteStride.Get() == elementSize)
{
data = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
}
else
{
data = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride);
data = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride.Get());
}
return data;
@ -169,14 +168,13 @@ namespace Microsoft
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
if (bufferView.byteStride == 0U ||
bufferView.byteStride == elementSize)
if (!bufferView.byteStride || bufferView.byteStride.Get() == elementSize)
{
baseData = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
}
else
{
baseData = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride);
baseData = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride.Get());
}
}
@ -367,26 +365,24 @@ namespace Microsoft
std::vector<I> indices;
if (indicesBufferView.byteStride == 0U ||
indicesBufferView.byteStride == sizeof(I))
if (!indicesBufferView.byteStride || indicesBufferView.byteStride.Get() == sizeof(I))
{
indices = ReadBinaryData<I>(indicesBuffer, indicesOffset, count);
}
else
{
indices = ReadBinaryDataInterleaved<I>(indicesBuffer, indicesOffset, count, 1U, indicesBufferView.byteStride);
indices = ReadBinaryDataInterleaved<I>(indicesBuffer, indicesOffset, count, 1U, indicesBufferView.byteStride.Get());
}
std::vector<T> values;
if (valuesBufferView.byteStride == 0U ||
valuesBufferView.byteStride == elementSize)
if (!valuesBufferView.byteStride || valuesBufferView.byteStride.Get() == elementSize)
{
values = ReadBinaryData<T>(valuesBuffer, valuesOffset, count * typeCount);
}
else
{
values = ReadBinaryDataInterleaved<T>(valuesBuffer, valuesOffset, count, typeCount, valuesBufferView.byteStride);
values = ReadBinaryDataInterleaved<T>(valuesBuffer, valuesOffset, count, typeCount, valuesBufferView.byteStride.Get());
}
for (size_t i = 0; i < indices.size(); i++)

Просмотреть файл

@ -0,0 +1,198 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Exceptions.h"
namespace Microsoft
{
namespace glTF
{
template<typename T>
class Optional final
{
public:
Optional() : isConstructed(false)
{
}
Optional(T&& t) : isConstructed(true)
{
new (this->GetStorage()) T(std::move(t)); // In-place new;
}
Optional(const T& t) : isConstructed(true)
{
new (this->GetStorage()) T(t); // In-place new;
}
Optional(Optional<T>&& other) : isConstructed(false)
{
if (other.isConstructed)
{
Swap(other);
}
}
Optional(const Optional& other) : isConstructed(other.isConstructed)
{
if (other.isConstructed)
{
new (this->GetStorage()) T(other.Get()); // In-place new;
}
}
~Optional()
{
Reset();
}
T& Get()
{
if (isConstructed)
{
return *static_cast<T*>(this->GetStorage());
}
else
{
throw GLTFException("Optional has no value");
}
}
const T& Get() const
{
if (isConstructed)
{
return *static_cast<const T*>(this->GetStorage());
}
else
{
throw GLTFException("Optional has no value");
}
}
bool HasValue() const noexcept
{
return isConstructed;
}
void Reset()
{
if (isConstructed)
{
Get().~T(); // In-place delete;
}
isConstructed = false;
}
void Swap(Optional& other)
{
Swap(*this, other);
}
static void Swap(Optional& lhs, Optional& rhs)
{
if (lhs && rhs)
{
std::swap(lhs.Get(), rhs.Get());
}
else if (lhs)
{
new (rhs.GetStorage()) T(std::move(lhs.Get()));
rhs.isConstructed = true;
lhs.Reset();
}
else if (rhs)
{
new (lhs.GetStorage()) T(std::move(rhs.Get()));
lhs.isConstructed = true;
rhs.Reset();
}
}
Optional& operator=(Optional&& other)
{
if (this != &other)
{
Optional(std::move(other)).Swap(*this);
}
return *this;
}
Optional& operator=(const Optional& other)
{
if (this != &other)
{
Optional(other).Swap(*this);
}
return *this;
}
Optional& operator=(T&& t)
{
if (isConstructed)
{
Get() = std::move(t);
}
else
{
new (this->GetStorage()) T(std::move(t)); // In-place new;
isConstructed = true;
}
return *this;
}
Optional& operator=(const T& t)
{
if (isConstructed)
{
Get() = t;
}
else
{
new (this->GetStorage()) T(t); // In-place new;
isConstructed = true;
}
return *this;
}
explicit operator bool() const noexcept
{
return HasValue();
}
private:
void* GetStorage()
{
return storage;
}
const void* GetStorage() const
{
return storage;
}
alignas(alignof(T)) unsigned char storage[sizeof(T)];
bool isConstructed;
};
template<typename T>
bool operator==(const Optional<T>& lhs, const Optional<T>& rhs)
{
return (!lhs && !rhs) || ((lhs && rhs) && (lhs.Get() == rhs.Get()));
}
template<typename T>
bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs)
{
return !(lhs == rhs);
}
}
}

Просмотреть файл

@ -62,7 +62,7 @@ const Buffer& BufferBuilder::AddBuffer(const char* bufferId)
return bufferRef;
}
const BufferView& BufferBuilder::AddBufferView(BufferViewTarget target)
const BufferView& BufferBuilder::AddBufferView(Optional<BufferViewTarget> target)
{
Buffer& buffer = m_buffers.Back();
BufferView bufferView;
@ -80,7 +80,7 @@ const BufferView& BufferBuilder::AddBufferView(BufferViewTarget target)
return m_bufferViews.Append(std::move(bufferView), AppendIdPolicy::GenerateOnEmpty);
}
const BufferView& BufferBuilder::AddBufferView(const void* data, size_t byteLength, size_t byteStride, BufferViewTarget target)
const BufferView& BufferBuilder::AddBufferView(const void* data, size_t byteLength, Optional<size_t> byteStride, Optional<BufferViewTarget> target)
{
Buffer& buffer = m_buffers.Back();
BufferView bufferView;
@ -170,7 +170,8 @@ void BufferBuilder::AddAccessors(const void* data, size_t count, size_t byteStri
extent = count * byteStride;
// Ensure all accessors fit within the buffer view's extent.
const size_t lastElement = (count - 1) * bufferView.byteStride;
const size_t lastElement = (count - 1) * (bufferView.byteStride ? bufferView.byteStride.Get() : 0U);
for (size_t i = 0; i < descCount; ++i)
{
const size_t accessorSize = Accessor::GetTypeCount(pDescs[i].accessorType) * Accessor::GetComponentTypeSize(pDescs[i].componentType);

Просмотреть файл

@ -181,18 +181,18 @@ namespace
bv.bufferId = std::to_string(FindRequiredMember("buffer", v)->value.GetUint());
bv.byteOffset = GetMemberValueOrDefault<size_t>(v, "byteOffset");
bv.byteLength = GetValue<size_t>(FindRequiredMember("byteLength", v)->value);
bv.byteStride = GetMemberValueOrDefault<size_t>(v, "byteStride", 0U);
auto itByteStride = v.FindMember("byteStride");
if (itByteStride != v.MemberEnd())
{
bv.byteStride = itByteStride->value.GetUint();
}
// When target is not provided, the bufferView contains animation or skin data
auto it = v.FindMember("target");
if (it != v.MemberEnd())
auto itTarget = v.FindMember("target");
if (itTarget != v.MemberEnd())
{
bv.target = static_cast<BufferViewTarget>(it->value.GetUint());
}
else
{
bv.target = BufferViewTarget::UNKNOWN_BUFFER;
bv.target = static_cast<BufferViewTarget>(itTarget->value.GetUint());
}
ParseProperty(v, bv, extensionDeserializer);
@ -413,13 +413,33 @@ namespace
throw InvalidGLTFException("Camera perspective projection undefined");
}
float aspectRatio = GetMemberValueOrDefault<float>(perspectiveIt->value, "aspectRatio", 0.0f);
Optional<float> aspectRatio;
auto itAspectRatio = perspectiveIt->value.FindMember("target");
if (itAspectRatio != perspectiveIt->value.MemberEnd())
{
aspectRatio = itAspectRatio->value.GetFloat();
}
float yfov = GetValue<float>(FindRequiredMember("yfov", perspectiveIt->value)->value);
float znear = GetValue<float>(FindRequiredMember("znear", perspectiveIt->value)->value);
float zfar = GetMemberValueOrDefault<float>(perspectiveIt->value, "zfar", std::numeric_limits<float>::infinity());
projection = std::make_unique<Perspective>(zfar, znear, aspectRatio, yfov);
ParseProperty(perspectiveIt->value, *projection, extensionDeserializer);
Optional<float> zfar;
auto itZFar = perspectiveIt->value.FindMember("zfar");
if (itZFar != perspectiveIt->value.MemberEnd())
{
zfar = itZFar->value.GetFloat();
}
auto perspective = std::make_unique<Perspective>(znear, yfov);
perspective->zfar = zfar;
perspective->aspectRatio = aspectRatio;
ParseProperty(perspectiveIt->value, *perspective, extensionDeserializer);
projection = std::move(perspective);
}
else if (projectionType == "orthographic")
{
@ -485,10 +505,20 @@ namespace
Sampler sampler;
sampler.name = GetMemberValueOrDefault<std::string>(v, "name");
sampler.minFilter = Sampler::GetSamplerMinFilterMode(GetMemberValueOrDefault<int>(v, "minFilter", static_cast<int>(Sampler::kMinFilterDefault)));
sampler.magFilter = Sampler::GetSamplerMagFilterMode(GetMemberValueOrDefault<int>(v, "magFilter", static_cast<int>(Sampler::kMagFilterDefault)));
sampler.wrapT = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<int>(v, "wrapT", static_cast<int>(Sampler::kWrapTDefault)));
sampler.wrapS = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<int>(v, "wrapS", static_cast<int>(Sampler::kWrapSDefault)));
sampler.wrapT = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<unsigned int>(v, "wrapT", static_cast<unsigned int>(WrapMode::Wrap_REPEAT)));
sampler.wrapS = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<unsigned int>(v, "wrapS", static_cast<unsigned int>(WrapMode::Wrap_REPEAT)));
auto itMin = v.FindMember("minFilter");
if (itMin != v.MemberEnd())
{
sampler.minFilter = Sampler::GetSamplerMinFilterMode(itMin->value.GetUint());
}
auto itMag = v.FindMember("magFilter");
if (itMag != v.MemberEnd())
{
sampler.magFilter = Sampler::GetSamplerMagFilterMode(itMag->value.GetUint());
}
ParseProperty(v, sampler, extensionDeserializer);

Просмотреть файл

@ -406,19 +406,17 @@ std::unique_ptr<Extension> KHR::MeshPrimitives::DeserializeDracoMeshCompression(
KHR::TextureInfos::TextureTransform::TextureTransform() :
offset(Vector2::ZERO),
rotation(0.0f),
scale(Vector2::ONE)
scale(Vector2::ONE),
texCoord()
{
}
KHR::TextureInfos::TextureTransform::TextureTransform(const TextureTransform& textureTransform) :
offset(textureTransform.offset),
rotation(textureTransform.rotation),
scale(textureTransform.scale)
scale(textureTransform.scale),
texCoord(textureTransform.texCoord)
{
if (textureTransform.texCoord)
{
texCoord = std::make_unique<size_t>(*textureTransform.texCoord);
}
}
std::unique_ptr<Extension> KHR::TextureInfos::TextureTransform::Clone() const
@ -435,9 +433,7 @@ bool KHR::TextureInfos::TextureTransform::IsEqual(const Extension& rhs) const
&& this->offset == other->offset
&& this->rotation == other->rotation
&& this->scale == other->scale
&& ((!this->texCoord && !other->texCoord) ||
((this->texCoord && other->texCoord) &&
*this->texCoord == *other->texCoord));
&& this->texCoord == other->texCoord;
}
std::string KHR::TextureInfos::SerializeTextureTransform(const TextureTransform& textureTransform, const Document& gltfDocument, const ExtensionSerializer& extensionSerializer)
@ -463,7 +459,7 @@ std::string KHR::TextureInfos::SerializeTextureTransform(const TextureTransform&
if (textureTransform.texCoord)
{
KHR_textureTransform.AddMember("texCoord", ToKnownSizeType(*textureTransform.texCoord), a);
KHR_textureTransform.AddMember("texCoord", ToKnownSizeType(textureTransform.texCoord.Get()), a);
}
SerializeProperty(gltfDocument, textureTransform, KHR_textureTransform, a, extensionSerializer);
@ -526,7 +522,7 @@ std::unique_ptr<Extension> KHR::TextureInfos::DeserializeTextureTransform(const
auto texCoordIt = sit.FindMember("texCoord");
if (texCoordIt != sit.MemberEnd())
{
textureTransform.texCoord = std::make_unique<size_t>(static_cast<size_t>(texCoordIt->value.GetUint()));
textureTransform.texCoord = static_cast<size_t>(texCoordIt->value.GetUint());
}
ParseProperty(sit, textureTransform, extensionDeserializer);

Просмотреть файл

@ -336,16 +336,14 @@ namespace
bufferViewValue.AddMember("byteOffset", ToKnownSizeType(bufferView.byteOffset), a);
bufferViewValue.AddMember("byteLength", ToKnownSizeType(bufferView.byteLength), a);
// byteStride of 0U (default) means that data is tightly packed, so omit byteStride
if (bufferView.byteStride != 0U)
if (bufferView.byteStride)
{
bufferViewValue.AddMember("byteStride", ToKnownSizeType(bufferView.byteStride), a);
bufferViewValue.AddMember("byteStride", ToKnownSizeType(bufferView.byteStride.Get()), a);
}
// Do not write default/invalid values
if (bufferView.target != UNKNOWN_BUFFER)
if (bufferView.target)
{
bufferViewValue.AddMember("target", bufferView.target, a);
bufferViewValue.AddMember("target", bufferView.target.Get(), a);
}
SerializeProperty(gltfDocument, bufferView, bufferViewValue, a, extensionSerializer);
@ -636,33 +634,39 @@ namespace
if (camera.projection->GetProjectionType() == ProjectionType::PERSPECTIVE)
{
projectionValue.AddMember("znear", RapidJsonUtils::ToFloatValue(camera.GetPerspective().znear), a);
projectionValue.AddMember("yfov", RapidJsonUtils::ToFloatValue(camera.GetPerspective().yfov), a);
if (camera.GetPerspective().zfar != std::numeric_limits<float>::infinity())
const auto& perspective = camera.GetPerspective();
projectionValue.AddMember("znear", RapidJsonUtils::ToFloatValue(perspective.znear), a);
projectionValue.AddMember("yfov", RapidJsonUtils::ToFloatValue(perspective.yfov), a);
if (perspective.zfar)
{
projectionValue.AddMember("zfar", RapidJsonUtils::ToFloatValue(camera.projection->zfar), a);
}
if (camera.GetPerspective().HasCustomAspectRatio())
{
projectionValue.AddMember("aspectRatio", RapidJsonUtils::ToFloatValue(camera.GetPerspective().aspectRatio), a);
projectionValue.AddMember("zfar", RapidJsonUtils::ToFloatValue(perspective.zfar.Get()), a);
}
SerializeProperty(gltfDocument, *camera.projection, projectionValue, a, extensionSerializer);
if (perspective.aspectRatio)
{
projectionValue.AddMember("aspectRatio", RapidJsonUtils::ToFloatValue(perspective.aspectRatio.Get()), a);
}
SerializeProperty(gltfDocument, perspective, projectionValue, a, extensionSerializer);
cameraValue.AddMember("perspective", projectionValue, a);
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("perspective", a), a);
}
else if (camera.projection->GetProjectionType() == ProjectionType::ORTHOGRAPHIC)
{
projectionValue.AddMember("xmag", RapidJsonUtils::ToFloatValue(camera.GetOrthographic().xmag), a);
projectionValue.AddMember("ymag", RapidJsonUtils::ToFloatValue(camera.GetOrthographic().ymag), a);
projectionValue.AddMember("znear", RapidJsonUtils::ToFloatValue(camera.GetOrthographic().znear), a);
projectionValue.AddMember("zfar", RapidJsonUtils::ToFloatValue(camera.GetOrthographic().zfar), a);
const auto& orthographic = camera.GetOrthographic();
SerializeProperty(gltfDocument, *camera.projection, projectionValue, a, extensionSerializer);
projectionValue.AddMember("xmag", RapidJsonUtils::ToFloatValue(orthographic.xmag), a);
projectionValue.AddMember("ymag", RapidJsonUtils::ToFloatValue(orthographic.ymag), a);
projectionValue.AddMember("znear", RapidJsonUtils::ToFloatValue(orthographic.znear), a);
projectionValue.AddMember("zfar", RapidJsonUtils::ToFloatValue(orthographic.zfar), a);
SerializeProperty(gltfDocument, orthographic, projectionValue, a, extensionSerializer);
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("orthographic", a), a);
cameraValue.AddMember("orthographic", projectionValue, a);
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("orthographic", a), a);
}
SerializeProperty(gltfDocument, camera, cameraValue, a, extensionSerializer);
@ -676,28 +680,33 @@ namespace
{
rapidjson::Document::AllocatorType& a = document.GetAllocator();
rapidjson::Value samplerValue(rapidjson::kObjectType);
{
RapidJsonUtils::AddOptionalMember("name", samplerValue, sampler.name, a);
if (sampler.magFilter != Sampler::kMagFilterDefault)
if (sampler.magFilter)
{
samplerValue.AddMember("magFilter", sampler.magFilter, a);
samplerValue.AddMember("magFilter", sampler.magFilter.Get(), a);
}
if (sampler.minFilter != Sampler::kMinFilterDefault)
if (sampler.minFilter)
{
samplerValue.AddMember("minFilter", sampler.minFilter, a);
samplerValue.AddMember("minFilter", sampler.minFilter.Get(), a);
}
if (sampler.wrapS != Sampler::kWrapSDefault)
if (sampler.wrapS != WrapMode::Wrap_REPEAT)
{
samplerValue.AddMember("wrapS", sampler.wrapS, a);
}
if (sampler.wrapT != Sampler::kWrapTDefault)
if (sampler.wrapT != WrapMode::Wrap_REPEAT)
{
samplerValue.AddMember("wrapT", sampler.wrapT, a);
}
SerializeProperty(gltfDocument, sampler, samplerValue, a, extensionSerializer);
}
return samplerValue;
}