| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace HighlightingSystem
- {
- public enum LoopMode
- {
- Once,
- Loop,
- PingPong,
- ClampForever,
- }
- public enum Easing
- {
- Linear,
- QuadIn,
- QuadOut,
- QuadInOut,
- CubicIn,
- CubicOut,
- CubicInOut,
- SineIn,
- SineOut,
- SineInOut,
- }
- public enum RendererFilterMode
- {
- None,
- Include,
- Exclude,
- }
- [AddComponentMenu("Highlighting System/Highlighter", 0)]
- public class Highlighter : HighlighterCore
- {
- #region Constants
- protected const float HALFPI = Mathf.PI * 0.5f;
- #endregion
- #region Inspector Fields
- /* General */
- /// <summary>
- /// When set to true - highlighting will be rendered on top of all other geometry.
- /// </summary>
- public bool overlay
- {
- get { return _overlay; }
- set { _overlay = value; }
- }
- /// <summary>
- /// Controls occluder mode.
- /// </summary>
- public bool occluder
- {
- get { return _occluder; }
- set { _occluder = value; }
- }
- /* Tween */
- public bool tween
- {
- get { return _tween; }
- set { TweenSet(value); }
- }
- public Gradient tweenGradient
- {
- get { return _tweenGradient; }
- set { _tweenGradient = value; }
- }
- public float tweenDuration
- {
- get { return _tweenDuration; }
- set { _tweenDuration = value; ValidateRanges(); }
- }
- public float tweenDelay
- {
- get { return _tweenDelay; }
- set { _tweenDelay = value; }
- }
- public bool tweenUseUnscaledTime
- {
- get { return _tweenUseUnscaledTime; }
- set
- {
- if (_tweenUseUnscaledTime != value)
- {
- float delta = GetTweenTime() - _tweenStart;
- _tweenUseUnscaledTime = value;
- _tweenStart = GetTweenTime() - delta;
- }
- }
- }
- public LoopMode tweenLoop
- {
- get { return _tweenLoop; }
- set { _tweenLoop = value; }
- }
- public Easing tweenEasing
- {
- get { return _tweenEasing; }
- set { _tweenEasing = value; }
- }
- public bool tweenReverse
- {
- get { return _tweenReverse; }
- set { _tweenReverse = value; }
- }
- public int tweenRepeatCount
- {
- get { return _tweenRepeatCount; }
- set { _tweenRepeatCount = value; }
- }
- /* Constant */
- public bool constant
- {
- get { return _constant; }
- set { ConstantSet(value); }
- }
- public Color constantColor
- {
- get { return _constantColor; }
- set { _constantColor = value; }
- }
- public float constantFadeTime
- {
- set
- {
- _constantFadeInTime = value;
- _constantFadeOutTime = value;
- ValidateRanges();
- ConstantSet();
- }
- }
- public float constantFadeInTime
- {
- get { return _constantFadeInTime; }
- set
- {
- _constantFadeInTime = value;
- ValidateRanges();
- if (_constant) { ConstantSet(); }
- }
- }
- public float constantFadeOutTime
- {
- get { return _constantFadeOutTime; }
- set
- {
- _constantFadeOutTime = value;
- ValidateRanges();
- if (!_constant) { ConstantSet(); }
- }
- }
- public bool constantUseUnscaledTime
- {
- get { return _constantUseUnscaledTime; }
- set
- {
- if (_constantUseUnscaledTime != value)
- {
- float delta = GetConstantTime() - _constantStart;
- _constantUseUnscaledTime = value;
- _constantStart = GetConstantTime() - delta;
- }
- }
- }
- public Easing constantEasing
- {
- get { return _constantEasing; }
- set { _constantEasing = value; }
- }
- public RendererFilterMode filterMode
- {
- get { return _filterMode; }
- set
- {
- if (_filterMode != value)
- {
- _filterMode = value;
- // Update highlighted Renderers
- SetDirty();
- }
- }
- }
- /// <summary>
- /// Make sure to trigger SetDirty() after modifying this list
- /// </summary>
- public List<Transform> filterList
- {
- get { return _filterList; }
- }
-
- protected override RendererFilter rendererFilterToUse
- {
- get
- {
- if (rendererFilter != null)
- {
- return rendererFilter;
- }
- else if (_filterMode == RendererFilterMode.None)
- {
- return globalRendererFilter != null ? globalRendererFilter : DefaultRendererFilter;
- }
- else if (_filterMode == RendererFilterMode.Include)
- {
- return TransformFilterInclude;
- }
- else if (_filterMode == RendererFilterMode.Exclude)
- {
- return TransformFilterExclude;
- }
-
- // Should never happen
- return DefaultRendererFilter;
- }
- }
- #endregion
- #region Protected Fields
- // General
- [SerializeField] protected bool _overlay;
- [SerializeField] protected bool _occluder;
- // Hover (do not serialize this!)
- protected Color _hoverColor = Color.red;
- protected int _hoverFrame = -1;
- // Tween
- [SerializeField] protected bool _tween = false;
- [SerializeField] protected Gradient _tweenGradient = new Gradient()
- {
- colorKeys = new GradientColorKey[]
- {
- new GradientColorKey(new Color(0f, 1f, 1f, 1f), 0f),
- new GradientColorKey(new Color(0f, 1f, 1f, 1f), 1f),
- },
- alphaKeys = new GradientAlphaKey[]
- {
- new GradientAlphaKey(0f, 0f),
- new GradientAlphaKey(1f, 1f),
- }
- };
- [SerializeField] protected float _tweenDuration = 1f;
- [SerializeField] protected bool _tweenReverse = false;
- [SerializeField] protected LoopMode _tweenLoop = LoopMode.PingPong;
- [SerializeField] protected Easing _tweenEasing = Easing.Linear;
- [SerializeField] protected float _tweenDelay = 0f;
- [SerializeField] protected int _tweenRepeatCount = -1;
- [SerializeField] protected bool _tweenUseUnscaledTime = false;
-
- // Constant highlighting mode (with optional fade in/out transition)
- [SerializeField] protected bool _constant = false;
- [SerializeField] protected Color _constantColor = Color.yellow;
- [SerializeField] protected float _constantFadeInTime = 0.1f;
- [SerializeField] protected float _constantFadeOutTime = 0.25f;
- [SerializeField] protected Easing _constantEasing = Easing.Linear;
- [SerializeField] protected bool _constantUseUnscaledTime = false;
- [SerializeField] protected RendererFilterMode _filterMode = RendererFilterMode.None;
- [SerializeField] protected List<Transform> _filterList = new List<Transform>();
- // Runtime only (do not serialize this!)
- protected bool _tweenEnabled;
- protected float _tweenStart; // Time when the tween has started
- protected bool _constantEnabled;
- protected float _constantStart;
- protected float _constantDuration;
- #endregion
- #region Protected Accessors
- protected bool hover
- {
- get { return _hoverFrame == Time.frameCount; }
- set { _hoverFrame = value ? Time.frameCount : -1; }
- }
-
- // constantValue is always increasing from 0 to 1 (for both fade in and out transitions)
- protected float constantValue
- {
- get { return _constantDuration > 0f ? Mathf.Clamp01((GetConstantTime() - _constantStart) / _constantDuration) : 1f; }
- }
- #endregion
-
- #region MonoBehaviour
- //
- protected virtual void OnDidApplyAnimationProperties()
- {
- ValidateAll();
- }
-
- #if UNITY_EDITOR
- //
- void OnValidate()
- {
- ValidateAll();
- }
-
- //
- void Reset()
- {
- ValidateAll();
- }
- #endif
- #endregion
-
- #region MonoBehaviour Overrides
- //
- protected override void OnEnableSafe()
- {
- ValidateAll();
- }
-
- //
- protected override void OnDisableSafe()
- {
- // Make sure transition won't continue if component will be re-enabled
- _tweenEnabled = false;
- _constantEnabled = false;
- _constantStart = GetConstantTime() - _constantDuration;
- }
- #endregion
-
- #region Validation
- //
- protected void ValidateAll()
- {
- ValidateRanges();
- TweenSet();
- ConstantSet();
- SetDirty();
- }
- //
- protected void ValidateRanges()
- {
- if (_tweenDuration < 0f) { _tweenDuration = 0f; }
- if (_constantFadeInTime < 0f) { _constantFadeInTime = 0f; }
- if (_constantFadeOutTime < 0f) { _constantFadeInTime = 0f; }
- }
- #endregion
- #region Public Methods
- /// <summary>
- /// Turn on one-frame highlighting with specified color.
- /// Can be called multiple times per update, color only from the latest call will be used.
- /// </summary>
- /// <param name='color'>
- /// Highlighting color.
- /// </param>
- public void Hover(Color color)
- {
- _hoverColor = color;
- hover = true;
- }
-
- /// <summary>
- /// Fade in constant highlighting using specified transition duration.
- /// </summary>
- /// <param name="time">
- /// Transition time.
- /// </param>
- public void ConstantOn(float fadeTime = 0.25f)
- {
- ConstantSet(fadeTime, true);
- }
-
- /// <summary>
- /// Fade in constant highlighting using specified color and transition duration.
- /// </summary>
- /// <param name="color">
- /// Constant highlighting color.
- /// </param>
- /// <param name="time">
- /// Transition duration.
- /// </param>
- public void ConstantOn(Color color, float fadeTime = 0.25f)
- {
- _constantColor = color;
- ConstantSet(fadeTime, true);
- }
- /// <summary>
- /// Fade out constant highlighting using specified transition duration.
- /// </summary>
- /// <param name="time">
- /// Transition time.
- /// </param>
- public void ConstantOff(float fadeTime = 0.25f)
- {
- ConstantSet(fadeTime, false);
- }
-
- /// <summary>
- /// Switch constant highlighting using specified transition duration.
- /// </summary>
- /// <param name="time">
- /// Transition time.
- /// </param>
- public void ConstantSwitch(float fadeTime = 0.25f)
- {
- ConstantSet(fadeTime, !_constant);
- }
- /// <summary>
- /// Turn on constant highlighting immediately (without fading in).
- /// </summary>
- public void ConstantOnImmediate()
- {
- ConstantSet(0f, true);
- }
-
- /// <summary>
- /// Turn on constant highlighting using specified color immediately (without fading in).
- /// </summary>
- /// <param name='color'>
- /// Constant highlighting color.
- /// </param>
- public void ConstantOnImmediate(Color color)
- {
- _constantColor = color;
- ConstantSet(0f, true);
- }
-
- /// <summary>
- /// Turn off constant highlighting immediately (without fading out).
- /// </summary>
- public void ConstantOffImmediate()
- {
- ConstantSet(0f, false);
- }
-
- /// <summary>
- /// Switch constant highlighting immediately (without fading in/out).
- /// </summary>
- public void ConstantSwitchImmediate()
- {
- ConstantSet(0f, !_constant);
- }
- /// <summary>
- /// Turn off all types of highlighting (occlusion mode remains intact).
- /// </summary>
- public void Off()
- {
- hover = false;
- TweenSet(false);
- ConstantSet(0f, false);
- }
- //
- public void TweenStart()
- {
- TweenSet(true);
- }
- //
- public void TweenStop()
- {
- TweenSet(false);
- }
-
- // Updates tween state. (!) Sets _tween value.
- public void TweenSet(bool value)
- {
- _tween = value;
- if (_tweenEnabled != _tween)
- {
- _tweenEnabled = _tween;
- _tweenStart = GetTweenTime();
- }
- }
- // Updates constant state. (!) Sets _constant value.
- public void ConstantSet(float fadeTime, bool value)
- {
- // Order matters. Should always set _constantDuration prior to _constantEnabled
- // Transition duration
- if (fadeTime < 0f) { fadeTime = 0f; }
- if (_constantDuration != fadeTime)
- {
- float timeNow = GetConstantTime();
- // Recalculate start time if duration changed
- _constantStart = _constantDuration > 0f ? timeNow - (fadeTime / _constantDuration) * (timeNow - _constantStart) : timeNow - fadeTime;
- _constantDuration = fadeTime;
- }
- // Transition target
- _constant = value;
- if (_constantEnabled != _constant)
- {
- _constantEnabled = _constant;
- // Recalculate start time if value changed
- _constantStart = GetConstantTime() - _constantDuration * (1f - constantValue);
- }
- }
- #endregion
- #region Protected Methods
- // Helper
- protected void TweenSet()
- {
- TweenSet(_tween);
- }
- // Helper
- protected void ConstantSet()
- {
- ConstantSet(_constant);
- }
- // Helper
- protected void ConstantSet(bool value)
- {
- ConstantSet(value ? constantFadeInTime : _constantFadeOutTime, value);
- }
- // Updates highlighting color
- protected override void UpdateHighlighting()
- {
- // Hover
- if (hover)
- {
- color = _hoverColor;
- mode = _overlay ? HighlighterMode.Overlay : HighlighterMode.Default;
- return;
- }
- // Tween
- if (_tweenEnabled)
- {
- float delta = GetTweenTime() - (_tweenStart + _tweenDelay);
- if (delta >= 0f)
- {
- float t = _tweenDuration > 0f ? delta / _tweenDuration : 0f;
- t = Loop(t, _tweenLoop, _tweenReverse, _tweenRepeatCount);
- if (t >= 0f)
- {
- t = Ease(t, _tweenEasing);
- color = _tweenGradient.Evaluate(t);
- mode = _overlay ? HighlighterMode.Overlay : HighlighterMode.Default;
- return;
- }
- }
- }
- // Constant
- float c = _constantEnabled ? constantValue : 1f - constantValue;
- if (c > 0f)
- {
- c = Ease(c, _constantEasing);
- color = _constantColor;
- color.a *= c;
- mode = _overlay ? HighlighterMode.Overlay : HighlighterMode.Default;
- return;
- }
- // Occluder
- if (_occluder)
- {
- mode = HighlighterMode.Occluder;
- return;
- }
- // Disabled
- mode = HighlighterMode.Disabled;
- }
- #endregion
- #region Protected Methods
- //
- protected bool TransformFilterInclude(Renderer renderer, List<int> submeshIndices)
- {
- Transform child = renderer.transform;
- for (int i = 0; i < _filterList.Count; i++)
- {
- Transform parent = _filterList[i];
- if (parent == null) { continue; }
- // Highlight if child of inclusion list transform
- if (child.IsChildOf(parent))
- {
- // Highlight all submeshes
- submeshIndices.Add(-1);
- return true;
- }
- }
- return false;
- }
- //
- protected bool TransformFilterExclude(Renderer renderer, List<int> submeshIndices)
- {
- Transform child = renderer.transform;
- for (int i = 0; i < _filterList.Count; i++)
- {
- Transform parent = _filterList[i];
- if (parent == null) { continue; }
- // Do not highlight if child of exclusion list transform
- if (child.IsChildOf(parent)) { return false; }
- }
- // Highlight all submeshes
- submeshIndices.Add(-1);
- return true;
- }
- //
- protected float Loop(float x, LoopMode loop, bool reverse = false, int repeatCount = -1)
- {
- float y = -1f;
- switch (loop)
- {
- default:
- case LoopMode.Once:
- if (x >= 0f && x <= 1f) { y = x; }
- break;
- case LoopMode.Loop:
- int n1 = Mathf.FloorToInt(x);
- if (repeatCount < 0 || n1 < repeatCount)
- {
- y = x - n1;
- }
- break;
- case LoopMode.PingPong:
- // Performs 0-1-0 transition in tweenDuration time
- //int n2 = Mathf.FloorToInt(x);
- //if (repeatCount < 0 || n2 < repeatCount)
- //{
- // y = 1f - Mathf.Abs((x - n2) * 2f - 1f);
- //}
- // Performs 0-1-0 transition in 2 * tweenDuration time,
- // so the 0-1 transition is performed with the same speed as in Loop mode.
- int n2 = Mathf.FloorToInt(x * 0.5f);
- if (repeatCount < 0 || n2 < repeatCount)
- {
- y = 1f - Mathf.Abs(x - n2 * 2f - 1f);
- }
- break;
- case LoopMode.ClampForever:
- y = Mathf.Clamp01(x);
- break;
- }
- // Reverse. Check y for positive value since there is no loop if it's negative.
- if (y >= 0f && reverse) { y = 1f - y; }
- return y;
- }
- //
- protected float Ease(float x, Easing easing)
- {
- x = Mathf.Clamp01(x);
- float y;
- switch (easing)
- {
- // Linear
- default:
- case Easing.Linear:
- y = x;
- break;
-
- // Quad
- case Easing.QuadIn:
- y = x * x;
- break;
- case Easing.QuadOut:
- y = -x * (x - 2f);
- break;
- case Easing.QuadInOut:
- y = x < 0.5f ? 2f * x * x : 2f * x * (2f - x) - 1f;
- break;
-
- // Cubic
- case Easing.CubicIn:
- y = x * x * x;
- break;
- case Easing.CubicOut:
- x = x - 1f;
- y = x * x * x + 1f;
- break;
- case Easing.CubicInOut:
- if (x < 0.5f)
- {
- y = 4f * x * x * x;
- }
- else
- {
- x = 2f * x - 2f;
- y = 0.5f * (x * x * x + 2f);
- }
- break;
-
- // Sine
- case Easing.SineIn:
- y = 1f - Mathf.Cos(x * HALFPI);
- break;
- case Easing.SineOut:
- y = Mathf.Sin(x * HALFPI);
- break;
- case Easing.SineInOut:
- y = -0.5f * (Mathf.Cos(x * Mathf.PI) - 1f);
- break;
- //y = x * x * (3f - 2f * x);
- }
- return y;
- }
- //
- protected float GetTweenTime()
- {
- return _tweenUseUnscaledTime ? Time.unscaledTime : Time.time;
- }
- //
- protected float GetConstantTime()
- {
- return _constantUseUnscaledTime ? Time.unscaledTime : Time.time;
- }
- #endregion
- #region Static Methods
- // Color helper
- static public Color HSVToRGB(float hue, float saturation, float value)
- {
- float x = 6f * Mathf.Clamp01(hue);
- saturation = Mathf.Clamp01(saturation);
- value = Mathf.Clamp01(value);
- return new Color
- (
- value * (1f + (Mathf.Clamp01(Mathf.Max(2f - x, x - 4f)) - 1f) * saturation),
- value * (1f + (Mathf.Clamp01(Mathf.Min(x, 4f - x)) - 1f) * saturation),
- value * (1f + (Mathf.Clamp01(Mathf.Min(x - 2f, 6f - x)) - 1f) * saturation)
- );
- }
- #endregion
- #region DEPRECATED
- private GradientColorKey[] flashingColorKeys = new GradientColorKey[]
- {
- new GradientColorKey(new Color(0f, 1f, 1f, 0f), 0f),
- new GradientColorKey(new Color(0f, 1f, 1f, 1f), 1f)
- };
- private GradientAlphaKey[] flashingAlphaKeys = new GradientAlphaKey[]
- {
- new GradientAlphaKey(1f, 0f),
- new GradientAlphaKey(1f, 1f),
- };
- /// <summary>
- /// DEPRECATED. Use hover = true; instead.
- /// </summary>
- [System.Obsolete]
- public void On()
- {
- hover = true;
- }
- /// <summary>
- /// DEPRECATED. Use Hover(Color color) instead.
- /// </summary>
- [System.Obsolete]
- public void On(Color color)
- {
- Hover(color);
- }
-
- /// <summary>
- /// DEPRECATED. Use Hover(new Color(1f, 0f, 0f, 1f)); instead.
- /// </summary>
- [System.Obsolete]
- public void OnParams(Color color)
- {
- _hoverColor = color;
- }
-
- /// <summary>
- /// DEPRECATED. Use constantColor = new Color(0f, 1f, 1f, 1f); instead.
- /// </summary>
- [System.Obsolete]
- public void ConstantParams(Color color)
- {
- _constantColor = color;
- }
-
- /// <summary>
- /// DEPRECATED. Use tweenGradient and tweenDuration instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingParams(Color color1, Color color2, float freq)
- {
- flashingColorKeys[0].color = color1;
- flashingColorKeys[1].color = color2;
- _tweenGradient.SetKeys(flashingColorKeys, flashingAlphaKeys);
- _tweenDuration = 1f / freq;
- }
- /// <summary>
- /// DEPRECATED. Use TweenStart() instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingOn()
- {
- TweenSet(true);
- }
-
- /// <summary>
- /// DEPRECATED. Use tweenGradient instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingOn(Color color1, Color color2)
- {
- flashingColorKeys[0].color = color1;
- flashingColorKeys[1].color = color2;
- _tweenGradient.SetKeys(flashingColorKeys, flashingAlphaKeys);
- TweenSet(true);
- }
-
- /// <summary>
- /// DEPRECATED. Use tweenGradient and tweenDuration instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingOn(Color color1, Color color2, float freq)
- {
- flashingColorKeys[0].color = color1;
- flashingColorKeys[1].color = color2;
- _tweenGradient.SetKeys(flashingColorKeys, flashingAlphaKeys);
- _tweenDuration = 1f / freq;
- TweenSet(true);
- }
- /// <summary>
- /// DEPRECATED. Use tweenDuration instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingOn(float freq)
- {
- _tweenDuration = 1f / freq;
- TweenSet(true);
- }
- /// <summary>
- /// DEPRECATED. Use TweenStop() instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingOff()
- {
- TweenSet(false);
- }
- /// <summary>
- /// DEPRECATED. Use TweenStart() and TweenStop() instead.
- /// </summary>
- [System.Obsolete]
- public void FlashingSwitch()
- {
- tween = !tween;
- }
- #endregion
- }
- }
|