RenderCombinedMesh.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated July 28, 2023. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2023, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software or
  13. * otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
  27. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
  30. #define NEW_PREFAB_SYSTEM
  31. #endif
  32. #if UNITY_2019_3_OR_NEWER
  33. #define SET_VERTICES_HAS_LENGTH_PARAMETER
  34. #endif
  35. using System.Collections.Generic;
  36. using System.Linq;
  37. using UnityEngine;
  38. namespace Spine.Unity.Examples {
  39. #if NEW_PREFAB_SYSTEM
  40. [ExecuteAlways]
  41. #else
  42. [ExecuteInEditMode]
  43. #endif
  44. public class RenderCombinedMesh : MonoBehaviour {
  45. public SkeletonRenderer skeletonRenderer;
  46. public SkeletonRenderSeparator renderSeparator;
  47. public MeshRenderer[] referenceRenderers;
  48. bool updateViaSkeletonCallback = false;
  49. MeshFilter[] referenceMeshFilters;
  50. MeshRenderer ownRenderer;
  51. MeshFilter ownMeshFilter;
  52. protected DoubleBuffered<Mesh> doubleBufferedMesh;
  53. protected ExposedList<Vector3> positionBuffer;
  54. protected ExposedList<Color32> colorBuffer;
  55. protected ExposedList<Vector2> uvBuffer;
  56. protected ExposedList<int> indexBuffer;
  57. #if UNITY_EDITOR
  58. private void Reset () {
  59. if (skeletonRenderer == null)
  60. skeletonRenderer = this.GetComponentInParent<SkeletonRenderer>();
  61. GatherRenderers();
  62. Awake();
  63. if (referenceRenderers.Length > 0)
  64. ownRenderer.sharedMaterial = referenceRenderers[0].sharedMaterial;
  65. LateUpdate();
  66. }
  67. #endif
  68. protected void GatherRenderers () {
  69. referenceRenderers = this.GetComponentsInChildren<MeshRenderer>();
  70. if (referenceRenderers.Length == 0 ||
  71. (referenceRenderers.Length == 1 && referenceRenderers[0].gameObject == this.gameObject)) {
  72. Transform parent = this.transform.parent;
  73. if (parent)
  74. referenceRenderers = parent.GetComponentsInChildren<MeshRenderer>();
  75. }
  76. referenceRenderers = referenceRenderers.Where(
  77. (val, idx) => val.gameObject != this.gameObject && val.enabled).ToArray();
  78. }
  79. void Awake () {
  80. if (skeletonRenderer == null)
  81. skeletonRenderer = this.GetComponentInParent<SkeletonRenderer>();
  82. if (referenceRenderers == null || referenceRenderers.Length == 0) {
  83. GatherRenderers();
  84. }
  85. if (renderSeparator == null) {
  86. if (skeletonRenderer)
  87. renderSeparator = skeletonRenderer.GetComponent<SkeletonRenderSeparator>();
  88. else
  89. renderSeparator = this.GetComponentInParent<SkeletonRenderSeparator>();
  90. }
  91. int count = referenceRenderers.Length;
  92. referenceMeshFilters = new MeshFilter[count];
  93. for (int i = 0; i < count; ++i) {
  94. referenceMeshFilters[i] = referenceRenderers[i].GetComponent<MeshFilter>();
  95. }
  96. ownRenderer = this.GetComponent<MeshRenderer>();
  97. if (ownRenderer == null)
  98. ownRenderer = this.gameObject.AddComponent<MeshRenderer>();
  99. ownMeshFilter = this.GetComponent<MeshFilter>();
  100. if (ownMeshFilter == null)
  101. ownMeshFilter = this.gameObject.AddComponent<MeshFilter>();
  102. }
  103. void OnEnable () {
  104. #if UNITY_EDITOR
  105. if (Application.isPlaying)
  106. Awake();
  107. #endif
  108. if (skeletonRenderer) {
  109. skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  110. skeletonRenderer.OnMeshAndMaterialsUpdated += UpdateOnCallback;
  111. updateViaSkeletonCallback = true;
  112. }
  113. if (renderSeparator) {
  114. renderSeparator.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  115. renderSeparator.OnMeshAndMaterialsUpdated += UpdateOnCallback;
  116. updateViaSkeletonCallback = true;
  117. }
  118. }
  119. void OnDisable () {
  120. if (skeletonRenderer)
  121. skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  122. if (renderSeparator)
  123. renderSeparator.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  124. }
  125. void OnDestroy () {
  126. for (int i = 0; i < 2; ++i) {
  127. Mesh mesh = doubleBufferedMesh.GetNext();
  128. #if UNITY_EDITOR
  129. if (Application.isEditor && !Application.isPlaying)
  130. UnityEngine.Object.DestroyImmediate(mesh);
  131. else
  132. UnityEngine.Object.Destroy(mesh);
  133. #else
  134. UnityEngine.Object.Destroy(mesh);
  135. #endif
  136. }
  137. }
  138. void LateUpdate () {
  139. #if UNITY_EDITOR
  140. if (!Application.isPlaying) {
  141. UpdateMesh();
  142. return;
  143. }
  144. #endif
  145. if (updateViaSkeletonCallback)
  146. return;
  147. UpdateMesh();
  148. }
  149. void UpdateOnCallback (SkeletonRenderer r) {
  150. UpdateMesh();
  151. }
  152. protected void EnsureBufferSizes (int combinedVertexCount, int combinedIndexCount) {
  153. if (positionBuffer == null) {
  154. positionBuffer = new ExposedList<Vector3>(combinedVertexCount);
  155. uvBuffer = new ExposedList<Vector2>(combinedVertexCount);
  156. colorBuffer = new ExposedList<Color32>(combinedVertexCount);
  157. indexBuffer = new ExposedList<int>(combinedIndexCount);
  158. }
  159. if (positionBuffer.Count != combinedVertexCount) {
  160. positionBuffer.Resize(combinedVertexCount);
  161. uvBuffer.Resize(combinedVertexCount);
  162. colorBuffer.Resize(combinedVertexCount);
  163. }
  164. if (indexBuffer.Count != combinedIndexCount) {
  165. indexBuffer.Resize(combinedIndexCount);
  166. }
  167. }
  168. void InitMesh () {
  169. if (doubleBufferedMesh == null) {
  170. doubleBufferedMesh = new DoubleBuffered<Mesh>();
  171. for (int i = 0; i < 2; ++i) {
  172. Mesh combinedMesh = doubleBufferedMesh.GetNext();
  173. combinedMesh.MarkDynamic();
  174. combinedMesh.name = "RenderCombinedMesh" + i;
  175. combinedMesh.subMeshCount = 1;
  176. }
  177. }
  178. }
  179. void UpdateMesh () {
  180. InitMesh();
  181. int combinedVertexCount = 0;
  182. int combinedIndexCount = 0;
  183. GetCombinedMeshInfo(ref combinedVertexCount, ref combinedIndexCount);
  184. EnsureBufferSizes(combinedVertexCount, combinedIndexCount);
  185. int combinedV = 0;
  186. int combinedI = 0;
  187. for (int r = 0, rendererCount = referenceMeshFilters.Length; r < rendererCount; ++r) {
  188. MeshFilter meshFilter = referenceMeshFilters[r];
  189. Mesh mesh = meshFilter.sharedMesh;
  190. if (mesh == null) continue;
  191. int vertexCount = mesh.vertexCount;
  192. Vector3[] positions = mesh.vertices;
  193. Vector2[] uvs = mesh.uv;
  194. Color32[] colors = mesh.colors32;
  195. System.Array.Copy(positions, 0, this.positionBuffer.Items, combinedV, vertexCount);
  196. System.Array.Copy(uvs, 0, this.uvBuffer.Items, combinedV, vertexCount);
  197. System.Array.Copy(colors, 0, this.colorBuffer.Items, combinedV, vertexCount);
  198. for (int s = 0, submeshCount = mesh.subMeshCount; s < submeshCount; ++s) {
  199. int submeshIndexCount = (int)mesh.GetIndexCount(s);
  200. int[] submeshIndices = mesh.GetIndices(s);
  201. int[] dstIndices = this.indexBuffer.Items;
  202. for (int i = 0; i < submeshIndexCount; ++i)
  203. dstIndices[i + combinedI] = submeshIndices[i] + combinedV;
  204. combinedI += submeshIndexCount;
  205. }
  206. combinedV += vertexCount;
  207. }
  208. Mesh combinedMesh = doubleBufferedMesh.GetNext();
  209. combinedMesh.Clear();
  210. #if SET_VERTICES_HAS_LENGTH_PARAMETER
  211. combinedMesh.SetVertices(this.positionBuffer.Items, 0, this.positionBuffer.Count);
  212. combinedMesh.SetUVs(0, this.uvBuffer.Items, 0, this.uvBuffer.Count);
  213. combinedMesh.SetColors(this.colorBuffer.Items, 0, this.colorBuffer.Count);
  214. combinedMesh.SetTriangles(this.indexBuffer.Items, 0, this.indexBuffer.Count, 0);
  215. #else
  216. // Note: excess already contains zero positions and indices after ExposedList.Resize().
  217. combinedMesh.vertices = this.positionBuffer.Items;
  218. combinedMesh.uv = this.uvBuffer.Items;
  219. combinedMesh.colors32 = this.colorBuffer.Items;
  220. combinedMesh.triangles = this.indexBuffer.Items;
  221. #endif
  222. ownMeshFilter.sharedMesh = combinedMesh;
  223. }
  224. void GetCombinedMeshInfo (ref int vertexCount, ref int indexCount) {
  225. for (int r = 0, rendererCount = referenceMeshFilters.Length; r < rendererCount; ++r) {
  226. MeshFilter meshFilter = referenceMeshFilters[r];
  227. Mesh mesh = meshFilter.sharedMesh;
  228. if (mesh == null) continue;
  229. vertexCount += mesh.vertexCount;
  230. for (int s = 0, submeshCount = mesh.subMeshCount; s < submeshCount; ++s) {
  231. indexCount += (int)mesh.GetIndexCount(s);
  232. }
  233. }
  234. }
  235. }
  236. }