2025-06-07 17:43:34 +08:00

320 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI.Utils;
namespace FairyGUI
{
/// <summary>
/// UpdateContext is for internal use.
/// </summary>
public class UpdateContext
{
public struct ClipInfo
{
public Rect rect;
public Vector4 clipBox;
public bool soft;
public Vector4 softness;//left-top-right-bottom
public uint clipId;
public int rectMaskDepth;
public int referenceValue;
public bool reversed;
}
Stack<ClipInfo> _clipStack;
public bool clipped;
public ClipInfo clipInfo;
public int renderingOrder;
public int batchingDepth;
public int rectMaskDepth;
public int stencilReferenceValue;
public int stencilCompareValue;
public float alpha;
public bool grayed;
public static UpdateContext current;
public static bool working;
public static event Action OnBegin;
public static event Action OnEnd;
static Action _tmpBegin;
public UpdateContext()
{
_clipStack = new Stack<ClipInfo>();
}
/// <summary>
///
/// </summary>
public void Begin()
{
current = this;
renderingOrder = 0;
batchingDepth = 0;
rectMaskDepth = 0;
stencilReferenceValue = 0;
alpha = 1;
grayed = false;
clipped = false;
_clipStack.Clear();
Stats.ObjectCount = 0;
Stats.GraphicsCount = 0;
_tmpBegin = OnBegin;
OnBegin = null;
//允许OnBegin里再次Add这里没有做死锁检查
while (_tmpBegin != null)
{
_tmpBegin.Invoke();
_tmpBegin = OnBegin;
OnBegin = null;
}
working = true;
}
/// <summary>
///
/// </summary>
public void End()
{
working = false;
if (OnEnd != null)
OnEnd.Invoke();
OnEnd = null;
}
/// <summary>
///
/// </summary>
/// <param name="clipId"></param>
/// <param name="clipRect"></param>
/// <param name="softness"></param>
public void EnterClipping(uint clipId, Rect clipRect, Vector4? softness)
{
_clipStack.Push(clipInfo);
if (rectMaskDepth > 0)
clipRect = ToolSet.Intersection(ref clipInfo.rect, ref clipRect);
clipped = true;
clipInfo.rectMaskDepth = ++rectMaskDepth;
/* clipPos = xy * clipBox.zw + clipBox.xy
* 利用这个公式使clipPos变为当前顶点距离剪切区域中心的距离值剪切区域的大小为2x2
* 那么abs(clipPos)>1的都是在剪切区域外
*/
clipInfo.rect = clipRect;
clipRect.x = clipRect.x + clipRect.width * 0.5f;
clipRect.y = clipRect.y + clipRect.height * 0.5f;
clipRect.width *= 0.5f;
clipRect.height *= 0.5f;
if (clipRect.width == 0 || clipRect.height == 0)
clipInfo.clipBox = new Vector4(-2, -2, 0, 0);
else
clipInfo.clipBox = new Vector4(-clipRect.x / clipRect.width, -clipRect.y / clipRect.height,
1.0f / clipRect.width, 1.0f / clipRect.height);
clipInfo.clipId = clipId;
clipInfo.soft = softness != null;
if (clipInfo.soft)
{
clipInfo.softness = (Vector4)softness;
float vx = clipInfo.rect.width * Screen.height * 0.25f;
float vy = clipInfo.rect.height * Screen.height * 0.25f;
if (clipInfo.softness.x > 0)
clipInfo.softness.x = vx / clipInfo.softness.x;
else
clipInfo.softness.x = 10000f;
if (clipInfo.softness.y > 0)
clipInfo.softness.y = vy / clipInfo.softness.y;
else
clipInfo.softness.y = 10000f;
if (clipInfo.softness.z > 0)
clipInfo.softness.z = vx / clipInfo.softness.z;
else
clipInfo.softness.z = 10000f;
if (clipInfo.softness.w > 0)
clipInfo.softness.w = vy / clipInfo.softness.w;
else
clipInfo.softness.w = 10000f;
}
}
/// <summary>
///
/// </summary>
/// <param name="clipId"></param>
/// <param name="reversedMask"></param>
public void EnterClipping(uint clipId, bool reversedMask)
{
_clipStack.Push(clipInfo);
if (stencilReferenceValue == 0)
stencilReferenceValue = 1;
else
stencilReferenceValue = stencilReferenceValue << 1;
if (reversedMask)
{
if (clipInfo.reversed)
stencilCompareValue = (stencilReferenceValue >> 1) - 1;
else
stencilCompareValue = stencilReferenceValue - 1;
}
else
stencilCompareValue = (stencilReferenceValue << 1) - 1;
clipInfo.clipId = clipId;
clipInfo.referenceValue = stencilReferenceValue;
clipInfo.reversed = reversedMask;
clipped = true;
}
/// <summary>
///
/// </summary>
public void LeaveClipping()
{
clipInfo = _clipStack.Pop();
stencilReferenceValue = clipInfo.referenceValue;
rectMaskDepth = clipInfo.rectMaskDepth;
clipped = stencilReferenceValue != 0 || rectMaskDepth != 0;
}
public void EnterPaintingMode()
{
//Reset clipping
_clipStack.Push(clipInfo);
clipInfo.rectMaskDepth = 0;
clipInfo.referenceValue = 0;
clipInfo.reversed = false;
clipped = false;
}
public void LeavePaintingMode()
{
clipInfo = _clipStack.Pop();
stencilReferenceValue = clipInfo.referenceValue;
rectMaskDepth = clipInfo.rectMaskDepth;
clipped = stencilReferenceValue != 0 || rectMaskDepth != 0;
}
public void ApplyClippingProperties(Material mat, bool isStdMaterial)
{
if (rectMaskDepth > 0) //在矩形剪裁下,且不是遮罩对象
{
mat.SetVector(ShaderConfig.ID_ClipBox, clipInfo.clipBox);
if (clipInfo.soft)
mat.SetVector(ShaderConfig.ID_ClipSoftness, clipInfo.softness);
}
if (stencilReferenceValue > 0)
{
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Equal);
mat.SetInt(ShaderConfig.ID_Stencil, stencilCompareValue);
mat.SetInt(ShaderConfig.ID_Stencil2, stencilCompareValue);
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Keep);
mat.SetInt(ShaderConfig.ID_StencilReadMask, stencilReferenceValue | (stencilReferenceValue - 1));
mat.SetInt(ShaderConfig.ID_ColorMask, 15);
}
else
{
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Always);
mat.SetInt(ShaderConfig.ID_Stencil, 0);
mat.SetInt(ShaderConfig.ID_Stencil2, 0);
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Keep);
mat.SetInt(ShaderConfig.ID_StencilReadMask, 255);
mat.SetInt(ShaderConfig.ID_ColorMask, 15);
}
if (!isStdMaterial)
{
if (rectMaskDepth > 0)
{
if (clipInfo.soft)
mat.EnableKeyword("SOFT_CLIPPED");
else
mat.EnableKeyword("CLIPPED");
}
else
{
mat.DisableKeyword("CLIPPED");
mat.DisableKeyword("SOFT_CLIPPED");
}
}
}
public void ApplyAlphaMaskProperties(Material mat, bool erasing)
{
if (!erasing)
{
if (stencilReferenceValue == 1)
{
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Always);
mat.SetInt(ShaderConfig.ID_Stencil, 1);
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Replace);
mat.SetInt(ShaderConfig.ID_StencilReadMask, 255);
mat.SetInt(ShaderConfig.ID_ColorMask, 0);
}
else
{
if (stencilReferenceValue != 0 & _clipStack.Peek().reversed)
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.NotEqual);
else
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Equal);
mat.SetInt(ShaderConfig.ID_Stencil, stencilReferenceValue | (stencilReferenceValue - 1));
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Replace);
mat.SetInt(ShaderConfig.ID_StencilReadMask, stencilReferenceValue - 1);
mat.SetInt(ShaderConfig.ID_ColorMask, 0);
}
}
else
{
if (stencilReferenceValue != 0 & _clipStack.Peek().reversed)
{
int refValue = stencilReferenceValue | (stencilReferenceValue - 1);
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Equal);
mat.SetInt(ShaderConfig.ID_Stencil, refValue);
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Zero);
mat.SetInt(ShaderConfig.ID_StencilReadMask, refValue);
mat.SetInt(ShaderConfig.ID_ColorMask, 0);
}
else
{
int refValue = stencilReferenceValue - 1;
mat.SetInt(ShaderConfig.ID_StencilComp, (int)UnityEngine.Rendering.CompareFunction.Equal);
mat.SetInt(ShaderConfig.ID_Stencil, refValue);
mat.SetInt(ShaderConfig.ID_StencilOp, (int)UnityEngine.Rendering.StencilOp.Replace);
mat.SetInt(ShaderConfig.ID_StencilReadMask, refValue);
mat.SetInt(ShaderConfig.ID_ColorMask, 0);
}
}
}
#if UNITY_2019_3_OR_NEWER
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void InitializeOnLoad()
{
OnBegin = null;
OnEnd = null;
}
#endif
}
}