241 lines
6.1 KiB
C++
241 lines
6.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "MuCOE/CustomizableObjectLayout.h"
|
|
|
|
#include "Engine/StaticMesh.h"
|
|
#include "MuCO/CustomizableObjectCompilerTypes.h"
|
|
#include "MuCO/CustomizableObjectInstancePrivate.h"
|
|
#include "MuCOE/CustomizableObjectCompiler.h"
|
|
#include "MuCOE/GenerateMutableSource/GenerateMutableSourceLayout.h"
|
|
#include "MuCOE/GraphTraversal.h"
|
|
#include "MuCOE/MutableUtils.h"
|
|
#include "MuCOE/CustomizableObjectEditor.h"
|
|
#include "MuCOE/Nodes/CustomizableObjectNodeSkeletalMesh.h"
|
|
#include "MuCOE/Nodes/CustomizableObjectNodeMesh.h"
|
|
#include "MuCOE/Nodes/CustomizableObjectNodeTable.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "CustomizableObjectEditor"
|
|
|
|
UCustomizableObjectLayout::UCustomizableObjectLayout()
|
|
{
|
|
GridSize = FIntPoint(4, 4);
|
|
MaxGridSize = FIntPoint(4, 4);
|
|
|
|
FCustomizableObjectLayoutBlock Block(FIntPoint(0, 0), FIntPoint(4, 4));
|
|
Blocks.Add(Block);
|
|
|
|
PackingStrategy = ECustomizableObjectTextureLayoutPackingStrategy::Resizable;
|
|
BlockReductionMethod = ECustomizableObjectLayoutBlockReductionMethod::Halve;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetLayout(int32 LODIndex, int32 MatIndex, int32 UVIndex)
|
|
{
|
|
LOD = LODIndex;
|
|
Material = MatIndex;
|
|
UVChannel = UVIndex;
|
|
}
|
|
|
|
|
|
mu::EPackStrategy ConvertLayoutStrategy(const ECustomizableObjectTextureLayoutPackingStrategy LayoutPackStrategy)
|
|
{
|
|
mu::EPackStrategy PackStrategy = mu::EPackStrategy::Fixed;
|
|
|
|
switch (LayoutPackStrategy)
|
|
{
|
|
case ECustomizableObjectTextureLayoutPackingStrategy::Fixed:
|
|
PackStrategy = mu::EPackStrategy::Fixed;
|
|
break;
|
|
|
|
case ECustomizableObjectTextureLayoutPackingStrategy::Resizable:
|
|
PackStrategy = mu::EPackStrategy::Resizeable;
|
|
break;
|
|
|
|
case ECustomizableObjectTextureLayoutPackingStrategy::Overlay:
|
|
PackStrategy = mu::EPackStrategy::Overlay;
|
|
break;
|
|
|
|
default:
|
|
checkNoEntry();
|
|
}
|
|
|
|
return PackStrategy;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetGridSize(FIntPoint Size)
|
|
{
|
|
GridSize = Size;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetMaxGridSize(FIntPoint Size)
|
|
{
|
|
MaxGridSize = Size;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetLayoutName(FString Name)
|
|
{
|
|
LayoutName = Name;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::GenerateAutomaticBlocksFromUVs()
|
|
{
|
|
UCustomizableObjectNode* Node = Cast<UCustomizableObjectNode>(GetOuter());
|
|
TSoftObjectPtr<const UObject> Mesh = GetMesh();
|
|
|
|
if (!Node || !Mesh)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TSharedPtr<FCustomizableObjectEditor> Editor = StaticCastSharedPtr<FCustomizableObjectEditor>(Node->GetGraphEditor());
|
|
|
|
if (AutomaticBlocksStrategy == ECustomizableObjectLayoutAutomaticBlocksStrategy::Ignore || !Editor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Create a GenerationContext
|
|
TSharedRef<FCustomizableObjectCompiler> Compiler = MakeShared<FCustomizableObjectCompiler>();
|
|
UCustomizableObject* Object = Editor->GetCustomizableObject();
|
|
check(Object);
|
|
|
|
FCompilationOptions Options = Object->GetPrivate()->GetCompileOptions();
|
|
|
|
FMutableCompilationContext CompilationContext(Object, Compiler, Options);
|
|
FMutableGraphGenerationContext GenerationContext(CompilationContext);
|
|
|
|
bool bOutWasEmpty = false;
|
|
mu::Ptr<mu::NodeLayout> LayoutNode = CreateMutableLayoutNode(GenerationContext, this, false, bOutWasEmpty );
|
|
|
|
if (LayoutNode)
|
|
{
|
|
AutomaticBlocks.Empty();
|
|
|
|
// Generate the editor layout blocks from the mutable layout
|
|
for (int32 i = 0; i < LayoutNode->Blocks.Num(); ++i)
|
|
{
|
|
FIntPoint Min = FIntPoint(LayoutNode->Blocks[i].Min.X, LayoutNode->Blocks[i].Min.Y);
|
|
FIntPoint Size = FIntPoint(LayoutNode->Blocks[i].Size.X, LayoutNode->Blocks[i].Size.Y);
|
|
|
|
// Ignore blocks contained inside any block in the initial block set.
|
|
bool bContainedInInitialSet = false;
|
|
for (const FCustomizableObjectLayoutBlock& Block : Blocks)
|
|
{
|
|
FInt32Rect ExistingRect(Block.Min, Block.Max + FIntPoint(1));
|
|
if (ExistingRect.Contains(Min) && ExistingRect.Contains(Min + Size))
|
|
{
|
|
bContainedInInitialSet = true;
|
|
break;
|
|
}
|
|
}
|
|
if (bContainedInInitialSet)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FCustomizableObjectLayoutBlock Block(FIntPoint(Min.X, Min.Y), FIntPoint(Min.X + Size.X, Min.Y + Size.Y));
|
|
Block.bIsAutomatic = true;
|
|
Block.Id = FGuid::NewGuid();
|
|
|
|
TSharedPtr<mu::FImage> Mask = LayoutNode->Blocks[i].Mask;
|
|
if (Mask)
|
|
{
|
|
UTexture2D* UnrealImage = NewObject<UTexture2D>(UTexture2D::StaticClass());
|
|
|
|
FMutableModelImageProperties Props;
|
|
Props.Filter = TF_Nearest;
|
|
Props.SRGB = true;
|
|
Props.LODBias = 0;
|
|
ConvertImage(UnrealImage, Mask, Props );
|
|
UnrealImage->NeverStream = true;
|
|
UnrealImage->UpdateResource();
|
|
|
|
Block.Mask = UnrealImage;
|
|
}
|
|
AutomaticBlocks.Add(Block);
|
|
}
|
|
|
|
Node->PostEditChange();
|
|
Node->GetGraph()->MarkPackageDirty();
|
|
}
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::ConsolidateAutomaticBlocks()
|
|
{
|
|
Blocks.Append(AutomaticBlocks);
|
|
AutomaticBlocks.Empty();
|
|
for (FCustomizableObjectLayoutBlock& Block : Blocks)
|
|
{
|
|
Block.Id = FGuid::NewGuid();
|
|
Block.bIsAutomatic = false;
|
|
}
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::GetUVs(TArray<FVector2f>& UVs) const
|
|
{
|
|
if (const UObject* Mesh = MutablePrivate::LoadObject(GetMesh()))
|
|
{
|
|
if (const USkeletalMesh* SkeletalMesh = Cast<const USkeletalMesh>(Mesh))
|
|
{
|
|
UVs = GetUV(*SkeletalMesh, LOD, Material, UVChannel);
|
|
}
|
|
else if (const UStaticMesh* StaticMesh = Cast<const UStaticMesh>(Mesh))
|
|
{
|
|
UVs = GetUV(*StaticMesh, LOD, Material, UVChannel);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int32 UCustomizableObjectLayout::FindBlock(const FGuid& InId) const
|
|
{
|
|
for (int32 Index = 0; Index < Blocks.Num(); ++Index)
|
|
{
|
|
if (Blocks[Index].Id == InId)
|
|
{
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetIgnoreVertexLayoutWarnings(bool bValue)
|
|
{
|
|
bIgnoreUnassignedVertexWarning = bValue;
|
|
}
|
|
|
|
|
|
void UCustomizableObjectLayout::SetIgnoreWarningsLOD(int32 LODValue)
|
|
{
|
|
FirstLODToIgnore = LODValue;
|
|
}
|
|
|
|
|
|
TSoftObjectPtr<UObject> UCustomizableObjectLayout::GetMesh() const
|
|
{
|
|
if (UObject* Node = GetOuter())
|
|
{
|
|
if (const UCustomizableObjectNodeMesh* TypedNodeSkeletalMesh = Cast<UCustomizableObjectNodeMesh>(Node))
|
|
{
|
|
return TypedNodeSkeletalMesh->GetMesh();
|
|
}
|
|
else if (const UCustomizableObjectNodeTable* TypedNodeTable = Cast<UCustomizableObjectNodeTable>(Node))
|
|
{
|
|
return TypedNodeTable->GetDefaultMeshForLayout(this);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|