Files
Main/Assets/Launcher/ExternalLibs/NGUI/Scripts/Internal/UIDrawCall.cs

1483 lines
41 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
//#define SHOW_HIDDEN_OBJECTS
#define FUNCELL_MODIFIED
using UnityEngine;
using System.Collections.Generic;
using Nordeus.DataStructures;
using System;
/// <summary>
/// This is an internally-created script used by the UI system. You shouldn't be attaching it manually.
/// </summary>
[ExecuteInEditMode]
[AddComponentMenu("NGUI/Internal/Draw Call")]
public class UIDrawCall : MonoBehaviour
{
static Dictionary<int ,UIDrawCall> mActiveList = new Dictionary<int, UIDrawCall>();
static Queue<UIDrawCall> mInactiveList = new Queue<UIDrawCall>();
[System.Obsolete("Use UIDrawCall.activeList")]
static public Dictionary<int, UIDrawCall> list { get { return mActiveList; } }
/// <summary>
/// List of active draw calls.
/// </summary>
static public Dictionary<int, UIDrawCall> activeList { get { return mActiveList; } }
/// <summary>
/// List of inactive draw calls. Only used at run-time in order to avoid object creation/destruction.
/// </summary>
static public Queue<UIDrawCall> inactiveList { get { return mInactiveList; } }
static private Material[] emptyMaterials = new Material[] { };
//材质球缓存
static private Dictionary<Shader, List<Material>> cacheMatList = new Dictionary<Shader, List<Material>>();
public enum Clipping : int
{
None = 0,
TextureMask = 1, // Clipped using a texture rather than math
SoftClip = 3, // Alpha-based clipping with a softened edge
ConstrainButDontClip = 4, // No actual clipping, but does have an area
}
[HideInInspector][System.NonSerialized] public int widgetCount = 0;
[HideInInspector][System.NonSerialized] public int depthStart = int.MaxValue;
[HideInInspector][System.NonSerialized] public int depthEnd = int.MinValue;
[HideInInspector][System.NonSerialized] public UIPanel manager;
[HideInInspector][System.NonSerialized] public UIPanel panel;
[HideInInspector][System.NonSerialized] public Texture2D clipTexture;
[HideInInspector][System.NonSerialized] public bool alwaysOnScreen = false;
[HideInInspector][System.NonSerialized] public BetterList<Vector3> verts = new BetterList<Vector3>();
[HideInInspector][System.NonSerialized] public BetterList<Vector3> norms = new BetterList<Vector3>();
[HideInInspector][System.NonSerialized] public BetterList<Vector4> tans = new BetterList<Vector4>();
[HideInInspector][System.NonSerialized] public BetterList<Vector2> uvs = new BetterList<Vector2>();
[HideInInspector][System.NonSerialized] public BetterList<Color32> cols = new BetterList<Color32>();
Material mMaterial; // Material used by this draw call
Texture mTexture; // Main texture used by the material
#if FUNCELL_MODIFIED
string mShaderName;
#endif
Shader mShader; // Shader used by the dynamically created material
int mClipCount = 0; // Number of times the draw call's content is getting clipped
Transform mTrans; // Cached transform
Mesh mMesh; // First generated mesh
MeshFilter mFilter; // Mesh filter for this draw call
MeshRenderer mRenderer; // Mesh renderer for this screen
Material mDynamicMat; // Instantiated material
int[] mIndices; // Cached indices
bool mRebuildMat = true;
bool mLegacyShader = false;
int mRenderQueue = 3000;
int mTriangles = 0;
/// <summary>
/// Whether the draw call has changed recently.
/// </summary>
[System.NonSerialized]
public bool isDirty = false;
[System.NonSerialized]
bool mTextureClip = false;
public delegate void OnRenderCallback (Material mat);
/// <summary>
/// Callback that will be triggered at OnWillRenderObject() time.
/// </summary>
public OnRenderCallback onRender;
#if FUNCELL_MODIFIED
//是否为灰色
private bool _isGray = false;
public bool IsGray
{
get
{
return _isGray;
}
set
{
if (_isGray != value)
{
_isGray = value;
mRebuildMat = true;
}
}
}
//是否为OverLay叠加
private bool _isOverlay = false;
public bool IsOverlay
{
get
{
return _isOverlay;
}
set
{
if (_isOverlay != value)
{
_isOverlay = value;
mRebuildMat = true;
}
}
}
//是否为流光
private bool _isFlowLight = false;
public bool IsFlowLight
{
get
{
return _isFlowLight;
}
set
{
if (_isFlowLight != value)
{
_isFlowLight = value;
mRebuildMat = true;
}
}
}
//流光的颜色--这里使用整形,容易比较(很坑的是Color32不能比较,所以选择这个值)
//这里使用int来表示float,有效数字为10000.
private Vector3Int _flowColor = new Vector3Int(3000, 3000, 3000);
public Vector3Int FlowColor
{
get
{
return _flowColor;
}
set
{
if (_flowColor != value)
{
_flowColor = value;
mRebuildMat = true;
}
}
}
//流光的参数 v1:宽度--值越大就越细 v2:速度, 光在UI上流过的速度 v3:周期,周期越大,在UI上闪过的之后等待时间越长
//这里使用int来表示float,有效数字为10000.
private Vector3Int _flowParam = new Vector3Int(60000, 15000, 40000);
public Vector3Int FlowParam
{
get
{
return _flowParam;
}
set
{
if (_flowParam != value)
{
_flowParam = value;
mRebuildMat = true;
}
}
}
#endif
/// <summary>
/// Render queue used by the draw call.
/// </summary>
public int renderQueue
{
get
{
return mRenderQueue;
}
set
{
if (mRenderQueue != value)
{
mRenderQueue = value;
if (mDynamicMat != null)
{
mDynamicMat.renderQueue = value;
#if UNITY_EDITOR
if (mRenderer != null) mRenderer.enabled = isActive;
#endif
}
}
}
}
/// <summary>
/// Renderer's sorting order, to be used with Unity's 2D system.
/// </summary>
public int sortingOrder
{
get { return (mRenderer != null) ? mRenderer.sortingOrder : 0; }
set { if (mRenderer != null && mRenderer.sortingOrder != value) mRenderer.sortingOrder = value; }
}
/// <summary>
/// Final render queue used to draw the draw call's geometry.
/// </summary>
public int finalRenderQueue
{
get
{
return (mDynamicMat != null) ? mDynamicMat.renderQueue : mRenderQueue;
}
}
#if UNITY_EDITOR
/// <summary>
/// Whether the draw call is currently active.
/// </summary>
public bool isActive
{
get
{
return mActive;
}
set
{
if (mActive != value)
{
mActive = value;
if (mRenderer != null)
{
mRenderer.enabled = value;
NGUITools.SetDirty(gameObject);
}
}
}
}
bool mActive = true;
#endif
private bool _isCachedTrans = false;
/// <summary>
/// Transform is cached for speed and efficiency.
/// </summary>
public Transform cachedTransform
{
get
{
if (!_isCachedTrans)
{
mTrans = transform;
_isCachedTrans = true;
}
return mTrans;
}
}
/// <summary>
/// Material used by this screen.
/// </summary>
public Material baseMaterial
{
get
{
return mMaterial;
}
set
{
if (mMaterial != value)
{
mMaterial = value;
mRebuildMat = true;
}
}
}
/// <summary>
/// Dynamically created material used by the draw call to actually draw the geometry.
/// </summary>
public Material dynamicMaterial { get { return mDynamicMat; } }
/// <summary>
/// Texture used by the material.
/// </summary>
public Texture mainTexture
{
get
{
return mTexture;
}
set
{
mTexture = value;
if (mDynamicMat != null) mDynamicMat.mainTexture = value;
}
}
/// <summary>
/// Shader used by the material.
/// </summary>
public Shader shader
{
get
{
return mShader;
}
set
{
if (mShader != value)
{
mShader = value;
mRebuildMat = true;
if(mShader != null)
{
mShaderName = mShader.name;
}
else
{
mShaderName = null;
}
}
}
}
/// <summary>
/// The number of triangles in this draw call.
/// </summary>
public int triangles { get { return (mMesh != null) ? mTriangles : 0; } }
/// <summary>
/// Whether the draw call is currently using a clipped shader.
/// </summary>
public bool isClipped { get { return mClipCount != 0; } }
void FreeDynamicMat(Material mat)
{
List<Material> matList = null;
if (!cacheMatList.TryGetValue(shader, out matList))
{
matList = new List<Material>();
cacheMatList.Add(shader, matList);
}
mat.SetTexture("_MainTex", null);
if(!string.IsNullOrEmpty(mShaderName) && mShaderName.Contains("RGB"))
{
mat.SetTexture("_AlphaTex", null);
}
matList.Add(mat);
}
Material GetDynamicMat(Shader shader)
{
Material result = null;
List<Material> matList = null;
if (cacheMatList.TryGetValue(shader, out matList) && matList.Count > 0)
{
result = matList[matList.Count - 1];
matList.RemoveAt(matList.Count - 1);
}
else
{
result = new Material(shader);
result.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
}
return result;
}
/// <summary>
/// Create an appropriate material for the draw call.
/// </summary>
void CreateMaterial ()
{
mTextureClip = false;
mLegacyShader = false;
mClipCount = (panel != null) ? panel.clipCount : 0;
#if FUNCELL_MODIFIED
#if NGUI_USE_RGB
string shaderName = !string.IsNullOrEmpty(mShaderName) ? mShaderName : ((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored_RGB");
#else
string shaderName = !string.IsNullOrEmpty(mShaderName) ? mShaderName : ((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored");
#endif
#else
#if NGUI_USE_RGB
string shaderName = (mShader != null) ? mShader.name : ((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored_RGB");
#else
string shaderName = (mShader != null) ? mShader.name : ((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored");
#endif
#endif
//这里的shader是编译后的并且在包体内没有这个shader
bool mshaderInPackage = true;
if (mShader != null)
{
var sh = Shader.Find(mShader.name);
if (sh == null)
{
mshaderInPackage = false;
}
}
//如果当前shader在包体内
if (mshaderInPackage)
{
// Figure out the normal shader's name
shaderName = shaderName.Replace("GUI/Text Shader", "Unlit/Text");
if (shaderName.Length > 2)
{
if (shaderName[shaderName.Length - 2] == ' ')
{
int index = shaderName[shaderName.Length - 1];
if (index > '0' && index <= '9') shaderName = shaderName.Substring(0, shaderName.Length - 2);
}
}
if (shaderName.StartsWith("Hidden/"))
shaderName = shaderName.Substring(7);
// Legacy functionality
const string soft = " (SoftClip)";
shaderName = shaderName.Replace(soft, "");
const string textureClip = " (TextureClip)";
shaderName = shaderName.Replace(textureClip, "");
if (panel != null && panel.clipping == Clipping.TextureMask)
{
mTextureClip = true;
shader = Shader.Find("Hidden/" + shaderName + textureClip);
}
else if (mClipCount != 0)
{
shader = Shader.Find("Hidden/" + shaderName + " " + mClipCount);
if (shader == null) shader = Shader.Find(shaderName + " " + mClipCount);
// Legacy functionality
if (shader == null && mClipCount == 1)
{
mLegacyShader = true;
shader = Shader.Find(shaderName + soft);
}
}
else
{
shader = Shader.Find(shaderName);
}
#if NGUI_USE_RGB
if (shader == null) shader = Shader.Find("Unlit/Transparent Colored_RGB");
#else
// Always fallback to the default shader
if (shader == null) shader = Shader.Find("Unlit/Transparent Colored");
#endif
}
else
{//如果不在包体内,那么就直接使用它
shader = mShader;
}
if (mMaterial != null)
{
//mDynamicMat = new Material(mMaterial);
if(shader != null)
{
mDynamicMat = GetDynamicMat(shader);
}
else
{
mDynamicMat = GetDynamicMat(mMaterial.shader);
}
//mDynamicMat.name = "[NGUI] " + mMaterial.name;
mDynamicMat.CopyPropertiesFromMaterial(mMaterial);
#if !UNITY_FLASH
string[] keywords = mMaterial.shaderKeywords;
for (int i = 0; i < keywords.Length; ++i)
{
mDynamicMat.EnableKeyword(keywords[i]);
}
#endif
// If there is a valid shader, assign it to the custom material
if (shader != null)
{
//mDynamicMat.shader = shader;
}
else if (mClipCount != 0)
{
Debug.LogError(shaderName + " shader doesn't have a clipped shader version for " + mClipCount + " clip regions");
}
}
else
{
mDynamicMat = GetDynamicMat(shader);
//mDynamicMat = new Material(shader);
//mDynamicMat.name = "[NGUI] " + shader.name;
}
#if FUNCELL_MODIFIED
if (_isGray)
{
mDynamicMat.EnableKeyword("_USE_GRAY_ON");
mDynamicMat.DisableKeyword("_USE_GRAY_OFF");
}
else
{
mDynamicMat.DisableKeyword("_USE_GRAY_ON");
mDynamicMat.EnableKeyword("_USE_GRAY_OFF");
}
if (_isFlowLight)
{
mDynamicMat.EnableKeyword("_USE_UI_FLOW_LIGHT_ON");
mDynamicMat.DisableKeyword("_USE_UI_FLOW_LIGHT_OFF");
mDynamicMat.SetColor("_FlowColor", new Color(_flowColor.x * 0.0001f, _flowColor.y * 0.0001f, _flowColor.z * 0.0001f));
mDynamicMat.SetFloat("_FlowWidth", _flowParam.x * 0.0001f);
mDynamicMat.SetFloat("_FlowSpeed", _flowParam.y * 0.0001f);
mDynamicMat.SetFloat("_FlowPeriod", _flowParam.z * 0.0001f);
}
else
{
mDynamicMat.DisableKeyword("_USE_UI_FLOW_LIGHT_ON");
mDynamicMat.EnableKeyword("_USE_UI_FLOW_LIGHT_OFF");
}
if (_isOverlay)
{
mDynamicMat.EnableKeyword("_USE_OVERLAY_ON");
mDynamicMat.DisableKeyword("_USE_OVERLAY_OFF");
}
else
{
mDynamicMat.DisableKeyword("_USE_OVERLAY_ON");
mDynamicMat.EnableKeyword("_USE_OVERLAY_OFF");
}
#endif
}
/// <summary>
/// Rebuild the draw call's material.
/// </summary>
Material RebuildMaterial ()
{
// Destroy the old material
if(mDynamicMat != null)
{
FreeDynamicMat(mDynamicMat);
}
//NGUITools.DestroyImmediate(mDynamicMat);
// Create a new material
CreateMaterial();
mDynamicMat.renderQueue = mRenderQueue;
// Assign the main texture
if (mTexture != null) mDynamicMat.mainTexture = mTexture;
// Update the renderer
if (mRenderer != null) mRenderer.sharedMaterials = new Material[] { mDynamicMat };
return mDynamicMat;
}
/// <summary>
/// Update the renderer's materials.
/// </summary>
void UpdateMaterials ()
{
if (panel == null) return;
// If clipping should be used, we need to find a replacement shader
if (mRebuildMat || mDynamicMat == null || mClipCount != panel.clipCount || mTextureClip != (panel.clipping == Clipping.TextureMask))
{
RebuildMaterial();
mRebuildMat = false;
}
else if (mRenderer.sharedMaterial != mDynamicMat)
{
#if UNITY_EDITOR
Debug.LogError("Hmm... This point got hit!");
#endif
mRenderer.sharedMaterials = new Material[] { mDynamicMat };
}
}
/// <summary>
/// Set the draw call's geometry.
/// </summary>
private void SetCallback(int[] array)
{
mIndices = array;
mMesh.triangles = mIndices;
}
Nordeus.DataStructures.VaryingIntList.ArrayAction _setCallback = null;
const int maxIndexBufferCache = 10;
private static int getindexcnt = 0;
private static int shotcnt = 0;
#if UNITY_FLASH
List<int[]> mCache = new List<int[]>(maxIndexBufferCache);
#else
//static List<int[]> mCache = new List<int[]>(maxIndexBufferCache);
//#if !OPTIMISE_NGUI_GC_ALLOC
// static List<int[]> mCache = new List<int[]>(maxIndexBufferCache);
//#else
//优化NGUI GC
public static Nordeus.DataStructures.VaryingIntList mCache = new Nordeus.DataStructures.VaryingIntList();
//优化NGUI GC
#endif
public void UpdateGeometry()
{
if (_setCallback == null) _setCallback = SetCallback;
int count = verts.size;
// Safety check to ensure we get valid values
if (count > 0 && (count == uvs.size && count == cols.size) && (count % 4) == 0)
{
// Cache all components
if (mFilter == null) mFilter = gameObject.GetComponent<MeshFilter>();
if (mFilter == null) mFilter = gameObject.AddComponent<MeshFilter>();
if (verts.size < 65000)
{
// Populate the index buffer
int indexCount = (count >> 1) * 3;
bool setIndices = (mIndices == null || mIndices.Length != indexCount);
// Create the mesh
if (mMesh == null)
{
mMesh = new Mesh();
mMesh.hideFlags = HideFlags.DontSave;
mMesh.name = (mMaterial != null) ? mMaterial.name : "Mesh";
mMesh.MarkDynamic();
setIndices = true;
}
#if !UNITY_FLASH
// If the buffer length doesn't match, we need to trim all buffers
bool trim = (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);
// Non-automatic render queues rely on Z position, so it's a good idea to trim everything
if (!trim && panel != null && panel.renderQueue != UIPanel.RenderQueue.Automatic)
trim = (mMesh == null || mMesh.vertexCount != verts.buffer.Length);
// NOTE: Apparently there is a bug with Adreno devices:
// http://www.tasharen.com/forum/index.php?topic=8415.0
#if !UNITY_ANDROID
// If the number of vertices in the buffer is less than half of the full buffer, trim it
if (!trim && (verts.size << 1) < verts.buffer.Length) trim = true;
#endif
mTriangles = (verts.size >> 1);
if (trim || verts.buffer.Length > 65000)
{
if (trim || mMesh.vertexCount != verts.size)
{
mMesh.Clear();
setIndices = true;
}
//mMesh.vertices = verts.ToArray();
//mMesh.uv = uvs.ToArray();
//mMesh.uv2 = uv2s.ToArray();
//mMesh.colors32 = cols.ToArray();
FillVertsMeshData(verts);
FillUvMeshData(uvs);
FillColsMeshData(cols);
//if (norms != null) mMesh.normals = norms.ToArray();
//if (tans != null) mMesh.tangents = tans.ToArray();
if (norms != null) FillNormalMeshData(norms);
if (tans != null) FillTangentsMeshData(tans);
}
else
{
if (mMesh.vertexCount != verts.buffer.Length)
{
mMesh.Clear();
setIndices = 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;
}
#else
mTriangles = (verts.size >> 1);
if (mMesh.vertexCount != verts.size)
{
mMesh.Clear();
setIndices = 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();
#endif
if (setIndices)
{
//优化NGUI GC
//GenerateCachedIndexBuffer(count, indexCount, SetCallback);
getindexcnt++;
if (mCache.size < indexCount)
{
mCache.MakeLargerThan(indexCount);
for (int i = mCache.size / 3 * 2; i < count; i += 4)
{
mCache.Add(i);
mCache.Add(i + 1);
mCache.Add(i + 2);
mCache.Add(i + 2);
mCache.Add(i + 3);
mCache.Add(i);
}
}
AsArrayOfLength(indexCount);
//mCache.AsArrayOfLength(indexCount, SetCallback);
//优化NGUI GC
//mIndices = GenerateCachedIndexBuffer(count, indexCount);
//mMesh.triangles = mIndices;
}
#if !UNITY_FLASH
if (trim || !alwaysOnScreen)
#endif
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 = gameObject.GetComponent<MeshRenderer>();
if (mRenderer == null)
{
mRenderer = gameObject.AddComponent<MeshRenderer>();
#if UNITY_EDITOR
mRenderer.enabled = isActive;
#endif
}
UpdateMaterials();
}
else
{
if (mFilter.mesh != null) mFilter.mesh.Clear();
Debug.LogError("UIWidgets must fill the buffer with 4 vertices per quad. Found " + count);
}
verts.Clear();
uvs.Clear();
cols.Clear();
norms.Clear();
tans.Clear();
}
#region//unsafe function
public unsafe void* GetVector4BufferPointer(BetterList<Vector4> btList)
{
fixed (void* pBuffer = btList.buffer)
{
return pBuffer;
}
}
public unsafe void* GetVector3BufferPointer(BetterList<Vector3> btList)
{
fixed (void* pBuffer = btList.buffer)
{
return pBuffer;
}
}
public unsafe void* GetVector2BufferPointer(BetterList<Vector2> btList)
{
fixed (void* pBuffer = btList.buffer)
{
return pBuffer;
}
}
public unsafe void* GetColorBufferPointer(BetterList<Color32> btList)
{
fixed (void* pBuffer = btList.buffer)
{
return pBuffer;
}
}
//填充mesh 的数据
public unsafe void FillVertsMeshData(BetterList<Vector3> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetVector3BufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.vertices = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
public unsafe void FillUvMeshData(BetterList<Vector2> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetVector2BufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.uv = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
public unsafe void FillUv2MeshData(BetterList<Vector2> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetVector2BufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.uv2 = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
public unsafe void FillColsMeshData(BetterList<Color32> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetColorBufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.colors32 = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
public unsafe void FillNormalMeshData(BetterList<Vector3> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetVector3BufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.normals = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
public unsafe void FillTangentsMeshData(BetterList<Vector4> btList)
{
if (btList.size <= 0) return;
void* pBuffer = GetVector4BufferPointer(btList);
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)btList.size);
mMesh.tangents = btList.buffer;
// Revert back to old length
header->length = originalLength;
}
//优化NGUI GC
public unsafe void AsArrayOfLength(int length)
{
if (length <= 0) return;
if (length > mCache.size) length = mCache.size;
void* pBuffer = mCache.GetBufferPointer();
// Get the header
ArrayHeader* header = (ArrayHeader*)pBuffer - 1;
// Change the length
UIntPtr originalLength = header->length;
header->length = new UIntPtr((ulong)length);
// Do stuff with the changed array
//if (action != null)
//{
// action(buffer);
//}
mIndices = mCache.buffer;
mMesh.triangles = mIndices;
// Revert back to old length
header->length = originalLength;
}
//优化NGUI GC
#endregion
public static void PrintCache()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("DrawCall PrintCache:" + mCache.Count);
int sum = 0;
for (int i = 0; i < mCache.Count; i++)
{
sb.AppendLine("i=" + i + ";;len:" + mCache.buffer.Length);
sum += mCache.buffer.Length;
}
sb.AppendLine("Sum:" + sum);
sb.AppendLine("Percent:" + shotcnt + "/" + getindexcnt + "==" + ((float)shotcnt / (float)getindexcnt));
Debug.Log(sb.ToString());
}
/// <summary>
/// Generates a new index buffer for the specified number of vertices (or reuses an existing one).
/// </summary>
//优化NGUI GC
void GenerateCachedIndexBuffer(int vertexCount, int indexCount, Nordeus.DataStructures.VaryingIntList.ArrayAction action)
{
getindexcnt++;
if (mCache.size < indexCount)
{
mCache.MakeLargerThan(indexCount);
for (int i = mCache.size / 3 * 2; i < vertexCount; i += 4)
{
mCache.Add(i);
mCache.Add(i + 1);
mCache.Add(i + 2);
mCache.Add(i + 2);
mCache.Add(i + 3);
mCache.Add(i);
}
}
mCache.AsArrayOfLength(indexCount, action);
}
//优化NGUI GC
// int[] GenerateCachedIndexBuffer (int vertexCount, int indexCount)
//{
// for (int i = 0, imax = mCache.Count; i < imax; ++i)
// {
// int[] ids = mCache[i];
// if (ids != null && ids.Length == indexCount)
// return ids;
// }
// int[] rv = new int[indexCount];
// int index = 0;
// for (int i = 0; i < vertexCount; i += 4)
// {
// rv[index++] = i;
// rv[index++] = i + 1;
// rv[index++] = i + 2;
// rv[index++] = i + 2;
// rv[index++] = i + 3;
// rv[index++] = i;
// }
// if (mCache.Count > maxIndexBufferCache) mCache.RemoveAt(0);
// mCache.Add(rv);
// return rv;
//}
/// <summary>
/// This function is called when it's clear that the object will be rendered.
/// We want to set the shader used by the material, creating a copy of the material in the process.
/// We also want to update the material's properties before it's actually used.
/// </summary>
void OnWillRenderObject ()
{
UpdateMaterials();
if (onRender != null)
{
onRender(mDynamicMat ?? mMaterial);
}
if (mDynamicMat == null || mClipCount == 0) return;
if (mTextureClip)
{
Vector4 cr = panel.drawCallClipRange;
Vector2 soft = panel.clipSoftness;
Vector2 sharpness = new Vector2(1000.0f, 1000.0f);
if (soft.x > 0f) sharpness.x = cr.z / soft.x;
if (soft.y > 0f) sharpness.y = cr.w / soft.y;
mDynamicMat.SetVector(ClipRange[0], new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w));
mDynamicMat.SetTexture("_ClipTex", clipTexture);
}
else if (!mLegacyShader)
{
ProcessPanelClip(panel, mDynamicMat);
}
else // Legacy functionality
{
Vector2 soft = panel.clipSoftness;
Vector4 cr = panel.drawCallClipRange;
Vector2 v0 = new Vector2(-cr.x / cr.z, -cr.y / cr.w);
Vector2 v1 = new Vector2(1f / cr.z, 1f / cr.w);
Vector2 sharpness = new Vector2(1000.0f, 1000.0f);
if (soft.x > 0f) sharpness.x = cr.z / soft.x;
if (soft.y > 0f) sharpness.y = cr.w / soft.y;
mDynamicMat.mainTextureOffset = v0;
mDynamicMat.mainTextureScale = v1;
mDynamicMat.SetVector("_ClipSharpness", sharpness);
}
}
static int[] ClipRange = null;
static int[] ClipArgs = null;
public static void InitClipArgs()
{
if (ClipRange == null)
{
ClipRange = new int[]
{
Shader.PropertyToID("_ClipRange0"),
Shader.PropertyToID("_ClipRange1"),
Shader.PropertyToID("_ClipRange2"),
Shader.PropertyToID("_ClipRange4"),
};
}
if (ClipArgs == null)
{
ClipArgs = new int[]
{
Shader.PropertyToID("_ClipArgs0"),
Shader.PropertyToID("_ClipArgs1"),
Shader.PropertyToID("_ClipArgs2"),
Shader.PropertyToID("_ClipArgs3"),
};
}
}
#if FUNCELL_MODIFIED
public static void SetClippingEx(Material mat,int index, Vector4 cr, Vector2 soft, Vector4 softHide, float angle)
#else
public staticvoid SetClippingEx (int index, Vector4 cr, Vector2 soft, float angle)
#endif
{
angle *= -Mathf.Deg2Rad;
Vector2 sharpness = new Vector2(1000.0f, 1000.0f);
if (soft.x > 0f) sharpness.x = cr.z / soft.x;
if (soft.y > 0f) sharpness.y = cr.w / soft.y;
if (index < ClipRange.Length)
{
//Debug.Log("ClipRange::" + new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w).ToString());
//Debug.Log("ClipArgs::" + new Vector4(sharpness.x, sharpness.y, Mathf.Sin(angle), Mathf.Cos(angle)).ToString());
mat.SetVector(ClipRange[index], new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w));
mat.SetVector(ClipArgs[index], new Vector4(sharpness.x, sharpness.y, Mathf.Sin(angle), Mathf.Cos(angle)));
#if FUNCELL_MODIFIED
//修改只针对一层的剪切
if (index == 0)
{
//Debug.Log(";;;" + softHide);
mat.SetVector("_ClipSoftnessHide", softHide);
}
#endif
}
}
public static void ProcessPanelClip(UIPanel panel,Material mat)
{
UIPanel currentPanel = panel;
for (int i = 0; currentPanel != null;)
{
if (currentPanel.hasClipping)
{
float angle = 0f;
Vector4 cr = currentPanel.drawCallClipRange;
// Clipping regions past the first one need additional math
if (currentPanel != panel)
{
Vector3 pos = currentPanel.cachedTransform.InverseTransformPoint(panel.cachedTransform.position);
cr.x -= pos.x;
cr.y -= pos.y;
Vector3 v0 = panel.cachedTransform.rotation.eulerAngles;
Vector3 v1 = currentPanel.cachedTransform.rotation.eulerAngles;
Vector3 diff = v1 - v0;
diff.x = NGUIMath.WrapAngle(diff.x);
diff.y = NGUIMath.WrapAngle(diff.y);
diff.z = NGUIMath.WrapAngle(diff.z);
if (Mathf.Abs(diff.x) > 0.001f || Mathf.Abs(diff.y) > 0.001f)
Debug.LogWarning("Panel can only be clipped properly if X and Y rotation is left at 0", panel);
angle = diff.z;
}
#if FUNCELL_MODIFIED
SetClippingEx(mat,i++, cr, currentPanel.clipSoftness, currentPanel.ClipSoftnessHide, angle);
#else
// Pass the clipping parameters to the shader
SetClippingEx(mat,i++, cr, currentPanel.clipSoftness, angle);
#endif
}
currentPanel = currentPanel.parentPanel;
}
}
/// <summary>
/// Set the shader clipping parameters.
/// </summary>
#if FUNCELL_MODIFIED
void SetClipping (int index, Vector4 cr, Vector2 soft, Vector4 softHide, float angle)
#else
void SetClipping (int index, Vector4 cr, Vector2 soft, float angle)
#endif
{
#if FUNCELL_MODIFIED
SetClippingEx(mDynamicMat, index, cr, soft, softHide, angle);
#else
SetClippingEx(mDynamicMat, index, cr, soft, angle);
#endif
}
/// <summary>
/// Cache the property IDs.
/// </summary>
void Awake ()
{
InitClipArgs();
#if FUNCELL_MODIFIED
if (mShader != null)
{
mShaderName = mShader.name;
}
else
{
mShaderName = null;
}
#endif
}
/// <summary>
/// The material should be rebuilt when the draw call is enabled.
/// </summary>
void OnEnable () { mRebuildMat = true; }
/// <summary>
/// Clear all references.
/// </summary>
void OnDisable ()
{
depthStart = int.MaxValue;
depthEnd = int.MinValue;
panel = null;
manager = null;
mMaterial = null;
mTexture = null;
clipTexture = null;
if (mRenderer != null)
mRenderer.sharedMaterials = emptyMaterials;
if (mDynamicMat != null)
{
FreeDynamicMat(mDynamicMat);
}
//NGUITools.DestroyImmediate(mDynamicMat);
mDynamicMat = null;
}
/// <summary>
/// Cleanup.
/// </summary>
void OnDestroy ()
{
NGUITools.DestroyImmediate(mMesh);
mMesh = null;
}
/// <summary>
/// Return an existing draw call.
/// </summary>
static public UIDrawCall Create (UIPanel panel, Material mat, Texture tex, Shader shader)
{
#if UNITY_EDITOR
string name = null;
if (tex != null) name = tex.name;
else if (shader != null) name = shader.name;
else if (mat != null) name = mat.name;
return Create(name, panel, mat, tex, shader);
#else
return Create(null, panel, mat, tex, shader);
#endif
}
/// <summary>
/// Create a new draw call, reusing an old one if possible.
/// </summary>
static UIDrawCall Create (string name, UIPanel pan, Material mat, Texture tex, Shader shader)
{
UIDrawCall dc = Create(name);
dc.gameObject.layer = pan.cachedGameObject.layer;
dc.baseMaterial = mat;
dc.mainTexture = tex;
dc.shader = shader;
dc.renderQueue = pan.startingRenderQueue;
dc.sortingOrder = pan.sortingOrder;
dc.manager = pan;
return dc;
}
/// <summary>
/// Create a new draw call, reusing an old one if possible.
/// </summary>
static UIDrawCall Create (string name)
{
#if SHOW_HIDDEN_OBJECTS && UNITY_EDITOR
name = (name != null) ? "_UIDrawCall [" + name + "]" : "DrawCall";
#endif
if (mInactiveList.Count > 0)
{
UIDrawCall dc = mInactiveList.Dequeue();
mActiveList.Add(dc.GetHashCode(), dc);
if (name != null) dc.name = name;
NGUITools.SetActive(dc.gameObject, true);
return dc;
}
#if UNITY_EDITOR
// If we're in the editor, create the game object with hide flags set right away
GameObject go = UnityEditor.EditorUtility.CreateGameObjectWithHideFlags(name,
#if SHOW_HIDDEN_OBJECTS
HideFlags.DontSave | HideFlags.NotEditable, typeof(UIDrawCall));
#else
HideFlags.HideAndDontSave, typeof(UIDrawCall));
#endif
UIDrawCall newDC = go.GetComponent<UIDrawCall>();
#else
GameObject go = new GameObject(name);
DontDestroyOnLoad(go);
UIDrawCall newDC = go.AddComponent<UIDrawCall>();
#endif
// Create the draw call
mActiveList.Add(newDC.GetHashCode(), newDC);
return newDC;
}
/// <summary>
/// Clear all draw calls.
/// </summary>
static public void ClearAll ()
{
bool playing = Application.isPlaying;
var iter = mActiveList.GetEnumerator();
try
{
while(iter.MoveNext())
{
UIDrawCall dc = iter.Current.Value;
if (dc)
{
if (playing) NGUITools.SetActive(dc.gameObject, false);
else NGUITools.DestroyImmediate(dc.gameObject);
}
}
}
finally
{
iter.Dispose();
}
mActiveList.Clear();
}
/// <summary>
/// Immediately destroy all draw calls.
/// </summary>
static public void ReleaseAll ()
{
ClearAll();
ReleaseInactive();
}
/// <summary>
/// Immediately destroy all inactive draw calls (draw calls that have been recycled and are waiting to be re-used).
/// </summary>
static public void ReleaseInactive()
{
while(mInactiveList.Count > 0)
{
var dc = mInactiveList.Dequeue();
if (dc) NGUITools.DestroyImmediate(dc.gameObject);
}
mInactiveList.Clear();
}
/// <summary>
/// Count all draw calls managed by the specified panel.
/// </summary>
static public int Count (UIPanel panel)
{
int count = 0;
if(panel != null)
{
var iter = mActiveList.GetEnumerator();
try
{
while (iter.MoveNext())
{
if (iter.Current.Value.manager == panel)
{
++count;
}
}
}
finally
{
iter.Dispose();
}
}
return count;
}
/// <summary>
/// Destroy the specified draw call.
/// </summary>
static public void Destroy(UIDrawCall dc)
{
if (dc)
{
dc.onRender = null;
if (Application.isPlaying)
{
if (mActiveList.Remove(dc.GetHashCode()))
{
NGUITools.SetActive(dc.gameObject, false);
mInactiveList.Enqueue(dc);
//优化NGUI GC
dc.FreeCache();
//优化NGUI GC
}
}
else
{
mActiveList.Remove(dc.GetHashCode());
#if SHOW_HIDDEN_OBJECTS && UNITY_EDITOR
if (UnityEditor.Selection.activeGameObject == dc.gameObject)
UnityEditor.Selection.activeGameObject = null;
#endif
NGUITools.DestroyImmediate(dc.gameObject);
}
}
}
//清理缓存
public void FreeCache()
{
CachedGeometries.Free(verts);
CachedGeometries.Free(uvs);
CachedGeometries.Free(cols);
verts = null;
uvs = null;
cols = null;
}
//检查缓存
public void CheckCacke(int vecCount)
{
if (verts == null || verts.buffer == null || verts.buffer.Length < vecCount)
{
FreeCache();
CachedGeometries.Get(vecCount, ref verts);
CachedGeometries.Get(vecCount, ref uvs);
CachedGeometries.Get(vecCount, ref cols);
}
}
}