Files
UnrealEngine/Engine/Plugins/Mutable/Source/CustomizableObjectEditor/Private/MuCOE/SMutableMeshViewer.cpp
2025-05-18 13:04:45 +08:00

819 lines
23 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MuCOE/SMutableMeshViewer.h"
#include "Engine/SkeletalMesh.h"
#include "Framework/Views/TableViewMetadata.h"
#include "MuCOE/SMutableMeshViewport.h"
#include "MuCOE/SMutableSkeletonViewer.h"
#include "MuCO/CustomizableObject.h"
#include "MuT/TypeInfo.h"
#include "MuR/MeshPrivate.h"
#include "PropertyCustomizationHelpers.h"
#include "Widgets/Layout/SScrollBox.h"
#include "Widgets/Views/SListView.h"
class ITableRow;
class STableViewBase;
class SWidget;
class USkeleton;
#define LOCTEXT_NAMESPACE "CustomizableObjectEditor"
/** Namespace containing the IDs for the header on the buffer's channels list */
namespace MutableBufferChannelsListColumns
{
static const FName ChannelSemanticIndexColumnID("Channel Semantic Index");
static const FName ChannelSemanticColumnID("Channel Semantic");
static const FName ChannelFormatColumnID("Format");
static const FName ChannelComponentCountID("Components");
};
/* Row element generated on the buffers list. It represents the UI side of the Buffers data**/
class SMutableMeshBufferChannelListRow : public SMultiColumnTableRow<TSharedPtr<FBufferChannelElement>>
{
public:
void Construct(const FArguments& Args, const TSharedRef<STableViewBase>& InOwnerTableView,
const TSharedPtr<FBufferChannelElement>& InRowItem)
{
RowItem = InRowItem;
SMultiColumnTableRow<TSharedPtr<FBufferChannelElement>>::Construct(
STableRow::FArguments()
.ShowSelection(true)
, InOwnerTableView
);
}
virtual TSharedRef<SWidget> GenerateWidgetForColumn(const FName& InColumnName) override
{
// Column with the index for the buffer .
// Useful for knowing the channels on what buffer reside
if (InColumnName == MutableBufferChannelsListColumns::ChannelSemanticIndexColumnID)
{
return SNew(SHorizontalBox) +
SHorizontalBox::Slot()
.Padding(4,0)
[
SNew(STextBlock).
Text(RowItem->SemanticIndex)
];
}
// Column with the name for the buffer (Semantic of the buffer)
if (InColumnName == MutableBufferChannelsListColumns::ChannelSemanticColumnID)
{
return SNew(SHorizontalBox) +
SHorizontalBox::Slot()
[
SNew(STextBlock).
Text(RowItem->BufferSemantic)
];
}
// Column with the format of the buffer
if (InColumnName == MutableBufferChannelsListColumns::ChannelFormatColumnID)
{
return SNew(SHorizontalBox) + SHorizontalBox::Slot()
[
SNew(STextBlock).
Text(RowItem->BufferFormat)
];
}
// Column with Buffer component count
if (InColumnName == MutableBufferChannelsListColumns::ChannelComponentCountID)
{
return SNew(SHorizontalBox) + SHorizontalBox::Slot()
[
SNew(STextBlock).
Text(RowItem->BufferComponentCount)
];
}
// Invalid column name so no widget will be produced
return SNullWidget::NullWidget;
}
private:
TSharedPtr<FBufferChannelElement> RowItem;
};
/** Namespace containing the IDs for the header on the buffers list */
namespace MutableMeshBuffersListColumns
{
static const FName BufferIndexColumnID("Buffer Index");
static const FName BufferChannelsColumnID("Channels");
}
class SMutableMeshBufferListRow : public SMultiColumnTableRow<TSharedPtr<FBufferElement>>
{
public:
void Construct(const FArguments& Args, const TSharedRef<STableViewBase>& InOwnerTableView,
const TSharedPtr<FBufferElement>& InRowItem, TSharedPtr<SMutableMeshViewer> InHost)
{
HostMutableMeshViewer = InHost;
RowItem = InRowItem;
SMultiColumnTableRow<TSharedPtr<FBufferElement>>::Construct(
STableRow::FArguments()
.ShowSelection(true)
, InOwnerTableView
);
}
virtual TSharedRef<SWidget> GenerateWidgetForColumn(const FName& InColumnName) override
{
// Column with the index for the buffer .
// Useful for knowing the channels on what buffer reside
if (InColumnName == MutableMeshBuffersListColumns::BufferIndexColumnID)
{
return SNew(SBorder)
.Content()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock).
Text(RowItem->BufferIndex)
]
];
}
// Generate the sub table here
if (InColumnName == MutableMeshBuffersListColumns::BufferChannelsColumnID)
{
const TSharedRef<SWidget> GeneratedChannelList =
HostMutableMeshViewer->GenerateBufferChannelsListView(RowItem->BufferChannels);
return SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[
GeneratedChannelList
];
}
// Invalid column name so no widget will be produced
return SNullWidget::NullWidget;
}
private:
TSharedPtr<FBufferElement> RowItem;
TSharedPtr<SMutableMeshViewer> HostMutableMeshViewer;
};
void SMutableMeshViewer::Construct(const FArguments& InArgs)
{
// Splitter values
constexpr float TablesSplitterValue = 0.5f;
constexpr float ViewportSplitterValue = 0.5f;
ChildSlot
[
SNew(SSplitter)
+ SSplitter::Slot()
.Value(TablesSplitterValue)
[
GenerateDataTableSlates()
]
+ SSplitter::Slot()
.Value(ViewportSplitterValue)
[
GenerateViewportSlates()
]
];
// If a mesh has been provided then do set the mesh for this object
if (InArgs._Mesh)
{
SetMesh(InArgs._Mesh);
}
}
void SMutableMeshViewer::SetMesh(const TSharedPtr<const mu::FMesh>& InMesh)
{
if (InMesh != MutableMesh)
{
MutableMesh = InMesh;
// Extract a copy of the tags
int32 TagCount = MutableMesh ? MutableMesh->GetTagCount() : 0;
MeshTagList.SetNum(TagCount, EAllowShrinking::No);
for (int32 TagIndex=0; TagIndex<TagCount; ++TagIndex)
{
MeshTagList[TagIndex] = MakeShared<FString>(MutableMesh->GetTag(TagIndex));
}
if (MutableMesh)
{
OnMeshChanged();
// Skeleton slate viewer update
if (TSharedPtr<const mu::FSkeleton> MutableSkeleton = MutableMesh->GetSkeleton())
{
MutableSkeletonViewer->SetSkeleton(MutableSkeleton);
MutableSkeletonViewer->SetVisibility(EVisibility::Visible);
}
else
{
MutableSkeletonViewer->SetVisibility(EVisibility::Hidden);
}
FString DebugLog;
MutableMesh->Log(DebugLog, 8);
UE_LOG(LogMutable, Warning, TEXT("[%s]"), *DebugLog);
}
MeshViewport->SetMesh(MutableMesh);
}
}
TSharedRef<SWidget> SMutableMeshViewer::GenerateViewportSlates()
{
TSharedRef<SWidget> Container = SNew(SVerticalBox)
// User warning messages
// + SVerticalBox::Slot()
// .AutoHeight()
// [
// // TODO: Add a message to tell the user why no mesh is being displayed
// SNew(SWarningOrErrorBox)
// .MessageStyle(EMessageStyle::Warning)
// .Message(FText::FromString(FString("This is just a simulation")))
// ]
// Mesh Drawing space
+ SVerticalBox::Slot()
[
SAssignNew(MeshViewport, SMutableMeshViewport)
.Mesh(MutableMesh)
];
return Container;
}
TSharedRef<SWidget> SMutableMeshViewer::GenerateDataTableSlates()
{
// Formatting
constexpr int32 IndentationSpace = 16;
constexpr int32 SimpleSpacing = 1;
constexpr int32 AfterTitleSpacing = 4;
constexpr int32 EndOfSectionSpacing = 12;
// Naming
const FText GeneralDataTitle = LOCTEXT("GeneralDataTitle", "General Data");
const FText VerticesCountTitle = LOCTEXT("VerticesCountTitle", "Vertex count : ");
const FText FacesCountTitle = LOCTEXT("FacesCountTitle", "Face count : ");
const FText BonesCountTitle = LOCTEXT("BonesCountTitle", "Bone count : ");
const FText MeshIdPrefixTitle = LOCTEXT("MeshIdPrefixTitle", "Mesh ID prefix : ");
const FText MeshFlagsTitle = LOCTEXT("MeshFlagsTitle", "Mesh flags : ");
const FText BuffersTitle = LOCTEXT("BuffersTitle", "Buffers");
return SNew(SScrollBox)
+ SScrollBox::Slot()
[
SNew(SVerticalBox)
// General data ----------------------------------------------------------------
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock).
Text(GeneralDataTitle)
]
+ SVerticalBox::Slot().
Padding(IndentationSpace, AfterTitleSpacing).
AutoHeight()
[
SNew(SVerticalBox)
// Vertices
+ SVerticalBox::Slot().
Padding(0, SimpleSpacing).
AutoHeight()
[
SNew(SHorizontalBox)
// Vertices title
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(VerticesCountTitle)
]
// Vertices value
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(this, &SMutableMeshViewer::GetVertexCount)
]
]
// Faces
+ SVerticalBox::Slot().
Padding(0, SimpleSpacing).
AutoHeight()
[
SNew(SHorizontalBox)
// Faces title
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(FacesCountTitle)
]
// Faces Value
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(this, &SMutableMeshViewer::GetFaceCount)
]
]
// Bones
+ SVerticalBox::Slot().
Padding(0, SimpleSpacing).
AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(BonesCountTitle)
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(this, &SMutableMeshViewer::GetBoneCount)
]
]
// Vertex ID
+ SVerticalBox::Slot().
Padding(0, SimpleSpacing).
AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(MeshIdPrefixTitle)
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(this, &SMutableMeshViewer::GetMeshIdPrefix)
]
]
// Flags
+ SVerticalBox::Slot().
Padding(0, SimpleSpacing).
AutoHeight()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(MeshFlagsTitle)
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock).
Text(this, &SMutableMeshViewer::GetMeshFlags)
]
]
]
// Buffers Data --------------------------------------------------------------
+ SVerticalBox::Slot()
.Padding(0, EndOfSectionSpacing)
.AutoHeight()
[
SNew(SVerticalBox)
+ SVerticalBox::Slot().
AutoHeight()
[
// Buffers data Title
SNew(STextBlock).
Text(BuffersTitle)
]
+ SVerticalBox::Slot()
.Padding(IndentationSpace, AfterTitleSpacing)
.AutoHeight()
[
SNew(SVerticalBox)
// List of vertex buffers ----------
+ SVerticalBox::Slot()
.AutoHeight()
[
GenerateBuffersListView(
VertexBuffersSlateView,
VertexBuffers,
FText(LOCTEXT("VertexBufferType", "Vertex")))
]
// ---------------------------------
]
+ SVerticalBox::Slot()
.Padding(IndentationSpace, 6)
.AutoHeight()
[
SNew(SVerticalBox)
// List of Index buffers ----------
+ SVerticalBox::Slot()
.AutoHeight()
[
GenerateBuffersListView(
IndexBuffersSlateView,
IndexBuffers,
FText(LOCTEXT("IndexBufferType", "Index")))
]
// ---------------------------------
]
]
// Bones data ----------------------------------------------------------------
+ SVerticalBox::Slot()
.Padding(0, EndOfSectionSpacing)
.AutoHeight()
[
SAssignNew(MutableSkeletonViewer, SMutableSkeletonViewer)
]
// ---------------------------------
// Tags
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock).
Text(LOCTEXT("Tags", "Tags"))
]
+ SVerticalBox::Slot()
.Padding(IndentationSpace, AfterTitleSpacing)
.AutoHeight()
[
SNew(SListView< TSharedPtr<FString> >)
.ListItemsSource(&MeshTagList)
.OnGenerateRow(this, &SMutableMeshViewer::GenerateTagRow)
]
// ---------------------------------
// UVs
+SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock).
Text(LOCTEXT("UVs", "UVs"))
]
+ SVerticalBox::Slot()
.Padding(IndentationSpace, AfterTitleSpacing)
.AutoHeight()
.MinHeight(300.0f)
[
SAssignNew(LayoutGridWidget, SCustomizableObjectLayoutGrid)
.Mode(ELGM_Show)
.GridSize(this, &SMutableMeshViewer::GetGridSize)
.Blocks(this, &SMutableMeshViewer::GetBlocks)
.UVLayout(this, &SMutableMeshViewer::GetUVs)
]
// ---------------------------------
];
}
FIntPoint SMutableMeshViewer::GetGridSize() const
{
// TODO
return FIntPoint(8,8);
}
TArray<FCustomizableObjectLayoutBlock> SMutableMeshViewer::GetBlocks() const
{
TArray<FCustomizableObjectLayoutBlock> Blocks;
// TODO
return Blocks;
}
TArray<FVector2f> SMutableMeshViewer::GetUVs() const
{
TArray<FVector2f> Lines;
if (MutableMesh && !MutableMesh->VertexBuffers.IsDescriptor())
{
int32 NumFaces = MutableMesh->GetFaceCount();
Lines.Reserve(NumFaces*6);
// TODO
int32 UVIndex = 0;
mu::UntypedMeshBufferIteratorConst ItIndices(MutableMesh->IndexBuffers, mu::EMeshBufferSemantic::VertexIndex, 0);
mu::UntypedMeshBufferIteratorConst It(MutableMesh->VertexBuffers, mu::EMeshBufferSemantic::TexCoords, UVIndex);
for (int32 FaceIndex=0; FaceIndex<NumFaces; ++FaceIndex)
{
uint32 V0 = (ItIndices + FaceIndex * 3 + 0).GetAsUINT32();
uint32 V1 = (ItIndices + FaceIndex * 3 + 1).GetAsUINT32();
uint32 V2 = (ItIndices + FaceIndex * 3 + 2).GetAsUINT32();
Lines.Add((It + V0).GetAsVec2f());
Lines.Add((It + V1).GetAsVec2f());
Lines.Add((It + V1).GetAsVec2f());
Lines.Add((It + V2).GetAsVec2f());
Lines.Add((It + V2).GetAsVec2f());
Lines.Add((It + V0).GetAsVec2f());
}
}
return Lines;
}
TSharedRef<ITableRow> SMutableMeshViewer::GenerateTagRow(TSharedPtr<FString> InItem, const TSharedRef<STableViewBase>& OwnerTable)
{
return SNew(STableRow<TSharedPtr<FName>>, OwnerTable)
[
SNew(STextBlock).Text(FText::FromString(*InItem))
];
}
TSharedRef<SWidget> SMutableMeshViewer::GenerateBuffersListView(
TSharedPtr<SListView<TSharedPtr<FBufferElement>>>& OutHostListView,
const TArray<TSharedPtr<FBufferElement>>& InBufferElements,
const FText& InBufferSetTypeName)
{
// Headers
const FText BufferIndexTitle = FText(LOCTEXT("BufferIndexTitle", "Buffer"));
const FText BufferChannelsTitle = FText::Format(
LOCTEXT("NumberOfBufferChannels", "{0} Buffer Channels"), InBufferSetTypeName);
// Tooltips
const FText BufferIndexTooltip = FText(LOCTEXT("BufferIndexTooltip",
"Represents the index where the mutable buffer is found inside the buffer set"));
const FText BufferChannelsTooltip = FText(LOCTEXT("BufferChannelsTooltip",
"The channels contained inside each mutable buffer."));
return SAssignNew(OutHostListView, SListView<TSharedPtr<FBufferElement>>)
.ListItemsSource(&InBufferElements)
.OnGenerateRow(this, &SMutableMeshViewer::OnGenerateBufferRow)
.SelectionMode(ESelectionMode::None)
.HeaderRow
(
SNew(SHeaderRow)
+ SHeaderRow::Column(MutableMeshBuffersListColumns::BufferIndexColumnID)
.DefaultTooltip(BufferIndexTooltip)
.DefaultLabel(BufferIndexTitle)
.FillWidth(0.1f)
+ SHeaderRow::Column(MutableMeshBuffersListColumns::BufferChannelsColumnID)
.DefaultTooltip(BufferChannelsTooltip)
.DefaultLabel(BufferChannelsTitle)
.FillWidth(0.9f)
);
}
TSharedRef<SWidget> SMutableMeshViewer::GenerateBufferChannelsListView(
const TSharedPtr<TArray<TSharedPtr<FBufferChannelElement>>>& InBufferChannelElements)
{
// Headers
const FText ChannelIndex = FText(LOCTEXT("ChannelIndexTitle", "Index"));
const FText ChannelSemanticTitle = FText(LOCTEXT("SemanticLabelTitle", "Semantic"));
const FText ChannelFormatTitle = FText(LOCTEXT("FormatLabelTitle", "Format"));
const FText ComponentCountTitle = FText(LOCTEXT("ComponentCountLabelTitle", "Components"));
// Tooltips
const FText ChannelIndexTooltip = FText(LOCTEXT("ChannelIndexTooltip","Represents the SemanticIndex of the mutable channel inside the whole buffer set. Usefull when more than one channel does share the same type."));
const FText ChannelSemanticTooltip = FText(LOCTEXT("ChannelSemanticTooltip","The semantic that identifies this channel."));
const FText ChannelFormatTooltip = FText(LOCTEXT("ChannelFormatTooltip","The format of the data being held."));
const FText ComponentCountTooltip = FText(LOCTEXT("ChannelComponentTooltip","The amount of components each unit of data has."));
return SNew(SListView<TSharedPtr<FBufferChannelElement>>)
.ListItemsSource(InBufferChannelElements.Get())
.OnGenerateRow(this, &SMutableMeshViewer::OnGenerateBufferChannelRow)
.SelectionMode(ESelectionMode::None)
.HeaderRow
(
SNew(SHeaderRow)
+ SHeaderRow::Column(MutableBufferChannelsListColumns::ChannelSemanticIndexColumnID)
.DefaultTooltip(ChannelIndexTooltip)
.DefaultLabel(ChannelIndex)
.FillWidth(0.14f)
+ SHeaderRow::Column(MutableBufferChannelsListColumns::ChannelSemanticColumnID)
.DefaultTooltip(ChannelSemanticTooltip)
.DefaultLabel(ChannelSemanticTitle)
.FillWidth(0.35f)
+ SHeaderRow::Column(MutableBufferChannelsListColumns::ChannelFormatColumnID)
.DefaultTooltip(ChannelFormatTooltip)
.DefaultLabel(ChannelFormatTitle)
.FillWidth(0.65f)
+ SHeaderRow::Column(MutableBufferChannelsListColumns::ChannelComponentCountID)
.DefaultTooltip(ComponentCountTooltip)
.DefaultLabel(ComponentCountTitle)
.FillWidth(0.3f)
);
}
void SMutableMeshViewer::OnMeshChanged()
{
// Cache the data accessible from the mu::FMesh to be later used by the UI
FillTargetBufferSetDataArray(MutableMesh->GetVertexBuffers(), VertexBuffers, VertexBuffersSlateView);
FillTargetBufferSetDataArray(MutableMesh->GetIndexBuffers(), IndexBuffers, IndexBuffersSlateView);
// Restore the widths of the columns each time the mesh gets changed.
VertexBuffersSlateView->GetHeaderRow()->ResetColumnWidths();
IndexBuffersSlateView->GetHeaderRow()->ResetColumnWidths();
}
void SMutableMeshViewer::FillTargetBufferSetDataArray(const mu::FMeshBufferSet& InMuMeshBufferSet,
TArray<TSharedPtr<FBufferElement>>& OutBuffersDataArray,
TSharedPtr<SListView<TSharedPtr<FBufferElement>>>& InHostListView)
{
// Make sure no data is left from previous runs
OutBuffersDataArray.Empty();
// Iterate over the buffers and get the type and semantic
const int32 BuffersCount = InMuMeshBufferSet.GetBufferCount();
for (int32 BufferIndexOnBufferSet = 0; BufferIndexOnBufferSet < BuffersCount; BufferIndexOnBufferSet++)
{
// Object tasked with the displaying of all the channels it is made with
TSharedPtr<FBufferElement> NewBufferDefinition = MakeShareable(new FBufferElement());
// Array with the data from all channels found inside the current buffer object
TSharedPtr<TArray<TSharedPtr<FBufferChannelElement>>> ChannelsArray =
MakeShareable(new TArray<TSharedPtr<FBufferChannelElement>>);
// Get the channels the buffer has
const int32 ChannelsOnBuffer = InMuMeshBufferSet.GetBufferChannelCount(BufferIndexOnBufferSet);
if (ChannelsOnBuffer == 0)
{
// Add a new row telling the user no channels are set on the buffer
const TSharedPtr<FBufferChannelElement> NewChannelDefinition = MakeShareable(new FBufferChannelElement());
NewChannelDefinition->BufferSemantic = FText(INVTEXT("No Channels found..."));
ChannelsArray->Add(NewChannelDefinition);
NewBufferDefinition->BufferChannels = ChannelsArray;
continue;
}
// Load all channels found onto our array of channels to be later displayed by the UI
for (int32 ChannelIndexOnBuffer = 0; ChannelIndexOnBuffer < ChannelsOnBuffer; ChannelIndexOnBuffer++)
{
TSharedPtr<FBufferChannelElement> NewChannelDefinition = MakeShareable(new FBufferChannelElement());
mu::EMeshBufferSemantic BufferChannelSemantic = mu::EMeshBufferSemantic::None;
mu::EMeshBufferFormat BufferFormat = mu::EMeshBufferFormat::None;
int32 BufferComponentCount = 0;
int32 SemanticIndex = -1;
// Get the data from mutable that we require from the selected buffer set buffer
InMuMeshBufferSet.GetChannel
(
BufferIndexOnBufferSet,
ChannelIndexOnBuffer,
&(BufferChannelSemantic),
&(SemanticIndex),
&(BufferFormat),
&(BufferComponentCount),
nullptr
);
// In order to get the indexes for the UI display, cast the value of the enumeration to int
const int32 SemanticTypeIndex = static_cast<int32>(BufferChannelSemantic);
const int32 BufferFormatIndex = static_cast<int32>(BufferFormat);
// Using mu::TypeInfo find what is the name of the buffer semantic and the buffer format
NewChannelDefinition->SemanticIndex = FText::AsNumber(SemanticIndex);
NewChannelDefinition->BufferSemantic = FText::FromString(
*FString(mu::TypeInfo::s_meshBufferSemanticName[SemanticTypeIndex]));
NewChannelDefinition->BufferFormat = FText::FromString(
*FString(mu::TypeInfo::s_meshBufferFormatName[BufferFormatIndex]));
NewChannelDefinition->BufferComponentCount = FText::FromString(*FString::FromInt(BufferComponentCount));
ChannelsArray->Add(NewChannelDefinition);
}
NewBufferDefinition->BufferIndex = FText::AsNumber( BufferIndexOnBufferSet);
NewBufferDefinition->BufferChannels = ChannelsArray;
OutBuffersDataArray.Add(NewBufferDefinition);
}
// If no data has been found ad an element to show it
if (OutBuffersDataArray.IsEmpty())
{
const TSharedPtr<FBufferElement> NewBufferDefinition = MakeShareable(new FBufferElement());
NewBufferDefinition->BufferIndex = FText(INVTEXT("N/A"));
const TSharedPtr<FBufferChannelElement> NewChannelDefinition = MakeShareable(new FBufferChannelElement());
NewChannelDefinition->BufferSemantic = FText(INVTEXT("No buffers found..."));
TSharedPtr<TArray<TSharedPtr<FBufferChannelElement>>> ChannelsArray =
MakeShareable(new TArray<TSharedPtr<FBufferChannelElement>>);
ChannelsArray->Add(NewChannelDefinition);
NewBufferDefinition->BufferChannels = ChannelsArray;
OutBuffersDataArray.Add(NewBufferDefinition);
}
// Make sure the list gets refreshed with the new contents
InHostListView->RequestListRefresh();
}
FText SMutableMeshViewer::GetVertexCount() const
{
return FText::AsNumber(MutableMesh ? MutableMesh->GetVertexCount() : 0);
}
FText SMutableMeshViewer::GetFaceCount() const
{
return FText::AsNumber(MutableMesh ? MutableMesh->GetFaceCount() : 0);
}
FText SMutableMeshViewer::GetBoneCount() const
{
return FText::AsNumber(MutableMesh && MutableMesh->GetSkeleton() ? MutableMesh->GetSkeleton()->GetBoneCount() : 0);
}
FText SMutableMeshViewer::GetMeshIdPrefix() const
{
return FText::AsNumber(MutableMesh ? MutableMesh->MeshIDPrefix : 0);
}
FText SMutableMeshViewer::GetMeshFlags() const
{
return FText::AsNumber(MutableMesh ? uint32(MutableMesh->Flags) : uint32(0));
}
TSharedRef<ITableRow> SMutableMeshViewer::OnGenerateBufferRow(TSharedPtr<FBufferElement, ESPMode::ThreadSafe> InBuffer,
const TSharedRef<STableViewBase, ESPMode::ThreadSafe>& OwnerTable)
{
TSharedRef<SMutableMeshBufferListRow> Row = SNew(SMutableMeshBufferListRow, OwnerTable, InBuffer, SharedThis(this) );
return Row;
}
TSharedRef<ITableRow> SMutableMeshViewer::OnGenerateBufferChannelRow(TSharedPtr<FBufferChannelElement> InBufferChannel,
const TSharedRef<STableViewBase>& OwnerTable)
{
TSharedRef<SMutableMeshBufferChannelListRow> Row = SNew(SMutableMeshBufferChannelListRow, OwnerTable, InBufferChannel);
return Row;
}
#undef LOCTEXT_NAMESPACE