2024-10-23 17:55:55 +08:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Spine Runtimes License Agreement
2024-11-21 09:35:48 +08:00
* Last updated July 28 , 2023. Replaces all prior versions .
2024-10-23 17:55:55 +08:00
*
2024-11-21 09:35:48 +08:00
* Copyright ( c ) 2013 - 2023 , Esoteric Software LLC
2024-10-23 17:55:55 +08:00
*
* 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
*
2024-11-21 09:35:48 +08:00
* Otherwise , it is permitted to integrate the Spine Runtimes into software or
* otherwise create derivative works of the Spine Runtimes ( collectively ,
2024-10-23 17:55:55 +08:00
* "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
2024-11-21 09:35:48 +08:00
* ( 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 .
2024-10-23 17:55:55 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2024-11-21 09:35:48 +08:00
// Optimization option: Allows faster BuildMeshWithArrays call and avoids calling SetTriangles at the cost of
// checking for mesh differences (vertex counts, member-wise attachment list compare) every frame.
#define SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
//#define SPINE_DEBUG
2024-11-21 09:35:48 +08:00
// Important Note: When disabling this define, also disable the one in MeshGenerator.cs
// For details, see MeshGenerator.cs.
#define SLOT_ALPHA_DISABLES_ATTACHMENT
2024-10-23 17:55:55 +08:00
using System ;
using System.Collections.Generic ;
2024-11-21 09:35:48 +08:00
using UnityEngine ;
2024-10-23 17:55:55 +08:00
namespace Spine.Unity {
/// <summary>Instructions used by a SkeletonRenderer to render a mesh.</summary>
public class SkeletonRendererInstruction {
public readonly ExposedList < SubmeshInstruction > submeshInstructions = new ExposedList < SubmeshInstruction > ( ) ;
public bool immutableTriangles ;
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
public bool hasActiveClipping ;
public int rawVertexCount = - 1 ;
public readonly ExposedList < Attachment > attachments = new ExposedList < Attachment > ( ) ;
2024-11-21 09:35:48 +08:00
#else
/// <summary>Returns constant true to avoid BuildMeshWithArrays in renderers.</summary>
public bool hasActiveClipping { get { return true ; } }
/// <summary>Returns constant vertex count for early-return if-clauses in renderers.</summary>
public int rawVertexCount { get { return 1 ; } }
#endif
2024-10-23 17:55:55 +08:00
public void Clear ( ) {
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
this . attachments . Clear ( false ) ;
rawVertexCount = - 1 ;
hasActiveClipping = false ;
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
this . submeshInstructions . Clear ( false ) ;
}
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
public void Dispose ( ) {
attachments . Clear ( true ) ;
}
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
public void SetWithSubset ( ExposedList < SubmeshInstruction > instructions , int startSubmesh , int endSubmesh ) {
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
int runningVertexCount = 0 ;
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
2024-11-21 09:35:48 +08:00
ExposedList < SubmeshInstruction > submeshes = this . submeshInstructions ;
2024-10-23 17:55:55 +08:00
submeshes . Clear ( false ) ;
int submeshCount = endSubmesh - startSubmesh ;
submeshes . Resize ( submeshCount ) ;
2024-11-21 09:35:48 +08:00
SubmeshInstruction [ ] submeshesItems = submeshes . Items ;
SubmeshInstruction [ ] instructionsItems = instructions . Items ;
2024-10-23 17:55:55 +08:00
for ( int i = 0 ; i < submeshCount ; i + + ) {
2024-11-21 09:35:48 +08:00
SubmeshInstruction instruction = instructionsItems [ startSubmesh + i ] ;
2024-10-23 17:55:55 +08:00
submeshesItems [ i ] = instruction ;
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
this . hasActiveClipping | = instruction . hasClipping ;
submeshesItems [ i ] . rawFirstVertexIndex = runningVertexCount ; // Ensure current instructions have correct cached values.
runningVertexCount + = instruction . rawVertexCount ; // vertexCount will also be used for the rest of this method.
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
}
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
this . rawVertexCount = runningVertexCount ;
// assumption: instructions are contiguous. start and end are valid within instructions.
int startSlot = instructionsItems [ startSubmesh ] . startSlot ;
int endSlot = instructionsItems [ endSubmesh - 1 ] . endSlot ;
attachments . Clear ( false ) ;
int attachmentCount = endSlot - startSlot ;
attachments . Resize ( attachmentCount ) ;
2024-11-21 09:35:48 +08:00
Attachment [ ] attachmentsItems = attachments . Items ;
2024-10-23 17:55:55 +08:00
2024-11-21 09:35:48 +08:00
Slot [ ] drawOrderItems = instructionsItems [ 0 ] . skeleton . DrawOrder . Items ;
2024-10-23 17:55:55 +08:00
for ( int i = 0 ; i < attachmentCount ; i + + ) {
Slot slot = drawOrderItems [ startSlot + i ] ;
2024-11-21 09:35:48 +08:00
if ( ! slot . Bone . Active
#if SLOT_ALPHA_DISABLES_ATTACHMENT
| | slot . A = = 0f
#endif
) {
attachmentsItems [ i ] = null ;
continue ;
}
attachmentsItems [ i ] = slot . Attachment ;
2024-10-23 17:55:55 +08:00
}
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
}
public void Set ( SkeletonRendererInstruction other ) {
this . immutableTriangles = other . immutableTriangles ;
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
2024-10-23 17:55:55 +08:00
this . hasActiveClipping = other . hasActiveClipping ;
this . rawVertexCount = other . rawVertexCount ;
this . attachments . Clear ( false ) ;
this . attachments . EnsureCapacity ( other . attachments . Capacity ) ;
this . attachments . Count = other . attachments . Count ;
other . attachments . CopyTo ( this . attachments . Items ) ;
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
this . submeshInstructions . Clear ( false ) ;
this . submeshInstructions . EnsureCapacity ( other . submeshInstructions . Capacity ) ;
this . submeshInstructions . Count = other . submeshInstructions . Count ;
other . submeshInstructions . CopyTo ( this . submeshInstructions . Items ) ;
}
public static bool GeometryNotEqual ( SkeletonRendererInstruction a , SkeletonRendererInstruction b ) {
2024-11-21 09:35:48 +08:00
#if SPINE_TRIANGLECHECK
#if UNITY_EDITOR
2024-10-23 17:55:55 +08:00
if ( ! Application . isPlaying )
2024-11-21 09:35:48 +08:00
return true ;
#endif
2024-10-23 17:55:55 +08:00
if ( a . hasActiveClipping | | b . hasActiveClipping ) return true ; // Triangles are unpredictable when clipping is active.
// Everything below assumes the raw vertex and triangle counts were used. (ie, no clipping was done)
if ( a . rawVertexCount ! = b . rawVertexCount ) return true ;
if ( a . immutableTriangles ! = b . immutableTriangles ) return true ;
int attachmentCountB = b . attachments . Count ;
if ( a . attachments . Count ! = attachmentCountB ) return true ; // Bounds check for the looped storedAttachments count below.
// Submesh count changed
int submeshCountA = a . submeshInstructions . Count ;
int submeshCountB = b . submeshInstructions . Count ;
if ( submeshCountA ! = submeshCountB ) return true ;
// Submesh Instruction mismatch
2024-11-21 09:35:48 +08:00
SubmeshInstruction [ ] submeshInstructionsItemsA = a . submeshInstructions . Items ;
SubmeshInstruction [ ] submeshInstructionsItemsB = b . submeshInstructions . Items ;
2024-10-23 17:55:55 +08:00
2024-11-21 09:35:48 +08:00
Attachment [ ] attachmentsA = a . attachments . Items ;
Attachment [ ] attachmentsB = b . attachments . Items ;
2024-10-23 17:55:55 +08:00
for ( int i = 0 ; i < attachmentCountB ; i + + )
if ( ! System . Object . ReferenceEquals ( attachmentsA [ i ] , attachmentsB [ i ] ) ) return true ;
for ( int i = 0 ; i < submeshCountB ; i + + ) {
2024-11-21 09:35:48 +08:00
SubmeshInstruction submeshA = submeshInstructionsItemsA [ i ] ;
SubmeshInstruction submeshB = submeshInstructionsItemsB [ i ] ;
2024-10-23 17:55:55 +08:00
if ( ! (
submeshA . rawVertexCount = = submeshB . rawVertexCount & &
submeshA . startSlot = = submeshB . startSlot & &
submeshA . endSlot = = submeshB . endSlot
& & submeshA . rawTriangleCount = = submeshB . rawTriangleCount & &
submeshA . rawFirstVertexIndex = = submeshB . rawFirstVertexIndex
) )
return true ;
}
return false ;
2024-11-21 09:35:48 +08:00
#else
2024-10-23 17:55:55 +08:00
// In normal immutable triangle use, immutableTriangles will be initially false, forcing the smartmesh to update the first time but never again after that, unless there was an immutableTriangles flag mismatch..
if ( a . immutableTriangles | | b . immutableTriangles )
return ( a . immutableTriangles ! = b . immutableTriangles ) ;
return true ;
2024-11-21 09:35:48 +08:00
#endif
2024-10-23 17:55:55 +08:00
}
}
}