This commit is contained in:
2020-07-04 14:41:25 +08:00
parent 70c346d2c1
commit a8f02e4da5
3748 changed files with 587372 additions and 0 deletions

View File

@@ -0,0 +1,881 @@
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
//#define SHOW_HIDDEN_OBJECTS
using UnityEngine;
using System.Collections.Generic;
/// <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 BetterList<UIDrawCall> mActiveList = new BetterList<UIDrawCall>();
static BetterList<UIDrawCall> mInactiveList = new BetterList<UIDrawCall>();
[System.Obsolete("Use UIDrawCall.activeList")]
static public BetterList<UIDrawCall> list { get { return mActiveList; } }
/// <summary>
/// List of active draw calls.
/// </summary>
static public BetterList<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 BetterList<UIDrawCall> inactiveList { get { return mInactiveList; } }
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
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;
/// <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
/// <summary>
/// Transform is cached for speed and efficiency.
/// </summary>
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; 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;
}
}
}
/// <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; } }
/// <summary>
/// Create an appropriate material for the draw call.
/// </summary>
void CreateMaterial ()
{
mTextureClip = false;
mLegacyShader = false;
mClipCount = panel.clipCount;
string shaderName = (mShader != null) ? mShader.name :
((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored");
// 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.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);
// Always fallback to the default shader
if (shader == null) shader = Shader.Find("Unlit/Transparent Colored");
if (mMaterial != null)
{
mDynamicMat = new Material(mMaterial);
mDynamicMat.name = "[NGUI] " + mMaterial.name;
mDynamicMat.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
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 = new Material(shader);
mDynamicMat.name = "[NGUI] " + shader.name;
mDynamicMat.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
}
}
/// <summary>
/// Rebuild the draw call's material.
/// </summary>
Material RebuildMaterial ()
{
// Destroy the old material
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 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>
public void UpdateGeometry (int widgetCount)
{
this.widgetCount = widgetCount;
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) ? "[NGUI] " + mMaterial.name : "[NGUI] 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.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.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();
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)
{
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();
}
const int maxIndexBufferCache = 10;
#if UNITY_FLASH
List<int[]> mCache = new List<int[]>(maxIndexBufferCache);
#else
static List<int[]> mCache = new List<int[]>(maxIndexBufferCache);
#endif
/// <summary>
/// Generates a new index buffer for the specified number of vertices (or reuses an existing one).
/// </summary>
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)
{
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;
}
// Pass the clipping parameters to the shader
SetClipping(i++, cr, currentPanel.clipSoftness, angle);
}
currentPanel = currentPanel.parentPanel;
}
}
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;
/// <summary>
/// Set the shader clipping parameters.
/// </summary>
void SetClipping (int index, Vector4 cr, Vector2 soft, float angle)
{
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)
{
mDynamicMat.SetVector(ClipRange[index], new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w));
mDynamicMat.SetVector(ClipArgs[index], new Vector4(sharpness.x, sharpness.y, Mathf.Sin(angle), Mathf.Cos(angle)));
}
}
/// <summary>
/// Cache the property IDs.
/// </summary>
void Awake ()
{
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"),
};
}
}
/// <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 = new Material[] {};
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.size > 0)
{
UIDrawCall dc = mInactiveList.Pop();
mActiveList.Add(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);
return newDC;
}
/// <summary>
/// Clear all draw calls.
/// </summary>
static public void ClearAll ()
{
bool playing = Application.isPlaying;
for (int i = mActiveList.size; i > 0; )
{
UIDrawCall dc = mActiveList[--i];
if (dc)
{
if (playing) NGUITools.SetActive(dc.gameObject, false);
else NGUITools.DestroyImmediate(dc.gameObject);
}
}
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()
{
for (int i = mInactiveList.size; i > 0; )
{
UIDrawCall dc = mInactiveList[--i];
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;
for (int i = 0; i < mActiveList.size; ++i)
if (mActiveList[i].manager == panel) ++count;
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))
{
NGUITools.SetActive(dc.gameObject, false);
mInactiveList.Add(dc);
}
}
else
{
mActiveList.Remove(dc);
NGUITools.DestroyImmediate(dc.gameObject);
}
}
}
}