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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
using System ;
namespace Spine {
/// <summary>>An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's
/// <see cref="Slot.Deform"/>.</summary>
public abstract class VertexAttachment : Attachment {
static int nextID = 0 ;
static readonly Object nextIdLock = new Object ( ) ;
internal readonly int id ;
2024-11-21 09:35:48 +08:00
internal VertexAttachment timelineAttachment ;
2024-10-23 17:55:55 +08:00
internal int [ ] bones ;
internal float [ ] vertices ;
internal int worldVerticesLength ;
/// <summary>Gets a unique ID for this attachment.</summary>
public int Id { get { return id ; } }
public int [ ] Bones { get { return bones ; } set { bones = value ; } }
public float [ ] Vertices { get { return vertices ; } set { vertices = value ; } }
public int WorldVerticesLength { get { return worldVerticesLength ; } set { worldVerticesLength = value ; } }
2024-11-21 09:35:48 +08:00
/// <summary>Timelines for the timeline attachment are also applied to this attachment.
/// May be null if no attachment-specific timelines should be applied.</summary>
public VertexAttachment TimelineAttachment { get { return timelineAttachment ; } set { timelineAttachment = value ; } }
2024-10-23 17:55:55 +08:00
public VertexAttachment ( string name )
: base ( name ) {
lock ( VertexAttachment . nextIdLock ) {
2024-11-21 09:35:48 +08:00
id = VertexAttachment . nextID + + ;
2024-10-23 17:55:55 +08:00
}
2024-11-21 09:35:48 +08:00
timelineAttachment = this ;
}
/// <summary>Copy constructor.</summary>
public VertexAttachment ( VertexAttachment other )
: base ( other ) {
lock ( VertexAttachment . nextIdLock ) {
id = VertexAttachment . nextID + + ;
}
timelineAttachment = other . timelineAttachment ;
if ( other . bones ! = null ) {
bones = new int [ other . bones . Length ] ;
Array . Copy ( other . bones , 0 , bones , 0 , bones . Length ) ;
} else
bones = null ;
if ( other . vertices ! = null ) {
vertices = new float [ other . vertices . Length ] ;
Array . Copy ( other . vertices , 0 , vertices , 0 , vertices . Length ) ;
} else
vertices = null ;
worldVerticesLength = other . worldVerticesLength ;
2024-10-23 17:55:55 +08:00
}
public void ComputeWorldVertices ( Slot slot , float [ ] worldVertices ) {
ComputeWorldVertices ( slot , 0 , worldVerticesLength , worldVertices , 0 ) ;
}
/// <summary>
/// Transforms the attachment's local <see cref="Vertices"/> to world coordinates. If the slot's <see cref="Slot.Deform"/> is
/// not empty, it is used to deform the vertices.
/// <para />
/// See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
/// Runtimes Guide.
/// </summary>
/// <param name="start">The index of the first <see cref="Vertices"/> value to transform. Each vertex has 2 values, x and y.</param>
/// <param name="count">The number of world vertex values to output. Must be less than or equal to <see cref="WorldVerticesLength"/> - start.</param>
/// <param name="worldVertices">The output world vertices. Must have a length greater than or equal to <paramref name="offset"/> + <paramref name="count"/>.</param>
/// <param name="offset">The <paramref name="worldVertices"/> index to begin writing values.</param>
/// <param name="stride">The number of <paramref name="worldVertices"/> entries between the value pairs written.</param>
2024-11-21 09:35:48 +08:00
public virtual void ComputeWorldVertices ( Slot slot , int start , int count , float [ ] worldVertices , int offset , int stride = 2 ) {
2024-10-23 17:55:55 +08:00
count = offset + ( count > > 1 ) * stride ;
2024-11-21 09:35:48 +08:00
ExposedList < float > deformArray = slot . deform ;
2024-10-23 17:55:55 +08:00
float [ ] vertices = this . vertices ;
int [ ] bones = this . bones ;
if ( bones = = null ) {
if ( deformArray . Count > 0 ) vertices = deformArray . Items ;
Bone bone = slot . bone ;
float x = bone . worldX , y = bone . worldY ;
float a = bone . a , b = bone . b , c = bone . c , d = bone . d ;
for ( int vv = start , w = offset ; w < count ; vv + = 2 , w + = stride ) {
float vx = vertices [ vv ] , vy = vertices [ vv + 1 ] ;
worldVertices [ w ] = vx * a + vy * b + x ;
worldVertices [ w + 1 ] = vx * c + vy * d + y ;
}
return ;
}
int v = 0 , skip = 0 ;
for ( int i = 0 ; i < start ; i + = 2 ) {
int n = bones [ v ] ;
v + = n + 1 ;
skip + = n ;
}
2024-11-21 09:35:48 +08:00
Bone [ ] skeletonBones = slot . bone . skeleton . bones . Items ;
2024-10-23 17:55:55 +08:00
if ( deformArray . Count = = 0 ) {
for ( int w = offset , b = skip * 3 ; w < count ; w + = stride ) {
float wx = 0 , wy = 0 ;
int n = bones [ v + + ] ;
n + = v ;
for ( ; v < n ; v + + , b + = 3 ) {
Bone bone = skeletonBones [ bones [ v ] ] ;
float vx = vertices [ b ] , vy = vertices [ b + 1 ] , weight = vertices [ b + 2 ] ;
wx + = ( vx * bone . a + vy * bone . b + bone . worldX ) * weight ;
wy + = ( vx * bone . c + vy * bone . d + bone . worldY ) * weight ;
}
worldVertices [ w ] = wx ;
worldVertices [ w + 1 ] = wy ;
}
} else {
float [ ] deform = deformArray . Items ;
for ( int w = offset , b = skip * 3 , f = skip < < 1 ; w < count ; w + = stride ) {
float wx = 0 , wy = 0 ;
int n = bones [ v + + ] ;
n + = v ;
for ( ; v < n ; v + + , b + = 3 , f + = 2 ) {
Bone bone = skeletonBones [ bones [ v ] ] ;
float vx = vertices [ b ] + deform [ f ] , vy = vertices [ b + 1 ] + deform [ f + 1 ] , weight = vertices [ b + 2 ] ;
wx + = ( vx * bone . a + vy * bone . b + bone . worldX ) * weight ;
wy + = ( vx * bone . c + vy * bone . d + bone . worldY ) * weight ;
}
worldVertices [ w ] = wx ;
worldVertices [ w + 1 ] = wy ;
}
}
}
}
}