763 lines
No EOL
21 KiB
C++
763 lines
No EOL
21 KiB
C++
// Copyright 2020 Phyronnaz
|
|
|
|
#include "VoxelTools/VoxelAssetTools.h"
|
|
#include "VoxelTools/VoxelToolHelpers.h"
|
|
#include "VoxelData/VoxelDataIncludes.h"
|
|
#include "VoxelAssets/VoxelDataAsset.h"
|
|
#include "VoxelAssets/VoxelDataAssetData.inl"
|
|
#include "VoxelGenerators/VoxelGeneratorInstanceWrapper.h"
|
|
#include "VoxelWorld.h"
|
|
|
|
inline TVoxelSharedPtr<FVoxelTransformableGeneratorInstance> ImportAssetHelper(
|
|
const FString& FunctionName,
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform& Transform,
|
|
FVoxelIntBox& Bounds,
|
|
bool bConvertToVoxelSpace)
|
|
{
|
|
Transform = FVoxelToolHelpers::GetRealTransform(World, Transform, bConvertToVoxelSpace);
|
|
|
|
if (!Asset || !Asset->IsValid())
|
|
{
|
|
FVoxelMessages::Error(FunctionName + ": Invalid asset");
|
|
return nullptr;
|
|
}
|
|
if (!Bounds.IsValid())
|
|
{
|
|
if (Asset->Instance->HasBounds())
|
|
{
|
|
Bounds = Asset->Instance->GetBounds().ApplyTransform(Transform);
|
|
}
|
|
else
|
|
{
|
|
FVoxelMessages::Error(FunctionName + ": Invalid Bounds, and cannot deduce them from Asset");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return Asset->Instance;
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportAssetAsReference(
|
|
FVoxelAssetItemReference& Reference,
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
int32 Priority,
|
|
bool bConvertToVoxelSpace,
|
|
bool bUpdateRender)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
auto& Data = World->GetData();
|
|
|
|
{
|
|
FVoxelWriteScopeLock Lock(Data, Bounds, FUNCTION_FNAME);
|
|
Reference.Bounds = Bounds;
|
|
Reference.Item = Data.AddItem<FVoxelAssetItem>(
|
|
AssetInstance.ToSharedRef(),
|
|
Bounds,
|
|
Transform,
|
|
Priority);
|
|
}
|
|
|
|
if (bUpdateRender)
|
|
{
|
|
FVoxelToolHelpers::UpdateWorld(World, Bounds);
|
|
}
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportAssetAsReferenceAsync(
|
|
UObject* WorldContextObject,
|
|
FLatentActionInfo LatentInfo,
|
|
FVoxelAssetItemReference& Reference,
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
int32 Priority,
|
|
bool bConvertToVoxelSpace,
|
|
bool bUpdateRender,
|
|
bool bHideLatentWarnings)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
FVoxelToolHelpers::StartAsyncLatentAction_WithWorld_WithValue(
|
|
WorldContextObject,
|
|
LatentInfo,
|
|
World,
|
|
FUNCTION_FNAME,
|
|
bHideLatentWarnings,
|
|
Reference,
|
|
[Bounds, AssetInstance, Transform, Priority](FVoxelData& Data, FVoxelAssetItemReference& InReference)
|
|
{
|
|
FVoxelWriteScopeLock Lock(Data, Bounds, FUNCTION_FNAME);
|
|
InReference.Bounds = Bounds;
|
|
InReference.Item = Data.AddItem<FVoxelAssetItem>(
|
|
AssetInstance.ToSharedRef(),
|
|
Bounds,
|
|
Transform,
|
|
Priority);
|
|
},
|
|
bUpdateRender ? EVoxelUpdateRender::UpdateRender : EVoxelUpdateRender::DoNotUpdateRender,
|
|
Bounds);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::ImportModifierAssetImpl(
|
|
FVoxelData& Data,
|
|
const FVoxelIntBox& Bounds,
|
|
const FTransform& Transform,
|
|
const FVoxelTransformableGeneratorInstance& Instance,
|
|
bool bModifyValues,
|
|
bool bModifyMaterials)
|
|
{
|
|
VOXEL_ASYNC_FUNCTION_COUNTER();
|
|
|
|
FVoxelOctreeUtilities::IterateTreeInBounds(Data.GetOctree(), Bounds, [&](FVoxelDataOctreeBase& Tree)
|
|
{
|
|
if (Tree.IsLeaf())
|
|
{
|
|
ensureThreadSafe(Tree.IsLockedForWrite());
|
|
auto& Leaf = Tree.AsLeaf();
|
|
FVoxelDataUtilities::AddAssetItemToLeafData(Data, Leaf, Instance, Bounds, Transform, bModifyValues, bModifyMaterials);
|
|
}
|
|
else
|
|
{
|
|
auto& Parent = Tree.AsParent();
|
|
if (!Parent.HasChildren())
|
|
{
|
|
ensureThreadSafe(Parent.IsLockedForWrite());
|
|
Parent.CreateChildren();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportModifierAsset(
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
bool bModifyValues,
|
|
bool bModifyMaterials,
|
|
bool bLockEntireWorld,
|
|
bool bConvertToVoxelSpace)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
auto& Data = World->GetData();
|
|
{
|
|
FVoxelWriteScopeLock Lock(Data, bLockEntireWorld ? FVoxelIntBox::Infinite : Bounds, FUNCTION_FNAME);
|
|
ImportModifierAssetImpl(Data, Bounds, Transform, *AssetInstance, bModifyValues, bModifyMaterials);
|
|
}
|
|
FVoxelToolHelpers::UpdateWorld(World, Bounds);
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportModifierAssetAsync(
|
|
UObject* WorldContextObject,
|
|
FLatentActionInfo LatentInfo,
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
bool bModifyValues,
|
|
bool bModifyMaterials,
|
|
bool bLockEntireWorld,
|
|
bool bConvertToVoxelSpace,
|
|
bool bHideLatentWarnings)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
FVoxelToolHelpers::StartAsyncLatentAction_WithWorld(
|
|
WorldContextObject,
|
|
LatentInfo,
|
|
World,
|
|
FUNCTION_FNAME,
|
|
bHideLatentWarnings,
|
|
[=](FVoxelData& Data)
|
|
{
|
|
FVoxelWriteScopeLock Lock(Data, bLockEntireWorld ? FVoxelIntBox::Infinite : Bounds, FUNCTION_FNAME);
|
|
ImportModifierAssetImpl(Data, Bounds, Transform, *AssetInstance, bModifyValues, bModifyMaterials);
|
|
},
|
|
EVoxelUpdateRender::UpdateRender, Bounds);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename TA, typename TB>
|
|
void ImportAssetImplImpl(
|
|
FVoxelData& Data,
|
|
const FVoxelIntBox& Bounds,
|
|
bool bSubtractive,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
TA GetInstanceValue,
|
|
TB GetInstanceMaterial,
|
|
uint32 MaterialMask)
|
|
{
|
|
VOXEL_TOOL_FUNCTION_COUNTER(Bounds.Count());
|
|
|
|
const auto GetInstanceMaterialImpl = [&](int32 X, int32 Y, int32 Z, FVoxelMaterial Material)
|
|
{
|
|
const auto NewMaterial = GetInstanceMaterial(X, Y, Z);
|
|
Material.CopyFrom(NewMaterial, MaterialMask);
|
|
return Material;
|
|
};
|
|
|
|
switch (MergeMode)
|
|
{
|
|
case EVoxelAssetMergeMode::AllValues:
|
|
{
|
|
Data.Set<FVoxelValue>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value)
|
|
{
|
|
Value = GetInstanceValue(X, Y, Z);
|
|
});
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::AllMaterials:
|
|
{
|
|
Data.Set<FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelMaterial& Material)
|
|
{
|
|
Material = GetInstanceMaterialImpl(X, Y, Z, Material);
|
|
});
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::AllValuesAndAllMaterials:
|
|
{
|
|
Data.Set<FVoxelValue, FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value, FVoxelMaterial& Material)
|
|
{
|
|
Value = GetInstanceValue(X, Y, Z);
|
|
Material = GetInstanceMaterialImpl(X, Y, Z, Material);
|
|
});
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerValues:
|
|
{
|
|
Data.Set<FVoxelValue>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value)
|
|
{
|
|
const auto InstanceValue = GetInstanceValue(X, Y, Z);
|
|
Value = FVoxelUtilities::MergeAsset(Value, InstanceValue, bSubtractive);
|
|
});
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerMaterials:
|
|
{
|
|
Data.Set<const FVoxelValue, FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, const FVoxelValue& Value, FVoxelMaterial& Material)
|
|
{
|
|
const auto InstanceValue = GetInstanceValue(X, Y, Z);
|
|
const auto NewValue = FVoxelUtilities::MergeAsset(Value, InstanceValue, bSubtractive);
|
|
if (NewValue == InstanceValue)
|
|
{
|
|
Material = GetInstanceMaterialImpl(X, Y, Z, Material);
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerValuesAndInnerMaterials:
|
|
{
|
|
Data.Set<FVoxelValue, FVoxelMaterial>(Bounds, [&](int32 X, int32 Y, int32 Z, FVoxelValue& Value, FVoxelMaterial& Material)
|
|
{
|
|
const auto InstanceValue = GetInstanceValue(X, Y, Z);
|
|
const auto NewValue = FVoxelUtilities::MergeAsset(Value, InstanceValue, bSubtractive);
|
|
Value = NewValue;
|
|
if (NewValue == InstanceValue)
|
|
{
|
|
Material = GetInstanceMaterialImpl(X, Y, Z, Material);
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
default: ensure(false);
|
|
}
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportAssetImpl(
|
|
FVoxelData& Data,
|
|
const FVoxelIntBox& Bounds,
|
|
const FTransform& Transform,
|
|
const FVoxelTransformableGeneratorInstance& Instance,
|
|
bool bSubtractive,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
uint32 MaterialMask)
|
|
{
|
|
VOXEL_ASYNC_FUNCTION_COUNTER();
|
|
|
|
bool bNeedValues;
|
|
bool bNeedMaterials;
|
|
switch (MergeMode)
|
|
{
|
|
case EVoxelAssetMergeMode::AllValues:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = false;
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::AllMaterials:
|
|
{
|
|
bNeedValues = false;
|
|
bNeedMaterials = true;
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::AllValuesAndAllMaterials:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = true;
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerValues:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = false;
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerMaterials:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = true;
|
|
break;
|
|
}
|
|
case EVoxelAssetMergeMode::InnerValuesAndInnerMaterials:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = true;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
bNeedValues = true;
|
|
bNeedMaterials = true;
|
|
ensure(false);
|
|
}
|
|
}
|
|
|
|
const auto Size = Bounds.Size();
|
|
check(FVoxelUtilities::CountIs32Bits(Size));
|
|
|
|
TArray<FVoxelValue> Values;
|
|
if (bNeedValues)
|
|
{
|
|
Values.SetNumUninitialized(Size.X * Size.Y * Size.Z);
|
|
TVoxelQueryZone<FVoxelValue> QueryZone(Bounds, Values);
|
|
Instance.GetValues_Transform(Transform, QueryZone, 0, FVoxelItemStack::Empty);
|
|
}
|
|
|
|
TArray<FVoxelMaterial> Materials;
|
|
if (bNeedMaterials)
|
|
{
|
|
Materials.SetNumUninitialized(Size.X * Size.Y * Size.Z);
|
|
TVoxelQueryZone<FVoxelMaterial> QueryZone(Bounds, Materials);
|
|
Instance.GetMaterials_Transform(Transform, QueryZone, 0, FVoxelItemStack::Empty);
|
|
}
|
|
|
|
const auto GetIndex = [&](int32 X, int32 Y, int32 Z)
|
|
{
|
|
checkVoxelSlow(Bounds.Contains(X, Y, Z));
|
|
const int32 LX = X - Bounds.Min.X;
|
|
const int32 LY = Y - Bounds.Min.Y;
|
|
const int32 LZ = Z - Bounds.Min.Z;
|
|
checkVoxelSlow(0 <= LX && LX < Size.X);
|
|
checkVoxelSlow(0 <= LY && LY < Size.Y);
|
|
checkVoxelSlow(0 <= LZ && LZ < Size.Z);
|
|
return LX + LY * Size.X + LZ * Size.X * Size.Y;
|
|
};
|
|
|
|
const auto GetInstanceValue = [&](int32 X, int32 Y, int32 Z)
|
|
{
|
|
checkVoxelSlow(bNeedValues);
|
|
const int32 Index = GetIndex(X, Y, Z);
|
|
checkVoxelSlow(Values.IsValidIndex(Index));
|
|
return Values.GetData()[Index];
|
|
};
|
|
const auto GetInstanceMaterial = [&](int32 X, int32 Y, int32 Z)
|
|
{
|
|
checkVoxelSlow(bNeedMaterials);
|
|
const int32 Index = GetIndex(X, Y, Z);
|
|
checkVoxelSlow(Materials.IsValidIndex(Index));
|
|
return Materials.GetData()[Index];
|
|
};
|
|
|
|
ImportAssetImplImpl(
|
|
Data,
|
|
Bounds,
|
|
bSubtractive,
|
|
MergeMode,
|
|
GetInstanceValue,
|
|
GetInstanceMaterial,
|
|
MaterialMask);
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportDataAssetImpl(
|
|
FVoxelData& Data,
|
|
const FVoxelIntBox& Bounds,
|
|
const FVoxelVector& Position,
|
|
const FVoxelDataAssetData& AssetData,
|
|
bool bSubtractive,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
uint32 MaterialMask)
|
|
{
|
|
VOXEL_ASYNC_FUNCTION_COUNTER();
|
|
|
|
ensure(Bounds == FVoxelIntBox(Position, Position + AssetData.GetSize()));
|
|
|
|
const FVoxelValue DefaultValue = bSubtractive ? FVoxelValue::Full() : FVoxelValue::Empty();
|
|
const auto GetInstanceValue = [&](int32 X, int32 Y, int32 Z)
|
|
{
|
|
const v_flt NewValueFlt = AssetData.GetInterpolatedValue(
|
|
X - Position.X,
|
|
Y - Position.Y,
|
|
Z - Position.Z,
|
|
DefaultValue);
|
|
return FVoxelValue(NewValueFlt);
|
|
};
|
|
const auto GetInstanceMaterial = [&](int32 X, int32 Y, int32 Z)
|
|
{
|
|
return AssetData.HasMaterials() ? AssetData.GetInterpolatedMaterial(
|
|
X - Position.X,
|
|
Y - Position.Y,
|
|
Z - Position.Z) : FVoxelMaterial::Default();
|
|
};
|
|
ImportAssetImplImpl(
|
|
Data,
|
|
Bounds,
|
|
bSubtractive,
|
|
MergeMode,
|
|
GetInstanceValue,
|
|
GetInstanceMaterial,
|
|
MaterialMask);
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportAsset(
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
bool bSubtractive,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
bool bConvertToVoxelSpace)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
VOXEL_TOOL_HELPER_BODY(Write, UpdateRender,
|
|
ImportAssetImpl(
|
|
Data,
|
|
Bounds,
|
|
Transform,
|
|
*AssetInstance,
|
|
bSubtractive,
|
|
MergeMode,
|
|
EVoxelMaterialMask::All));
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportAssetAsync(
|
|
UObject* WorldContextObject,
|
|
FLatentActionInfo LatentInfo,
|
|
AVoxelWorld* World,
|
|
UVoxelTransformableGeneratorInstanceWrapper* Asset,
|
|
FTransform Transform,
|
|
FVoxelIntBox Bounds,
|
|
bool bSubtractive,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
bool bConvertToVoxelSpace,
|
|
bool bHideLatentWarnings)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
const auto AssetInstance = ImportAssetHelper(__FUNCTION__, World, Asset, Transform, Bounds, bConvertToVoxelSpace);
|
|
if (!AssetInstance) return;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
VOXEL_TOOL_LATENT_HELPER_BODY(Write, UpdateRender,
|
|
ImportAssetImpl(
|
|
Data,
|
|
Bounds,
|
|
Transform,
|
|
*AssetInstance,
|
|
bSubtractive,
|
|
MergeMode,
|
|
EVoxelMaterialMask::All));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::ImportDataAssetFast(
|
|
AVoxelWorld* World,
|
|
UVoxelDataAsset* Asset,
|
|
FVector InPosition,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
bool bConvertToVoxelSpace)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
if (!Asset)
|
|
{
|
|
FVoxelMessages::Error(FUNCTION_ERROR("Invalid asset"));
|
|
return;
|
|
}
|
|
|
|
FVoxelVector Position = FVoxelToolHelpers::GetRealPosition(World, InPosition, bConvertToVoxelSpace);
|
|
Position += Asset->PositionOffset;
|
|
|
|
const auto AssetData = Asset->GetData();
|
|
const FVoxelIntBox Bounds(Position, Position + AssetData->GetSize());
|
|
const bool bSubtractiveAsset = Asset->bSubtractiveAsset;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
VOXEL_TOOL_HELPER_BODY(Write, UpdateRender,
|
|
ImportDataAssetImpl(
|
|
Data,
|
|
Bounds,
|
|
Position,
|
|
*AssetData,
|
|
bSubtractiveAsset,
|
|
MergeMode,
|
|
EVoxelMaterialMask::All));
|
|
}
|
|
|
|
void UVoxelAssetTools::ImportDataAssetFastAsync(
|
|
UObject* WorldContextObject,
|
|
FLatentActionInfo LatentInfo,
|
|
AVoxelWorld* World,
|
|
UVoxelDataAsset* Asset,
|
|
FVector InPosition,
|
|
EVoxelAssetMergeMode MergeMode,
|
|
bool bConvertToVoxelSpace,
|
|
bool bHideLatentWarnings)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
|
|
if (!Asset)
|
|
{
|
|
FVoxelMessages::Error(FUNCTION_ERROR("Invalid asset"));
|
|
return;
|
|
}
|
|
|
|
FVoxelVector Position = FVoxelToolHelpers::GetRealPosition(World, InPosition, bConvertToVoxelSpace);
|
|
Position += Asset->PositionOffset;
|
|
const auto AssetData = Asset->GetData();
|
|
const FVoxelIntBox Bounds(Position, Position + AssetData->GetSize());
|
|
const bool bSubtractiveAsset = Asset->bSubtractiveAsset;
|
|
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
CHECK_BOUNDS_ARE_32BITS_VOID();
|
|
|
|
VOXEL_TOOL_LATENT_HELPER_BODY(Write, UpdateRender,
|
|
ImportDataAssetImpl(
|
|
Data,
|
|
Bounds,
|
|
Position,
|
|
*AssetData,
|
|
bSubtractiveAsset,
|
|
MergeMode,
|
|
EVoxelMaterialMask::All));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::InvertDataAssetImpl(const FVoxelDataAssetData& AssetData, FVoxelDataAssetData& InvertedAssetData)
|
|
{
|
|
VOXEL_TOOL_FUNCTION_COUNTER(AssetData.GetSize().X * AssetData.GetSize().Y * AssetData.GetSize().Z);
|
|
|
|
InvertedAssetData.SetSize(AssetData.GetSize(), AssetData.HasMaterials());
|
|
const int32 Num = AssetData.GetRawValues().Num();
|
|
#if VOXEL_DEBUG
|
|
const auto& Src = AssetData.GetRawValues();
|
|
auto& Dst = InvertedAssetData.GetRawValues();
|
|
#else
|
|
const auto* RESTRICT Src = AssetData.GetRawValues().GetData();
|
|
auto* RESTRICT Dst = InvertedAssetData.GetRawValues().GetData();
|
|
#endif
|
|
for (int32 Index = 0; Index < Num; Index++)
|
|
{
|
|
Dst[Index] = Src[Index].GetInverse();
|
|
}
|
|
|
|
InvertedAssetData.GetRawMaterials() = AssetData.GetRawMaterials();
|
|
}
|
|
|
|
void UVoxelAssetTools::InvertDataAsset(UVoxelDataAsset* Asset, UVoxelDataAsset*& InvertedAsset)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
|
|
if (!Asset)
|
|
{
|
|
FVoxelMessages::Error(FUNCTION_ERROR("Invalid asset"));
|
|
return;
|
|
}
|
|
|
|
const auto InvertedAssetData = MakeVoxelShared<FVoxelDataAssetData>();
|
|
InvertDataAssetImpl(*Asset->GetData(), *InvertedAssetData);
|
|
|
|
InvertedAsset = NewObject<UVoxelDataAsset>(GetTransientPackage());
|
|
InvertedAsset->SetData(InvertedAssetData);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::SetDataAssetMaterialImpl(
|
|
const FVoxelDataAssetData& AssetData,
|
|
FVoxelDataAssetData& NewAssetData,
|
|
FVoxelMaterial Material)
|
|
{
|
|
VOXEL_TOOL_FUNCTION_COUNTER(AssetData.GetSize().X * AssetData.GetSize().Y * AssetData.GetSize().Z);
|
|
|
|
NewAssetData.SetSize(AssetData.GetSize(), true);
|
|
NewAssetData.GetRawValues() = AssetData.GetRawValues();
|
|
const int32 Num = AssetData.GetRawValues().Num();
|
|
#if VOXEL_DEBUG
|
|
auto& Ptr = NewAssetData.GetRawMaterials();
|
|
#else
|
|
auto* RESTRICT Ptr = NewAssetData.GetRawMaterials().GetData();
|
|
#endif
|
|
for (int32 Index = 0; Index < Num; Index++)
|
|
{
|
|
Ptr[Index] = Material;
|
|
}
|
|
}
|
|
|
|
void UVoxelAssetTools::SetDataAssetMaterial(UVoxelDataAsset* Asset, UVoxelDataAsset*& NewAsset, FVoxelMaterial Material)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
|
|
if (!Asset)
|
|
{
|
|
FVoxelMessages::Error(FUNCTION_ERROR("Invalid asset"));
|
|
return;
|
|
}
|
|
|
|
const auto NewAssetData = MakeVoxelShared<FVoxelDataAssetData>();
|
|
SetDataAssetMaterialImpl(*Asset->GetData(), *NewAssetData, Material);
|
|
|
|
NewAsset = NewObject<UVoxelDataAsset>(GetTransientPackage());
|
|
NewAsset->SetData(NewAssetData);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::CreateDataAssetFromWorldSectionImpl(
|
|
const FVoxelData& Data,
|
|
const FVoxelIntBox& Bounds,
|
|
const bool bCopyMaterials,
|
|
FVoxelDataAssetData& AssetData)
|
|
{
|
|
VOXEL_TOOL_FUNCTION_COUNTER(Bounds.Count());
|
|
|
|
AssetData.SetSize(Bounds.Size(), bCopyMaterials);
|
|
|
|
{
|
|
TVoxelQueryZone<FVoxelValue> QueryZone(Bounds, AssetData.GetRawValues());
|
|
Data.Get<FVoxelValue>(QueryZone, 0);
|
|
}
|
|
if (bCopyMaterials)
|
|
{
|
|
TVoxelQueryZone<FVoxelMaterial> QueryZone(Bounds, AssetData.GetRawMaterials());
|
|
Data.Get<FVoxelMaterial>(QueryZone, 0);
|
|
}
|
|
}
|
|
|
|
UVoxelDataAsset* UVoxelAssetTools::CreateDataAssetFromWorldSection(
|
|
AVoxelWorld* World,
|
|
FVoxelIntBox Bounds,
|
|
bool bCopyMaterials)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED();
|
|
CHECK_BOUNDS_ARE_VALID();
|
|
|
|
const auto AssetData = MakeVoxelShared<FVoxelDataAssetData>();
|
|
|
|
VOXEL_TOOL_HELPER_BODY(Read, DoNotUpdateRender, CreateDataAssetFromWorldSectionImpl(Data, Bounds, bCopyMaterials, *AssetData));
|
|
|
|
auto* Asset = NewObject<UVoxelDataAsset>(GetTransientPackage());
|
|
Asset->SetData(AssetData);
|
|
return Asset;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UVoxelAssetTools::AddDisableEditsBox(
|
|
FVoxelDisableEditsBoxItemReference& Reference,
|
|
AVoxelWorld* World,
|
|
FVoxelIntBox Bounds)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
|
|
VOXEL_TOOL_HELPER_BODY(Write, DoNotUpdateRender,
|
|
{
|
|
Reference.Bounds = Bounds;
|
|
Reference.Item = Data.AddItem<FVoxelDisableEditsBoxItem>(Bounds);
|
|
});
|
|
}
|
|
|
|
void UVoxelAssetTools::AddDisableEditsBoxAsync(
|
|
UObject* WorldContextObject,
|
|
FLatentActionInfo LatentInfo,
|
|
FVoxelDisableEditsBoxItemReference& Reference,
|
|
AVoxelWorld* World,
|
|
FVoxelIntBox Bounds,
|
|
bool bHideLatentWarnings)
|
|
{
|
|
VOXEL_FUNCTION_COUNTER();
|
|
CHECK_VOXELWORLD_IS_CREATED_VOID();
|
|
CHECK_BOUNDS_ARE_VALID_VOID();
|
|
|
|
VOXEL_TOOL_LATENT_HELPER_WITH_VALUE_BODY(Reference, Write, DoNotUpdateRender,
|
|
{
|
|
InReference.Bounds = Bounds;
|
|
InReference.Item = Data.AddItem<FVoxelDisableEditsBoxItem>(Bounds);
|
|
});
|
|
} |