Merge remote-tracking branch 'origin/master' into gi

# Conflicts:
#	Flax.flaxproj
#	Source/Engine/Core/Math/Vector3.h
#	Source/Engine/Graphics/Textures/GPUTexture.cpp
#	Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp
#	Source/Engine/Terrain/Terrain.cpp
#	Source/Engine/Tools/ModelTool/ModelTool.Build.cs
#	Source/FlaxEngine.Gen.cs
#	Source/FlaxEngine.Gen.h
This commit is contained in:
Wojciech Figat
2022-03-22 13:00:21 +01:00
49 changed files with 647 additions and 163 deletions

View File

@@ -2,6 +2,7 @@
#include "Asset.h"
#include "Content.h"
#include "SoftAssetReference.h"
#include "Cache/AssetsCache.h"
#include "Loading/ContentLoadingManager.h"
#include "Loading/Tasks/LoadAssetTask.h"
@@ -102,6 +103,65 @@ void WeakAssetReferenceBase::OnUnloaded(Asset* asset)
_asset = nullptr;
}
String SoftAssetReferenceBase::ToString() const
{
return _asset ? _asset->ToString() : (_id.IsValid() ? _id.ToString() : TEXT("<null>"));
}
void SoftAssetReferenceBase::OnSet(Asset* asset)
{
if (_asset == asset)
return;
if (_asset)
{
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->RemoveReference();
}
_asset = asset;
_id = asset ? asset->GetID() : Guid::Empty;
if (asset)
{
asset->AddReference();
asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
}
Changed();
}
void SoftAssetReferenceBase::OnSet(const Guid& id)
{
if (_id == id)
return;
if (_asset)
{
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->RemoveReference();
}
_asset = nullptr;
_id = id;
Changed();
}
void SoftAssetReferenceBase::OnResolve(const ScriptingTypeHandle& type)
{
ASSERT(!_asset);
_asset = ::LoadAsset(_id, type);
if (_asset)
{
_asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset->AddReference();
}
}
void SoftAssetReferenceBase::OnUnloaded(Asset* asset)
{
ASSERT(_asset == asset);
_asset->RemoveReference();
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
_asset = nullptr;
_id = Guid::Empty;
Changed();
}
Asset::Asset(const SpawnParams& params, const AssetInfo* info)
: ManagedScriptingObject(params)
, _refCount(0)

View File

