Merge branch 'master' into Improve-HighlightedPopUpColor
This commit is contained in:
Binary file not shown.
@@ -36,6 +36,30 @@
|
||||
#include "CreateAnimation.h"
|
||||
#include "CreateBehaviorTree.h"
|
||||
#include "CreateJson.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool IsAssetTypeNameTextureFile(const String& typeName)
|
||||
{
|
||||
return typeName == Texture::TypeName || typeName == SpriteAtlas::TypeName;
|
||||
}
|
||||
|
||||
bool IsAssetTypeNameModelFile(const String& typeName)
|
||||
{
|
||||
return typeName == Model::TypeName || typeName == SkinnedModel::TypeName || typeName == Animation::TypeName;
|
||||
}
|
||||
|
||||
bool IsAssetTypeNameMatch(const String& a, const String& b)
|
||||
{
|
||||
// Special case when reimporting model/texture but different type
|
||||
if (IsAssetTypeNameTextureFile(a) && IsAssetTypeNameTextureFile(b))
|
||||
return true;
|
||||
if (IsAssetTypeNameModelFile(a) && IsAssetTypeNameModelFile(b))
|
||||
return true;
|
||||
return a == b;
|
||||
}
|
||||
}
|
||||
|
||||
// Tags used to detect asset creation mode
|
||||
const String AssetsImportingManager::CreateTextureTag(TEXT("Texture"));
|
||||
@@ -84,8 +108,6 @@ CreateAssetContext::CreateAssetContext(const StringView& inputPath, const String
|
||||
CustomArg = arg;
|
||||
Data.Header.ID = id;
|
||||
SkipMetadata = false;
|
||||
|
||||
// TODO: we should use ASNI only chars path (Assimp can use only that kind)
|
||||
OutputPath = Content::CreateTemporaryAssetPath();
|
||||
}
|
||||
|
||||
@@ -122,6 +144,24 @@ CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
|
||||
Data.Metadata.Copy((const byte*)buffer.GetString(), (uint32)buffer.GetSize());
|
||||
}
|
||||
|
||||
// Check if target asset already exists but has different type
|
||||
AssetInfo targetAssetInfo;
|
||||
if (Content::GetAssetInfo(TargetAssetPath, targetAssetInfo) && !IsAssetTypeNameMatch(targetAssetInfo.TypeName, Data.Header.TypeName))
|
||||
{
|
||||
// Change path
|
||||
int32 index = 0;
|
||||
String newTargetAssetPath;
|
||||
do
|
||||
{
|
||||
newTargetAssetPath = StringUtils::GetDirectoryName(TargetAssetPath);
|
||||
newTargetAssetPath /= StringUtils::GetFileNameWithoutExtension(TargetAssetPath) + String::Format(TEXT(" ({})."), index++) + FileSystem::GetExtension(TargetAssetPath);
|
||||
} while (index < 100 && FileSystem::FileExists(newTargetAssetPath));
|
||||
TargetAssetPath = newTargetAssetPath;
|
||||
|
||||
// Change id
|
||||
Data.Header.ID = Guid::New();
|
||||
}
|
||||
|
||||
// Save file
|
||||
result = FlaxStorage::Create(OutputPath, Data) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
|
||||
if (result == CreateAssetResult::Ok)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
|
||||
#define FOLIAGE_GET_DRAW_MODES(renderContext, type) (type.DrawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(type.ShadowsMode))
|
||||
#define FOLIAGE_GET_DRAW_MODES(renderContext, type) (type._drawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(type.ShadowsMode))
|
||||
#define FOLIAGE_CAN_DRAW(renderContext, type) (type.IsReady() && FOLIAGE_GET_DRAW_MODES(renderContext, type) != DrawPass::None && type.Model->CanBeRendered())
|
||||
|
||||
Foliage::Foliage(const SpawnParams& params)
|
||||
@@ -360,7 +360,7 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D
|
||||
draw.DrawState = &instance.DrawState;
|
||||
draw.Bounds = sphere;
|
||||
draw.PerInstanceRandom = instance.Random;
|
||||
draw.DrawModes = type.DrawModes;
|
||||
draw.DrawModes = type._drawModes;
|
||||
draw.SetStencilValue(_layer);
|
||||
type.Model->Draw(context.RenderContext, draw);
|
||||
|
||||
@@ -597,14 +597,22 @@ void Foliage::DrawType(RenderContext& renderContext, const FoliageType& type, Me
|
||||
|
||||
void Foliage::InitType(const RenderView& view, FoliageType& type)
|
||||
{
|
||||
const DrawPass drawModes = type.DrawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
|
||||
const DrawPass drawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
|
||||
type._canDraw = type.IsReady() && drawModes != DrawPass::None && type.Model && type.Model->CanBeRendered();
|
||||
bool drawModesDirty = false;
|
||||
for (int32 j = 0; j < type.Entries.Count(); j++)
|
||||
{
|
||||
auto& e = type.Entries[j];
|
||||
e.ReceiveDecals = type.ReceiveDecals != 0;
|
||||
e.ShadowsMode = type.ShadowsMode;
|
||||
if (type._drawModesDirty)
|
||||
{
|
||||
type._drawModesDirty = 0;
|
||||
drawModesDirty = true;
|
||||
}
|
||||
}
|
||||
if (drawModesDirty)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::DrawModes);
|
||||
}
|
||||
|
||||
int32 Foliage::GetInstancesCount() const
|
||||
@@ -1250,7 +1258,7 @@ void Foliage::Draw(RenderContext& renderContext)
|
||||
draw.Deformation = nullptr;
|
||||
draw.Bounds = instance.Bounds;
|
||||
draw.PerInstanceRandom = instance.Random;
|
||||
draw.DrawModes = type.DrawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
|
||||
draw.DrawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
|
||||
draw.SetStencilValue(_layer);
|
||||
type.Model->Draw(renderContext, draw);
|
||||
return;
|
||||
|
||||
@@ -13,6 +13,7 @@ FoliageType::FoliageType()
|
||||
, Index(-1)
|
||||
{
|
||||
_isReady = 0;
|
||||
_drawModesDirty = 0;
|
||||
|
||||
ReceiveDecals = true;
|
||||
UseDensityScaling = false;
|
||||
@@ -32,7 +33,7 @@ FoliageType& FoliageType::operator=(const FoliageType& other)
|
||||
CullDistance = other.CullDistance;
|
||||
CullDistanceRandomRange = other.CullDistanceRandomRange;
|
||||
ScaleInLightmap = other.ScaleInLightmap;
|
||||
DrawModes = other.DrawModes;
|
||||
SetDrawModes(other._drawModes);
|
||||
ShadowsMode = other.ShadowsMode;
|
||||
PaintDensity = other.PaintDensity;
|
||||
PaintRadius = other.PaintRadius;
|
||||
@@ -69,6 +70,19 @@ void FoliageType::SetMaterials(const Array<MaterialBase*>& value)
|
||||
Entries[i].Material = value[i];
|
||||
}
|
||||
|
||||
DrawPass FoliageType::GetDrawModes() const
|
||||
{
|
||||
return _drawModes;
|
||||
}
|
||||
|
||||
void FoliageType::SetDrawModes(DrawPass value)
|
||||
{
|
||||
if (_drawModes == value)
|
||||
return;
|
||||
_drawModes = value;
|
||||
_drawModesDirty = 1;
|
||||
}
|
||||
|
||||
Float3 FoliageType::GetRandomScale() const
|
||||
{
|
||||
Float3 result;
|
||||
@@ -150,7 +164,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(CullDistance);
|
||||
SERIALIZE(CullDistanceRandomRange);
|
||||
SERIALIZE(ScaleInLightmap);
|
||||
SERIALIZE(DrawModes);
|
||||
SERIALIZE_MEMBER(DrawModes, _drawModes);
|
||||
SERIALIZE(ShadowsMode);
|
||||
SERIALIZE_BIT(ReceiveDecals);
|
||||
SERIALIZE_BIT(UseDensityScaling);
|
||||
@@ -191,7 +205,7 @@ void FoliageType::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
DESERIALIZE(CullDistance);
|
||||
DESERIALIZE(CullDistanceRandomRange);
|
||||
DESERIALIZE(ScaleInLightmap);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE_MEMBER(DrawModes, _drawModes);
|
||||
DESERIALIZE(ShadowsMode);
|
||||
DESERIALIZE_BIT(ReceiveDecals);
|
||||
DESERIALIZE_BIT(UseDensityScaling);
|
||||
|
||||
@@ -48,6 +48,8 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API FoliageType : public ScriptingOb
|
||||
private:
|
||||
uint8 _isReady : 1;
|
||||
uint8 _canDraw : 1;
|
||||
uint8 _drawModesDirty : 1;
|
||||
DrawPass _drawModes = DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -124,9 +126,15 @@ public:
|
||||
API_FIELD() float ScaleInLightmap = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The draw passes to use for rendering this foliage type.
|
||||
/// Gets the draw passes to use for rendering this foliage type.
|
||||
/// </summary>
|
||||
API_FIELD() DrawPass DrawModes = DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward;
|
||||
API_PROPERTY(Attributes="DefaultValue(DrawPass.Depth | DrawPass.GBuffer | DrawPass.Forward)")
|
||||
DrawPass GetDrawModes() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the draw passes to use for rendering this foliage type.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetDrawModes(DrawPass value);
|
||||
|
||||
/// <summary>
|
||||
/// The shadows casting mode.
|
||||
@@ -184,7 +192,7 @@ public:
|
||||
API_FIELD() float PlacementRandomRollAngle = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The density scaling scale applied to the global scale for the foliage instances of this type. Can be used to boost or reduce density scaling effect on this foliage type. Default is 1.
|
||||
/// The density scale factor applied to the global scale for the foliage instances of this type. Can be used to boost or reduce density scaling effect on this foliage type. Default is 1. Lower to reduce density scaling effect when downscaling foliage via global quality/scalability.
|
||||
/// </summary>
|
||||
API_FIELD() float DensityScalingScale = 1.0f;
|
||||
|
||||
|
||||
@@ -158,6 +158,14 @@ void MeshAccessor::Stream::CopyTo(Span<Float3> dst) const
|
||||
{
|
||||
Platform::MemoryCopy(dst.Get(), _data.Get(), _data.Length());
|
||||
}
|
||||
else if (IsLinear(PixelFormat::R16G16B16A16_Float))
|
||||
{
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
auto v = *(Half4*)(_data.Get() + i * _stride);
|
||||
dst.Get()[i] = Float3(Float16Compressor::Decompress(v.X), Float16Compressor::Decompress(v.Y), Float16Compressor::Decompress(v.Z));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 i = 0; i < count; i++)
|
||||
|
||||
@@ -66,6 +66,20 @@ void StaticModel::SetBoundsScale(float value)
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
DrawPass StaticModel::GetDrawModes() const
|
||||
{
|
||||
return _drawModes;
|
||||
}
|
||||
|
||||
void StaticModel::SetDrawModes(DrawPass value)
|
||||
{
|
||||
if (_drawModes == value)
|
||||
return;
|
||||
_drawModes = value;
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::DrawModes);
|
||||
}
|
||||
|
||||
int32 StaticModel::GetLODBias() const
|
||||
{
|
||||
return _lodBias;
|
||||
@@ -330,13 +344,13 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
return;
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
||||
{
|
||||
if (EnumHasAnyFlags(DrawModes, DrawPass::GlobalSDF) && Model->SDF.Texture)
|
||||
if (EnumHasAnyFlags(_drawModes, DrawPass::GlobalSDF) && Model->SDF.Texture)
|
||||
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _transform, _box);
|
||||
return;
|
||||
}
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
||||
{
|
||||
if (EnumHasAnyFlags(DrawModes, DrawPass::GlobalSurfaceAtlas) && Model->SDF.Texture)
|
||||
if (EnumHasAnyFlags(_drawModes, DrawPass::GlobalSurfaceAtlas) && Model->SDF.Texture)
|
||||
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
|
||||
return;
|
||||
}
|
||||
@@ -353,7 +367,7 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
|
||||
draw.LightmapUVs = &Lightmap.UVsArea;
|
||||
draw.Flags = _staticFlags;
|
||||
draw.DrawModes = DrawModes;
|
||||
draw.DrawModes = _drawModes;
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
@@ -390,7 +404,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
|
||||
draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
|
||||
draw.LightmapUVs = &Lightmap.UVsArea;
|
||||
draw.Flags = _staticFlags;
|
||||
draw.DrawModes = DrawModes;
|
||||
draw.DrawModes = _drawModes;
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
@@ -435,7 +449,7 @@ void StaticModel::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE_MEMBER(LODBias, _lodBias);
|
||||
SERIALIZE_MEMBER(ForcedLOD, _forcedLod);
|
||||
SERIALIZE_MEMBER(SortOrder, _sortOrder);
|
||||
SERIALIZE(DrawModes);
|
||||
SERIALIZE_MEMBER(DrawModes, _drawModes);
|
||||
|
||||
if (HasLightmap()
|
||||
#if USE_EDITOR
|
||||
@@ -487,7 +501,7 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
DESERIALIZE_MEMBER(LODBias, _lodBias);
|
||||
DESERIALIZE_MEMBER(ForcedLOD, _forcedLod);
|
||||
DESERIALIZE_MEMBER(SortOrder, _sortOrder);
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE_MEMBER(DrawModes, _drawModes);
|
||||
DESERIALIZE_MEMBER(LightmapIndex, Lightmap.TextureIndex);
|
||||
DESERIALIZE_MEMBER(LightmapArea, Lightmap.UVsArea);
|
||||
|
||||
@@ -537,27 +551,27 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
if (member != stream.MemberEnd() && member->value.IsBool() && member->value.GetBool())
|
||||
{
|
||||
MARK_CONTENT_DEPRECATED();
|
||||
DrawModes = DrawPass::Depth;
|
||||
_drawModes = DrawPass::Depth;
|
||||
}
|
||||
}
|
||||
// [Deprecated on 07.02.2022, expires on 07.02.2024]
|
||||
if (modifier->EngineBuild <= 6330)
|
||||
{
|
||||
MARK_CONTENT_DEPRECATED();
|
||||
DrawModes |= DrawPass::GlobalSDF;
|
||||
_drawModes |= DrawPass::GlobalSDF;
|
||||
}
|
||||
// [Deprecated on 27.04.2022, expires on 27.04.2024]
|
||||
if (modifier->EngineBuild <= 6331)
|
||||
{
|
||||
MARK_CONTENT_DEPRECATED();
|
||||
DrawModes |= DrawPass::GlobalSurfaceAtlas;
|
||||
_drawModes |= DrawPass::GlobalSurfaceAtlas;
|
||||
}
|
||||
|
||||
{
|
||||
const auto member = stream.FindMember("RenderPasses");
|
||||
if (member != stream.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
DrawModes = (DrawPass)member->value.GetInt();
|
||||
_drawModes = (DrawPass)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ private:
|
||||
bool _vertexColorsDirty;
|
||||
byte _vertexColorsCount;
|
||||
int8 _sortOrder;
|
||||
DrawPass _drawModes = DrawPass::Default;
|
||||
Array<Color32> _vertexColorsData[MODEL_MAX_LODS];
|
||||
GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS];
|
||||
Model* _residencyChangedModel = nullptr;
|
||||
@@ -40,12 +41,6 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(20), DefaultValue(null), EditorDisplay(\"Model\")")
|
||||
AssetReference<Model> Model;
|
||||
|
||||
/// <summary>
|
||||
/// The draw passes to use for rendering this object.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(15), DefaultValue(DrawPass.Default), EditorDisplay(\"Model\")")
|
||||
DrawPass DrawModes = DrawPass::Default;
|
||||
|
||||
/// <summary>
|
||||
/// The baked lightmap entry.
|
||||
/// </summary>
|
||||
@@ -74,6 +69,17 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetBoundsScale(float value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the draw passes to use for rendering this object.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(15), DefaultValue(DrawPass.Default), EditorDisplay(\"Model\")")
|
||||
DrawPass GetDrawModes() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the draw passes to use for rendering this object.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetDrawModes(DrawPass value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality.
|
||||
/// </summary>
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
Layer = 4,
|
||||
StaticFlags = 8,
|
||||
AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked
|
||||
DrawModes = 32,
|
||||
Auto = Visual | Bounds | Layer,
|
||||
};
|
||||
|
||||
|
||||
@@ -408,7 +408,8 @@ public:
|
||||
if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle()))
|
||||
{
|
||||
ScopeWriteLock lock(Locker);
|
||||
OnSceneRenderingDirty(BoundingBox::FromSphere(prevBounds));
|
||||
if (flags != DrawModes && flags != Layer && flags != StaticFlags)
|
||||
OnSceneRenderingDirty(BoundingBox::FromSphere(prevBounds));
|
||||
OnSceneRenderingDirty(a->GetBox());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,19 +549,22 @@ bool Terrain::DrawSetup(RenderContext& renderContext)
|
||||
const DrawPass drawModes = DrawModes & renderContext.View.Pass;
|
||||
if (drawModes == DrawPass::GlobalSDF)
|
||||
{
|
||||
const float chunkSize = TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize;
|
||||
const float posToUV = 0.25f / chunkSize;
|
||||
Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f);
|
||||
const float chunkScale = 0.25f / (TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize); // Patch heightfield is divided into 4x4 chunks
|
||||
for (const TerrainPatch* patch : _patches)
|
||||
{
|
||||
if (!patch->Heightmap)
|
||||
continue;
|
||||
GPUTexture* heightfield = patch->Heightmap->GetTexture();
|
||||
float size = (float)heightfield->Width();
|
||||
Float4 localToUV;
|
||||
localToUV.X = localToUV.Y = chunkScale * (size - 1) / size; // Skip the last edge texel
|
||||
localToUV.Z = localToUV.W = 0.5f / size; // Include half-texel offset
|
||||
Transform patchTransform;
|
||||
patchTransform.Translation = patch->_offset + Vector3(0, patch->_yOffset, 0);
|
||||
patchTransform.Orientation = Quaternion::Identity;
|
||||
patchTransform.Scale = Float3(1.0f, patch->_yHeight, 1.0f);
|
||||
patchTransform = _transform.LocalToWorld(patchTransform);
|
||||
GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, patch->Heightmap->GetTexture(), patchTransform, patch->_bounds, localToUV);
|
||||
GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, heightfield, patchTransform, patch->_bounds, localToUV);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Graphics/GPUBuffer.h"
|
||||
#include "Engine/Graphics/Models/ModelData.h"
|
||||
#include "Engine/Graphics/Models/MeshAccessor.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
|
||||
PACK_STRUCT(struct GPUBVH {
|
||||
@@ -321,7 +322,6 @@ void MeshAccelerationStructure::Add(Model* model, int32 lodIndex)
|
||||
lodIndex = Math::Clamp(lodIndex, model->HighestResidentLODIndex(), model->LODs.Count() - 1);
|
||||
ModelLOD& lod = model->LODs[lodIndex];
|
||||
_meshes.EnsureCapacity(_meshes.Count() + lod.Meshes.Count());
|
||||
bool failed = false;
|
||||
for (int32 i = 0; i < lod.Meshes.Count(); i++)
|
||||
{
|
||||
auto& mesh = lod.Meshes[i];
|
||||
@@ -336,25 +336,19 @@ void MeshAccelerationStructure::Add(Model* model, int32 lodIndex)
|
||||
auto& meshData = _meshes.AddOne();
|
||||
meshData.Asset = model;
|
||||
model->AddReference();
|
||||
if (model->IsVirtual())
|
||||
{
|
||||
meshData.Indices = mesh.GetTriangleCount() * 3;
|
||||
meshData.Vertices = mesh.GetVertexCount();
|
||||
failed |= mesh.DownloadDataGPU(MeshBufferType::Index, meshData.IndexBuffer);
|
||||
failed |= mesh.DownloadDataGPU(MeshBufferType::Vertex0, meshData.VertexBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed |= mesh.DownloadDataCPU(MeshBufferType::Index, meshData.IndexBuffer, meshData.Indices);
|
||||
failed |= mesh.DownloadDataCPU(MeshBufferType::Vertex0, meshData.VertexBuffer, meshData.Vertices);
|
||||
}
|
||||
if (failed)
|
||||
MeshAccessor accessor;
|
||||
MeshBufferType bufferTypes[2] = { MeshBufferType::Index, MeshBufferType::Vertex0 };
|
||||
if (accessor.LoadMesh(&mesh, false, ToSpan(bufferTypes, 2)))
|
||||
return;
|
||||
if (!meshData.IndexBuffer.IsAllocated() && meshData.IndexBuffer.Length() != 0)
|
||||
{
|
||||
// BVH nodes modifies index buffer (sorts data in-place) so clone it
|
||||
meshData.IndexBuffer.Copy(meshData.IndexBuffer.Get(), meshData.IndexBuffer.Length());
|
||||
}
|
||||
auto indexStream = accessor.Index();
|
||||
auto positionStream = accessor.Position();
|
||||
if (!indexStream.IsValid() || !positionStream.IsValid())
|
||||
return;
|
||||
meshData.Indices = indexStream.GetCount();
|
||||
meshData.Vertices = positionStream.GetCount();
|
||||
meshData.IndexBuffer.Copy(indexStream.GetData());
|
||||
meshData.VertexBuffer.Allocate(meshData.Vertices * sizeof(Float3));
|
||||
positionStream.CopyTo(ToSpan(meshData.VertexBuffer.Get<Float3>(), meshData.Vertices));
|
||||
meshData.Use16BitIndexBuffer = mesh.Use16BitIndexBuffer();
|
||||
meshData.Bounds = mesh.GetBox();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#if FLAX_EDITOR
|
||||
using FlaxEditor.Options;
|
||||
#endif
|
||||
@@ -42,6 +44,38 @@ namespace FlaxEngine.GUI
|
||||
'<',
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The allowable characters to use for the text.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum AllowableCharacters
|
||||
{
|
||||
/// <summary>
|
||||
/// Wether to not allow any character in the text.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use letters in the text.
|
||||
/// </summary>
|
||||
Letters = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use numbers in the text.
|
||||
/// </summary>
|
||||
Numbers = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use symbols in the text.
|
||||
/// </summary>
|
||||
Symbols = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use all characters in the text.
|
||||
/// </summary>
|
||||
All = Letters | Numbers | Symbols,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default height of the text box
|
||||
/// </summary>
|
||||
@@ -86,6 +120,11 @@ namespace FlaxEngine.GUI
|
||||
/// Flag used to indicate whenever text can contain multiple lines.
|
||||
/// </summary>
|
||||
protected bool _isMultiline;
|
||||
|
||||
/// <summary>
|
||||
/// The characters to allow in the text.
|
||||
/// </summary>
|
||||
protected AllowableCharacters _charactersToAllow = AllowableCharacters.All;
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to indicate whenever text is read-only and cannot be modified by the user.
|
||||
@@ -188,6 +227,16 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character to allow in the text.
|
||||
/// </summary>
|
||||
[EditorOrder(41), Tooltip("The character to allow in the text.")]
|
||||
public AllowableCharacters CharactersToAllow
|
||||
{
|
||||
get => _charactersToAllow;
|
||||
set => _charactersToAllow = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of characters the user can type into the text box control.
|
||||
/// </summary>
|
||||
@@ -395,15 +444,42 @@ namespace FlaxEngine.GUI
|
||||
value = value.GetLines()[0];
|
||||
}
|
||||
|
||||
if (_text != value)
|
||||
if (_text.Equals(value, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
if (CharactersToAllow != AllowableCharacters.All)
|
||||
{
|
||||
Deselect();
|
||||
ResetViewOffset();
|
||||
|
||||
_text = value;
|
||||
|
||||
OnTextChanged();
|
||||
if (CharactersToAllow == AllowableCharacters.None)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CharactersToAllow.HasFlag(AllowableCharacters.Letters))
|
||||
{
|
||||
if (value != null)
|
||||
value = new string(value.Where(c => !char.IsLetter(c)).ToArray());
|
||||
}
|
||||
if (!CharactersToAllow.HasFlag(AllowableCharacters.Numbers))
|
||||
{
|
||||
if (value != null)
|
||||
value = new string(value.Where(c => !char.IsNumber(c)).ToArray());
|
||||
}
|
||||
if (!CharactersToAllow.HasFlag(AllowableCharacters.Symbols))
|
||||
{
|
||||
if (value != null)
|
||||
value = new string(value.Where(c => !char.IsSymbol(c)).ToArray());
|
||||
}
|
||||
value ??= string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
Deselect();
|
||||
ResetViewOffset();
|
||||
|
||||
_text = value;
|
||||
|
||||
OnTextChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -170,15 +170,14 @@ void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
// Convert voxel world-space position into heightfield local-space position and get heightfield UV
|
||||
float4x4 worldToLocal = ToMatrix4x4(objectData.WorldToVolume);
|
||||
float3 volumePos = mul(float4(voxelWorldPos, 1), worldToLocal).xyz;
|
||||
float3 volumeUV = volumePos * objectData.VolumeToUVWMul + objectData.VolumeToUVWAdd;
|
||||
float2 heightfieldUV = float2(volumeUV.x, volumeUV.z);
|
||||
|
||||
// Sample heightfield around the voxel location (heightmap uses point sampler)
|
||||
Texture2D<float4> heightmap = ObjectsTextures[i];
|
||||
float4 localToUV = float4(objectData.VolumeToUVWMul.xz, objectData.VolumeToUVWAdd.xz);
|
||||
#if 1
|
||||
float3 n00, n10, n01, n11;
|
||||
bool h00, h10, h01, h11;
|
||||
float offset = CascadeVoxelSize * 2;
|
||||
float offset = CascadeVoxelSize;
|
||||
float3 p00 = SampleHeightmap(heightmap, volumePos + float3(-offset, 0, 0), localToUV, n00, h00, objectData.MipOffset);
|
||||
float3 p10 = SampleHeightmap(heightmap, volumePos + float3(+offset, 0, 0), localToUV, n10, h10, objectData.MipOffset);
|
||||
float3 p01 = SampleHeightmap(heightmap, volumePos + float3(0, 0, -offset), localToUV, n01, h01, objectData.MipOffset);
|
||||
@@ -189,6 +188,11 @@ void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float3 heightfieldNormal = (n00 + n10 + n01 + n11) * 0.25f;
|
||||
heightfieldNormal = normalize(heightfieldNormal);
|
||||
bool isHole = h00 || h10 || h01 || h11;
|
||||
#else
|
||||
float3 heightfieldNormal;
|
||||
bool isHole;
|
||||
float3 heightfieldPosition = SampleHeightmap(heightmap, volumePos, localToUV, heightfieldNormal, isHole, objectData.MipOffset);
|
||||
#endif
|
||||
|
||||
// Skip holes and pixels outside the heightfield
|
||||
if (isHole)
|
||||
|
||||
@@ -35,11 +35,11 @@ float3 SampleHeightmap(Texture2D<float4> heightmap, float3 localPosition, float4
|
||||
{
|
||||
// Sample heightmap
|
||||
float2 uv = localPosition.xz * localToUV.xy + localToUV.zw;
|
||||
float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset);
|
||||
float4 value = heightmap.SampleLevel(SamplerLinearClamp, uv, mipOffset);
|
||||
|
||||
// Decode heightmap
|
||||
normal = DecodeHeightmapNormal(value, isHole);
|
||||
float height = DecodeHeightmapHeight(value);;
|
||||
float height = DecodeHeightmapHeight(value);
|
||||
float3 position = float3(localPosition.x, height, localPosition.z);
|
||||
|
||||
// UVs outside the heightmap are empty
|
||||
|
||||
Reference in New Issue
Block a user