Chriche/optional (#36)
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:
Родитель
fc96348a60
Коммит
bf524fe3e9
|
@ -60,6 +60,7 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Math.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Math.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\MeshPrimitiveUtils.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\MeshPrimitiveUtils.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\MicrosoftGeneratorVersion.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\PBRUtils.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\RapidJsonUtils.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\RapidJsonUtils.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\ResourceReaderUtils.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\ResourceReaderUtils.h" />
|
||||||
|
|
|
@ -197,6 +197,9 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\SchemaValidation.h">
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\SchemaValidation.h">
|
||||||
<Filter>Header Files\GLTFSDK</Filter>
|
<Filter>Header Files\GLTFSDK</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)..\GLTFSDK\Inc\GLTFSDK\Optional.h">
|
||||||
|
<Filter>Header Files\GLTFSDK</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(MSBuildThisFileDirectory)..\GLTFSDK\schema\accessor.schema.json">
|
<None Include="$(MSBuildThisFileDirectory)..\GLTFSDK\schema\accessor.schema.json">
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
<ClCompile Include="Source\IndexedContainerTests.cpp" />
|
<ClCompile Include="Source\IndexedContainerTests.cpp" />
|
||||||
<ClCompile Include="Source\MeshPrimitiveUtilsTests.cpp" />
|
<ClCompile Include="Source\MeshPrimitiveUtilsTests.cpp" />
|
||||||
<ClCompile Include="Source\MicrosoftGeneratorVersionTests.cpp" />
|
<ClCompile Include="Source\MicrosoftGeneratorVersionTests.cpp" />
|
||||||
|
<ClCompile Include="Source\OptionalTests.cpp" />
|
||||||
<ClCompile Include="Source\PBRUtilsTests.cpp" />
|
<ClCompile Include="Source\PBRUtilsTests.cpp" />
|
||||||
<ClCompile Include="Source\ResourceReaderUtilsTests.cpp" />
|
<ClCompile Include="Source\ResourceReaderUtilsTests.cpp" />
|
||||||
<ClCompile Include="Source\SerializeTests.cpp" />
|
<ClCompile Include="Source\SerializeTests.cpp" />
|
||||||
|
|
|
@ -92,6 +92,9 @@
|
||||||
<ClCompile Include="Source\GLBResourceWriterTests.cpp">
|
<ClCompile Include="Source\GLBResourceWriterTests.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Source\OptionalTests.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Resources\gltf\ReciprocatingSaw.gltf">
|
<None Include="Resources\gltf\ReciprocatingSaw.gltf">
|
||||||
|
@ -255,5 +258,8 @@
|
||||||
<None Include="Resources\glTF-Asset-Generator\Mesh_PrimitiveMode\Mesh_PrimitiveMode_15.bin">
|
<None Include="Resources\glTF-Asset-Generator\Mesh_PrimitiveMode\Mesh_PrimitiveMode_15.bin">
|
||||||
<Filter>Resource Files</Filter>
|
<Filter>Resource Files</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="Resources\gltf\TextureTransformTest.gltf">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -429,7 +429,7 @@ namespace Microsoft
|
||||||
|
|
||||||
auto checkTextureInfo = [](
|
auto checkTextureInfo = [](
|
||||||
const Material& material,
|
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;
|
auto& textureInfo = material.metallicRoughness.baseColorTexture;
|
||||||
|
|
||||||
|
@ -441,19 +441,19 @@ namespace Microsoft
|
||||||
expectedTextureTransform.offset = offset;
|
expectedTextureTransform.offset = offset;
|
||||||
expectedTextureTransform.scale = scale;
|
expectedTextureTransform.scale = scale;
|
||||||
expectedTextureTransform.rotation = rotation;
|
expectedTextureTransform.rotation = rotation;
|
||||||
expectedTextureTransform.texCoord = std::move(texCoord);
|
expectedTextureTransform.texCoord = texCoord;
|
||||||
|
|
||||||
Assert::IsTrue(textureTransform == expectedTextureTransform);
|
Assert::IsTrue(textureTransform == expectedTextureTransform);
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert::IsTrue(doc.materials.Size() == 9);
|
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[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[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[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[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[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[5], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTFSDK_TEST_METHOD(ExtensionsTests, Extensions_Test_HasTextureTransformExtension_TexCoord)
|
GLTFSDK_TEST_METHOD(ExtensionsTests, Extensions_Test_HasTextureTransformExtension_TexCoord)
|
||||||
|
@ -464,7 +464,7 @@ namespace Microsoft
|
||||||
|
|
||||||
auto checkTextureInfo = [](
|
auto checkTextureInfo = [](
|
||||||
const Material& material,
|
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;
|
auto& textureInfo = material.metallicRoughness.baseColorTexture;
|
||||||
|
|
||||||
|
@ -476,15 +476,15 @@ namespace Microsoft
|
||||||
expectedTextureTransform.offset = offset;
|
expectedTextureTransform.offset = offset;
|
||||||
expectedTextureTransform.scale = scale;
|
expectedTextureTransform.scale = scale;
|
||||||
expectedTextureTransform.rotation = rotation;
|
expectedTextureTransform.rotation = rotation;
|
||||||
expectedTextureTransform.texCoord = std::move(texCoord);
|
expectedTextureTransform.texCoord = texCoord;
|
||||||
|
|
||||||
Assert::IsTrue(textureTransform == expectedTextureTransform);
|
Assert::IsTrue(textureTransform == expectedTextureTransform);
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert::IsTrue(doc.materials.Size() == 2);
|
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[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), {});
|
checkTextureInfo(doc.materials[1], Vector2(-0.2f, -0.1f), 0.3f, Vector2(1.5f, 1.5f));
|
||||||
|
|
||||||
const auto extensionSerializer = KHR::GetKHRExtensionSerializer();
|
const auto extensionSerializer = KHR::GetKHRExtensionSerializer();
|
||||||
auto tt = Serialize(doc, extensionSerializer);
|
auto tt = Serialize(doc, extensionSerializer);
|
||||||
|
|
|
@ -254,7 +254,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
writer.Write(bufferView, data.data());
|
writer.Write(bufferView, data.data());
|
||||||
|
|
||||||
|
@ -280,7 +279,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
writer.Write(bufferView, data.data());
|
writer.Write(bufferView, data.data());
|
||||||
|
|
||||||
|
@ -306,7 +304,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
bufferView.byteLength = data.size() * sizeof(uint32_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
writer.Write(bufferView, data.data());
|
writer.Write(bufferView, data.data());
|
||||||
|
|
||||||
|
@ -332,7 +329,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data1.size() * sizeof(uint32_t);
|
bufferView.byteLength = data1.size() * sizeof(uint32_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
writer.Write(bufferView, data1.data());
|
writer.Write(bufferView, data1.data());
|
||||||
|
|
||||||
|
@ -361,7 +357,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(float);
|
bufferView.byteLength = data.size() * sizeof(float);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
Accessor accessor;
|
Accessor accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
@ -399,7 +394,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(float);
|
bufferView.byteLength = data.size() * sizeof(float);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
Accessor accessor;
|
Accessor accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
@ -435,7 +429,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data1.size() * sizeof(uint8_t);
|
bufferView.byteLength = data1.size() * sizeof(uint8_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
Accessor accessor;
|
Accessor accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
@ -488,7 +481,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data1.size() * sizeof(uint8_t);
|
bufferView.byteLength = data1.size() * sizeof(uint8_t);
|
||||||
bufferView.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
|
|
||||||
Accessor accessor;
|
Accessor accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
@ -535,7 +527,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 0;
|
bufferView.byteOffset = 0;
|
||||||
bufferView.byteLength = data.size() * sizeof(uint32_t) + 1U;// Add an additional byte as the accessor's byteOffset is 1;
|
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 accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
@ -563,7 +554,6 @@ namespace Microsoft
|
||||||
bufferView.bufferId = "0";
|
bufferView.bufferId = "0";
|
||||||
bufferView.byteOffset = 1U;
|
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.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 accessor;
|
||||||
accessor.id = "0";
|
accessor.id = "0";
|
||||||
|
|
|
@ -18,26 +18,26 @@ namespace
|
||||||
void TestBadGLTFSerializeToJson(const Document& doc)
|
void TestBadGLTFSerializeToJson(const Document& doc)
|
||||||
{
|
{
|
||||||
Assert::ExpectException<GLTFException>([&doc]
|
Assert::ExpectException<GLTFException>([&doc]
|
||||||
{
|
{
|
||||||
Serialize(doc);
|
Serialize(doc);
|
||||||
}, L"Expected exception was not thrown");
|
}, L"Expected exception was not thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestBadGLTFDeserializeToDocument(const char* data)
|
void TestBadGLTFDeserializeToDocument(const char* data)
|
||||||
{
|
{
|
||||||
Assert::ExpectException<GLTFException>([&data]
|
Assert::ExpectException<GLTFException>([&data]
|
||||||
{
|
{
|
||||||
Deserialize(data);
|
Deserialize(data);
|
||||||
}, L"Expected exception was not thrown");
|
}, L"Expected exception was not thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestDocumentValidationFail(const char* data)
|
void TestDocumentValidationFail(const char* data)
|
||||||
{
|
{
|
||||||
Assert::ExpectException<ValidationException>([&data]
|
Assert::ExpectException<ValidationException>([&data]
|
||||||
{
|
{
|
||||||
auto doc = Deserialize(data);
|
auto doc = Deserialize(data);
|
||||||
Validation::Validate(doc);
|
Validation::Validate(doc);
|
||||||
}, L"Expected exception was not thrown");
|
}, L"Expected exception was not thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* c_invalidPrimitiveAccessorComponentType = R"({
|
const char* c_invalidPrimitiveAccessorComponentType = R"({
|
||||||
|
@ -294,12 +294,77 @@ namespace
|
||||||
],
|
],
|
||||||
"scene": 0
|
"scene": 0
|
||||||
})";
|
})";
|
||||||
|
|
||||||
|
const char* c_validSamplerDocument = R"({
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"minFilter": 9728,
|
||||||
|
"magFilter": 9729
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wrapS": 33648,
|
||||||
|
"wrapT": 33071
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft
|
namespace Microsoft
|
||||||
{
|
{
|
||||||
namespace glTF
|
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
|
namespace Test
|
||||||
{
|
{
|
||||||
GLTFSDK_TEST_CLASS(SerializerGLTFTests)
|
GLTFSDK_TEST_CLASS(SerializerGLTFTests)
|
||||||
|
@ -423,6 +488,25 @@ namespace Microsoft
|
||||||
|
|
||||||
TestBadGLTFSerializeToJson(doc);
|
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 Buffer& AddBuffer(const char* bufferId = nullptr);
|
||||||
|
|
||||||
const BufferView& AddBufferView(BufferViewTarget target);
|
const BufferView& AddBufferView(Optional<BufferViewTarget> target);
|
||||||
const BufferView& AddBufferView(const void* data, size_t byteLength, size_t byteStride = 0, BufferViewTarget target = BufferViewTarget::UNKNOWN_BUFFER);
|
const BufferView& AddBufferView(const void* data, size_t byteLength, Optional<size_t> byteStride = {}, Optional<BufferViewTarget> target = {});
|
||||||
|
|
||||||
template<typename T>
|
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);
|
return AddBufferView(data.data(), data.size() * sizeof(T), byteStride, target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <GLTFSDK/ExtensionHandlers.h>
|
#include <GLTFSDK/ExtensionHandlers.h>
|
||||||
|
#include <GLTFSDK/Optional.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -84,8 +85,7 @@ namespace Microsoft
|
||||||
Vector2 offset;
|
Vector2 offset;
|
||||||
float rotation;
|
float rotation;
|
||||||
Vector2 scale;
|
Vector2 scale;
|
||||||
// TexCoord is optional
|
Optional<size_t> texCoord; // TexCoord is an optional property
|
||||||
std::unique_ptr<size_t> texCoord;
|
|
||||||
|
|
||||||
std::unique_ptr<Extension> Clone() const override;
|
std::unique_ptr<Extension> Clone() const override;
|
||||||
bool IsEqual(const Extension& rhs) const override;
|
bool IsEqual(const Extension& rhs) const override;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <GLTFSDK/Extension.h>
|
#include <GLTFSDK/Extension.h>
|
||||||
#include <GLTFSDK/IndexedContainer.h>
|
#include <GLTFSDK/IndexedContainer.h>
|
||||||
#include <GLTFSDK/Math.h>
|
#include <GLTFSDK/Math.h>
|
||||||
|
#include <GLTFSDK/Optional.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -23,7 +24,6 @@ namespace Microsoft
|
||||||
{
|
{
|
||||||
enum BufferViewTarget
|
enum BufferViewTarget
|
||||||
{
|
{
|
||||||
UNKNOWN_BUFFER = 0,
|
|
||||||
ARRAY_BUFFER = 34962,
|
ARRAY_BUFFER = 34962,
|
||||||
ELEMENT_ARRAY_BUFFER = 34963
|
ELEMENT_ARRAY_BUFFER = 34963
|
||||||
};
|
};
|
||||||
|
@ -332,8 +332,8 @@ namespace Microsoft
|
||||||
std::string bufferId;
|
std::string bufferId;
|
||||||
size_t byteOffset = 0U;
|
size_t byteOffset = 0U;
|
||||||
size_t byteLength = 0U;
|
size_t byteLength = 0U;
|
||||||
size_t byteStride = 0U; // 0 = tight packing
|
Optional<size_t> byteStride;
|
||||||
BufferViewTarget target = UNKNOWN_BUFFER;
|
Optional<BufferViewTarget> target;
|
||||||
|
|
||||||
bool operator==(const BufferView& rhs) const
|
bool operator==(const BufferView& rhs) const
|
||||||
{
|
{
|
||||||
|
@ -880,16 +880,12 @@ namespace Microsoft
|
||||||
|
|
||||||
struct Projection : glTFProperty
|
struct Projection : glTFProperty
|
||||||
{
|
{
|
||||||
float zfar;
|
|
||||||
float znear;
|
float znear;
|
||||||
|
|
||||||
virtual ProjectionType GetProjectionType() const = 0;
|
virtual ProjectionType GetProjectionType() const = 0;
|
||||||
virtual std::unique_ptr<Projection> Clone() const = 0;
|
virtual std::unique_ptr<Projection> Clone() const = 0;
|
||||||
|
|
||||||
virtual bool IsValid() const
|
virtual bool IsValid() const = 0;
|
||||||
{
|
|
||||||
return zfar > znear;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Projection& rhs) const
|
bool operator==(const Projection& rhs) const
|
||||||
{
|
{
|
||||||
|
@ -902,16 +898,13 @@ namespace Microsoft
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Projection(float zfar, float znear) :
|
Projection(float znear) : znear(znear)
|
||||||
zfar(zfar),
|
|
||||||
znear(znear)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool IsEqual(const Projection& rhs) const
|
virtual bool IsEqual(const Projection& rhs) const
|
||||||
{
|
{
|
||||||
return glTFProperty::Equals(*this, rhs)
|
return glTFProperty::Equals(*this, rhs)
|
||||||
&& this->zfar == rhs.zfar
|
|
||||||
&& this->znear == rhs.znear;
|
&& this->znear == rhs.znear;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -920,37 +913,41 @@ namespace Microsoft
|
||||||
{
|
{
|
||||||
float xmag;
|
float xmag;
|
||||||
float ymag;
|
float ymag;
|
||||||
|
float zfar;
|
||||||
|
|
||||||
Orthographic(float zfar, float znear, float xmag, float ymag) :
|
Orthographic(float zfar, float znear, float xmag, float ymag) :
|
||||||
Projection(zfar, znear),
|
Projection(znear),
|
||||||
xmag(xmag),
|
xmag(xmag),
|
||||||
ymag(ymag)
|
ymag(ymag),
|
||||||
|
zfar(zfar)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool IsValid() const
|
bool IsValid() const override
|
||||||
{
|
{
|
||||||
return Projection::IsValid()
|
return (zfar > znear)
|
||||||
&& ymag != 0.0
|
&& (ymag != 0.0)
|
||||||
&& xmag != 0.0;
|
&& (xmag != 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ProjectionType GetProjectionType() const
|
ProjectionType GetProjectionType() const override
|
||||||
{
|
{
|
||||||
return ProjectionType::ORTHOGRAPHIC;
|
return ProjectionType::ORTHOGRAPHIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<Projection> Clone() const
|
std::unique_ptr<Projection> Clone() const override
|
||||||
{
|
{
|
||||||
return std::make_unique<Orthographic>(*this);
|
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))
|
if (const auto other = dynamic_cast<const Orthographic*>(&rhs))
|
||||||
{
|
{
|
||||||
return Projection::IsEqual(rhs)
|
return Projection::IsEqual(rhs)
|
||||||
&& xmag == other->xmag
|
&& xmag == other->xmag
|
||||||
&& ymag == other->ymag;
|
&& ymag == other->ymag
|
||||||
|
&& zfar == other->zfar;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -959,43 +956,59 @@ namespace Microsoft
|
||||||
|
|
||||||
struct Perspective : Projection
|
struct Perspective : Projection
|
||||||
{
|
{
|
||||||
float aspectRatio;
|
Optional<float> aspectRatio;
|
||||||
float yfov;
|
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) :
|
Perspective(float zfar, float znear, float aspectRatio, float yfov) :
|
||||||
Projection(zfar, znear),
|
Projection(znear),
|
||||||
aspectRatio(aspectRatio),
|
aspectRatio(aspectRatio),
|
||||||
yfov(yfov)
|
yfov(yfov),
|
||||||
|
zfar(zfar)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValid() const override
|
||||||
|
{
|
||||||
|
return !zfar.HasValue() || (zfar.Get() > znear);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsFinite() const
|
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
|
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;
|
return ProjectionType::PERSPECTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<Projection> Clone() const
|
std::unique_ptr<Projection> Clone() const override
|
||||||
{
|
{
|
||||||
return std::make_unique<Perspective>(*this);
|
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))
|
if (const auto other = dynamic_cast<const Perspective*>(&rhs))
|
||||||
{
|
{
|
||||||
return Projection::IsEqual(rhs)
|
return Projection::IsEqual(rhs)
|
||||||
&& aspectRatio == other->aspectRatio
|
&& aspectRatio == other->aspectRatio
|
||||||
&& yfov == other->yfov;
|
&& yfov == other->yfov
|
||||||
|
&& zfar == other->zfar;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1038,6 +1051,7 @@ namespace Microsoft
|
||||||
{
|
{
|
||||||
return *ret;
|
return *ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw GLTFException("Failed to cast projection to orthographic");
|
throw GLTFException("Failed to cast projection to orthographic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,6 +1061,7 @@ namespace Microsoft
|
||||||
{
|
{
|
||||||
return *ret;
|
return *ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw GLTFException("Failed to cast projection to orthographic");
|
throw GLTFException("Failed to cast projection to orthographic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,6 +1076,7 @@ namespace Microsoft
|
||||||
{
|
{
|
||||||
return !projection && !rhs.projection;
|
return !projection && !rhs.projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *projection == *(rhs.projection);
|
return *projection == *(rhs.projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,15 +1194,12 @@ namespace Microsoft
|
||||||
|
|
||||||
struct Sampler : glTFChildOfRootProperty
|
struct Sampler : glTFChildOfRootProperty
|
||||||
{
|
{
|
||||||
static const MagFilterMode kMagFilterDefault = MagFilter_LINEAR;
|
// The glTF spec doesn't define default values for magFilter and minFilter members. When
|
||||||
static const MinFilterMode kMinFilterDefault = MinFilter_NEAREST_MIPMAP_LINEAR;
|
// filtering options are not defined implementations are free to select a suitable value
|
||||||
static const WrapMode kWrapSDefault = Wrap_REPEAT;
|
Optional<MagFilterMode> magFilter;
|
||||||
static const WrapMode kWrapTDefault = Wrap_REPEAT;
|
Optional<MinFilterMode> minFilter;
|
||||||
|
WrapMode wrapS = Wrap_REPEAT;
|
||||||
MagFilterMode magFilter = kMagFilterDefault;
|
WrapMode wrapT = Wrap_REPEAT;
|
||||||
MinFilterMode minFilter = kMinFilterDefault;
|
|
||||||
WrapMode wrapS = kWrapSDefault;
|
|
||||||
WrapMode wrapT = kWrapTDefault;
|
|
||||||
|
|
||||||
static MinFilterMode GetSamplerMinFilterMode(size_t readValue)
|
static MinFilterMode GetSamplerMinFilterMode(size_t readValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -137,14 +137,13 @@ namespace Microsoft
|
||||||
|
|
||||||
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
|
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
|
||||||
|
|
||||||
if (bufferView.byteStride == 0U ||
|
if (!bufferView.byteStride || bufferView.byteStride.Get() == elementSize)
|
||||||
bufferView.byteStride == elementSize)
|
|
||||||
{
|
{
|
||||||
data = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
|
data = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride);
|
data = ReadBinaryDataInterleaved<T>(buffer, offset, accessor.count, typeCount, bufferView.byteStride.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -169,14 +168,13 @@ namespace Microsoft
|
||||||
|
|
||||||
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
|
const size_t offset = accessor.byteOffset + bufferView.byteOffset;
|
||||||
|
|
||||||
if (bufferView.byteStride == 0U ||
|
if (!bufferView.byteStride || bufferView.byteStride.Get() == elementSize)
|
||||||
bufferView.byteStride == elementSize)
|
|
||||||
{
|
{
|
||||||
baseData = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
|
baseData = ReadBinaryData<T>(buffer, offset, accessor.count * typeCount);
|
||||||
}
|
}
|
||||||
else
|
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;
|
std::vector<I> indices;
|
||||||
|
|
||||||
if (indicesBufferView.byteStride == 0U ||
|
if (!indicesBufferView.byteStride || indicesBufferView.byteStride.Get() == sizeof(I))
|
||||||
indicesBufferView.byteStride == sizeof(I))
|
|
||||||
{
|
{
|
||||||
indices = ReadBinaryData<I>(indicesBuffer, indicesOffset, count);
|
indices = ReadBinaryData<I>(indicesBuffer, indicesOffset, count);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
indices = ReadBinaryDataInterleaved<I>(indicesBuffer, indicesOffset, count, 1U, indicesBufferView.byteStride);
|
indices = ReadBinaryDataInterleaved<I>(indicesBuffer, indicesOffset, count, 1U, indicesBufferView.byteStride.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<T> values;
|
std::vector<T> values;
|
||||||
|
|
||||||
if (valuesBufferView.byteStride == 0U ||
|
if (!valuesBufferView.byteStride || valuesBufferView.byteStride.Get() == elementSize)
|
||||||
valuesBufferView.byteStride == elementSize)
|
|
||||||
{
|
{
|
||||||
values = ReadBinaryData<T>(valuesBuffer, valuesOffset, count * typeCount);
|
values = ReadBinaryData<T>(valuesBuffer, valuesOffset, count * typeCount);
|
||||||
}
|
}
|
||||||
else
|
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++)
|
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;
|
return bufferRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BufferView& BufferBuilder::AddBufferView(BufferViewTarget target)
|
const BufferView& BufferBuilder::AddBufferView(Optional<BufferViewTarget> target)
|
||||||
{
|
{
|
||||||
Buffer& buffer = m_buffers.Back();
|
Buffer& buffer = m_buffers.Back();
|
||||||
BufferView bufferView;
|
BufferView bufferView;
|
||||||
|
@ -80,7 +80,7 @@ const BufferView& BufferBuilder::AddBufferView(BufferViewTarget target)
|
||||||
return m_bufferViews.Append(std::move(bufferView), AppendIdPolicy::GenerateOnEmpty);
|
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();
|
Buffer& buffer = m_buffers.Back();
|
||||||
BufferView bufferView;
|
BufferView bufferView;
|
||||||
|
@ -170,7 +170,8 @@ void BufferBuilder::AddAccessors(const void* data, size_t count, size_t byteStri
|
||||||
extent = count * byteStride;
|
extent = count * byteStride;
|
||||||
|
|
||||||
// Ensure all accessors fit within the buffer view's extent.
|
// 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)
|
for (size_t i = 0; i < descCount; ++i)
|
||||||
{
|
{
|
||||||
const size_t accessorSize = Accessor::GetTypeCount(pDescs[i].accessorType) * Accessor::GetComponentTypeSize(pDescs[i].componentType);
|
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.bufferId = std::to_string(FindRequiredMember("buffer", v)->value.GetUint());
|
||||||
bv.byteOffset = GetMemberValueOrDefault<size_t>(v, "byteOffset");
|
bv.byteOffset = GetMemberValueOrDefault<size_t>(v, "byteOffset");
|
||||||
bv.byteLength = GetValue<size_t>(FindRequiredMember("byteLength", v)->value);
|
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
|
// When target is not provided, the bufferView contains animation or skin data
|
||||||
auto it = v.FindMember("target");
|
auto itTarget = v.FindMember("target");
|
||||||
|
if (itTarget != v.MemberEnd())
|
||||||
if (it != v.MemberEnd())
|
|
||||||
{
|
{
|
||||||
bv.target = static_cast<BufferViewTarget>(it->value.GetUint());
|
bv.target = static_cast<BufferViewTarget>(itTarget->value.GetUint());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bv.target = BufferViewTarget::UNKNOWN_BUFFER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseProperty(v, bv, extensionDeserializer);
|
ParseProperty(v, bv, extensionDeserializer);
|
||||||
|
@ -413,13 +413,33 @@ namespace
|
||||||
throw InvalidGLTFException("Camera perspective projection undefined");
|
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 yfov = GetValue<float>(FindRequiredMember("yfov", perspectiveIt->value)->value);
|
||||||
float znear = GetValue<float>(FindRequiredMember("znear", 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")
|
else if (projectionType == "orthographic")
|
||||||
{
|
{
|
||||||
|
@ -485,10 +505,20 @@ namespace
|
||||||
Sampler sampler;
|
Sampler sampler;
|
||||||
|
|
||||||
sampler.name = GetMemberValueOrDefault<std::string>(v, "name");
|
sampler.name = GetMemberValueOrDefault<std::string>(v, "name");
|
||||||
sampler.minFilter = Sampler::GetSamplerMinFilterMode(GetMemberValueOrDefault<int>(v, "minFilter", static_cast<int>(Sampler::kMinFilterDefault)));
|
sampler.wrapT = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<unsigned int>(v, "wrapT", static_cast<unsigned int>(WrapMode::Wrap_REPEAT)));
|
||||||
sampler.magFilter = Sampler::GetSamplerMagFilterMode(GetMemberValueOrDefault<int>(v, "magFilter", static_cast<int>(Sampler::kMagFilterDefault)));
|
sampler.wrapS = Sampler::GetSamplerWrapMode(GetMemberValueOrDefault<unsigned int>(v, "wrapS", static_cast<unsigned int>(WrapMode::Wrap_REPEAT)));
|
||||||
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)));
|
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);
|
ParseProperty(v, sampler, extensionDeserializer);
|
||||||
|
|
||||||
|
|
|
@ -406,19 +406,17 @@ std::unique_ptr<Extension> KHR::MeshPrimitives::DeserializeDracoMeshCompression(
|
||||||
KHR::TextureInfos::TextureTransform::TextureTransform() :
|
KHR::TextureInfos::TextureTransform::TextureTransform() :
|
||||||
offset(Vector2::ZERO),
|
offset(Vector2::ZERO),
|
||||||
rotation(0.0f),
|
rotation(0.0f),
|
||||||
scale(Vector2::ONE)
|
scale(Vector2::ONE),
|
||||||
|
texCoord()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
KHR::TextureInfos::TextureTransform::TextureTransform(const TextureTransform& textureTransform) :
|
KHR::TextureInfos::TextureTransform::TextureTransform(const TextureTransform& textureTransform) :
|
||||||
offset(textureTransform.offset),
|
offset(textureTransform.offset),
|
||||||
rotation(textureTransform.rotation),
|
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
|
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->offset == other->offset
|
||||||
&& this->rotation == other->rotation
|
&& this->rotation == other->rotation
|
||||||
&& this->scale == other->scale
|
&& 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)
|
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)
|
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);
|
SerializeProperty(gltfDocument, textureTransform, KHR_textureTransform, a, extensionSerializer);
|
||||||
|
@ -526,7 +522,7 @@ std::unique_ptr<Extension> KHR::TextureInfos::DeserializeTextureTransform(const
|
||||||
auto texCoordIt = sit.FindMember("texCoord");
|
auto texCoordIt = sit.FindMember("texCoord");
|
||||||
if (texCoordIt != sit.MemberEnd())
|
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);
|
ParseProperty(sit, textureTransform, extensionDeserializer);
|
||||||
|
|
|
@ -336,16 +336,14 @@ namespace
|
||||||
bufferViewValue.AddMember("byteOffset", ToKnownSizeType(bufferView.byteOffset), a);
|
bufferViewValue.AddMember("byteOffset", ToKnownSizeType(bufferView.byteOffset), a);
|
||||||
bufferViewValue.AddMember("byteLength", ToKnownSizeType(bufferView.byteLength), a);
|
bufferViewValue.AddMember("byteLength", ToKnownSizeType(bufferView.byteLength), a);
|
||||||
|
|
||||||
// byteStride of 0U (default) means that data is tightly packed, so omit byteStride
|
if (bufferView.byteStride)
|
||||||
if (bufferView.byteStride != 0U)
|
|
||||||
{
|
{
|
||||||
bufferViewValue.AddMember("byteStride", ToKnownSizeType(bufferView.byteStride), a);
|
bufferViewValue.AddMember("byteStride", ToKnownSizeType(bufferView.byteStride.Get()), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not write default/invalid values
|
if (bufferView.target)
|
||||||
if (bufferView.target != UNKNOWN_BUFFER)
|
|
||||||
{
|
{
|
||||||
bufferViewValue.AddMember("target", bufferView.target, a);
|
bufferViewValue.AddMember("target", bufferView.target.Get(), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeProperty(gltfDocument, bufferView, bufferViewValue, a, extensionSerializer);
|
SerializeProperty(gltfDocument, bufferView, bufferViewValue, a, extensionSerializer);
|
||||||
|
@ -636,33 +634,39 @@ namespace
|
||||||
|
|
||||||
if (camera.projection->GetProjectionType() == ProjectionType::PERSPECTIVE)
|
if (camera.projection->GetProjectionType() == ProjectionType::PERSPECTIVE)
|
||||||
{
|
{
|
||||||
projectionValue.AddMember("znear", RapidJsonUtils::ToFloatValue(camera.GetPerspective().znear), a);
|
const auto& perspective = camera.GetPerspective();
|
||||||
projectionValue.AddMember("yfov", RapidJsonUtils::ToFloatValue(camera.GetPerspective().yfov), a);
|
|
||||||
if (camera.GetPerspective().zfar != std::numeric_limits<float>::infinity())
|
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);
|
projectionValue.AddMember("zfar", RapidJsonUtils::ToFloatValue(perspective.zfar.Get()), a);
|
||||||
}
|
|
||||||
if (camera.GetPerspective().HasCustomAspectRatio())
|
|
||||||
{
|
|
||||||
projectionValue.AddMember("aspectRatio", RapidJsonUtils::ToFloatValue(camera.GetPerspective().aspectRatio), 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("perspective", projectionValue, a);
|
||||||
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("perspective", a), a);
|
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("perspective", a), a);
|
||||||
}
|
}
|
||||||
else if (camera.projection->GetProjectionType() == ProjectionType::ORTHOGRAPHIC)
|
else if (camera.projection->GetProjectionType() == ProjectionType::ORTHOGRAPHIC)
|
||||||
{
|
{
|
||||||
projectionValue.AddMember("xmag", RapidJsonUtils::ToFloatValue(camera.GetOrthographic().xmag), a);
|
const auto& orthographic = camera.GetOrthographic();
|
||||||
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);
|
|
||||||
|
|
||||||
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("orthographic", projectionValue, a);
|
||||||
|
cameraValue.AddMember("type", RapidJsonUtils::ToStringValue("orthographic", a), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeProperty(gltfDocument, camera, cameraValue, a, extensionSerializer);
|
SerializeProperty(gltfDocument, camera, cameraValue, a, extensionSerializer);
|
||||||
|
@ -676,28 +680,33 @@ namespace
|
||||||
{
|
{
|
||||||
rapidjson::Document::AllocatorType& a = document.GetAllocator();
|
rapidjson::Document::AllocatorType& a = document.GetAllocator();
|
||||||
rapidjson::Value samplerValue(rapidjson::kObjectType);
|
rapidjson::Value samplerValue(rapidjson::kObjectType);
|
||||||
|
|
||||||
{
|
{
|
||||||
RapidJsonUtils::AddOptionalMember("name", samplerValue, sampler.name, a);
|
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);
|
samplerValue.AddMember("wrapS", sampler.wrapS, a);
|
||||||
}
|
}
|
||||||
if (sampler.wrapT != Sampler::kWrapTDefault)
|
|
||||||
|
if (sampler.wrapT != WrapMode::Wrap_REPEAT)
|
||||||
{
|
{
|
||||||
samplerValue.AddMember("wrapT", sampler.wrapT, a);
|
samplerValue.AddMember("wrapT", sampler.wrapT, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeProperty(gltfDocument, sampler, samplerValue, a, extensionSerializer);
|
SerializeProperty(gltfDocument, sampler, samplerValue, a, extensionSerializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return samplerValue;
|
return samplerValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче