123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825 |
- /******************************************************************************
- * Spine Runtimes License Agreement
- * Last updated January 1, 2020. Replaces all prior versions.
- *
- * Copyright (c) 2013-2020, Esoteric Software LLC
- *
- * Integration of the Spine Runtimes into software or otherwise creating
- * derivative works of the Spine Runtimes is permitted under the terms and
- * conditions of Section 2 of the Spine Editor License Agreement:
- * http://esotericsoftware.com/spine-editor-license
- *
- * Otherwise, it is permitted to integrate the Spine Runtimes into software
- * or otherwise create derivative works of the Spine Runtimes (collectively,
- * "Products"), provided that each user of the Products must obtain their own
- * Spine Editor license and redistribution of the Products in any form must
- * include this license and copyright notice.
- *
- * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
- * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- #if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
- #define NEW_PREFAB_SYSTEM
- #endif
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- namespace Spine.Unity {
- #if NEW_PREFAB_SYSTEM
- [ExecuteAlways]
- #else
- [ExecuteInEditMode]
- #endif
- [RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent]
- [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")]
- [HelpURL("http://esotericsoftware.com/spine-unity#SkeletonGraphic-Component")]
- public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, IHasSkeletonDataAsset {
- #region Inspector
- public SkeletonDataAsset skeletonDataAsset;
- public SkeletonDataAsset SkeletonDataAsset { get { return skeletonDataAsset; } }
- [SpineSkin(dataField:"skeletonDataAsset", defaultAsEmptyString:true)]
- public string initialSkinName;
- public bool initialFlipX, initialFlipY;
- [SpineAnimation(dataField:"skeletonDataAsset")]
- public string startingAnimation;
- public bool startingLoop;
- public float timeScale = 1f;
- public bool freeze;
- /// <summary>Update mode to optionally limit updates to e.g. only apply animations but not update the mesh.</summary>
- public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } }
- protected UpdateMode updateMode = UpdateMode.FullUpdate;
- /// <summary>Update mode used when the MeshRenderer becomes invisible
- /// (when <c>OnBecameInvisible()</c> is called). Update mode is automatically
- /// reset to <c>UpdateMode.FullUpdate</c> when the mesh becomes visible again.</summary>
- public UpdateMode updateWhenInvisible = UpdateMode.FullUpdate;
- public bool unscaledTime;
- public bool allowMultipleCanvasRenderers = false;
- public List<CanvasRenderer> canvasRenderers = new List<CanvasRenderer>();
- protected List<RawImage> rawImages = new List<RawImage>();
- protected int usedRenderersCount = 0;
- // Submesh Separation
- public const string SeparatorPartGameObjectName = "Part";
- /// <summary>Slot names used to populate separatorSlots list when the Skeleton is initialized. Changing this after initialization does nothing.</summary>
- [SerializeField] [SpineSlot] protected string[] separatorSlotNames = new string[0];
- /// <summary>Slots that determine where the render is split. This is used by components such as SkeletonRenderSeparator so that the skeleton can be rendered by two separate renderers on different GameObjects.</summary>
- [System.NonSerialized] public readonly List<Slot> separatorSlots = new List<Slot>();
- public bool enableSeparatorSlots = false;
- [SerializeField] protected List<Transform> separatorParts = new List<Transform>();
- public List<Transform> SeparatorParts { get { return separatorParts; } }
- public bool updateSeparatorPartLocation = true;
- private bool wasUpdatedAfterInit = true;
- private Texture baseTexture = null;
- #if UNITY_EDITOR
- protected override void OnValidate () {
- // This handles Scene View preview.
- base.OnValidate ();
- if (this.IsValid) {
- if (skeletonDataAsset == null) {
- Clear();
- } else if (skeletonDataAsset.skeletonJSON == null) {
- Clear();
- } else if (skeletonDataAsset.GetSkeletonData(true) != skeleton.data) {
- Clear();
- Initialize(true);
- if (!allowMultipleCanvasRenderers && (skeletonDataAsset.atlasAssets.Length > 1 || skeletonDataAsset.atlasAssets[0].MaterialCount > 1))
- Debug.LogError("Unity UI does not support multiple textures per Renderer. Please enable 'Advanced - Multiple CanvasRenderers' to generate the required CanvasRenderer GameObjects. Otherwise your skeleton will not be rendered correctly.", this);
- } else {
- if (freeze) return;
- if (!string.IsNullOrEmpty(initialSkinName)) {
- var skin = skeleton.data.FindSkin(initialSkinName);
- if (skin != null) {
- if (skin == skeleton.data.defaultSkin)
- skeleton.SetSkin((Skin)null);
- else
- skeleton.SetSkin(skin);
- }
- }
- // Only provide visual feedback to inspector changes in Unity Editor Edit mode.
- if (!Application.isPlaying) {
- skeleton.ScaleX = this.initialFlipX ? -1 : 1;
- skeleton.ScaleY = this.initialFlipY ? -1 : 1;
- state.ClearTrack(0);
- skeleton.SetToSetupPose();
- if (!string.IsNullOrEmpty(startingAnimation)) {
- state.SetAnimation(0, startingAnimation, startingLoop);
- Update(0f);
- }
- }
- }
- } else {
- // Under some circumstances (e.g. sometimes on the first import) OnValidate is called
- // before SpineEditorUtilities.ImportSpineContent, causing an unnecessary exception.
- // The (skeletonDataAsset.skeletonJSON != null) condition serves to prevent this exception.
- if (skeletonDataAsset != null && skeletonDataAsset.skeletonJSON != null)
- Initialize(true);
- }
- }
- protected override void Reset () {
- base.Reset();
- if (material == null || material.shader != Shader.Find("Spine/SkeletonGraphic"))
- Debug.LogWarning("SkeletonGraphic works best with the SkeletonGraphic material.");
- }
- #endif
- #endregion
- #region Runtime Instantiation
- /// <summary>Create a new GameObject with a SkeletonGraphic component.</summary>
- /// <param name="material">Material for the canvas renderer to use. Usually, the default SkeletonGraphic material will work.</param>
- public static SkeletonGraphic NewSkeletonGraphicGameObject (SkeletonDataAsset skeletonDataAsset, Transform parent, Material material) {
- var sg = SkeletonGraphic.AddSkeletonGraphicComponent(new GameObject("New Spine GameObject"), skeletonDataAsset, material);
- if (parent != null) sg.transform.SetParent(parent, false);
- return sg;
- }
- /// <summary>Add a SkeletonGraphic component to a GameObject.</summary>
- /// <param name="material">Material for the canvas renderer to use. Usually, the default SkeletonGraphic material will work.</param>
- public static SkeletonGraphic AddSkeletonGraphicComponent (GameObject gameObject, SkeletonDataAsset skeletonDataAsset, Material material) {
- var c = gameObject.AddComponent<SkeletonGraphic>();
- if (skeletonDataAsset != null) {
- c.material = material;
- c.skeletonDataAsset = skeletonDataAsset;
- c.Initialize(false);
- }
- return c;
- }
- #endregion
- #region Overrides
- [System.NonSerialized] readonly Dictionary<Texture, Texture> customTextureOverride = new Dictionary<Texture, Texture>();
- /// <summary>Use this Dictionary to override a Texture with a different Texture.</summary>
- public Dictionary<Texture, Texture> CustomTextureOverride { get { return customTextureOverride; } }
- [System.NonSerialized] readonly Dictionary<Texture, Material> customMaterialOverride = new Dictionary<Texture, Material>();
- /// <summary>Use this Dictionary to override the Material where the Texture was used at the original atlas.</summary>
- public Dictionary<Texture, Material> CustomMaterialOverride { get { return customMaterialOverride; } }
- // This is used by the UI system to determine what to put in the MaterialPropertyBlock.
- Texture overrideTexture;
- public Texture OverrideTexture {
- get { return overrideTexture; }
- set {
- overrideTexture = value;
- canvasRenderer.SetTexture(this.mainTexture); // Refresh canvasRenderer's texture. Make sure it handles null.
- }
- }
- #endregion
- #region Internals
- public override Texture mainTexture {
- get {
- if (overrideTexture != null) return overrideTexture;
- return baseTexture;
- }
- }
- protected override void Awake () {
- base.Awake ();
- this.onCullStateChanged.AddListener(OnCullStateChanged);
- SyncRawImagesWithCanvasRenderers();
- if (!this.IsValid) {
- #if UNITY_EDITOR
- // workaround for special import case of open scene where OnValidate and Awake are
- // called in wrong order, before setup of Spine assets.
- if (!Application.isPlaying) {
- if (this.skeletonDataAsset != null && this.skeletonDataAsset.skeletonJSON == null)
- return;
- }
- #endif
- Initialize(false);
- Rebuild(CanvasUpdate.PreRender);
- }
- }
- protected override void OnDestroy () {
- Clear();
- base.OnDestroy();
- }
- public override void Rebuild (CanvasUpdate update) {
- base.Rebuild(update);
- if (canvasRenderer.cull) return;
- if (update == CanvasUpdate.PreRender) UpdateMesh(keepRendererCount : true);
- if (allowMultipleCanvasRenderers) canvasRenderer.Clear();
- }
- protected override void OnDisable () {
- base.OnDisable();
- foreach (var canvasRenderer in canvasRenderers) {
- canvasRenderer.Clear();
- }
- }
- public virtual void Update () {
- #if UNITY_EDITOR
- if (!Application.isPlaying) {
- Update(0f);
- return;
- }
- #endif
- if (freeze) return;
- Update(unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
- }
- public virtual void Update (float deltaTime) {
- if (!this.IsValid) return;
- wasUpdatedAfterInit = true;
- if (updateMode < UpdateMode.OnlyAnimationStatus)
- return;
- UpdateAnimationStatus(deltaTime);
- if (updateMode == UpdateMode.OnlyAnimationStatus)
- return;
- ApplyAnimation();
- }
- protected void SyncRawImagesWithCanvasRenderers () {
- rawImages.Clear();
- foreach (var canvasRenderer in canvasRenderers) {
- var rawImage = canvasRenderer.GetComponent<RawImage>();
- if (rawImage == null) {
- rawImage = canvasRenderer.gameObject.AddComponent<RawImage>();
- rawImage.maskable = this.maskable;
- rawImage.raycastTarget = false;
- }
- rawImages.Add(rawImage);
- }
- }
- protected void UpdateAnimationStatus (float deltaTime) {
- deltaTime *= timeScale;
- skeleton.Update(deltaTime);
- state.Update(deltaTime);
- }
- protected void ApplyAnimation () {
- if (BeforeApply != null)
- BeforeApply(this);
- if (updateMode != UpdateMode.OnlyEventTimelines)
- state.Apply(skeleton);
- else
- state.ApplyEventTimelinesOnly(skeleton);
- if (UpdateLocal != null)
- UpdateLocal(this);
- skeleton.UpdateWorldTransform();
- if (UpdateWorld != null) {
- UpdateWorld(this);
- skeleton.UpdateWorldTransform();
- }
- if (UpdateComplete != null)
- UpdateComplete(this);
- }
- public void LateUpdate () {
- // instantiation can happen from Update() after this component, leading to a missing Update() call.
- if (!wasUpdatedAfterInit) Update(0);
- if (freeze) return;
- if (updateMode != UpdateMode.FullUpdate) return;
- UpdateMesh();
- }
- protected void OnCullStateChanged (bool culled) {
- if (culled)
- OnBecameInvisible();
- else
- OnBecameVisible();
- }
- public void OnBecameVisible () {
- updateMode = UpdateMode.FullUpdate;
- }
- public void OnBecameInvisible () {
- updateMode = updateWhenInvisible;
- }
- public void ReapplySeparatorSlotNames () {
- if (!IsValid)
- return;
- separatorSlots.Clear();
- for (int i = 0, n = separatorSlotNames.Length; i < n; i++) {
- string slotName = separatorSlotNames[i];
- if (slotName == "")
- continue;
- var slot = skeleton.FindSlot(slotName);
- if (slot != null) {
- separatorSlots.Add(slot);
- }
- #if UNITY_EDITOR
- else
- {
- Debug.LogWarning(slotName + " is not a slot in " + skeletonDataAsset.skeletonJSON.name);
- }
- #endif
- }
- UpdateSeparatorPartParents();
- }
- #endregion
- #region API
- protected Skeleton skeleton;
- public Skeleton Skeleton {
- get {
- Initialize(false);
- return skeleton;
- }
- set {
- skeleton = value;
- }
- }
- public SkeletonData SkeletonData { get { return skeleton == null ? null : skeleton.data; } }
- public bool IsValid { get { return skeleton != null; } }
- public delegate void SkeletonRendererDelegate (SkeletonGraphic skeletonGraphic);
- /// <summary>OnRebuild is raised after the Skeleton is successfully initialized.</summary>
- public event SkeletonRendererDelegate OnRebuild;
- /// <summary>OnMeshAndMaterialsUpdated is at the end of LateUpdate after the Mesh and
- /// all materials have been updated.</summary>
- public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated;
- protected Spine.AnimationState state;
- public Spine.AnimationState AnimationState {
- get {
- Initialize(false);
- return state;
- }
- }
- [SerializeField] protected Spine.Unity.MeshGenerator meshGenerator = new MeshGenerator();
- public Spine.Unity.MeshGenerator MeshGenerator { get { return this.meshGenerator; } }
- DoubleBuffered<Spine.Unity.MeshRendererBuffers.SmartMesh> meshBuffers;
- SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
- readonly ExposedList<Mesh> meshes = new ExposedList<Mesh>();
- public Mesh GetLastMesh () {
- return meshBuffers.GetCurrent().mesh;
- }
- public bool MatchRectTransformWithBounds () {
- UpdateMesh();
- if (!this.allowMultipleCanvasRenderers)
- return MatchRectTransformSingleRenderer();
- else
- return MatchRectTransformMultipleRenderers();
- }
- protected bool MatchRectTransformSingleRenderer () {
- Mesh mesh = this.GetLastMesh();
- if (mesh == null) {
- return false;
- }
- if (mesh.vertexCount == 0) {
- this.rectTransform.sizeDelta = new Vector2(50f, 50f);
- this.rectTransform.pivot = new Vector2(0.5f, 0.5f);
- return false;
- }
- mesh.RecalculateBounds();
- SetRectTransformBounds(mesh.bounds);
- return true;
- }
- protected bool MatchRectTransformMultipleRenderers () {
- bool anyBoundsAdded = false;
- Bounds combinedBounds = new Bounds();
- for (int i = 0; i < canvasRenderers.Count; ++i) {
- var canvasRenderer = canvasRenderers[i];
- if (!canvasRenderer.gameObject.activeSelf)
- continue;
- Mesh mesh = meshes.Items[i];
- if (mesh == null || mesh.vertexCount == 0)
- continue;
- mesh.RecalculateBounds();
- var bounds = mesh.bounds;
- if (anyBoundsAdded)
- combinedBounds.Encapsulate(bounds);
- else {
- anyBoundsAdded = true;
- combinedBounds = bounds;
- }
- }
- if (!anyBoundsAdded) {
- this.rectTransform.sizeDelta = new Vector2(50f, 50f);
- this.rectTransform.pivot = new Vector2(0.5f, 0.5f);
- return false;
- }
- SetRectTransformBounds(combinedBounds);
- return true;
- }
- private void SetRectTransformBounds (Bounds combinedBounds) {
- var size = combinedBounds.size;
- var center = combinedBounds.center;
- var p = new Vector2(
- 0.5f - (center.x / size.x),
- 0.5f - (center.y / size.y)
- );
- this.rectTransform.sizeDelta = size;
- this.rectTransform.pivot = p;
- }
- public event UpdateBonesDelegate BeforeApply;
- public event UpdateBonesDelegate UpdateLocal;
- public event UpdateBonesDelegate UpdateWorld;
- public event UpdateBonesDelegate UpdateComplete;
- /// <summary> Occurs after the vertex data populated every frame, before the vertices are pushed into the mesh.</summary>
- public event Spine.Unity.MeshGeneratorDelegate OnPostProcessVertices;
- public void Clear () {
- skeleton = null;
- canvasRenderer.Clear();
- for (int i = 0; i < canvasRenderers.Count; ++i)
- canvasRenderers[i].Clear();
- DestroyMeshes();
- DisposeMeshBuffers();
- }
- public void TrimRenderers () {
- var newList = new List<CanvasRenderer>();
- foreach (var canvasRenderer in canvasRenderers) {
- if (canvasRenderer.gameObject.activeSelf) {
- newList.Add(canvasRenderer);
- }
- else {
- if (Application.isEditor && !Application.isPlaying)
- DestroyImmediate(canvasRenderer.gameObject);
- else
- Destroy(canvasRenderer.gameObject);
- }
- }
- canvasRenderers = newList;
- SyncRawImagesWithCanvasRenderers();
- }
- public void Initialize (bool overwrite) {
- if (this.IsValid && !overwrite) return;
- if (this.skeletonDataAsset == null) return;
- var skeletonData = this.skeletonDataAsset.GetSkeletonData(false);
- if (skeletonData == null) return;
- if (skeletonDataAsset.atlasAssets.Length <= 0 || skeletonDataAsset.atlasAssets[0].MaterialCount <= 0) return;
- this.state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData());
- if (state == null) {
- Clear();
- return;
- }
- this.skeleton = new Skeleton(skeletonData) {
- ScaleX = this.initialFlipX ? -1 : 1,
- ScaleY = this.initialFlipY ? -1 : 1
- };
- InitMeshBuffers();
- baseTexture = skeletonDataAsset.atlasAssets[0].PrimaryMaterial.mainTexture;
- canvasRenderer.SetTexture(this.mainTexture); // Needed for overwriting initializations.
- // Set the initial Skin and Animation
- if (!string.IsNullOrEmpty(initialSkinName))
- skeleton.SetSkin(initialSkinName);
- separatorSlots.Clear();
- for (int i = 0; i < separatorSlotNames.Length; i++)
- separatorSlots.Add(skeleton.FindSlot(separatorSlotNames[i]));
- wasUpdatedAfterInit = false;
- if (!string.IsNullOrEmpty(startingAnimation)) {
- var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(startingAnimation);
- if (animationObject != null) {
- state.SetAnimation(0, animationObject, startingLoop);
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- Update(0f);
- #endif
- }
- }
- if (OnRebuild != null)
- OnRebuild(this);
- }
- public void UpdateMesh (bool keepRendererCount = false) {
- if (!this.IsValid) return;
- skeleton.SetColor(this.color);
- var currentInstructions = this.currentInstructions;
- if (!this.allowMultipleCanvasRenderers) {
- UpdateMeshSingleCanvasRenderer();
- }
- else {
- UpdateMeshMultipleCanvasRenderers(currentInstructions, keepRendererCount);
- }
- if (OnMeshAndMaterialsUpdated != null)
- OnMeshAndMaterialsUpdated(this);
- }
- public bool HasMultipleSubmeshInstructions () {
- if (!IsValid)
- return false;
- return MeshGenerator.RequiresMultipleSubmeshesByDrawOrder(skeleton);
- }
- #endregion
- protected void InitMeshBuffers () {
- if (meshBuffers != null) {
- meshBuffers.GetNext().Clear();
- meshBuffers.GetNext().Clear();
- }
- else {
- meshBuffers = new DoubleBuffered<MeshRendererBuffers.SmartMesh>();
- }
- }
- protected void DisposeMeshBuffers () {
- if (meshBuffers != null) {
- meshBuffers.GetNext().Dispose();
- meshBuffers.GetNext().Dispose();
- meshBuffers = null;
- }
- }
- protected void UpdateMeshSingleCanvasRenderer () {
- if (canvasRenderers.Count > 0)
- DisableUnusedCanvasRenderers(usedCount : 0);
- var smartMesh = meshBuffers.GetNext();
- MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, null);
- bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed);
- meshGenerator.Begin();
- if (currentInstructions.hasActiveClipping && currentInstructions.submeshInstructions.Count > 0) {
- meshGenerator.AddSubmesh(currentInstructions.submeshInstructions.Items[0], updateTriangles);
- }
- else {
- meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
- }
- if (canvas != null) meshGenerator.ScaleVertexData(canvas.referencePixelsPerUnit);
- if (OnPostProcessVertices != null) OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
- var mesh = smartMesh.mesh;
- meshGenerator.FillVertexData(mesh);
- if (updateTriangles) meshGenerator.FillTriangles(mesh);
- meshGenerator.FillLateVertexData(mesh);
- canvasRenderer.SetMesh(mesh);
- smartMesh.instructionUsed.Set(currentInstructions);
- if (currentInstructions.submeshInstructions.Count > 0) {
- var material = currentInstructions.submeshInstructions.Items[0].material;
- if (material != null && baseTexture != material.mainTexture) {
- baseTexture = material.mainTexture;
- if (overrideTexture == null)
- canvasRenderer.SetTexture(this.mainTexture);
- }
- }
- //this.UpdateMaterial(); // note: This would allocate memory.
- usedRenderersCount = 0;
- }
- protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions, bool keepRendererCount) {
- MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, null,
- enableSeparatorSlots ? separatorSlots : null,
- enableSeparatorSlots ? separatorSlots.Count > 0 : false,
- false);
- int submeshCount = currentInstructions.submeshInstructions.Count;
- if (keepRendererCount && submeshCount != usedRenderersCount)
- return;
- EnsureCanvasRendererCount(submeshCount);
- EnsureMeshesCount(submeshCount);
- EnsureSeparatorPartCount();
- var c = canvas;
- float scale = (c == null) ? 100 : c.referencePixelsPerUnit;
- // Generate meshes.
- var meshesItems = meshes.Items;
- bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0);
- int separatorSlotGroupIndex = 0;
- Transform parent = this.separatorSlots.Count == 0 ? this.transform : this.separatorParts[0];
- if (updateSeparatorPartLocation) {
- for (int p = 0; p < this.separatorParts.Count; ++p) {
- separatorParts[p].position = this.transform.position;
- separatorParts[p].rotation = this.transform.rotation;
- }
- }
- int targetSiblingIndex = 0;
- for (int i = 0; i < submeshCount; i++) {
- var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
- meshGenerator.Begin();
- meshGenerator.AddSubmesh(submeshInstructionItem);
- var targetMesh = meshesItems[i];
- meshGenerator.ScaleVertexData(scale);
- if (OnPostProcessVertices != null) OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
- meshGenerator.FillVertexData(targetMesh);
- meshGenerator.FillTriangles(targetMesh);
- meshGenerator.FillLateVertexData(targetMesh);
- var submeshMaterial = submeshInstructionItem.material;
- var canvasRenderer = canvasRenderers[i];
- if (i >= usedRenderersCount)
- canvasRenderer.gameObject.SetActive(true);
- canvasRenderer.SetMesh(targetMesh);
- canvasRenderer.materialCount = 1;
- if (canvasRenderer.transform.parent != parent.transform) {
- canvasRenderer.transform.SetParent(parent.transform, false);
- canvasRenderer.transform.localPosition = Vector3.zero;
- }
- canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++);
- if (submeshInstructionItem.forceSeparate) {
- targetSiblingIndex = 0;
- parent = separatorParts[++separatorSlotGroupIndex];
- }
- if (useOriginalTextureAndMaterial)
- canvasRenderer.SetMaterial(this.materialForRendering, submeshMaterial.mainTexture);
- else {
- var originalTexture = submeshMaterial.mainTexture;
- Material usedMaterial;
- Texture usedTexture;
- if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial))
- usedMaterial = material;
- if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture))
- usedTexture = originalTexture;
- canvasRenderer.SetMaterial(usedMaterial, usedTexture);
- }
- }
- DisableUnusedCanvasRenderers(usedCount : submeshCount);
- usedRenderersCount = submeshCount;
- }
- protected void EnsureCanvasRendererCount (int targetCount) {
- #if UNITY_EDITOR
- RemoveNullCanvasRenderers();
- #endif
- int currentCount = canvasRenderers.Count;
- for (int i = currentCount; i < targetCount; ++i) {
- var go = new GameObject(string.Format("Renderer{0}", i), typeof(RectTransform));
- go.transform.SetParent(this.transform, false);
- go.transform.localPosition = Vector3.zero;
- var canvasRenderer = go.AddComponent<CanvasRenderer>();
- canvasRenderers.Add(canvasRenderer);
- var rawImage = go.AddComponent<RawImage>();
- rawImage.maskable = this.maskable;
- rawImage.raycastTarget = false;
- rawImages.Add(rawImage);
- }
- }
- protected void DisableUnusedCanvasRenderers (int usedCount) {
- #if UNITY_EDITOR
- RemoveNullCanvasRenderers();
- #endif
- for (int i = usedCount; i < canvasRenderers.Count; i++) {
- canvasRenderers[i].Clear();
- canvasRenderers[i].gameObject.SetActive(false);
- }
- }
- #if UNITY_EDITOR
- private void RemoveNullCanvasRenderers () {
- if (Application.isEditor && !Application.isPlaying) {
- for (int i = canvasRenderers.Count - 1; i >= 0; --i) {
- if (canvasRenderers[i] == null) {
- canvasRenderers.RemoveAt(i);
- }
- }
- }
- }
- #endif
- protected void EnsureMeshesCount (int targetCount) {
- int oldCount = meshes.Count;
- meshes.EnsureCapacity(targetCount);
- for (int i = oldCount; i < targetCount; i++)
- meshes.Add(SpineMesh.NewSkeletonMesh());
- }
- protected void DestroyMeshes () {
- foreach (var mesh in meshes) {
- #if UNITY_EDITOR
- if (Application.isEditor && !Application.isPlaying)
- UnityEngine.Object.DestroyImmediate(mesh);
- else
- UnityEngine.Object.Destroy(mesh);
- #else
- UnityEngine.Object.Destroy(mesh);
- #endif
- }
- meshes.Clear();
- }
- protected void EnsureSeparatorPartCount () {
- #if UNITY_EDITOR
- RemoveNullSeparatorParts();
- #endif
- int targetCount = separatorSlots.Count + 1;
- if (targetCount == 1)
- return;
- #if UNITY_EDITOR
- if (Application.isEditor && !Application.isPlaying) {
- for (int i = separatorParts.Count-1; i >= 0; --i) {
- if (separatorParts[i] == null) {
- separatorParts.RemoveAt(i);
- }
- }
- }
- #endif
- int currentCount = separatorParts.Count;
- for (int i = currentCount; i < targetCount; ++i) {
- var go = new GameObject(string.Format("{0}[{1}]", SeparatorPartGameObjectName, i), typeof(RectTransform));
- go.transform.SetParent(this.transform, false);
- go.transform.localPosition = Vector3.zero;
- separatorParts.Add(go.transform);
- }
- }
- protected void UpdateSeparatorPartParents () {
- int usedCount = separatorSlots.Count + 1;
- if (usedCount == 1) {
- usedCount = 0; // placed directly at the SkeletonGraphic parent
- for (int i = 0; i < canvasRenderers.Count; ++i) {
- var canvasRenderer = canvasRenderers[i];
- if (canvasRenderer.transform.parent.name.Contains(SeparatorPartGameObjectName)) {
- canvasRenderer.transform.SetParent(this.transform, false);
- canvasRenderer.transform.localPosition = Vector3.zero;
- }
- }
- }
- for (int i = 0; i < separatorParts.Count; ++i) {
- bool isUsed = i < usedCount;
- separatorParts[i].gameObject.SetActive(isUsed);
- }
- }
- #if UNITY_EDITOR
- private void RemoveNullSeparatorParts () {
- if (Application.isEditor && !Application.isPlaying) {
- for (int i = separatorParts.Count - 1; i >= 0; --i) {
- if (separatorParts[i] == null) {
- separatorParts.RemoveAt(i);
- }
- }
- }
- }
- #endif
- }
- }
|