// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.Scripting;
using FlaxEngine;
namespace FlaxEditor.CustomEditors.Editors
{
///
/// Default implementation of the inspector used to edit value type properties.
///
[CustomEditor(typeof(ModelInstanceEntry)), DefaultEditor]
public sealed class ModelInstanceEntryEditor : GenericEditor
{
private GroupElement _group;
private bool _updateName;
private int _entryIndex;
private bool _isRefreshing;
private MaterialBase _material;
private ModelInstanceActor _modelInstance;
private AssetRefEditor _materialEditor;
///
public override void Initialize(LayoutElementsContainer layout)
{
_updateName = true;
var group = layout.Group("Entry");
_group = group;
if (ParentEditor == null)
return;
var entry = (ModelInstanceEntry)Values[0];
var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this);
var materialLabel = new PropertyNameLabel("Material");
materialLabel.TooltipText = "The mesh surface material used for the rendering.";
if (ParentEditor.ParentEditor?.Values[0] is ModelInstanceActor modelInstance)
{
_entryIndex = entryIndex;
_modelInstance = modelInstance;
var slots = modelInstance.MaterialSlots;
if (slots == null || entryIndex >= slots.Length)
return;
if (entry.Material == slots[entryIndex].Material)
{
// Ensure that entry with default material set is set back to null
modelInstance.SetMaterial(entryIndex, null);
}
_material = modelInstance.GetMaterial(entryIndex);
var defaultValue = GPUDevice.Instance.DefaultMaterial;
if (slots[entryIndex].Material)
{
// Use default value set on asset (eg. Model Asset)
defaultValue = slots[entryIndex].Material;
}
// Create material picker
var materialValue = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase);
var materialEditor = (AssetRefEditor)_group.Property(materialLabel, materialValue);
materialEditor.Values.SetDefaultValue(defaultValue);
materialEditor.RefreshDefaultValue();
materialEditor.Picker.SelectedItemChanged += OnSelectedMaterialChanged;
_materialEditor = materialEditor;
}
base.Initialize(group);
}
private void OnSelectedMaterialChanged()
{
if (_isRefreshing)
return;
_isRefreshing = true;
var slots = _modelInstance.MaterialSlots;
var material = _materialEditor.Picker.SelectedAsset as MaterialBase;
var defaultMaterial = GPUDevice.Instance.DefaultMaterial;
var value = (ModelInstanceEntry)Values[0];
var prevMaterial = value.Material;
if (!material)
{
// Fallback to default material
_materialEditor.Picker.SelectedAsset = defaultMaterial;
value.Material = defaultMaterial;
}
else if (material == slots[_entryIndex].Material)
{
// Asset default material
value.Material = null;
}
else if (material == defaultMaterial && !slots[_entryIndex].Material)
{
// Default material while asset has no set as well
value.Material = null;
}
else
{
// Custom material
value.Material = material;
}
if (prevMaterial != value.Material)
SetValue(value);
_isRefreshing = false;
}
///
protected override void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item)
{
// Skip material member as it is overridden
if (item.Info.Name == "Material" && _materialEditor != null)
return;
base.SpawnProperty(itemLayout, itemValues, item);
}
///
public override void Refresh()
{
// Update panel title to match material slot name
if (_updateName &&
_group != null &&
ParentEditor?.ParentEditor != null &&
ParentEditor.ParentEditor.Values.Count > 0)
{
var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this);
if (ParentEditor.ParentEditor.Values[0] is ModelInstanceActor modelInstance)
{
var slots = modelInstance.MaterialSlots;
if (slots != null && slots.Length > entryIndex)
{
_updateName = false;
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
}
}
}
// Refresh currently selected material
_material = _modelInstance.GetMaterial(_entryIndex);
base.Refresh();
}
///
protected override void Deinitialize()
{
_material = null;
_modelInstance = null;
_materialEditor = null;
base.Deinitialize();
}
}
}