using Godot; using System.Reflection; using System.Collections.Generic; namespace Rokojori { public class Materials { public static int CountOf( Node node ) { var s = new StandardMaterial3D(); if ( node is MeshInstance3D mi ) { return mi.GetSurfaceOverrideMaterialCount(); } return 1; } public static List GetAll( Node node, int index = 0 ) where M:Material { var list = new List(); var count = CountOf( node ); for ( int i = 0; i < count; i++ ) { list.Add( Get( node, index ) ); } return list; } public static M Get( Node node, int index = 0 ) where M:Material { if ( node is MeshInstance3D mi ) { var material = mi.GetSurfaceOverrideMaterial( index ) as M; if ( material != null ) { return material; } } else if ( node is CsgPrimitive3D ) { return ReflectionHelper.GetMemberValue( node, "material" ) as M; } else if ( node is GpuParticles3D gp) { return gp.ProcessMaterial as M; } if ( node is GeometryInstance3D gi ) { return gi.MaterialOverride as M; } return null; } public static void SetAll( Node node, Material material ) { var count = CountOf( node ); for ( int i = 0; i < count; i++ ) { Set( node, material, i ); } } public static void Set( Node node, List materials ) { var count = CountOf( node ); for ( int i = 0; i < count && i < materials.Count; i++ ) { Set( node, materials[ i ], i ); } } public static void Set( Node node, Material material, int index = 0 ) { if ( node is MeshInstance3D mi) { mi.SetSurfaceOverrideMaterial( index, material ); if ( index == 0 && mi.MaterialOverride != null ) { mi.MaterialOverride = null; } return; } if ( node is CsgPrimitive3D csg ) { ReflectionHelper.SetMemberValue( node, "material", material ); if ( csg.MaterialOverride != null ) { csg.MaterialOverride = null; } return; } if ( node is GpuParticles3D gp ) { gp.ProcessMaterial = material; if ( gp.MaterialOverride != null ) { gp.MaterialOverride = null; } } if ( node is GeometryInstance3D gi ) { gi.MaterialOverride = material; return; } } public static void AddOverlay( Node node, Material material, bool forceTop = true ) { if ( node is GeometryInstance3D gi ) { if ( gi.MaterialOverlay == null || forceTop ) { gi.MaterialOverlay = material; } else { gi.MaterialOverlay.NextPass = material; } return; } } public static void RemoveOverlay( Node node, Material material, bool forceTop = true ) { if ( node is GeometryInstance3D gi ) { if ( forceTop ) { gi.MaterialOverlay = null; } else if ( gi.MaterialOverlay == material ) { gi.MaterialOverlay = gi.MaterialOverlay.NextPass; } else { var mo = gi.MaterialOverlay; while ( mo != null && mo.NextPass != material ) { mo = mo.NextPass; } var next = material.NextPass; mo.NextPass = next; } return; } } } }