@@ -0,0 +1,234 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Content/Asset.h"
/// <summary>
/// The asset soft reference. Asset gets referenced (loaded) on actual use (ID reference is resolving it).
/// </summary>
class FLAXENGINE_API SoftAssetReferenceBase
{
protected:
Asset* _asset = nullptr;
Guid _id = Guid::Empty;
public:
/// <summary>
/// Action fired when field gets changed (link a new asset or change to the another value).
/// </summary>
Delegate<> Changed;
public:
NON_COPYABLE(SoftAssetReferenceBase);
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReferenceBase"/> class.
/// </summary>
SoftAssetReferenceBase() = default;
/// <summary>
/// Finalizes an instance of the <see cref="SoftAssetReferenceBase"/> class.
/// </summary>
~SoftAssetReferenceBase()
{
}
public:
/// <summary>
/// Gets the asset ID or Guid::Empty if not set.
/// </summary>
FORCE_INLINE Guid GetID() const
{
return _id;
}
/// <summary>
/// Gets the asset property value as string.
/// </summary>
String ToString() const;
protected:
void OnSet(Asset* asset);
void OnSet(const Guid& id);
void OnResolve(const ScriptingTypeHandle& type);
void OnUnloaded(Asset* asset);
};
/// <summary>
/// The asset soft reference. Asset gets referenced (loaded) on actual use (ID reference is resolving it).
/// </summary>
template<typename T>
API_CLASS(InBuild) class SoftAssetReference : public SoftAssetReferenceBase
{
public:
typedef T AssetType;
typedef SoftAssetReference<T> Type;
public:
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
/// </summary>
SoftAssetReference()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
/// </summary>
/// <param name="asset">The asset to set.</param>
SoftAssetReference(T* asset)
{
OnSet(asset);
}
/// <summary>
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
/// </summary>
/// <param name="other">The other.</param>
SoftAssetReference(const SoftAssetReference& other)
{
OnSet(other.Get());
}
SoftAssetReference(SoftAssetReference&& other)
{
OnSet(other.Get());
other.OnSet(nullptr);
}
/// <summary>
/// Finalizes an instance of the <see cref="SoftAssetReference"/> class.
/// </summary>
~SoftAssetReference()
{
}
public:
FORCE_INLINE bool operator==(T* other)
{
return Get() == other;
}
FORCE_INLINE bool operator==(const SoftAssetReference& other)
{
return GetID() == other.GetID();
}
FORCE_INLINE bool operator!=(T* other)
{
return Get() != other;
}
FORCE_INLINE bool operator!=(const SoftAssetReference& other)
{
return GetID() != other.GetID();
}
SoftAssetReference& operator=(const SoftAssetReference& other)
{
if (this != &other)
OnSet(other.GetID());
return *this;
}
SoftAssetReference& operator=(SoftAssetReference&& other)
{
if (this != &other)
{
OnSet(other.GetID());
other.OnSet(nullptr);
}
return *this;
}
FORCE_INLINE SoftAssetReference& operator=(const T& other)
{
OnSet(&other);
return *this;
}
FORCE_INLINE SoftAssetReference& operator=(T* other)
{
OnSet(other);
return *this;
}
FORCE_INLINE SoftAssetReference& operator=(const Guid& id)
{
OnSet(id);
return *this;
}
FORCE_INLINE operator T*() const
{
return (T*)Get();
}
FORCE_INLINE operator bool() const
{
return Get() != nullptr;
}
FORCE_INLINE T* operator->() const
{
return (T*)Get();
}
template<typename U>
FORCE_INLINE U* As() const
{
return static_cast<U*>(Get());
}
public:
/// <summary>
/// Gets the asset (or null if unassigned).
/// </summary>
T* Get() const
{
if (!_asset)
const_cast<SoftAssetReference*>(this)->OnResolve(T::TypeInitializer);
return (T*)_asset;
}
/// <summary>
/// Gets managed instance object (or null if no asset linked).
/// </summary>
MObject* GetManagedInstance() const
{
auto asset = Get();
return asset ? asset->GetOrCreateManagedInstance() : nullptr;
}
/// <summary>
/// Determines whether asset is assigned and managed instance of the asset is alive.
/// </summary>
bool HasManagedInstance() const
{
auto asset = Get();
return asset && asset->HasManagedInstance();
}
/// <summary>
/// Gets the managed instance object or creates it if missing or null if not assigned.
/// </summary>
MObject* GetOrCreateManagedInstance() const
{
auto asset = Get();
return asset ? asset->GetOrCreateManagedInstance() : nullptr;
}
/// <summary>
/// Sets the asset.
/// </summary>
/// <param name="id">The object ID. Uses Scripting to find the registered asset of the given ID.</param>
FORCE_INLINE void Set(const Guid& id)
{
OnSet(id);
}
/// <summary>
/// Sets the asset.
/// </summary>
/// <param name="asset">The asset.</param>
FORCE_INLINE void Set(T* asset)
{
OnSet(asset);
}
};
template<typename T>
uint32 GetHash(const SoftAssetReference<T>& key)
{
return GetHash(key.GetID());
}

View File

@@ -75,8 +75,8 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb1[i].TexCoord;
output->WriteText(StringAnsi::Format("vt {0} {1}\n", Float16Compressor::Decompress(v.X), Float16Compressor::Decompress(v.Y)));
auto v = vb1[i].TexCoord.ToVector2();
output->WriteText(StringAnsi::Format("vt {0} {1}\n", v.X, v.Y));
}
output->WriteChar('\n');
@@ -180,8 +180,8 @@ ExportAssetResult AssetExporters::ExportSkinnedModel(ExportAssetContext& context
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].TexCoord;
output->WriteText(StringAnsi::Format("vt {0} {1}\n", Float16Compressor::Decompress(v.X), Float16Compressor::Decompress(v.Y)));
auto v = vb0[i].TexCoord.ToVector2();
output->WriteText(StringAnsi::Format("vt {0} {1}\n", v.X, v.Y));
}
output->WriteChar('\n');

View File

@@ -6,7 +6,9 @@
#if COMPILE_WITH_ASSETS_IMPORTER
#if COMPILE_WITH_PHYSICS_COOKING
#include "Engine/Physics/CollisionCooking.h"
#endif
/// <summary>
/// Creating collision data asset utility
@@ -23,7 +25,6 @@ public:
static CreateAssetResult Create(CreateAssetContext& context);
#if COMPILE_WITH_PHYSICS_COOKING
/// <summary>
/// Cooks the mesh collision data and saves it to the asset using <see cref="CollisionData"/> format.
/// </summary>
@@ -31,7 +32,6 @@ public:
/// <param name="arg">The input argument data.</param>
/// <returns>True if failed, otherwise false. See log file to track errors better.</returns>
static bool CookMeshCollision(const String& outputPath, CollisionCooking::Argument& arg);
#endif
};

