using DG.Tweening;
using UnityEngine;
using AibisDream.Utility;
namespace AibisDream
{
///
/// Drives the unified EyeUnifiedSprite path for Peipei eye targets.
///
public class EyeTargetVisual : MonoBehaviour
{
private static readonly int ColorRevealId = Shader.PropertyToID("_ColorReveal");
private static readonly int GrayAmountId = Shader.PropertyToID("_GrayAmount");
private static readonly int BlurAmountId = Shader.PropertyToID("_BlurAmount");
private static readonly int BlurSizeId = Shader.PropertyToID("_BlurSize");
private static readonly int DistortAmountId = Shader.PropertyToID("_DistortAmount");
private static readonly int WrongColorAmountId = Shader.PropertyToID("_WrongColorAmount");
private static readonly int SpriteFadeId = Shader.PropertyToID("_SpriteFade");
private static readonly int AsciiAmountId = Shader.PropertyToID("_AsciiAmount");
private static readonly int DreamAmountId = Shader.PropertyToID("_DreamAmount");
private static readonly int MemoryAmountId = Shader.PropertyToID("_MemoryAmount");
private static readonly int ScanlineAmountId = Shader.PropertyToID("_ScanlineAmount");
private static readonly int GlitchAmountId = Shader.PropertyToID("_GlitchAmount");
private static readonly int HsvShiftId = Shader.PropertyToID("_HsvShift");
private static readonly int HsvSaturationId = Shader.PropertyToID("_HsvSaturation");
private static readonly int RoundWaveStrengthId = Shader.PropertyToID("_RoundWaveStrength");
private static readonly int RevealWidthId = Shader.PropertyToID("_RevealWidth");
private static readonly int RevealRotationId = Shader.PropertyToID("_RevealRotation");
private static readonly int RevealNoiseId = Shader.PropertyToID("_RevealNoise");
private static readonly int WrongColorId = Shader.PropertyToID("_WrongColor");
[SerializeField] private SpriteRenderer spriteRenderer;
[SerializeField] private SpriteRenderer imageSpriteRenderer;
[SerializeField] private bool driveImageLayer = true;
private Material material;
private float activeBlurSize = 0.008f;
public bool IsReady => material != null && material.HasProperty(ColorRevealId);
public bool CanDriveImageLayer => driveImageLayer && imageSpriteRenderer != null;
public Material Material => material;
private void Awake()
{
EnsureMaterial();
}
public bool EnsureMaterial()
{
if (spriteRenderer == null)
{
spriteRenderer = GetComponent();
}
if (spriteRenderer == null)
{
return false;
}
material = Application.isPlaying
? spriteRenderer.material
: spriteRenderer.sharedMaterial;
return IsReady;
}
public void Configure(SpriteRenderer mainRenderer, SpriteRenderer imageRenderer)
{
spriteRenderer = mainRenderer;
imageSpriteRenderer = imageRenderer;
EnsureMaterial();
}
public void ApplyTuning(EyeVisualSettings settings)
{
if (settings == null)
{
return;
}
activeBlurSize = settings.blurSize;
if (!EnsureMaterial())
{
return;
}
material.SetFloat(RevealWidthId, settings.revealWidth);
material.SetFloat(RevealRotationId, settings.revealRotation);
material.SetFloat(RevealNoiseId, settings.revealNoise);
material.SetColor(WrongColorId, settings.wrongColor);
SetFloatRaw(HsvSaturationId, settings.hsvSaturation);
SyncBlurSizeToMaterial();
}
public void SyncBlurSizeToMaterial()
{
if (!EnsureMaterial() || !material.HasProperty(BlurSizeId))
{
return;
}
float blur = material.GetFloat(BlurAmountId);
material.SetFloat(BlurSizeId, blur > 0.01f ? activeBlurSize : 0f);
}
public void KillActiveTweens()
{
if (material != null)
{
material.DOKill();
}
if (driveImageLayer && imageSpriteRenderer != null)
{
imageSpriteRenderer.DOKill();
}
ClearTransientEffects(null);
}
public void ClearTransientEffects(EyeVisualSettings settings)
{
if (!EnsureMaterial())
{
return;
}
SetFloat(GlitchAmountId, 0f);
SetFloat(DistortAmountId, 0f);
SetFloat(ScanlineAmountId, 0f);
SetFloatRaw(HsvShiftId, 0f);
SetFloatRaw(RevealNoiseId, settings != null ? settings.revealNoise : 0f);
}
public void ResetVisual(float reveal)
{
if (!EnsureMaterial())
{
return;
}
SetFloat(ColorRevealId, reveal);
SetFloat(GrayAmountId, 1f - reveal);
SetFloat(BlurAmountId, 1f);
if (material.HasProperty(BlurSizeId))
{
material.SetFloat(BlurSizeId, activeBlurSize);
}
SetFloat(DistortAmountId, 0f);
SetFloat(WrongColorAmountId, 0f);
SetFloat(SpriteFadeId, 1f);
SetFloat(AsciiAmountId, 0f);
SetFloat(DreamAmountId, 0f);
SetFloat(MemoryAmountId, 0f);
SetFloat(ScanlineAmountId, 0f);
SetFloat(GlitchAmountId, 0f);
SetFloat(HsvShiftId, 0f);
SetFloat(HsvSaturationId, 1f);
SetFloat(RoundWaveStrengthId, 0f);
SetImageAlpha(0f);
}
public void SetColorReveal(float value)
{
SetFloat(ColorRevealId, value);
SetFloat(GrayAmountId, 1f - value);
}
public float GetColorReveal()
{
if (!EnsureMaterial() || !material.HasProperty(ColorRevealId))
{
return 0f;
}
return material.GetFloat(ColorRevealId);
}
public bool IsAtColorReveal(float target, float epsilon = 0.02f)
{
return Mathf.Abs(GetColorReveal() - target) <= epsilon;
}
public Tween TweenColorReveal(float value, float duration)
{
if (!EnsureMaterial())
{
return null;
}
value = Mathf.Clamp01(value);
Sequence sequence = DOTween.Sequence();
sequence.Join(material.DOFloat(value, ColorRevealId, duration));
sequence.Join(material.DOFloat(1f - value, GrayAmountId, duration));
return sequence;
}
public void SetBlur(float value)
{
SetFloat(BlurAmountId, value);
if (EnsureMaterial() && material.HasProperty(BlurSizeId))
{
material.SetFloat(BlurSizeId, value > 0.01f ? activeBlurSize : 0f);
}
}
public Tween TweenBlur(float value, float duration)
{
if (!EnsureMaterial())
{
return null;
}
Tween tween = material.DOFloat(value, BlurAmountId, duration);
tween.OnUpdate(SyncBlurSizeToMaterial);
tween.OnComplete(SyncBlurSizeToMaterial);
return tween;
}
///
/// One focus transition: sharpen, brief defocus, settle. Total wall time equals .
///
public Tween TweenBlurFocusSettle(EyeVisualSettings settings, float duration)
{
if (!EnsureMaterial() || settings == null || duration <= 0f)
{
return null;
}
float sharpBlur = settings.focusedBlurAmount;
float bumpBlur = Mathf.Clamp(
sharpBlur + settings.focusSettleDefocusBump,
sharpBlur,
settings.idleBlurAmount);
Vector3 ratios = settings.focusSettlePhaseRatios;
float ratioSum = ratios.x + ratios.y + ratios.z;
if (ratioSum <= 0.001f)
{
ratios = new Vector3(0.5f, 0.22f, 0.28f);
ratioSum = ratios.x + ratios.y + ratios.z;
}
float primaryDuration = duration * (ratios.x / ratioSum);
float defocusDuration = duration * (ratios.y / ratioSum);
float refocusDuration = duration * (ratios.z / ratioSum);
Sequence sequence = DOTween.Sequence();
Tween primaryFocus = TweenBlur(sharpBlur, primaryDuration);
if (primaryFocus != null)
{
primaryFocus.SetEase(Ease.InOutSine);
sequence.Append(primaryFocus);
}
Tween microDefocus = TweenBlur(bumpBlur, defocusDuration);
if (microDefocus != null)
{
microDefocus.SetEase(Ease.InOutSine);
sequence.Append(microDefocus);
}
Tween refocus = TweenBlur(sharpBlur, refocusDuration);
if (refocus != null)
{
refocus.SetEase(Ease.InOutSine);
sequence.Append(refocus);
}
return sequence;
}
public void SetWrongColor(float value)
{
SetFloat(WrongColorAmountId, value);
}
public Tween TweenWrongColor(float value, float duration)
{
return TweenFloat(WrongColorAmountId, value, duration);
}
public Tween PlayColorSweepTransition(EyeVisualSettings settings, float duration, bool colorIn)
{
if (!EnsureMaterial() || settings == null || duration <= 0f)
{
return null;
}
duration = Mathf.Max(0.01f, duration);
float chromaPeak = settings.colorSweepChromaPeak;
float ramp = Mathf.Clamp(settings.colorSweepChromaRamp, 0.1f, 0.6f);
float rampDuration = duration * ramp;
float settleDuration = duration - rampDuration;
float targetReveal = colorIn ? settings.colorRevealMax : settings.colorRevealMin;
float targetBlur = colorIn ? settings.focusedBlurAmount : settings.idleBlurAmount;
Ease sweepEase = colorIn ? Ease.InOutSine : Ease.InSine;
ClearTransientEffects(null);
SetFloatRaw(RevealNoiseId, 0f);
Sequence sequence = DOTween.Sequence();
Tween colorTween = TweenColorReveal(targetReveal, duration);
if (colorTween != null)
{
colorTween.SetEase(sweepEase);
sequence.Join(colorTween);
}
Tween blurTween = TweenBlur(targetBlur, duration);
if (blurTween != null)
{
blurTween.SetEase(sweepEase);
sequence.Join(blurTween);
}
if (chromaPeak > 0.001f)
{
Sequence chromaEnvelope = DOTween.Sequence();
chromaEnvelope.Append(material.DOFloat(chromaPeak, GlitchAmountId, rampDuration)
.SetEase(Ease.OutSine));
chromaEnvelope.Append(material.DOFloat(0f, GlitchAmountId, settleDuration)
.SetEase(Ease.InSine));
sequence.Join(chromaEnvelope);
}
sequence.OnComplete(() => ClearTransientEffects(settings));
return sequence;
}
public void SetImageAlpha(float alpha)
{
if (!driveImageLayer || imageSpriteRenderer == null)
{
return;
}
alpha = Mathf.Clamp01(alpha);
if (alpha > 0f)
{
imageSpriteRenderer.gameObject.SetActive(true);
imageSpriteRenderer.enabled = true;
}
imageSpriteRenderer.SetAlpha(alpha);
if (alpha <= 0f)
{
imageSpriteRenderer.gameObject.SetActive(false);
}
}
public Tween TweenImageAlpha(float alpha, float duration)
{
if (!driveImageLayer || imageSpriteRenderer == null)
{
return null;
}
alpha = Mathf.Clamp01(alpha);
if (alpha > 0f)
{
imageSpriteRenderer.gameObject.SetActive(true);
imageSpriteRenderer.enabled = true;
}
return imageSpriteRenderer.DOFade(alpha, duration)
.OnComplete(() =>
{
if (alpha <= 0f && imageSpriteRenderer != null)
{
imageSpriteRenderer.gameObject.SetActive(false);
}
});
}
public void SetUfWeights(float ascii, float dream, float memory)
{
SetFloat(AsciiAmountId, ascii);
SetFloat(DreamAmountId, dream);
SetFloat(MemoryAmountId, memory);
SetFloat(ScanlineAmountId, Mathf.Max(ascii, memory));
}
public Tween TweenUfWeights(float ascii, float dream, float memory, float duration)
{
if (!EnsureMaterial())
{
return null;
}
Sequence sequence = DOTween.Sequence();
sequence.Join(material.DOFloat(Mathf.Clamp01(ascii), AsciiAmountId, duration));
sequence.Join(material.DOFloat(Mathf.Clamp01(dream), DreamAmountId, duration));
sequence.Join(material.DOFloat(Mathf.Clamp01(memory), MemoryAmountId, duration));
sequence.Join(material.DOFloat(Mathf.Clamp01(Mathf.Max(ascii, memory)), ScanlineAmountId, duration));
return sequence;
}
public void SetSaturation(float saturation)
{
SetFloatRaw(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f));
}
public Tween TweenSaturation(float saturation, float duration)
{
return TweenFloat(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f), duration);
}
public Sequence StartGlitch(float duration = 1f)
{
if (!EnsureMaterial())
{
return null;
}
duration = Mathf.Max(0.01f, duration);
Sequence sequence = DOTween.Sequence();
sequence.Join(material.DOFloat(1f, GlitchAmountId, duration));
sequence.Join(material.DOFloat(0.02f, DistortAmountId, duration));
sequence.Join(material.DOFloat(360f, HsvShiftId, duration).SetLoops(-1, LoopType.Yoyo));
return sequence;
}
public void StopGlitch(float duration)
{
TweenFloat(GlitchAmountId, 0f, duration);
TweenFloat(DistortAmountId, 0f, duration);
TweenFloat(HsvShiftId, 0f, duration);
}
public Tween TweenRoundWave(float value, float duration)
{
return TweenFloat(RoundWaveStrengthId, value, duration);
}
private Tween TweenFloat(int propertyId, float value, float duration)
{
if (!EnsureMaterial() || !material.HasProperty(propertyId))
{
return null;
}
return material.DOFloat(value, propertyId, duration);
}
private void SetFloat(int propertyId, float value)
{
if (!EnsureMaterial() || !material.HasProperty(propertyId))
{
return;
}
material.SetFloat(propertyId, Mathf.Clamp01(value));
}
private void SetFloatRaw(int propertyId, float value)
{
if (!EnsureMaterial() || !material.HasProperty(propertyId))
{
return;
}
material.SetFloat(propertyId, value);
}
}
}