Files
2025-01-25 04:38:09 +08:00

1483 lines
41 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.

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