212 lines
7.1 KiB
C++
212 lines
7.1 KiB
C++
// Copyright 2016 Mookie. All Rights Reserved.
|
|
|
|
#include "EBPhysicalMaterialCustomization.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "EditorStyleSet.h"
|
|
#include "Engine/Engine.h"
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
#include "ContentBrowserModule.h"
|
|
#include "IContentBrowserSingleton.h"
|
|
#include "Framework/Notifications/NotificationManager.h"
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "EBPhysicalMaterialCustomization"
|
|
|
|
TSharedRef<IDetailCustomization> FEBPhysicalMaterialCustomization::MakeInstance()
|
|
{
|
|
return MakeShareable(new FEBPhysicalMaterialCustomization);
|
|
}
|
|
|
|
void FEBPhysicalMaterialCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
|
{
|
|
DetailBuilderPtr = &DetailBuilder;
|
|
|
|
TArray<TWeakObjectPtr<UObject>> Objects;
|
|
DetailBuilder.GetObjectsBeingCustomized(Objects);
|
|
|
|
if (Objects.Num() == 1)
|
|
{
|
|
PhysicalMaterialPtr = Cast<UPhysicalMaterial>(Objects[0].Get());
|
|
|
|
if (PhysicalMaterialPtr.IsValid())
|
|
{
|
|
// Add Ballistics category
|
|
IDetailCategoryBuilder& BallisticsCategory = DetailBuilder.EditCategory("Ballistics", LOCTEXT("BallisticsCategory", "Ballistics"), ECategoryPriority::Important);
|
|
|
|
UEBMaterialPropertiesAsset* CurrentProperties = GetBallisticProperties(PhysicalMaterialPtr.Get());
|
|
|
|
// Show current ballistic properties if assigned
|
|
if (CurrentProperties)
|
|
{
|
|
BallisticsCategory.AddCustomRow(LOCTEXT("CurrentPropertiesLabel", "Ballistic Properties"))
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("CurrentPropertiesName", "Ballistic Properties"))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(CurrentProperties->GetName()))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f, 0.0f)
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("EditProperties", "Edit"))
|
|
.OnClicked(this, &FEBPhysicalMaterialCustomization::OnEditBallisticProperties)
|
|
.ToolTipText(LOCTEXT("EditPropertiesTooltip", "Edit the ballistic properties asset"))
|
|
]
|
|
];
|
|
}
|
|
else
|
|
{
|
|
// Show assignment options
|
|
BallisticsCategory.AddCustomRow(LOCTEXT("AssignPropertiesLabel", "Assign Ballistic Properties"))
|
|
.WholeRowContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f, 0.0f)
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("CreateNew", "Create New"))
|
|
.OnClicked(this, &FEBPhysicalMaterialCustomization::OnCreateBallisticProperties)
|
|
.ToolTipText(LOCTEXT("CreateNewTooltip", "Create a new ballistic properties asset for this material"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f, 0.0f)
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("AssignExisting", "Assign Existing"))
|
|
.OnClicked(this, &FEBPhysicalMaterialCustomization::OnAssignBallisticProperties)
|
|
.ToolTipText(LOCTEXT("AssignExistingTooltip", "Assign an existing ballistic properties asset to this material"))
|
|
]
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FReply FEBPhysicalMaterialCustomization::OnCreateBallisticProperties()
|
|
{
|
|
if (PhysicalMaterialPtr.IsValid())
|
|
{
|
|
// Create new Material Properties Asset
|
|
FString PackageName = PhysicalMaterialPtr->GetPackage()->GetName() + TEXT("_BallisticProps");
|
|
FString AssetName = PhysicalMaterialPtr->GetName() + TEXT("_BallisticProps");
|
|
|
|
UPackage* Package = CreatePackage(*PackageName);
|
|
UEBMaterialPropertiesAsset* NewAsset = NewObject<UEBMaterialPropertiesAsset>(Package, *AssetName, RF_Public | RF_Standalone);
|
|
|
|
// Set some sensible defaults based on material name
|
|
FString MaterialName = PhysicalMaterialPtr->GetName().ToLower();
|
|
if (MaterialName.Contains("steel") || MaterialName.Contains("metal"))
|
|
{
|
|
NewAsset->MaterialProperties.DensityGPerCm3 = 7.85f;
|
|
NewAsset->MaterialProperties.MaterialHardness = 200.0f;
|
|
NewAsset->MaterialName = "Steel";
|
|
}
|
|
else if (MaterialName.Contains("wood"))
|
|
{
|
|
NewAsset->MaterialProperties.DensityGPerCm3 = 0.6f;
|
|
NewAsset->MaterialProperties.MaterialHardness = 30.0f;
|
|
NewAsset->MaterialName = "Wood";
|
|
}
|
|
else if (MaterialName.Contains("concrete"))
|
|
{
|
|
NewAsset->MaterialProperties.DensityGPerCm3 = 2.4f;
|
|
NewAsset->MaterialProperties.MaterialHardness = 100.0f;
|
|
NewAsset->MaterialName = "Concrete";
|
|
}
|
|
|
|
// Mark package dirty and register with asset registry
|
|
Package->MarkPackageDirty();
|
|
FAssetRegistryModule::AssetCreated(NewAsset);
|
|
|
|
// Associate with physical material
|
|
SetBallisticProperties(PhysicalMaterialPtr.Get(), NewAsset);
|
|
|
|
// Refresh the details panel
|
|
if (DetailBuilderPtr)
|
|
{
|
|
DetailBuilderPtr->ForceRefreshDetails();
|
|
}
|
|
|
|
// Show success notification
|
|
FNotificationInfo Info(LOCTEXT("CreatedBallisticProps", "Created ballistic properties asset"));
|
|
Info.ExpireDuration = 3.0f;
|
|
FSlateNotificationManager::Get().AddNotification(Info);
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply FEBPhysicalMaterialCustomization::OnAssignBallisticProperties()
|
|
{
|
|
// Open content browser to select existing Material Properties Asset
|
|
FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
|
|
|
|
FAssetPickerConfig AssetPickerConfig;
|
|
AssetPickerConfig.Filter.ClassPaths.Add(UEBMaterialPropertiesAsset::StaticClass()->GetClassPathName());
|
|
AssetPickerConfig.bAllowNullSelection = false;
|
|
AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateLambda([this](const FAssetData& AssetData)
|
|
{
|
|
if (UEBMaterialPropertiesAsset* SelectedAsset = Cast<UEBMaterialPropertiesAsset>(AssetData.GetAsset()))
|
|
{
|
|
SetBallisticProperties(PhysicalMaterialPtr.Get(), SelectedAsset);
|
|
|
|
if (DetailBuilderPtr)
|
|
{
|
|
DetailBuilderPtr->ForceRefreshDetails();
|
|
}
|
|
}
|
|
});
|
|
|
|
ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply FEBPhysicalMaterialCustomization::OnEditBallisticProperties()
|
|
{
|
|
if (UEBMaterialPropertiesAsset* Properties = GetBallisticProperties(PhysicalMaterialPtr.Get()))
|
|
{
|
|
// Open the asset for editing
|
|
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(Properties);
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
UEBMaterialPropertiesAsset* FEBPhysicalMaterialCustomization::GetBallisticProperties(UPhysicalMaterial* PhysMat) const
|
|
{
|
|
if (!PhysMat) return nullptr;
|
|
|
|
// For now, use a simple naming convention or metadata
|
|
// In a production system, you might add a UPROPERTY to UPhysicalMaterial
|
|
FString AssetName = PhysMat->GetName() + TEXT("_BallisticProps");
|
|
FString PackageName = PhysMat->GetPackage()->GetName() + TEXT("_BallisticProps");
|
|
|
|
return LoadObject<UEBMaterialPropertiesAsset>(nullptr, *PackageName, nullptr, LOAD_NoWarn | LOAD_Quiet);
|
|
}
|
|
|
|
void FEBPhysicalMaterialCustomization::SetBallisticProperties(UPhysicalMaterial* PhysMat, UEBMaterialPropertiesAsset* Properties)
|
|
{
|
|
// In a production system, you would store this reference properly
|
|
// For now, we rely on naming conventions and the Material Response Map system
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |