using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Text; using Godot; namespace Rokojori { public enum HighlightActionType { Start, End } public class HighlightAnimation { public Node3D[] targets; public int tweenID = -1; public List materials = new List(); public float phase; } [Tool] [GlobalClass] public partial class HighlightEffect:Resource { [Export] public TimeLine timeline; [Export] public float inDuration; [Export] public Curve inCurve = MathX.Curve( 0, 1 ); [Export] public float outDuration; [Export] public Curve outCurve = MathX.Curve( 0, 1 ); [Export] public HDRColor color; public enum MaterialMode { Flat_Outline, Custom_Material } [Export] public MaterialMode materialMode; [Export] public Material customMaterial; [Export] public ColorPropertyName customColorProperty; List _active = new List(); public void Highlight( HighlightActionType type, Node3D[] targets ) { if ( HighlightActionType.Start == type ) { StartHighlight( targets ); } else if ( HighlightActionType.End == type ) { EndHighlight( targets ); } } void StartHighlight( Node3D[] targets ) { var animation = _active.Find( a => Arrays.AreEntriesEqual( a.targets, targets ) ); var hdrColor = color.GetHDRColor(); var colorTransparent = ColorX.Fade( hdrColor, 0 ); if ( animation == null ) { animation = new HighlightAnimation(); animation.targets = targets; _active.Add( animation ); Material material = null; if ( MaterialMode.Flat_Outline == materialMode ) { var outlineMaterial = new OutlineMaterial(); outlineMaterial.albedo.Set( colorTransparent ); material = outlineMaterial; } else if ( MaterialMode.Custom_Material == materialMode ) { material = (Material) customMaterial.Duplicate(); customColorProperty.Set( material, colorTransparent ); } Arrays.ForEach( targets, t => { var m = (Material) material.Duplicate( true ); animation.materials.Add( m ); Materials.AddOverlay( t, m ); } ); } var startPhase = animation.phase; animation.tweenID = TimeLineManager.Tween( timeline, inDuration, ( id, type, phase )=> { // RJLog.Log( "Start Highlight: ", id, "Active:",animation.tweenID, "Phase:", phase ); if ( animation.tweenID != id ) { return; } animation.phase = MathX.Map( phase, 0, 1, startPhase, 1 ); var p = animation.phase; if ( inCurve != null ) { p = inCurve.Sample( p ); } var tweenColor = ColorX.Fade( hdrColor, p ); if ( TimeLineSpanUpdateType.End == type ) { tweenColor = hdrColor; animation.phase = 1; } animation.materials.ForEach( ( m )=> { if ( MaterialMode.Flat_Outline == materialMode ) { var outlineMaterial = ( OutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); } else if ( MaterialMode.Custom_Material == materialMode ) { customColorProperty.Set( m, tweenColor); } } ); } ); } void EndHighlight( Node3D[] targets ) { var animation = _active.Find( a => Arrays.AreEntriesEqual( a.targets, targets ) ); if ( animation == null ) { // RJLog.Log( "No animation found:", targets ); return; } var startPhase = animation.phase; var hdrColor = ColorX.Fade( color.GetHDRColor(), startPhase ); var colorTransparent = ColorX.Fade( hdrColor, 0 ); animation.tweenID = TimeLineManager.Tween( timeline, outDuration, ( id, type, phase )=> { // RJLog.Log( "End Highlight: ", id, "Active:",animation.tweenID, "Phase:", phase ); if ( animation.tweenID != id ) { return; } animation.phase = MathX.Map( phase, 0, 1, startPhase, 0 ); var p = animation.phase; if ( outCurve != null ) { p = outCurve.Sample( p ); } var tweenColor = ColorX.Fade( hdrColor, p ); if ( TimeLineSpanUpdateType.End == type ) { tweenColor = colorTransparent; animation.phase = 0; for ( int i = 0; i < animation.targets.Length; i ++ ) { Materials.RemoveOverlay( targets[ i ], animation.materials[ i ] ); } _active.Remove( animation ); } else { animation.materials.ForEach( ( m )=> { if ( MaterialMode.Flat_Outline == materialMode ) { var outlineMaterial = ( OutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); } else if ( MaterialMode.Custom_Material == materialMode ) { customColorProperty.Set( m, tweenColor ); } } ); } } ); } } }