| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 | 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);                }            }        }    }}
 |