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.GetDataMemberValue( node, "material" ); } 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.SetDataMemberValue( 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 Material GetLastMaterial( Material material ) { while ( material != null ) { var nextMaterial = material.NextPass; if ( nextMaterial == null ) { return material; } material = nextMaterial; } return null; } public static Material GetLastMaterialOverlay( Node node ) { if ( node is GeometryInstance3D gi ) { return GetLastMaterial( gi.MaterialOverlay ); } return null; } public static Material GetPreviousPass( Material firstMaterial, Material nextMaterial ) { var material = firstMaterial; while ( material != null ) { if ( material.NextPass == nextMaterial ) { return material; } material = material.NextPass; } return null; } public static void AddOverlay( Node node, Material material, bool forceTop = true ) { if ( node is GeometryInstance3D gi ) { if ( gi.MaterialOverlay == null || forceTop ) { gi.MaterialOverlay = material; return; } GetLastMaterial( gi.MaterialOverlay ).NextPass = material; return; } } public static void RemoveOverlay( Node node, Material material, bool forceTop = true ) { if ( node is GeometryInstance3D gi ) { if ( gi.MaterialOverlay == material || forceTop ) { gi.MaterialOverlay = null; } else { var previous = GetPreviousPass( gi.MaterialOverlay, material ); previous.NextPass = null; } return; } } } }