Merge branch 'master' into 1.11
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
ThreadLocal<bool> ContentDeprecatedFlags;
|
||||
|
||||
void ContentDeprecated::Mark()
|
||||
@@ -593,7 +595,7 @@ bool Asset::onLoad(LoadAssetTask* task)
|
||||
|
||||
#if USE_EDITOR
|
||||
// Auto-save deprecated assets to get rid of data in an old format
|
||||
if (isDeprecated && isLoaded)
|
||||
if (isDeprecated && isLoaded && !IsVirtual() && !GetPath().StartsWith(StringUtils::GetDirectoryName(Globals::TemporaryFolder)))
|
||||
{
|
||||
PROFILE_CPU_NAMED("Asset.Save");
|
||||
LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString());
|
||||
|
||||
@@ -326,7 +326,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
|
||||
lod.Link(this, lodIndex);
|
||||
lod.ScreenSize = 1.0f;
|
||||
const int32 meshesCount = meshesCountPerLod[lodIndex];
|
||||
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
|
||||
lod.Meshes.Resize(meshesCount);
|
||||
@@ -365,7 +365,7 @@ bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
|
||||
// Meshes
|
||||
uint16 meshesCount;
|
||||
stream.ReadUint16(&meshesCount);
|
||||
if (meshesCount == 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
ASSERT(lodIndex == 0 || LODs[0].Meshes.Count() >= meshesCount);
|
||||
lod.Meshes.Resize(meshesCount, false);
|
||||
|
||||
@@ -669,6 +669,8 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
Array<GPUVertexLayout::Elements, FixedAllocation<MODEL_MAX_VB>> vbElements;
|
||||
const bool useSeparatePositions = !isSkinned;
|
||||
const bool useSeparateColors = !isSkinned;
|
||||
PixelFormat positionsFormat = modelData.PositionFormat == ModelData::PositionFormats::Float32 ? PixelFormat::R32G32B32_Float : PixelFormat::R16G16B16A16_Float;
|
||||
PixelFormat texCoordsFormat = modelData.TexCoordFormat == ModelData::TexCoordFormats::Float16 ? PixelFormat::R16G16_Float : PixelFormat::R8G8_UNorm;
|
||||
PixelFormat blendIndicesFormat = PixelFormat::R8G8B8A8_UInt;
|
||||
PixelFormat blendWeightsFormat = PixelFormat::R8G8B8A8_UNorm;
|
||||
for (const Int4& indices : mesh.BlendIndices)
|
||||
@@ -681,14 +683,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
}
|
||||
{
|
||||
byte vbIndex = 0;
|
||||
// TODO: add option to quantize vertex positions (eg. 16-bit)
|
||||
// TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords)
|
||||
|
||||
// Position
|
||||
if (useSeparatePositions)
|
||||
{
|
||||
auto& vb0 = vbElements.AddOne();
|
||||
vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float });
|
||||
vb0.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
|
||||
vbIndex++;
|
||||
}
|
||||
|
||||
@@ -696,13 +697,13 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
{
|
||||
auto& vb = vbElements.AddOne();
|
||||
if (!useSeparatePositions)
|
||||
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, PixelFormat::R32G32B32_Float });
|
||||
vb.Add({ VertexElement::Types::Position, vbIndex, 0, 0, positionsFormat });
|
||||
for (int32 channelIdx = 0; channelIdx < mesh.UVs.Count(); channelIdx++)
|
||||
{
|
||||
auto& channel = mesh.UVs.Get()[channelIdx];
|
||||
if (channel.HasItems())
|
||||
{
|
||||
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, PixelFormat::R16G16_Float });
|
||||
vb.Add({ (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + channelIdx), vbIndex, 0, 0, texCoordsFormat });
|
||||
}
|
||||
}
|
||||
vb.Add({ VertexElement::Types::Normal, vbIndex, 0, 0, PixelFormat::R10G10B10A2_UNorm });
|
||||
@@ -737,7 +738,7 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
// Write vertex buffers
|
||||
for (int32 vbIndex = 0; vbIndex < vbCount; vbIndex++)
|
||||
{
|
||||
if (useSeparatePositions && vbIndex == 0)
|
||||
if (useSeparatePositions && vbIndex == 0 && positionsFormat == PixelFormat::R32G32B32_Float)
|
||||
{
|
||||
// Fast path for vertex positions of static models using the first buffer
|
||||
stream.WriteBytes(mesh.Positions.Get(), sizeof(Float3) * vertices);
|
||||
@@ -755,7 +756,15 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
case VertexElement::Types::Position:
|
||||
{
|
||||
const Float3 position = mesh.Positions.Get()[vertex];
|
||||
stream.Write(position);
|
||||
if (positionsFormat == PixelFormat::R16G16B16A16_Float)
|
||||
{
|
||||
const Half4 positionEnc(Float4(position, 0.0f));
|
||||
stream.Write(positionEnc);
|
||||
}
|
||||
else //if (positionsFormat == PixelFormat::R32G32B32_Float)
|
||||
{
|
||||
stream.Write(position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VertexElement::Types::Color:
|
||||
@@ -821,8 +830,16 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l
|
||||
{
|
||||
const int32 channelIdx = (int32)element.Type - (int32)VertexElement::Types::TexCoord0;
|
||||
const Float2 uv = mesh.UVs.Get()[channelIdx].Get()[vertex];
|
||||
const Half2 uvEnc(uv);
|
||||
stream.Write(uvEnc);
|
||||
if (texCoordsFormat == PixelFormat::R8G8_UNorm)
|
||||
{
|
||||
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.X * 255), 0, 255));
|
||||
stream.Write((uint8)Math::Clamp<int32>((int32)(uv.Y * 255), 0, 255));
|
||||
}
|
||||
else //if (texCoordsFormat == PixelFormat::R16G16_Float)
|
||||
{
|
||||
const Half2 uvEnc(uv);
|
||||
stream.Write(uvEnc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -478,7 +478,7 @@ bool SkinnedModel::Init(const Span<int32>& meshesCountPerLod)
|
||||
lod._lodIndex = lodIndex;
|
||||
lod.ScreenSize = 1.0f;
|
||||
const int32 meshesCount = meshesCountPerLod[lodIndex];
|
||||
if (meshesCount <= 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
if (meshesCount < 0 || meshesCount > MODEL_MAX_MESHES)
|
||||
return true;
|
||||
|
||||
lod.Meshes.Resize(meshesCount);
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "Engine/Level/Types.h"
|
||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Core/Collections/HashSet.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#endif
|
||||
#include <ThirdParty/rapidjson/document.h>
|
||||
|
||||
bool JsonStorageProxy::IsValidExtension(const StringView& extension)
|
||||
@@ -56,27 +60,31 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, const StringAnsi& srcId, const StringAnsi& dstId)
|
||||
void FindObjectIds(const rapidjson_flax::Value& obj, const rapidjson_flax::Document& document, HashSet<Guid>& ids, const char* parentName = nullptr)
|
||||
{
|
||||
if (obj.IsObject())
|
||||
{
|
||||
for (rapidjson_flax::Value::MemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
|
||||
for (rapidjson_flax::Value::ConstMemberIterator i = obj.MemberBegin(); i != obj.MemberEnd(); ++i)
|
||||
{
|
||||
ChangeIds(i->value, document, srcId, dstId);
|
||||
FindObjectIds(i->value, document, ids, i->name.GetString());
|
||||
}
|
||||
}
|
||||
else if (obj.IsArray())
|
||||
{
|
||||
for (rapidjson::SizeType i = 0; i < obj.Size(); i++)
|
||||
{
|
||||
ChangeIds(obj[i], document, srcId, dstId);
|
||||
FindObjectIds(obj[i], document, ids, parentName);
|
||||
}
|
||||
}
|
||||
else if (obj.IsString())
|
||||
else if (obj.IsString() && obj.GetStringLength() == 32)
|
||||
{
|
||||
if (StringUtils::Compare(srcId.Get(), obj.GetString()) == 0)
|
||||
if (parentName && StringUtils::Compare(parentName, "ID") == 0)
|
||||
{
|
||||
obj.SetString(dstId.Get(), document.GetAllocator());
|
||||
auto value = JsonTools::GetGuid(obj);
|
||||
if (value.IsValid())
|
||||
{
|
||||
ids.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,9 +99,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
// Load file
|
||||
Array<byte> fileData;
|
||||
if (File::ReadAllBytes(path, fileData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse data
|
||||
rapidjson_flax::Document document;
|
||||
@@ -107,33 +113,35 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try get asset metadata
|
||||
// Get all IDs inside the file
|
||||
HashSet<Guid> ids;
|
||||
FindObjectIds(document, document, ids);
|
||||
|
||||
// Remap into a unique IDs
|
||||
Dictionary<Guid, Guid> remap;
|
||||
remap.EnsureCapacity(ids.Count());
|
||||
for (const auto& id : ids)
|
||||
remap.Add(id.Item, Guid::New());
|
||||
|
||||
// Remap asset ID using the provided value
|
||||
auto idNode = document.FindMember("ID");
|
||||
if (idNode == document.MemberEnd())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
remap[JsonTools::GetGuid(idNode->value)] = newId;
|
||||
|
||||
// Change IDs
|
||||
auto oldIdStr = idNode->value.GetString();
|
||||
auto newIdStr = newId.ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
ChangeIds(document, document, oldIdStr, newIdStr);
|
||||
// Change IDs of asset and objects inside asset
|
||||
JsonTools::ChangeIds(document, remap);
|
||||
|
||||
// Save to file
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
PrettyJsonWriter writer(buffer);
|
||||
document.Accept(writer.GetWriter());
|
||||
if (File::WriteAllBytes(path, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
LOG(Warning, "Editing cooked content is invalid.");
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user