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 = new Node3D[ 0 ]; public int tweenID = -1; public List materials = new List(); public float phase; } [Tool] [GlobalClass] public partial class HighlightEffect:Resource { [Export] public TimeLine timeline; [ExportGroup( "Transition")] [Export] public float inDuration; [Export] public Curve inCurve = MathX.Curve( 0, 1 ); [Export] public float outDuration; [Export] public Curve outCurve = MathX.Curve( 0, 1 ); [ExportGroup( "Color")] [Export] public HDRColor color; [Export( PropertyHint.Range, "0,1")] public float opacityModulationStrength = 0.5f; [Export( PropertyHint.Range, "0,10")] public float opacityModulationDuration = 0.5f; [Export( PropertyHint.Range, "0,1")] public float opacityModulationTransition = 1f; public enum OutlineMaterialMode { Flat_Outline, Scanner_FancyOutline, Custom_Material } [ExportGroup( "Outline")] [Export] public OutlineMaterialMode outlineMaterialMode; [Export] public Material outlineCustomMaterial; [Export] public ColorPropertyName outlineCustomColorProperty; public enum OverlayMaterialMode { Flat_Overlay, Custom_Material } [ExportGroup( "Overlay")] [Export( PropertyHint.Range, "0,1")] public float overlayOpacity = 0.02f; [Export] public OverlayMaterialMode overlayMaterialMode; [Export] public Material overlayCustomMaterial; [Export] public ColorPropertyName overlayCustomColorProperty; 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 ( OutlineMaterialMode.Flat_Outline == outlineMaterialMode ) { var outlineMaterial = new OutlineMaterial(); outlineMaterial.albedo.Set( colorTransparent ); material = outlineMaterial; outlineMaterial.opacityModulationDuration.Set( opacityModulationDuration ); outlineMaterial.opacityModulationStrength.Set( opacityModulationStrength ); } else if ( OutlineMaterialMode.Scanner_FancyOutline == outlineMaterialMode ) { var outlineMaterial = new FancyOutlineMaterial(); outlineMaterial.albedo.Set( colorTransparent ); material = outlineMaterial; outlineMaterial.opacityModulationDuration.Set( opacityModulationDuration ); outlineMaterial.opacityModulationStrength.Set( opacityModulationStrength ); } else if ( OutlineMaterialMode.Custom_Material == outlineMaterialMode ) { material = (Material) outlineCustomMaterial.Duplicate(); outlineCustomColorProperty.Set( material, colorTransparent ); } if ( OverlayMaterialMode.Flat_Overlay == overlayMaterialMode ) { var overlay = new OverlayMaterial(); overlay.albedo.Set( ColorX.SetAlpha( hdrColor, 0 ) ); material.NextPass = overlay; overlay.opacityModulationDuration.Set( opacityModulationDuration ); overlay.opacityModulationStrength.Set( opacityModulationStrength ); } else if ( OverlayMaterialMode.Custom_Material == overlayMaterialMode ) { var overlay = (Material) overlayCustomMaterial.Duplicate(); overlayCustomColorProperty.Set( overlay, colorTransparent ); material.NextPass = overlay; } 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.ScheduleSpanIn( timeline, 0, inDuration, ( span, type )=> { if ( animation.tweenID != span.id ) { return; } var phase = span.phase; animation.phase = MathX.Map( phase, 0, 1, startPhase, 1 ); var p = animation.phase; if ( inCurve != null ) { p = inCurve.Sample( p ); } var transitionModulationStrength = Mathf.Lerp( opacityModulationStrength, opacityModulationStrength * p, opacityModulationTransition ); var tweenColor = ColorX.Fade( hdrColor, p ); if ( TimeLineSpanUpdateType.End == type ) { tweenColor = hdrColor; animation.phase = 1; } animation.materials.ForEach( ( m )=> { if ( OutlineMaterialMode.Flat_Outline == outlineMaterialMode ) { var outlineMaterial = ( OutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); outlineMaterial.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Scanner_FancyOutline == outlineMaterialMode ) { var outlineMaterial = ( FancyOutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); outlineMaterial.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Custom_Material == outlineMaterialMode ) { outlineCustomColorProperty.Set( m, tweenColor); } if ( OverlayMaterialMode.Flat_Overlay == overlayMaterialMode ) { var overlay = (OverlayMaterial) m.NextPass; overlay.albedo.Set( ColorX.Fade( tweenColor, overlayOpacity ) ); overlay.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Custom_Material == outlineMaterialMode ) { var material = (OverlayMaterial) m.NextPass; outlineCustomColorProperty.Set( m, tweenColor); } } ); } ).id; } void EndHighlight( Node3D[] targets ) { var animation = _active.Find( a => Arrays.AreEntriesEqual( a.targets, targets ) ); if ( animation == null ) { return; } var startPhase = animation.phase; var hdrColor = ColorX.Fade( color.GetHDRColor(), startPhase ); var colorTransparent = ColorX.Fade( hdrColor, 0 ); animation.tweenID = TimeLineManager.ScheduleSpanIn( timeline, 0, outDuration, ( span, type )=> { if ( animation.tweenID != span.id ) { return; } animation.phase = MathX.Map( span.phase, 0, 1, startPhase, 0 ); var p = animation.phase; if ( outCurve != null ) { p = outCurve.Sample( p ); } var transitionModulationStrength = Mathf.Lerp( opacityModulationStrength, opacityModulationStrength * p, opacityModulationTransition ); 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 ( OutlineMaterialMode.Flat_Outline == outlineMaterialMode ) { var outlineMaterial = ( OutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); outlineMaterial.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Scanner_FancyOutline == outlineMaterialMode ) { var outlineMaterial = ( FancyOutlineMaterial ) m; outlineMaterial.albedo.Set( tweenColor ); outlineMaterial.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Custom_Material == outlineMaterialMode ) { outlineCustomColorProperty.Set( m, tweenColor ); } if ( OverlayMaterialMode.Flat_Overlay == overlayMaterialMode ) { var overlay = (OverlayMaterial) m.NextPass; overlay.albedo.Set( ColorX.Fade( tweenColor, overlayOpacity ) ); overlay.opacityModulationStrength.Set( transitionModulationStrength ); } else if ( OutlineMaterialMode.Custom_Material == outlineMaterialMode ) { var material = (OverlayMaterial) m.NextPass; outlineCustomColorProperty.Set( m, tweenColor); } } ); } } ).id; } } }