View File

@@ -639,7 +639,7 @@ public:
{
Vector3 output = input;
const float length = input.Length();
if (!Math::IsZero(length))
if (Math::Abs(length) >= ZeroTolerance)
{
const float inv = 1.0f / length;
output.X *= inv;

View File

@@ -11,6 +11,7 @@
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/Assets/Material.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/SoftAssetReference.h"
#include "Engine/Platform/Windows/WindowsWindow.h"
#include "Engine/Render2D/Render2D.h"
#include "Engine/Engine/CommandLine.h"
@@ -19,7 +20,6 @@
#include "Engine/Profiler/Profiler.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Scripting/SoftObjectReference.h"
GPUPipelineState* GPUPipelineState::Spawn(const SpawnParams& params)
{
@@ -253,7 +253,7 @@ struct GPUDevice::PrivateData
GPUPipelineState* PS_Clear = nullptr;
GPUBuffer* FullscreenTriangleVB = nullptr;
AssetReference<Material> DefaultMaterial;
SoftObjectReference<Material> DefaultDeformableMaterial;
SoftAssetReference<Material> DefaultDeformableMaterial;
AssetReference<Texture> DefaultNormalMap;
AssetReference<Texture> DefaultWhiteTexture;
AssetReference<Texture> DefaultBlackTexture;

View File

@@ -9,7 +9,7 @@ BlendShapesInstance::MeshInstance::MeshInstance()
: IsUsed(false)
, IsDirty(false)
, DirtyMinVertexIndex(0)
, DirtyMaxVertexIndex(MAX_uint32)
, DirtyMaxVertexIndex(MAX_uint32 - 1)
, VertexBuffer(0, sizeof(VB0SkinnedElementType), TEXT("Skinned Mesh Blend Shape"))
{
}
@@ -112,7 +112,7 @@ void BlendShapesInstance::Update(SkinnedModel* skinnedModel)
// Initialize the dynamic vertex buffer data (use the dirty range from the previous update to be cleared with initial data)
instance.VertexBuffer.Data.Resize(vertexBuffer.Length());
const uint32 dirtyVertexDataStart = instance.DirtyMinVertexIndex * sizeof(VB0SkinnedElementType);
const uint32 dirtyVertexDataLength = Math::Min<uint32>(instance.DirtyMaxVertexIndex - instance.DirtyMinVertexIndex, vertexCount) * sizeof(VB0SkinnedElementType);
const uint32 dirtyVertexDataLength = Math::Min<uint32>(instance.DirtyMaxVertexIndex - instance.DirtyMinVertexIndex + 1, vertexCount) * sizeof(VB0SkinnedElementType);
Platform::MemoryCopy(instance.VertexBuffer.Data.Get() + dirtyVertexDataStart, vertexBuffer.Get() + dirtyVertexDataStart, dirtyVertexDataLength);
// Blend all blend shapes

View File

@@ -589,6 +589,17 @@ void MeshData::Merge(MeshData& other)
}
}
bool MaterialSlotEntry::UsesProperties() const
{
return Diffuse.Color != Color::White ||
Diffuse.TextureIndex != -1 ||
Emissive.Color != Color::Transparent ||
Emissive.TextureIndex != -1 ||
!Math::IsOne(Opacity.Value) ||
Opacity.TextureIndex != -1 ||
Normals.TextureIndex != -1;
}
void ModelData::CalculateLODsScreenSizes()
{
const float autoComputeLodPowerBase = 0.5f;

View File

@@ -373,16 +373,7 @@ struct FLAXENGINE_API MaterialSlotEntry
bool TwoSided = false;
bool UsesProperties() const
{
return Diffuse.Color != Color::White ||
Diffuse.TextureIndex != -1 ||
Emissive.Color != Color::Transparent ||
Emissive.TextureIndex != -1 ||
!Math::IsOne(Opacity.Value) ||
Opacity.TextureIndex != -1 ||
Normals.TextureIndex != -1;
}
bool UsesProperties() const;
};
/// <summary>

View File

@@ -1,7 +1,6 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "PixelFormatExtensions.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Core/Math/Math.h"
// ReSharper disable CppClangTidyClangDiagnosticSwitchEnum

View File

@@ -1047,7 +1047,7 @@ void GPUContextVulkan::BindIB(GPUBuffer* indexBuffer)
void GPUContextVulkan::BindSampler(int32 slot, GPUSampler* sampler)
{
ASSERT(slot >= GPU_STATIC_SAMPLERS_COUNT && slot < GPU_MAX_SAMPLER_BINDED);
const auto handle = sampler ? ((GPUSamplerVulkan*)sampler)->Sampler : nullptr;
const auto handle = sampler ? ((GPUSamplerVulkan*)sampler)->Sampler : VK_NULL_HANDLE;
_samplerHandles[slot] = handle;
}

View File

@@ -366,7 +366,7 @@ void GPUDeviceVulkan::GetInstanceLayersAndExtensions(Array<const char*>& outInst
}
#if VK_EXT_debug_utils
if (!vkTrace && outDebugUtils && FindLayerExtension(globalLayerExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME))
if (!vkTrace && FindLayerExtension(globalLayerExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME))
{
outInstanceExtensions.Add(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}

View File

@@ -185,6 +185,8 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
// Flush removed resources
_device->DeferredDeletionQueue.ReleaseResources(true);
}
ASSERT(_surface == VK_NULL_HANDLE);
ASSERT_LOW_LAYER(_backBuffers.Count() == 0);
// Create platform-dependent surface
VulkanPlatform::CreateSurface(windowHandle, GPUDeviceVulkan::Instance, &_surface);
@@ -205,7 +207,7 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
VALIDATE_VULKAN_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &surfaceFormatsCount, nullptr));
ASSERT(surfaceFormatsCount > 0);
Array<VkSurfaceFormatKHR> surfaceFormats;
Array<VkSurfaceFormatKHR, InlinedAllocation<16>> surfaceFormats;
surfaceFormats.AddZeroed(surfaceFormatsCount);
VALIDATE_VULKAN_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &surfaceFormatsCount, surfaceFormats.Get()));
@@ -414,8 +416,8 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
}
}
// Calculate memory usage
_memoryUsage = RenderTools::CalculateTextureMemoryUsage(_format, _width, _height, 1) * _backBuffers.Count();
// Estimate memory usage
_memoryUsage = 1024 + RenderTools::CalculateTextureMemoryUsage(_format, _width, _height, 1) * _backBuffers.Count();
return false;
}

