Merge pull request #37 from aws-lumberyard-dev/hultonha_LYN-2528_whitebox_prefab
Add Json serialization support for ByteStream Fixes serialization issue with the White Box component when Prefabs are enabled.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ByteStreamSerializer.h"
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace ByteSerializerInternal
|
||||
{
|
||||
static JsonSerializationResult::Result Load(void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
using JsonSerializationResult::Outcomes;
|
||||
using JsonSerializationResult::Tasks;
|
||||
|
||||
AZ_Assert(outputValue, "Expected a valid pointer to load from json value.");
|
||||
|
||||
switch (inputValue.GetType())
|
||||
{
|
||||
case rapidjson::kStringType: {
|
||||
JsonByteStream buffer;
|
||||
if (AZ::StringFunc::Base64::Decode(buffer, inputValue.GetString(), inputValue.GetStringLength()))
|
||||
{
|
||||
JsonByteStream* valAsByteStream = static_cast<JsonByteStream*>(outputValue);
|
||||
*valAsByteStream = AZStd::move(buffer);
|
||||
return context.Report(Tasks::ReadField, Outcomes::Success, "Successfully read ByteStream.");
|
||||
}
|
||||
return context.Report(Tasks::ReadField, Outcomes::Invalid, "Decode of Base64 encoded ByteStream failed.");
|
||||
}
|
||||
case rapidjson::kArrayType:
|
||||
case rapidjson::kObjectType:
|
||||
case rapidjson::kNullType:
|
||||
case rapidjson::kFalseType:
|
||||
case rapidjson::kTrueType:
|
||||
case rapidjson::kNumberType:
|
||||
return context.Report(
|
||||
Tasks::ReadField, Outcomes::Unsupported,
|
||||
"Unsupported type. ByteStream values cannot be read from arrays, objects, nulls, booleans or numbers.");
|
||||
default:
|
||||
return context.Report(Tasks::ReadField, Outcomes::Unknown, "Unknown json type encountered for ByteStream value.");
|
||||
}
|
||||
}
|
||||
|
||||
static JsonSerializationResult::Result StoreWithDefault(
|
||||
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, JsonSerializerContext& context)
|
||||
{
|
||||
using JsonSerializationResult::Outcomes;
|
||||
using JsonSerializationResult::Tasks;
|
||||
|
||||
const JsonByteStream& valAsByteStream = *static_cast<const JsonByteStream*>(inputValue);
|
||||
if (context.ShouldKeepDefaults() || !defaultValue || (valAsByteStream != *static_cast<const JsonByteStream*>(defaultValue)))
|
||||
{
|
||||
const auto base64ByteStream = AZ::StringFunc::Base64::Encode(valAsByteStream.data(), valAsByteStream.size());
|
||||
outputValue.SetString(base64ByteStream.c_str(), base64ByteStream.size(), context.GetJsonAllocator());
|
||||
return context.Report(Tasks::WriteValue, Outcomes::Success, "ByteStream successfully stored.");
|
||||
}
|
||||
|
||||
return context.Report(Tasks::WriteValue, Outcomes::DefaultsUsed, "Default ByteStream used.");
|
||||
}
|
||||
} // namespace ByteSerializerInternal
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonByteStreamSerializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonByteStreamSerializer::Load(
|
||||
void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
AZ_Assert(
|
||||
azrtti_typeid<JsonByteStream>() == outputValueTypeId,
|
||||
"Unable to deserialize AZStd::vector<AZ::u8>> to json because the provided type is %s",
|
||||
outputValueTypeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
return ByteSerializerInternal::Load(outputValue, inputValue, context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonByteStreamSerializer::Store(
|
||||
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context)
|
||||
{
|
||||
AZ_Assert(
|
||||
azrtti_typeid<JsonByteStream>() == valueTypeId,
|
||||
"Unable to serialize AZStd::vector<AZ::u8> to json because the provided type is %s",
|
||||
valueTypeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
return ByteSerializerInternal::StoreWithDefault(outputValue, inputValue, defaultValue, context);
|
||||
}
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
using JsonByteStream = AZStd::vector<AZ::u8>; //!< Alias for AZStd::vector<AZ::u8>.
|
||||
|
||||
//! Serialize a stream of bytes (usually binary data) as a json string value.
|
||||
//! @note Related to GenericClassByteStream (part of SerializeGenericTypeInfo<AZStd::vector<AZ::u8>> - see AZStdContainers.inl for more
|
||||
//! details).
|
||||
class JsonByteStreamSerializer : public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonByteStreamSerializer, "{30F0EA5A-CD13-4BA7-BAE1-D50D851CAC45}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
JsonSerializationResult::Result Load(
|
||||
void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context) override;
|
||||
};
|
||||
} // namespace AZ
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Serialization/Json/ArraySerializer.h>
|
||||
#include <AzCore/Serialization/Json/BasicContainerSerializer.h>
|
||||
#include <AzCore/Serialization/Json/BoolSerializer.h>
|
||||
#include <AzCore/Serialization/Json/ByteStreamSerializer.h>
|
||||
#include <AzCore/Serialization/Json/DoubleSerializer.h>
|
||||
#include <AzCore/Serialization/Json/IntSerializer.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
@@ -68,6 +69,8 @@ namespace AZ
|
||||
jsonContext->Serializer<JsonStringSerializer>()->HandlesType<AZStd::string>();
|
||||
jsonContext->Serializer<JsonOSStringSerializer>()->HandlesType<OSString>();
|
||||
|
||||
jsonContext->Serializer<JsonByteStreamSerializer>()->HandlesType<JsonByteStream>();
|
||||
|
||||
jsonContext->Serializer<JsonBasicContainerSerializer>()
|
||||
->HandlesType<AZStd::fixed_vector>()
|
||||
->HandlesType<AZStd::forward_list>()
|
||||
|
||||
@@ -505,6 +505,8 @@ set(FILES
|
||||
Serialization/Json/BasicContainerSerializer.cpp
|
||||
Serialization/Json/BoolSerializer.h
|
||||
Serialization/Json/BoolSerializer.cpp
|
||||
Serialization/Json/ByteStreamSerializer.h
|
||||
Serialization/Json/ByteStreamSerializer.cpp
|
||||
Serialization/Json/CastingHelpers.h
|
||||
Serialization/Json/DoubleSerializer.h
|
||||
Serialization/Json/DoubleSerializer.cpp
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Serialization/Json/ByteStreamSerializer.h>
|
||||
#include <Tests/Serialization/Json/BaseJsonSerializerFixture.h>
|
||||
#include <Tests/Serialization/Json/JsonSerializerConformityTests.h>
|
||||
|
||||
namespace JsonSerializationTests
|
||||
{
|
||||
class ByteStreamSerializerTestDescription : public JsonSerializerConformityTestDescriptor<AZ::JsonByteStream>
|
||||
{
|
||||
public:
|
||||
AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() override
|
||||
{
|
||||
return AZStd::make_shared<AZ::JsonByteStreamSerializer>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AZ::JsonByteStream> CreateDefaultInstance() override
|
||||
{
|
||||
return AZStd::make_shared<AZ::JsonByteStream>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AZ::JsonByteStream> CreateFullySetInstance() override
|
||||
{
|
||||
// create a JsonByteStream (AZStd::vector<u8>) with ten 'a's
|
||||
return AZStd::make_shared<AZ::JsonByteStream>(10, 'a');
|
||||
}
|
||||
|
||||
AZStd::string_view GetJsonForFullySetInstance() override
|
||||
{
|
||||
// Base64 encoded version of 'aaaaaaaaaa' (see CreateFullySetInstance)
|
||||
return R"("YWFhYWFhYWFhYQ==")";
|
||||
}
|
||||
|
||||
void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
|
||||
{
|
||||
features.EnableJsonType(rapidjson::kStringType);
|
||||
features.m_supportsPartialInitialization = false;
|
||||
features.m_supportsInjection = false;
|
||||
}
|
||||
|
||||
bool AreEqual(const AZ::JsonByteStream& lhs, const AZ::JsonByteStream& rhs) override
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
using ByteStreamConformityTestTypes = ::testing::Types<ByteStreamSerializerTestDescription>;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(JsonByteStreamSerialzier, JsonSerializerConformityTests, ByteStreamConformityTestTypes);
|
||||
} // namespace JsonSerializationTests
|
||||
@@ -98,6 +98,7 @@ set(FILES
|
||||
Serialization/Json/BaseJsonSerializerTests.cpp
|
||||
Serialization/Json/BasicContainerSerializerTests.cpp
|
||||
Serialization/Json/BoolSerializerTests.cpp
|
||||
Serialization/Json/ByteStreamSerializerTests.cpp
|
||||
Serialization/Json/ColorSerializerTests.cpp
|
||||
Serialization/Json/DoubleSerializerTests.cpp
|
||||
Serialization/Json/IntSerializerTests.cpp
|
||||
|
||||
@@ -102,6 +102,9 @@ namespace WhiteBox
|
||||
//! Alias for a collection of faces.
|
||||
using Faces = AZStd::vector<Face>;
|
||||
|
||||
//! Underlying representation of the White Box mesh (serialized halfedge data).
|
||||
using WhiteBoxMeshStream = AZStd::vector<AZ::u8>;
|
||||
|
||||
//! Represents the vertex handles to be used to form a new face.
|
||||
struct FaceVertHandles
|
||||
{
|
||||
@@ -726,19 +729,33 @@ namespace WhiteBox
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Serialization
|
||||
|
||||
//! The result of attempting to deserialize a white box mesh from a white box mesh stream.
|
||||
enum class ReadResult
|
||||
{
|
||||
Full, //!< The white box mesh stream was full and was read into white box mesh (it is now initialized).
|
||||
Empty, //!< The white box mesh stream was empty so no white box mesh was loaded.
|
||||
Error //!< An error occurred while trying to deserialize white box mesh stream.
|
||||
};
|
||||
|
||||
//! Take an input stream of bytes and create a white box mesh from the deserialized data.
|
||||
//! @return Will return false if any error was encountered during deserialization, true otherwise.
|
||||
//! @return Will return ReadResult::Full if the white box mesh stream was filled with data and
|
||||
//! the white box mesh was initialized, ReadResult::Empty if white box mesh stream did not contain
|
||||
//! any data (white box mesh will be left empty) or ReadResult::Error if any error was encountered
|
||||
//! during deserialization.
|
||||
//! @note A white box mesh must have been created first.
|
||||
bool ReadMesh(WhiteBoxMesh& whiteBox, const AZStd::vector<AZ::u8>& input);
|
||||
ReadResult ReadMesh(WhiteBoxMesh& whiteBox, const WhiteBoxMeshStream& input);
|
||||
|
||||
//! Take an input stream and create a white box mesh from the deserialized data.
|
||||
//! @return Will return false if any error was encountered during deserialization, true otherwise.
|
||||
//! @return Will return ReadResult::Full if the white box mesh stream was filled with data and
|
||||
//! the white box mesh was initialized, ReadResult::Empty if white box mesh stream did not contain
|
||||
//! any data (white box mesh will be left empty) or ReadResult::Error if any error was encountered
|
||||
//! during deserialization.
|
||||
//! @note The input stream must not skip white space characters (std::noskipws must be set on the stream).
|
||||
bool ReadMesh(WhiteBoxMesh& whiteBox, std::istream& input);
|
||||
ReadResult ReadMesh(WhiteBoxMesh& whiteBox, std::istream& input);
|
||||
|
||||
//! Take a white box mesh and write it out to a stream of bytes.
|
||||
//! @return Will return false if any error was encountered during serialization, true otherwise.
|
||||
bool WriteMesh(const WhiteBoxMesh& whiteBox, AZStd::vector<AZ::u8>& output);
|
||||
bool WriteMesh(const WhiteBoxMesh& whiteBox, WhiteBoxMeshStream& output);
|
||||
|
||||
//! Clones the white box mesh object into a new mesh.
|
||||
//! @return Will return null if any error was encountered during serialization, otherwise the cloned mesh.
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace WhiteBox
|
||||
{
|
||||
success = assetHandler->SaveAssetData(meshAsset, &fileStream);
|
||||
AZ_Printf(
|
||||
"EditorWhiteBoxComponent", "Save %s. Location: %s", success ? "succeeded" : "failed",
|
||||
"EditorWhiteBoxMeshAsset", "Save %s. Location: %s", success ? "succeeded" : "failed",
|
||||
absoluteFilePath.c_str());
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,15 @@ namespace WhiteBox
|
||||
{
|
||||
if (asset == m_meshAsset)
|
||||
{
|
||||
AZ_Warning("EditorWhiteBoxComponent", false, "OnAssetError: %s", asset.GetHint().c_str());
|
||||
AZ_Warning("EditorWhiteBoxMeshAsset", false, "OnAssetError: %s", asset.GetHint().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWhiteBoxMeshAsset::OnAssetReloadError(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (asset == m_meshAsset)
|
||||
{
|
||||
AZ_Warning("EditorWhiteBoxMeshAsset", false, "OnAssetReloadError: %s", asset.GetHint().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace WhiteBox
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetReloadError(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
// WhiteBoxMeshAssetNotificationBus ...
|
||||
void OnWhiteBoxMeshAssetModified(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
@@ -51,12 +51,12 @@ namespace WhiteBox
|
||||
return AZStd::move(m_mesh);
|
||||
}
|
||||
|
||||
void SetWhiteBoxData(AZStd::vector<AZ::u8> whiteBoxData)
|
||||
void SetWhiteBoxData(Api::WhiteBoxMeshStream whiteBoxData)
|
||||
{
|
||||
m_whiteBoxData = AZStd::move(whiteBoxData);
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::u8>& GetWhiteBoxData() const
|
||||
const Api::WhiteBoxMeshStream& GetWhiteBoxData() const
|
||||
{
|
||||
return m_whiteBoxData;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ namespace WhiteBox
|
||||
}
|
||||
|
||||
Api::WhiteBoxMeshPtr m_mesh;
|
||||
AZStd::vector<AZ::u8> m_whiteBoxData; //! Data used for creating undo commands.
|
||||
Api::WhiteBoxMeshStream m_whiteBoxData; //! Data used for creating undo commands.
|
||||
};
|
||||
} // namespace Pipeline
|
||||
} // namespace WhiteBox
|
||||
|
||||
@@ -112,16 +112,21 @@ namespace WhiteBox
|
||||
|
||||
const auto size = stream->GetLength();
|
||||
|
||||
AZStd::vector<AZ::u8> whiteBoxData(size);
|
||||
Api::WhiteBoxMeshStream whiteBoxData;
|
||||
whiteBoxData.resize(size);
|
||||
|
||||
stream->Read(size, whiteBoxData.data());
|
||||
|
||||
auto whiteBoxMesh = WhiteBox::Api::CreateWhiteBoxMesh();
|
||||
const bool success = WhiteBox::Api::ReadMesh(*whiteBoxMesh, whiteBoxData);
|
||||
const auto result = WhiteBox::Api::ReadMesh(*whiteBoxMesh, whiteBoxData);
|
||||
|
||||
// if result is not 'Full', then whiteBoxMeshAsset could be empty which is most likely an error
|
||||
// as no data was loaded from the asset, or it was not correctly read in stream->Read(..)
|
||||
const auto success = result == Api::ReadResult::Full;
|
||||
if (success)
|
||||
{
|
||||
whiteBoxMeshAsset->SetMesh(AZStd::move(whiteBoxMesh));
|
||||
whiteBoxMeshAsset->SetWhiteBoxData(whiteBoxData);
|
||||
whiteBoxMeshAsset->SetWhiteBoxData(AZStd::move(whiteBoxData));
|
||||
}
|
||||
|
||||
return success ? AZ::Data::AssetHandler::LoadResult::LoadComplete
|
||||
|
||||
@@ -29,12 +29,12 @@ namespace WhiteBox
|
||||
m_asset = asset;
|
||||
}
|
||||
|
||||
void WhiteBoxMeshAssetUndoCommand::SetUndoState(const AZStd::vector<AZ::u8>& undoState)
|
||||
void WhiteBoxMeshAssetUndoCommand::SetUndoState(const Api::WhiteBoxMeshStream& undoState)
|
||||
{
|
||||
m_undoState = undoState;
|
||||
}
|
||||
|
||||
void WhiteBoxMeshAssetUndoCommand::SetRedoState(const AZStd::vector<AZ::u8>& redoState)
|
||||
void WhiteBoxMeshAssetUndoCommand::SetRedoState(const Api::WhiteBoxMeshStream& redoState)
|
||||
{
|
||||
m_redoState = redoState;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace WhiteBox
|
||||
~WhiteBoxMeshAssetUndoCommand() override = default;
|
||||
|
||||
void SetAsset(AZ::Data::Asset<Pipeline::WhiteBoxMeshAsset> asset);
|
||||
void SetUndoState(const AZStd::vector<AZ::u8>& undoState);
|
||||
void SetRedoState(const AZStd::vector<AZ::u8>& redoState);
|
||||
void SetUndoState(const Api::WhiteBoxMeshStream& undoState);
|
||||
void SetRedoState(const Api::WhiteBoxMeshStream& redoState);
|
||||
|
||||
// AzToolsFramework::UndoSystem::URSequencePoint ...
|
||||
void Undo() override;
|
||||
@@ -44,7 +44,7 @@ namespace WhiteBox
|
||||
|
||||
protected:
|
||||
AZ::Data::Asset<Pipeline::WhiteBoxMeshAsset> m_asset;
|
||||
AZStd::vector<AZ::u8> m_undoState;
|
||||
AZStd::vector<AZ::u8> m_redoState;
|
||||
Api::WhiteBoxMeshStream m_undoState;
|
||||
Api::WhiteBoxMeshStream m_redoState;
|
||||
};
|
||||
} // namespace WhiteBox
|
||||
|
||||
@@ -3379,7 +3379,7 @@ namespace WhiteBox
|
||||
CalculatePlanarUVs(whiteBox);
|
||||
}
|
||||
|
||||
bool WriteMesh(const WhiteBoxMesh& whiteBox, AZStd::vector<AZ::u8>& output)
|
||||
bool WriteMesh(const WhiteBoxMesh& whiteBox, WhiteBoxMeshStream& output)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
@@ -3403,10 +3403,15 @@ namespace WhiteBox
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadMesh(WhiteBoxMesh& whiteBox, const AZStd::vector<AZ::u8>& input)
|
||||
ReadResult ReadMesh(WhiteBoxMesh& whiteBox, const WhiteBoxMeshStream& input)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
if (input.empty())
|
||||
{
|
||||
return ReadResult::Empty;
|
||||
}
|
||||
|
||||
std::string inputStr;
|
||||
inputStr.reserve(input.size());
|
||||
AZStd::copy(input.cbegin(), input.cend(), AZStd::back_inserter(inputStr));
|
||||
@@ -3418,33 +3423,33 @@ namespace WhiteBox
|
||||
return ReadMesh(whiteBox, whiteBoxStream);
|
||||
}
|
||||
|
||||
bool ReadMesh(WhiteBoxMesh& whiteBox, std::istream& input)
|
||||
ReadResult ReadMesh(WhiteBoxMesh& whiteBox, std::istream& input)
|
||||
{
|
||||
const auto skipws = input.flags() & std::ios_base::skipws;
|
||||
AZ_Assert(skipws == 0, "Input stream must not skip white space characters");
|
||||
|
||||
if (skipws != 0)
|
||||
{
|
||||
return false;
|
||||
return ReadResult::Error;
|
||||
}
|
||||
|
||||
AZStd::lock_guard lg(g_omSerializationLock);
|
||||
OpenMesh::IO::Options options{OpenMesh::IO::Options::FaceTexCoord | OpenMesh::IO::Options::FaceNormal};
|
||||
return OpenMesh::IO::read_mesh(whiteBox.mesh, input, ".om", options);
|
||||
return OpenMesh::IO::read_mesh(whiteBox.mesh, input, ".om", options) ? ReadResult::Full : ReadResult::Error;
|
||||
}
|
||||
|
||||
WhiteBoxMeshPtr CloneMesh(const WhiteBoxMesh& whiteBox)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
AZStd::vector<AZ::u8> clonedData;
|
||||
WhiteBoxMeshStream clonedData;
|
||||
if (!WriteMesh(whiteBox, clonedData))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WhiteBoxMeshPtr newMesh = CreateWhiteBoxMesh();
|
||||
if (!ReadMesh(*newMesh, clonedData))
|
||||
if (ReadMesh(*newMesh, clonedData) != ReadResult::Full)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -3461,7 +3466,7 @@ namespace WhiteBox
|
||||
|
||||
bool SaveToWbm(const WhiteBoxMesh& whiteBox, AZ::IO::GenericStream& stream)
|
||||
{
|
||||
AZStd::vector<AZ::u8> buffer;
|
||||
WhiteBoxMeshStream buffer;
|
||||
const bool success = WhiteBox::Api::WriteMesh(whiteBox, buffer);
|
||||
|
||||
const auto bytesWritten = stream.Write(buffer.size(), buffer.data());
|
||||
|
||||
@@ -348,14 +348,14 @@ namespace WhiteBox
|
||||
else
|
||||
{
|
||||
// attempt to load the mesh
|
||||
if (Api::ReadMesh(*m_whiteBox, m_whiteBoxData))
|
||||
const auto result = Api::ReadMesh(*m_whiteBox, m_whiteBoxData);
|
||||
AZ_Error("EditorWhiteBoxComponent", result != WhiteBox::Api::ReadResult::Error, "Error deserializing white box mesh stream");
|
||||
|
||||
// if the read was successful but the byte stream is empty
|
||||
// (there was nothing to load), create a default mesh
|
||||
if (result == Api::ReadResult::Empty)
|
||||
{
|
||||
// if the read was successful but the byte stream is empty
|
||||
// (there was nothing to load), create a default mesh
|
||||
if (m_whiteBoxData.empty())
|
||||
{
|
||||
Api::InitializeAsUnitCube(*m_whiteBox);
|
||||
}
|
||||
Api::InitializeAsUnitCube(*m_whiteBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace WhiteBox
|
||||
AZStd::optional<AZStd::unique_ptr<RenderMeshInterface>>
|
||||
m_renderMesh; //!< The render mesh to use for the White Box mesh data.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); //!< Cached world transform of Entity.
|
||||
AZStd::vector<AZ::u8> m_whiteBoxData; //!< Serialized White Box mesh data.
|
||||
Api::WhiteBoxMeshStream m_whiteBoxData; //!< Serialized White Box mesh data.
|
||||
//! Holds a reference to an optional WhiteBoxMeshAsset and manages the lifecycle of adding/removing an asset.
|
||||
EditorWhiteBoxMeshAsset* m_editorMeshAsset = nullptr;
|
||||
AZStd::optional<AZ::Aabb> m_worldAabb; //!< Cached world aabb (used for selection/view determination).
|
||||
|
||||
@@ -470,6 +470,7 @@ namespace UnitTest
|
||||
TEST_F(WhiteBoxTestFixture, MeshNotDeserializedWithSkipWhiteSpaceStream)
|
||||
{
|
||||
namespace Api = WhiteBox::Api;
|
||||
using testing::Eq;
|
||||
|
||||
Api::InitializeAsUnitCube(*m_whiteBox);
|
||||
AZStd::vector<AZ::u8> serializedWhiteBox;
|
||||
@@ -485,7 +486,7 @@ namespace UnitTest
|
||||
// note: std::stringstream will default to skip white space characters
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
EXPECT_FALSE(Api::ReadMesh(*m_whiteBox, whiteBoxStream));
|
||||
EXPECT_THAT(Api::ReadMesh(*m_whiteBox, whiteBoxStream), Eq(Api::ReadResult::Error));
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user