rj-action-library/Runtime/Procedural/Mesh/MaterialSurfaceContainer.cs

352 lines
8.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
public enum MaterialSlot
{
None,
MeshSurface,
MeshSurfaceOverride,
Override,
Overlay
}
public abstract class MaterialSurfaceContainer
{
protected Node3D _owner;
protected int _surfaceIndex;
public int surfaceIndex => _surfaceIndex;
protected MaterialSurfaceContainer( Node3D owner, int surfaceIndex )
{
_owner = owner;
_surfaceIndex = surfaceIndex;
}
public abstract MaterialSlot GetActiveMaterialSlot();
public abstract T GetMaterialInSlot<T>( MaterialSlot slot ) where T:Material;
public abstract void SetMaterialInSlot( MaterialSlot slot, Material material );
public static void SetMaterialInSlot( Node3D owner, int surfaceIndex, MaterialSlot slot, Material material )
{
var c = MaterialSurfaceContainer.From( owner, surfaceIndex );
c.SetMaterialInSlot( slot, material );
}
public static T GetMaterialInSlot<T>( Node3D owner, int surfaceIndex, MaterialSlot slot ) where T:Material
{
var c = MaterialSurfaceContainer.From( owner, surfaceIndex );
return c.GetMaterialInSlot<T>( slot );
}
public void SetActiveMaterial( Material material )
{
SetMaterialInSlot( GetActiveMaterialSlot(), material );
}
public T GetActiveMaterial<T>() where T:Material
{
return (T)GetMaterialInSlot<T>( GetActiveMaterialSlot() );
}
protected abstract void _MakeUnique( bool materials );
public void MakeUnique( bool materials )
{
if ( ! isOwner )
{
return;
}
_MakeUnique( materials );
}
public bool isOwner => _surfaceIndex == -1;
public virtual List<MaterialSurfaceContainer> GetOwnedSurfaceContainers()
{
if ( ! isOwner )
{
return null;
}
var surfaces = numSurfaces;
var type = GetType();
var list = new List<MaterialSurfaceContainer>();
for ( int i = 0; i < surfaces; i++ )
{
var surfaceContainer = ReflectionHelper.Create<MaterialSurfaceContainer>( type, _owner, i );
list.Add( surfaceContainer );
}
return list;
}
public virtual void ForAllSurfaces( Action<MaterialSurfaceContainer> action )
{
var surfaces = GetOwnedSurfaceContainers();
surfaces.ForEach( s => action( s ) );
}
public abstract int numSurfaces { get; }
public static void SetMaterialInSlot( Node3D owner, MaterialSlot slot, Material material, int surfaceIndex = 0 )
{
var mc = From( owner, surfaceIndex );
if ( mc == null )
{
return;
}
mc.SetMaterialInSlot( slot, material );
}
public static T GetMaterialInSlot<T>( Node3D owner, MaterialSlot slot, int surfaceIndex = 0 ) where T:Material
{
var mc = From( owner, surfaceIndex );
if ( mc == null )
{
return null;
}
return mc.GetMaterialInSlot<T>( slot );
}
public static MaterialSurfaceContainer From( Node3D owner, int surfaceIndex = -1 )
{
if ( owner is MeshInstance3D mesh )
{
return new MeshSurfaceContainer( mesh, surfaceIndex );
}
if ( owner is MultiMeshInstance3D multi )
{
return new MultiMeshSurfaceContainer( multi, surfaceIndex );
}
return null;
}
}
public abstract class MaterialSurfaceContainer<T>:MaterialSurfaceContainer where T:Node3D
{
public T node => (T)_owner;
protected MaterialSurfaceContainer( Node3D owner, int surfaceIndex ):base( owner, surfaceIndex ){}
}
public class MeshSurfaceContainer: MaterialSurfaceContainer<MeshInstance3D>
{
public MeshSurfaceContainer( MeshInstance3D owner, int surfaceIndex = -1 ):base( owner, surfaceIndex ){}
public override int numSurfaces => node == null || node.Mesh == null ? -1 : node.Mesh.GetSurfaceCount();
public override MaterialSlot GetActiveMaterialSlot()
{
if ( node.MaterialOverride != null )
{
return MaterialSlot.Override;
}
if ( node.Mesh == null || surfaceIndex == -1 )
{
return MaterialSlot.None;
}
if ( node.GetSurfaceOverrideMaterial( surfaceIndex ) != null )
{
return MaterialSlot.MeshSurfaceOverride;
}
var material = node.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MaterialSlot.None : MaterialSlot.MeshSurface;
}
public override void SetMaterialInSlot( MaterialSlot slot, Material material )
{
if ( surfaceIndex == -1 || MaterialSlot.None == slot || material == null || node == null )
{
return;
}
if ( MaterialSlot.MeshSurface == slot )
{
node.Mesh.SurfaceSetMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.MeshSurfaceOverride == slot )
{
node.SetSurfaceOverrideMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.Override == slot )
{
node.MaterialOverride = material;
}
else if ( MaterialSlot.Overlay == slot )
{
node.MaterialOverlay = material;
}
}
public override T GetMaterialInSlot<T>( MaterialSlot slot )
{
if ( MaterialSlot.None == slot )
{
return null;
}
else if ( MaterialSlot.MeshSurface == slot )
{
return (T) node.Mesh.SurfaceGetMaterial( surfaceIndex );
}
else if ( MaterialSlot.MeshSurfaceOverride == slot )
{
return (T) node.GetSurfaceOverrideMaterial( surfaceIndex );
}
else if ( MaterialSlot.Override == slot )
{
return (T) node.MaterialOverride;
}
else if ( MaterialSlot.Overlay == slot )
{
return (T) node.MaterialOverlay;
}
return null;
}
protected override void _MakeUnique( bool materials )
{
if ( node.Mesh == null )
{
return;
}
node.Mesh = (Mesh)node.Mesh.Duplicate();
if ( ! materials )
{
return;
}
for ( int i = 0; i < numSurfaces; i++ )
{
var m = node.Mesh.SurfaceGetMaterial( i );
node.Mesh.SurfaceSetMaterial( i, (Material)m.Duplicate() );
}
}
}
public class MultiMeshSurfaceContainer: MaterialSurfaceContainer<MultiMeshInstance3D>
{
public MultiMeshSurfaceContainer( MultiMeshInstance3D mi, int surfaceIndex = -1 ):base( mi, surfaceIndex ){}
public override int numSurfaces => node == null || node.Multimesh == null || node.Multimesh.Mesh == null ? -1 :
node.Multimesh.Mesh.GetSurfaceCount();
public override MaterialSlot GetActiveMaterialSlot()
{
if ( node.MaterialOverride != null )
{
return MaterialSlot.Override;
}
if ( node.Multimesh == null || node.Multimesh.Mesh == null || surfaceIndex == -1 )
{
return MaterialSlot.None;
}
var material = node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
return material == null ? MaterialSlot.None : MaterialSlot.MeshSurface;
}
public override void SetMaterialInSlot( MaterialSlot slot, Material material )
{
if ( surfaceIndex == -1 || MaterialSlot.None == slot )
{
return;
}
if ( MaterialSlot.MeshSurface == slot )
{
node.Multimesh.Mesh.SurfaceSetMaterial( surfaceIndex, material );
}
else if ( MaterialSlot.Override == slot )
{
node.MaterialOverride = material;
}
else if ( MaterialSlot.Overlay == slot )
{
node.MaterialOverlay = material;
}
}
public override T GetMaterialInSlot<T>( MaterialSlot slot )
{
if ( MaterialSlot.None == slot )
{
return null;
}
else if ( MaterialSlot.MeshSurface == slot )
{
return (T) node.Multimesh.Mesh.SurfaceGetMaterial( surfaceIndex );
}
else if ( MaterialSlot.Override == slot )
{
return (T) node.MaterialOverride;
}
else if ( MaterialSlot.Overlay == slot )
{
return (T) node.MaterialOverlay;
}
return null;
}
protected override void _MakeUnique( bool materials )
{
if ( node.Multimesh == null || node.Multimesh.Mesh == null )
{
return;
}
node.Multimesh.Mesh = (Mesh)node.Multimesh.Mesh.Duplicate();
if ( ! materials )
{
return;
}
for ( int i = 0; i < numSurfaces; i++ )
{
var m = node.Multimesh.Mesh .SurfaceGetMaterial( i );
node.Multimesh.Mesh.SurfaceSetMaterial( i, (Material)m.Duplicate() );
}
}
}
}