View File

@@ -270,6 +270,11 @@ bool GPUTextureVulkan::OnInit()
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (useUAV)
imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
#if PLATFORM_MAC
// MoltenVK: VK_ERROR_FEATURE_NOT_PRESENT: vkCreateImageView(): 2D views on 3D images can only be used as color attachments.
if (IsVolume() && _desc.HasPerSliceViews())
imageInfo.usage &= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
#endif
imageInfo.tiling = optimalTiling ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR;
imageInfo.samples = (VkSampleCountFlagBits)MultiSampleLevel();
// TODO: set initialLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for IsRegularTexture() ???

View File

@@ -8,6 +8,7 @@
void MacVulkanPlatform::GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers)
{
extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME);
extensions.Add(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
}

View File

@@ -1024,10 +1024,12 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
const auto& track = particleSystem->Tracks[j];
if (track.Type != ParticleSystem::Track::Types::Emitter || track.Disabled)
continue;
const uint32 emitterIndex = track.AsEmitter.Index;
auto emitter = particleSystem->Emitters[emitterIndex].Get();
auto& data = instance.Emitters[emitterIndex];
if (!emitter || !emitter->IsLoaded() || !data.Buffer || emitter->SimulationMode != ParticlesSimulationMode::GPU)
const int32 emitterIndex = track.AsEmitter.Index;
ParticleEmitter* emitter = particleSystem->Emitters[emitterIndex].Get();
if (!emitter || !emitter->IsLoaded() || emitter->SimulationMode != ParticlesSimulationMode::GPU || instance.Emitters.Count() <= emitterIndex)
continue;
ParticleEmitterInstance& data = instance.Emitters[emitterIndex];
if (!data.Buffer)
continue;
ASSERT(emitter->Capacity != 0 && emitter->Graph.Layout.Size != 0);

View File

