using System; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] [AddComponentMenu("NGUI/Internal/Draw Call")] public class UIDrawCall : MonoBehaviour { public enum Clipping { None = 0, TextureMask = 1, SoftClip = 3, ConstrainButDontClip = 4 } public delegate void OnRenderCallback(Material mat); private static BetterList mActiveList = new BetterList(); private static BetterList mInactiveList = new BetterList(); [NonSerialized] [HideInInspector] public int widgetCount; [NonSerialized] [HideInInspector] public int depthStart = int.MaxValue; [NonSerialized] [HideInInspector] public int depthEnd = int.MinValue; [NonSerialized] [HideInInspector] public UIPanel manager; [NonSerialized] [HideInInspector] public UIPanel panel; [NonSerialized] [HideInInspector] public Texture2D clipTexture; [NonSerialized] [HideInInspector] public bool alwaysOnScreen; [NonSerialized] [HideInInspector] public BetterList verts = new BetterList(); [NonSerialized] [HideInInspector] public BetterList norms = new BetterList(); [NonSerialized] [HideInInspector] public BetterList tans = new BetterList(); [NonSerialized] [HideInInspector] public BetterList uvs = new BetterList(); [NonSerialized] [HideInInspector] public BetterList cols = new BetterList(); private Material mMaterial; private Texture mTexture; private Shader mShader; private int mClipCount; private Transform mTrans; private Mesh mMesh; private MeshFilter mFilter; private MeshRenderer mRenderer; private Material mDynamicMat; private int[] mIndices; private bool mRebuildMat = true; private bool mLegacyShader; private int mRenderQueue = 3000; private int mTriangles; [NonSerialized] public bool isDirty; [NonSerialized] private bool mTextureClip; public OnRenderCallback onRender; private const int maxIndexBufferCache = 10; private static List mCache = new List(10); private static int[] ClipRange = null; private static int[] ClipArgs = null; [Obsolete("Use UIDrawCall.activeList")] public static BetterList list => mActiveList; public static BetterList activeList => mActiveList; public static BetterList inactiveList => mInactiveList; public int renderQueue { get { return mRenderQueue; } set { if (mRenderQueue != value) { mRenderQueue = value; if (mDynamicMat != null) { mDynamicMat.renderQueue = value; } } } } public int sortingOrder { get { if (!(mRenderer != null)) { return 0; } return mRenderer.sortingOrder; } set { if (mRenderer != null && mRenderer.sortingOrder != value) { mRenderer.sortingOrder = value; } } } public int finalRenderQueue { get { if (!(mDynamicMat != null)) { return mRenderQueue; } return mDynamicMat.renderQueue; } } public Transform cachedTransform { get { if (mTrans == null) { mTrans = base.transform; } return mTrans; } } public Material baseMaterial { get { return mMaterial; } set { if (mMaterial != value) { mMaterial = value; mRebuildMat = true; } } } public Material dynamicMaterial => mDynamicMat; public Texture mainTexture { get { return mTexture; } set { mTexture = value; if (mDynamicMat != null) { mDynamicMat.mainTexture = value; } } } public Shader shader { get { return mShader; } set { if (mShader != value) { mShader = value; mRebuildMat = true; } } } public int triangles { get { if (!(mMesh != null)) { return 0; } return mTriangles; } } public bool isClipped => mClipCount != 0; private void CreateMaterial() { mTextureClip = false; mLegacyShader = false; mClipCount = ((panel != null) ? panel.clipCount : 0); string text = ((mShader != null) ? mShader.name : ((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored")); text = text.Replace("GUI/Text Shader", "Unlit/Text"); if (text.Length > 2 && text[text.Length - 2] == ' ') { int num = text[text.Length - 1]; if (num > 48 && num <= 57) { text = text.Substring(0, text.Length - 2); } } if (text.StartsWith("Hidden/")) { text = text.Substring(7); } text = text.Replace(" (SoftClip)", ""); text = text.Replace(" (TextureClip)", ""); if (panel != null && panel.clipping == Clipping.TextureMask) { mTextureClip = true; shader = Shader.Find("Hidden/" + text + " (TextureClip)"); } else if (mClipCount != 0) { shader = Shader.Find("Hidden/" + text + " " + mClipCount); if (shader == null) { shader = Shader.Find(text + " " + mClipCount); } if (shader == null && mClipCount == 1) { mLegacyShader = true; shader = Shader.Find(text + " (SoftClip)"); } } else { shader = Shader.Find(text); } if (shader == null) { shader = Shader.Find("Unlit/Transparent Colored"); } if (mMaterial != null) { if (IsWizardMaterial()) { mDynamicMat = new Material(mMaterial); mDynamicMat.EnableKeyword("USE_VERTEX_COLOR"); mDynamicMat.SetFloat("_SleeveSrcFactor", 5f); mDynamicMat.SetFloat("_SleeveDstFactor", 10f); mDynamicMat.SetFloat("_CullMode", 0f); mDynamicMat.SetFloat("_ZWriteMode", 0f); mLegacyShader = false; if (isClipped) { mDynamicMat.EnableKeyword("USE_CLIP"); } if (IsSleeveMaterial()) { mDynamicMat.EnableKeyword("USE_SLEEVE"); } mDynamicMat.shader = Shader.Find(mMaterial.shader.name); } else { mDynamicMat = new Material(mMaterial); mDynamicMat.name = "[NGUI] " + mMaterial.name; mDynamicMat.hideFlags = HideFlags.DontSave | HideFlags.NotEditable; mDynamicMat.CopyPropertiesFromMaterial(mMaterial); string[] shaderKeywords = mMaterial.shaderKeywords; for (int i = 0; i < shaderKeywords.Length; i++) { mDynamicMat.EnableKeyword(shaderKeywords[i]); } if (shader != null) { mDynamicMat.shader = shader; } else if (mClipCount != 0) { Debug.LogError(text + " shader doesn't have a clipped shader version for " + mClipCount + " clip regions"); } } } else { mDynamicMat = new Material(shader); mDynamicMat.name = "[NGUI] " + shader.name; mDynamicMat.hideFlags = HideFlags.DontSave | HideFlags.NotEditable; } } private bool IsWizardMaterial() { if (mMaterial.shader.name == "Wizard/VariantSleeveShader") { return true; } return false; } private bool IsSleeveMaterial() { if (mMaterial.name.Contains("sleeve")) { return true; } return false; } public void SetDisableLegacyShader() { mLegacyShader = false; } private Material RebuildMaterial() { NGUITools.DestroyImmediate(mDynamicMat); CreateMaterial(); mDynamicMat.renderQueue = mRenderQueue; if (mTexture != null) { mDynamicMat.mainTexture = mTexture; } if (mRenderer != null) { mRenderer.sharedMaterials = new Material[1] { mDynamicMat }; } return mDynamicMat; } private void UpdateMaterials() { if (!(panel == null)) { if (mRebuildMat || mDynamicMat == null || mClipCount != panel.clipCount || mTextureClip != (panel.clipping == Clipping.TextureMask)) { RebuildMaterial(); mRebuildMat = false; } else if (mRenderer.sharedMaterial != mDynamicMat) { mRenderer.sharedMaterials = new Material[1] { mDynamicMat }; } } } public void UpdateGeometry(int widgetCount) { this.widgetCount = widgetCount; int size = verts.size; if (size > 0 && size == uvs.size && size == cols.size && size % 4 == 0) { if (mFilter == null) { mFilter = base.gameObject.GetComponent(); } if (mFilter == null) { mFilter = base.gameObject.AddComponent(); } if (verts.size < 65000) { int num = (size >> 1) * 3; bool flag = mIndices == null || mIndices.Length != num; if (mMesh == null) { mMesh = new Mesh(); mMesh.hideFlags = HideFlags.DontSave; mMesh.name = ((mMaterial != null) ? ("[NGUI] " + mMaterial.name) : "[NGUI] Mesh"); mMesh.MarkDynamic(); flag = true; } bool flag2 = uvs.buffer.Length != verts.buffer.Length || cols.buffer.Length != verts.buffer.Length || (norms.buffer != null && norms.buffer.Length != verts.buffer.Length) || (tans.buffer != null && tans.buffer.Length != verts.buffer.Length); if (!flag2 && panel != null && panel.renderQueue != UIPanel.RenderQueue.Automatic) { flag2 = mMesh == null || mMesh.vertexCount != verts.buffer.Length; } if (!flag2 && verts.size << 1 < verts.buffer.Length) { flag2 = true; } mTriangles = verts.size >> 1; if (flag2 || verts.buffer.Length > 65000) { if (flag2 || mMesh.vertexCount != verts.size) { mMesh.Clear(); flag = true; } mMesh.vertices = verts.ToArray(); mMesh.uv = uvs.ToArray(); mMesh.colors32 = cols.ToArray(); if (norms != null) { mMesh.normals = norms.ToArray(); } if (tans != null) { mMesh.tangents = tans.ToArray(); } } else { if (mMesh.vertexCount != verts.buffer.Length) { mMesh.Clear(); flag = true; } mMesh.vertices = verts.buffer; mMesh.uv = uvs.buffer; mMesh.colors32 = cols.buffer; if (norms != null) { mMesh.normals = norms.buffer; } if (tans != null) { mMesh.tangents = tans.buffer; } } if (flag) { mIndices = GenerateCachedIndexBuffer(size, num); mMesh.triangles = mIndices; } if (flag2 || !alwaysOnScreen) { mMesh.RecalculateBounds(); } mFilter.mesh = mMesh; } else { mTriangles = 0; if (mFilter.mesh != null) { mFilter.mesh.Clear(); } Debug.LogError("Too many vertices on one panel: " + verts.size); } if (mRenderer == null) { mRenderer = base.gameObject.GetComponent(); } if (mRenderer == null) { mRenderer = base.gameObject.AddComponent(); } UpdateMaterials(); } else { if (mFilter.mesh != null) { mFilter.mesh.Clear(); } Debug.LogError("UIWidgets must fill the buffer with 4 vertices per quad. Found " + size); } verts.Clear(); uvs.Clear(); cols.Clear(); norms.Clear(); tans.Clear(); } private int[] GenerateCachedIndexBuffer(int vertexCount, int indexCount) { int i = 0; for (int count = mCache.Count; i < count; i++) { int[] array = mCache[i]; if (array != null && array.Length == indexCount) { return array; } } int[] array2 = new int[indexCount]; int num = 0; for (int j = 0; j < vertexCount; j += 4) { array2[num++] = j; array2[num++] = j + 1; array2[num++] = j + 2; array2[num++] = j + 2; array2[num++] = j + 3; array2[num++] = j; } if (mCache.Count > 10) { mCache.RemoveAt(0); } mCache.Add(array2); return array2; } private void OnWillRenderObject() { UpdateMaterials(); if (onRender != null) { onRender(mDynamicMat ?? mMaterial); } if (mDynamicMat == null || mClipCount == 0) { return; } if (mTextureClip) { Vector4 drawCallClipRange = panel.drawCallClipRange; Vector2 clipSoftness = panel.clipSoftness; Vector2 vector = new Vector2(1000f, 1000f); if (clipSoftness.x > 0f) { vector.x = drawCallClipRange.z / clipSoftness.x; } if (clipSoftness.y > 0f) { vector.y = drawCallClipRange.w / clipSoftness.y; } mDynamicMat.SetVector(ClipRange[0], new Vector4((0f - drawCallClipRange.x) / drawCallClipRange.z, (0f - drawCallClipRange.y) / drawCallClipRange.w, 1f / drawCallClipRange.z, 1f / drawCallClipRange.w)); mDynamicMat.SetTexture("_ClipTex", clipTexture); } else if (!mLegacyShader) { UIPanel parentPanel = panel; int num = 0; while (parentPanel != null) { if (parentPanel.hasClipping) { float angle = 0f; Vector4 drawCallClipRange2 = parentPanel.drawCallClipRange; if (parentPanel != panel) { Vector3 vector2 = parentPanel.cachedTransform.InverseTransformPoint(panel.cachedTransform.position); drawCallClipRange2.x -= vector2.x; drawCallClipRange2.y -= vector2.y; Vector3 eulerAngles = panel.cachedTransform.rotation.eulerAngles; Vector3 vector3 = parentPanel.cachedTransform.rotation.eulerAngles - eulerAngles; vector3.x = NGUIMath.WrapAngle(vector3.x); vector3.y = NGUIMath.WrapAngle(vector3.y); vector3.z = NGUIMath.WrapAngle(vector3.z); if (!(Mathf.Abs(vector3.x) > 0.001f)) { Mathf.Abs(vector3.y); _ = 0.001f; } angle = vector3.z; } SetClipping(num++, drawCallClipRange2, parentPanel.clipSoftness, angle); } parentPanel = parentPanel.parentPanel; } } else { Vector2 clipSoftness2 = panel.clipSoftness; Vector4 drawCallClipRange3 = panel.drawCallClipRange; Vector2 mainTextureOffset = new Vector2((0f - drawCallClipRange3.x) / drawCallClipRange3.z, (0f - drawCallClipRange3.y) / drawCallClipRange3.w); Vector2 mainTextureScale = new Vector2(1f / drawCallClipRange3.z, 1f / drawCallClipRange3.w); Vector2 vector4 = new Vector2(1000f, 1000f); if (clipSoftness2.x > 0f) { vector4.x = drawCallClipRange3.z / clipSoftness2.x; } if (clipSoftness2.y > 0f) { vector4.y = drawCallClipRange3.w / clipSoftness2.y; } mDynamicMat.mainTextureOffset = mainTextureOffset; mDynamicMat.mainTextureScale = mainTextureScale; mDynamicMat.SetVector("_ClipSharpness", vector4); } } private void SetClipping(int index, Vector4 cr, Vector2 soft, float angle) { angle *= -(float)Math.PI / 180f; Vector2 vector = new Vector2(1000f, 1000f); if (soft.x > 0f) { vector.x = cr.z / soft.x; } if (soft.y > 0f) { vector.y = cr.w / soft.y; } if (index < ClipRange.Length) { mDynamicMat.SetVector(ClipRange[index], new Vector4((0f - cr.x) / cr.z, (0f - cr.y) / cr.w, 1f / cr.z, 1f / cr.w)); mDynamicMat.SetVector(ClipArgs[index], new Vector4(vector.x, vector.y, Mathf.Sin(angle), Mathf.Cos(angle))); } } private void Awake() { if (ClipRange == null) { ClipRange = new int[4] { Shader.PropertyToID("_ClipRange0"), Shader.PropertyToID("_ClipRange1"), Shader.PropertyToID("_ClipRange2"), Shader.PropertyToID("_ClipRange4") }; } if (ClipArgs == null) { ClipArgs = new int[4] { Shader.PropertyToID("_ClipArgs0"), Shader.PropertyToID("_ClipArgs1"), Shader.PropertyToID("_ClipArgs2"), Shader.PropertyToID("_ClipArgs3") }; } } private void OnEnable() { mRebuildMat = true; } private void OnDisable() { depthStart = int.MaxValue; depthEnd = int.MinValue; panel = null; manager = null; mMaterial = null; mTexture = null; clipTexture = null; if (mRenderer != null) { mRenderer.sharedMaterials = new Material[0]; } NGUITools.DestroyImmediate(mDynamicMat); mDynamicMat = null; } private void OnDestroy() { NGUITools.DestroyImmediate(mMesh); mMesh = null; } public static UIDrawCall Create(UIPanel panel, Material mat, Texture tex, Shader shader) { return Create(null, panel, mat, tex, shader); } private static UIDrawCall Create(string name, UIPanel pan, Material mat, Texture tex, Shader shader) { UIDrawCall uIDrawCall = Create(name); uIDrawCall.gameObject.layer = pan.cachedGameObject.layer; uIDrawCall.baseMaterial = mat; uIDrawCall.mainTexture = tex; uIDrawCall.shader = shader; uIDrawCall.renderQueue = pan.startingRenderQueue; uIDrawCall.sortingOrder = pan.sortingOrder; uIDrawCall.manager = pan; return uIDrawCall; } private static UIDrawCall Create(string name) { if (mInactiveList.size > 0) { UIDrawCall uIDrawCall = mInactiveList.Pop(); mActiveList.Add(uIDrawCall); if (name != null) { uIDrawCall.name = name; } NGUITools.SetActive(uIDrawCall.gameObject, state: true); return uIDrawCall; } GameObject obj = new GameObject(name); UnityEngine.Object.DontDestroyOnLoad(obj); UIDrawCall uIDrawCall2 = obj.AddComponent(); mActiveList.Add(uIDrawCall2); return uIDrawCall2; } public static void ClearAll() { bool isPlaying = Application.isPlaying; int num = mActiveList.size; while (num > 0) { UIDrawCall uIDrawCall = mActiveList[--num]; if ((bool)uIDrawCall) { if (isPlaying) { NGUITools.SetActive(uIDrawCall.gameObject, state: false); } else { NGUITools.DestroyImmediate(uIDrawCall.gameObject); } } } mActiveList.Clear(); } public static void ReleaseAll() { ClearAll(); ReleaseInactive(); } public static void ReleaseInactive() { int num = mInactiveList.size; while (num > 0) { UIDrawCall uIDrawCall = mInactiveList[--num]; if ((bool)uIDrawCall) { NGUITools.DestroyImmediate(uIDrawCall.gameObject); } } mInactiveList.Clear(); } public static int Count(UIPanel panel) { int num = 0; for (int i = 0; i < mActiveList.size; i++) { if (mActiveList[i].manager == panel) { num++; } } return num; } public static void Destroy(UIDrawCall dc) { if (!dc) { return; } dc.onRender = null; if (Application.isPlaying) { if (mActiveList.Remove(dc)) { NGUITools.SetActive(dc.gameObject, state: false); mInactiveList.Add(dc); } } else { mActiveList.Remove(dc); NGUITools.DestroyImmediate(dc.gameObject); } } }