@@ -242,7 +242,7 @@ void CharacterController::CreateShape()
void CharacterController::UpdateBounds()
{
void* actor = PhysicsBackend::GetShapeActor(_shape);
void* actor = _shape ? PhysicsBackend::GetShapeActor(_shape) : nullptr;
if (actor)
PhysicsBackend::GetActorBounds(actor, _box);
else

View File

@@ -837,8 +837,8 @@ DragDropEffect MacWindow::DoDragDrop(const StringView& data)
void MacWindow::SetCursor(CursorType type)
{
WindowBase::SetCursor(type);
if (!_isMouseOver)
return;
//if (!_isMouseOver)
// return;
NSCursor* cursor = nullptr;
switch (type)
{
@@ -875,6 +875,7 @@ void MacWindow::SetCursor(CursorType type)
if (cursor)
{
[cursor set];
[NSCursor unhide];
}
}

View File

@@ -25,7 +25,11 @@ public:
static void MemoryBarrier();
static int64 InterlockedExchange(int64 volatile* dst, int64 exchange)
{
#if WIN64
return _InterlockedExchange64(dst, exchange);
#else
return _interlockedexchange64(dst, exchange);
#endif
}
static int32 InterlockedCompareExchange(int32 volatile* dst, int32 exchange, int32 comperand)
{
@@ -37,15 +41,27 @@ public:
}
static int64 InterlockedIncrement(int64 volatile* dst)
{
#if WIN64
return _InterlockedExchangeAdd64(dst, 1) + 1;
#else
return _interlockedexchange64(dst, 1) + 1;
#endif
}
static int64 InterlockedDecrement(int64 volatile* dst)
{
#if WIN64
return _InterlockedExchangeAdd64(dst, -1) - 1;
#else
return _interlockedexchangeadd64(dst, -1) - 1;
#endif
}
static int64 InterlockedAdd(int64 volatile* dst, int64 value)
{
#if WIN64
return _InterlockedExchangeAdd64(dst, value);
#else
return _interlockedexchangeadd64(dst, value);
#endif
}
static int32 AtomicRead(int32 volatile* dst)
{
@@ -61,7 +77,11 @@ public:
}
static void AtomicStore(int64 volatile* dst, int64 value)
{
#if WIN64
_InterlockedExchange64(dst, value);
#else
_interlockedexchange64(dst, value);
#endif
}
static void Prefetch(void const* ptr);
static void* Allocate(uint64 size, uint64 alignment);

View File

@@ -18,7 +18,7 @@ class FLAXENGINE_API ScriptingEvents
public:
/// <summary>
/// Global table for registered even binder methods (key is pair of type and event name, value is method that takes instance with event, object to bind and flag to bind or unbind).
/// Global table for registered event binder methods (key is pair of type and event name, value is method that takes instance with event, object to bind and flag to bind or unbind).
/// </summary>
/// <remarks>
/// Key: pair of event type, event name.

View File

@@ -24,6 +24,7 @@ public:
Delegate<> Changed;
public:
NON_COPYABLE(SoftObjectReferenceBase);
/// <summary>
/// Initializes a new instance of the <see cref="SoftObjectReferenceBase"/> class.

View File

@@ -23,6 +23,8 @@
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Content/Asset.h"
#include "Engine/Utilities/Encryption.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h>

View File

@@ -5,14 +5,21 @@
#include "SerializationFwd.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Scripting/SoftObjectReference.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Content/WeakAssetReference.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Utilities/Encryption.h"
struct Version;
struct VariantType;
template<typename T>
class ScriptingObjectReference;
template<typename T>
class SoftObjectReference;
template<typename T>
class AssetReference;
template<typename T>
class WeakAssetReference;
template<typename T>
class SoftAssetReference;
// @formatter:off
@@ -513,6 +520,26 @@ namespace Serialization
v = id;
}
// Soft Asset Reference
template<typename T>
inline bool ShouldSerialize(const SoftAssetReference<T>& v, const void* otherObj)
{
return !otherObj || v.Get() != ((SoftAssetReference<T>*)otherObj)->Get();
}
template<typename T>
inline void Serialize(ISerializable::SerializeStream& stream, const SoftAssetReference<T>& v, const void* otherObj)
{
stream.Guid(v.GetID());
}
template<typename T>
inline void Deserialize(ISerializable::DeserializeStream& stream, SoftAssetReference<T>& v, ISerializeModifier* modifier)
{
Guid id;
Deserialize(stream, id, modifier);
v = id;
}
// Array
template<typename T, typename AllocationType = HeapAllocation>

View File

@@ -519,14 +519,12 @@ void ReadStream::ReadJson(ISerializable* obj)
void WriteStream::WriteText(const StringView& text)
{
for (int32 i = 0; i < text.Length(); i++)
WriteChar(text[i]);
WriteBytes(text.Get(), sizeof(Char) * text.Length());
}
void WriteStream::WriteText(const StringAnsiView& text)
{
for (int32 i = 0; i < text.Length(); i++)
WriteChar(text[i]);
WriteBytes(text.Get(), sizeof(char) * text.Length());
}
void WriteStream::WriteString(const StringView& data)

View File

@@ -423,7 +423,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
#endif
// Report progress
float hemispheresProgress = static_cast<float>(_workerStagePosition1) / lightmapEntry.Hemispheres.Count();
float hemispheresProgress = static_cast<float>(_workerStagePosition1) / Math::Max(lightmapEntry.Hemispheres.Count(), 1);
float lightmapsProgress = static_cast<float>(_workerStagePosition0 + hemispheresProgress) / scene->Lightmaps.Count();
float bouncesProgress = static_cast<float>(_giBounceRunningIndex) / _bounceCount;
reportProgress(BuildProgressStep::RenderHemispheres, lightmapsProgress / _bounceCount + bouncesProgress);

View File

@@ -42,6 +42,7 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
SERIALIZE(ImportVertexColors);
SERIALIZE(ImportBlendShapes);
SERIALIZE(LightmapUVsSource);
SERIALIZE(CollisionMeshesPrefix);
SERIALIZE(Scale);
SERIALIZE(Rotation);
SERIALIZE(Translation);
@@ -79,6 +80,7 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
DESERIALIZE(ImportVertexColors);
DESERIALIZE(ImportBlendShapes);
DESERIALIZE(LightmapUVsSource);
DESERIALIZE(CollisionMeshesPrefix);
DESERIALIZE(Scale);
DESERIALIZE(Rotation);
DESERIALIZE(Translation);

View File

@@ -16,6 +16,7 @@
#include "Engine/Tools/TextureTool/TextureTool.h"
#include "Engine/ContentImporters/AssetsImportingManager.h"
#include "Engine/ContentImporters/CreateMaterial.h"
#include "Engine/ContentImporters/CreateCollisionData.h"
#include "Editor/Utilities/EditorUtilities.h"
#include <ThirdParty/meshoptimizer/meshoptimizer.h>
@@ -562,7 +563,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID;
if (material.Normals.TextureIndex != -1)
materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID;
if (material.TwoSided | material.Diffuse.HasAlphaMask)
if (material.TwoSided || material.Diffuse.HasAlphaMask)
materialOptions.Info.CullMode = CullMode::TwoSided;
if (!Math::IsOne(material.Opacity.Value) || material.Opacity.TextureIndex != -1)
materialOptions.Info.BlendMode = MaterialBlendMode::Transparent;
@@ -624,6 +625,41 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
}
}
// Collision mesh output
if (options.CollisionMeshesPrefix.HasChars())
{
// Extract collision meshes
ModelData collisionModel;
for (auto& lod : data.LODs)
{
for (int32 i = lod.Meshes.Count() - 1; i >= 0; i--)
{
auto mesh = lod.Meshes[i];
if (mesh->Name.StartsWith(options.CollisionMeshesPrefix, StringSearchCase::IgnoreCase))
{
if (collisionModel.LODs.Count() == 0)
collisionModel.LODs.AddOne();
collisionModel.LODs[0].Meshes.Add(mesh);
lod.Meshes.RemoveAtKeepOrder(i);
if (lod.Meshes.IsEmpty())
break;
}
}
}
if (collisionModel.LODs.HasItems())
{
// Create collision
CollisionCooking::Argument arg;
arg.Type = CollisionDataType::TriangleMesh;
arg.OverrideModelData = &collisionModel;
auto assetPath = autoImportOutput / StringUtils::GetFileNameWithoutExtension(path) + TEXT("Collision") ASSET_FILES_EXTENSION_WITH_DOT;
if (CreateCollisionData::CookMeshCollision(assetPath, arg))
{
LOG(Error, "Failed to create collision mesh.");
}
}
}
// For generated lightmap UVs coordinates needs to be moved so all meshes are in unique locations in [0-1]x[0-1] coordinates space
if (options.LightmapUVsSource == ModelLightmapUVsSource::Generate && data.LODs.HasItems() && data.LODs[0].Meshes.Count() > 1)
{

View File

@@ -177,6 +177,7 @@ public:
bool ImportVertexColors = true;
bool ImportBlendShapes = false;
ModelLightmapUVsSource LightmapUVsSource = ModelLightmapUVsSource::Disable;
String CollisionMeshesPrefix;
// Transform
float Scale = 1.0f;