# 二进制导出文件格式

本页描述了Spine的skeleton和动画数据的二进制导出文件格式. [Spine 运行时](/spine-runtimes)将加载这些数据以绘制动画. 同时, Spine可以导入这种格式的数据从而实现与其他工具的操作互通. 二进制导出文件可在 Spine Runtimes 的[各示例项目](/git/spine-runtimes/tree/examples)中找到.

Spine 运行时能处理和加载JSON和二进制数据. 你无需自己编写加载代码吗, 除非你准备从零开始打造你自己的运行时(这工作量浩瀚无涯).

二进制格式的文件尺寸非常小, 且运行时加载它的速度非常快. 但缺点是灵活性, 运行时若发生了任何影响数据加载的改变, 都需要从Spine项目中重新导出二进制数据. 此外, 二进制格式不是人类可读的, 所以检查数据的最佳选择可能是[JSON格式](/spine-json-format). 

标记为 "非必要(nonessential)" 的数据只有在导出设置中勾选了 `Nonessential data` 时才会被输出. 在渲染时不需要这些数据, 但它对于其他工具或将数据导入Spine时可能有用.

二进制格式是序列化后的"skeleton data", 它有一个包含了骨骼、槽位、约束、皮肤和动画的列表. 它是无状态的数据, 与屏幕上某个具体的skeleton实例没有联系.

<a href="/files/runtime-diagram.png" target="blank"><img src="/files/runtime-diagram.png"/></a>

!!
# 数据类型

二进制格式使用了几种基本数据类型. 示例代码使用C语言.

## Boolean

`boolean`型占用1字节(byte), 值为1代表`true`而0代表`false`.

## Short

`short`型为16位数值, 占用2字节.

```
int readShort () {
	return (readByte() << 8) | readByte();
}
```

## Int

`int`型为32位数值, 占用4字节.

```
int readInt () {
	return (readByte() << 24) | (readByte() << 16) | (readByte() << 8) | readByte();
}
```

## Varint

一个变长整型(varint)就是一个int, 但是它的存储占用为1到5个字节(取决于数值的大小). varint有两种, `varint+`用于以更小的空间占用来存储的小正值, `varint-`用于小负值(和正值).

对于varint中的每个字节, 若有额外字节就使用MSB. 若需要存储小负值则使用移位.

```
int readVarint (int/*bool*/optimizePositive) {
	unsigned char b = readByte();
	int value = b & 0x7F;
	if (b & 0x80) {
		b = readByte();
		value |= (b & 0x7F) << 7;
		if (b & 0x80) {
			b = readByte();
			value |= (b & 0x7F) << 14;
			if (b & 0x80) {
				b = readByte();
				value |= (b & 0x7F) << 21;
				if (b & 0x80) value |= (readByte() & 0x7F) << 28;
			}
		}
	}
	if (!optimizePositive) value = (((unsigned int)value >> 1) ^ -(value & 1));
	return value;
}
```

## Float

`float`型为32位数值, 占用4字节. 根据语言和架构的不同, 这些字节可以合并为一个int, 然后类型转换为一个float值.

```
float readFloat () {
	union {
		int intValue;
		float floatValue;
	} intToFloat;
	intToFloat.intValue = readInt();
	return intToFloat.floatValue;
}
```

## String(字符串)

`string`型是以0结尾的变长UTF-8字符串. 若长度为0, 则字符串为null(在大多数情况下,也可当作空白字符串). 若长度为1, 则字符串为空. 其他情况下, 内存占用为`length - 1`字节. 一个UTF-8符可能不止一个字节, 所以`string`可能会占用更多的字节.

```
void readString (char* value, int maxLength) {
	int count = readVarint(true);
	if (count-- > 1) {
		if (count >= maxLength) count = maxLength - 1;
		for (int i = 0; i < count; i++)
			value[i] = readByte();
	}
	value[count] = '\0';
}
```

在skeleton数据中可以共享某些字符串, 例如附件名称. 为了减少文件的大小, 所有共享字符串被存储在二进制格式的初始元数据部分后的一个列表中.

可以从这个列表中读取的字符串在下文中记为`ref string`. `ref string`为共享字符串列表中的一个varint+索引. 若索引为0, 则字符串为null(在大多数情况下可以认为与空白字符串). 否则索引值将减1, 就能索引到共享字符串的列表中:

```
char* readRefString() {
	int index = readVarint(true);
	return index == 0 ? 0 : sharedStrings[index - 1];
}
```

## Color(色彩)

`color`型为用int来存储的一个RGBA值.

```
float* readColor (float* value) {
	int rgba = readInt();
	value[0] = ((rgba & 0xff000000) >>> 24) / 255f; // R
	value[1] = ((rgba & 0x00ff0000) >>> 16) / 255f; // G
	value[2] = ((rgba & 0x0000ff00) >>> 8) / 255f; // B
	value[3] = ((rgba & 0x000000ff)) / 255f; // A
}
```

## Constants(常量)

在某些地方使用常量作为标识. 一个常量是1个字节. 常量将前缀以`ALLCAPS`显示.

```
ATTACHMENT_REGION = 0
ATTACHMENT_BOUNDING_BOX = 1
ATTACHMENT_MESH = 2
ATTACHMENT_LINKED_MESH = 3
ATTACHMENT_PATH = 4
ATTACHMENT_POINT = 5
ATTACHMENT_CLIPPING = 6

BLEND_MODE_NORMAL = 0
BLEND_MODE_ADDITIVE = 1
BLEND_MODE_MULTIPLY = 2
BLEND_MODE_SCREEN = 3

CURVE_LINEAR = 0
CURVE_STEPPED = 1
CURVE_BEZIER = 2

BONE_ROTATE = 0
BONE_TRANSLATE = 1
BONE_SCALE = 2
BONE_SHEAR = 3

TRANSFORM_NORMAL = 0
TRANSFORM_ONLY_TRANSLATION = 1
TRANSFORM_NO_ROTATION_OR_REFLECTION = 2
TRANSFORM_NO_SCALE = 3
TRANSFORM_NO_SCALE_OR_REFLECTION = 4

SLOT_ATTACHMENT = 0
SLOT_COLOR = 1
SLOT_TWO_COLOR = 2

PATH_POSITION = 0
PATH_SPACING = 1
PATH_MIX = 2

PATH_POSITION_FIXED = 0
PATH_POSITION_PERCENT = 1

PATH_SPACING_LENGTH = 0
PATH_SPACING_FIXED = 1
PATH_SPACING_PERCENT = 2

PATH_ROTATE_TANGENT = 0
PATH_ROTATE_CHAIN = 1
PATH_ROTATE_CHAIN_SCALE = 2
```

# 格式

数据按以下方式组织:

<style>
blockquote {
	color: inherit;
}
blockquote p {
	margin-bottom: inherit;
}</style>!!


`string` **hash:** 所有skeleton数据的哈希值. 该值可被工具用来检测数据在上次加载后是否有变化.

`string` **version:** 导出这份数据的Spine版本. 该值可以被工具用来在读取时保持特定Spine版本.

`float` **x:** skeleton附件的AAB左下角的X坐标, 与Spine中的setup pose相同. 

`float` **y:** skeleton附件的AAB左下角的y坐标, 与Spine中的setup pose相同.

`float` **width:** skeleton附件的AABB宽度, 与Spine中的setup pose相同. 虽然骨架的AABB取决于其摆放方式, 但可将此参数作为skeleton的大概尺寸.

`float` **height:** skeleton附件的AABB高度, 与Spine中的setup pose相同.

`boolean` **非必要的参数:** 如果该参数为false, 则标记为非必要的参数将被忽略.

`float` **fps:** Dopesheet的帧率, 单位为帧数/每秒, 与Spine中一致. 非必要的参数.

`string` **images:** 图像路径, 与Spine中一致. 非必要的参数.

`string` **audio:** 音频路径, 与Spine中一致. 非必要的参数.

---

`varint+` **string count:** 附加的共享字符串的数量.

对于每个字符串:
> `string` **shared string**: 一个在skeleton中跨数据共享的字符串. 将被追加到所有共享字符串的列表中.

---

`varint+` **bone count:** 附加的骨骼数量.

对于每根骨骼:
>
`string` **name:** 骨骼名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **parent index:** 父骨骼的索引加1. 根骨骼的该参数是忽略的.
>
`float` **rotation:** 在setup pose中, 该骨骼相对于父骨骼的旋转角度.
>
`float` **x:** 在setup pose中骨骼相对于父骨骼坐标的X分量.
>
`float` **y:** 在setup pose中骨骼相对于父骨骼坐标的Y分量.
>
`float` **scaleX:** 在setup pose中骨骼在X方向的缩放值.
>
`float` **scaleY:** 在setup pose中骨骼在Y方向的缩放值.
>
`float` **shearX:** 在setup pose中骨骼在X方向斜切角度.
>
`float` **shearY:** 在setup pose中骨骼在Y方向斜切角度.
>
`float` **length:** 骨骼长度. 除了2骨骼IK和为骨骼绘制调试线外, 骨骼长度这个参数在运行时不常使用.
>
`TRANSFORM_*` **transform mode:** 决定了该骨骼如何继承父骨骼的transform.
>
`boolean` **skin required:** 如果为true, 则只有当活动皮肤中涉及到该骨骼时, 该骨骼才活动.
>
`color` **color:** 骨骼的颜色, 与Spine中一致. 非必要的参数.

---

`varint+` **slot count:** 附加的槽位数.

对于每个槽位:
>
`string` **name:** 槽位的名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **bone index:** 这个槽位所连接的骨骼的索引值.
>
`color` **color:** 在setup pose中槽位的颜色.
>
`dark` **color:** 在setup pose中槽位的暗色(dark color), 如果槽位没有使用tint black, 则为-1.
>
`ref string` **attachment:** 在setup pose中槽位的附件名称. 如果为空, 表示在setup pose没有附件.
>
`BLEND_MODE_*` **blend:** 在绘制槽位的可见附件时要使用的blending类型.

---

`varint+` **ik constraint count:** 附加的约束数量.

对于每个约束:
>
`string` **name:** 约束的名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **order index:** 应用约束的顺序.
>
`boolean` **skin required:** 如果为true, 该约束只有在活动皮肤涉及该约束时才会应用.
>
`varint+` **bone count:** 约束附加的骨骼数量 (1 or 2).
>
对于每根骨骼:
>>
`varint+` **bone index:** 其旋转被约束控制的骨骼的索引值.
>
`varint+` **target index:** 目标骨骼的索引.
>
`float` **mix:** 一个从0到1的值, 表示约束对骨骼的影响; 其中0表示只有FK, 1表示只有IK, 中间值表示FK和IK之间的混合.
>
`float` **softness:** 对于双骨骼IK, 表示目标骨骼到旋转减缓前骨骼的最大活动范围的距离.
>
`byte` **bendDirection:** 若为1, 则骨骼的弯曲方向为正的旋转方向. 若为-1, 则骨骼的弯曲方向则与旋转方向反向.
>
`boolean` **compress:** 若为true且只有一个骨骼被约束, 则当目标太近时会缩放骨骼以保持连接.
>
`boolean` **stretch:** 若为true且如果目标超出了范围, 将缩放父骨骼以保持连接. 若约束了多个骨骼且父骨骼的局部缩放比例非均匀(nonuniform), 则不应用拉伸(stretch).
>
`boolean` **uniform:** 若为true且只约束了一个骨骼, 而且使用了压缩或拉伸, 则该骨骼将在X和Y方向上缩放.

---

`varint+` **transform constraint count:** 附加的约束数量.

对于每个约束:
>
`string` **name:** 约束的名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **order index:** 应用约束的顺序.
>
`boolean` **skin required:** 如果为true, 该约束只有在活动皮肤涉及该约束时才会应用.
>
`varint+` **bone index:** 骨骼的索引, 其transform将受到约束条件限制.
>
`varint+` **target index:** T目标骨骼的索引值.
>
`boolean` **local:** 为true则目标骨骼的局部transform受到影响则, 反之则世界transform受到影响.
>
`boolean` **relative:** 为true则目标骨骼的transform按照相对值调整, 反之则transform按绝对值设置.
>
`float` **offset rotation:** 从目标骨骼的旋转偏移量.
>
`float` **offset x:** 从目标骨骼的位移偏移量的X分量.
>
`float` **offset y:** 从目标骨骼的位移偏移量的Y分量.
>
`float` **offset scale x:** 从目标骨骼的缩放偏移量的X分量.
>
`float` **offset scale y:** 从目标骨骼的缩放偏移量的Y分量.
>
`float` **offset shear y:** 从目标骨骼的斜切偏移量的Y分量.
>
`float` **rotate mix:** 一个从0到1的值, 表示约束对骨骼的影响. 其中0表示没有影响, 1表示完全约束, 中间值表示正常姿势和约束的混合.
>
`float` **translate mix:** 参见**rotate mix**.
>
`float` **scale mix:** 参见**rotate mix**.
>
`float` **shear mix:** 参见**rotate mix**.

---

`varint+` **path constraint count:** 附加的约束数量.

对于每个约束:
>
`string` **name:** 约束的名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **order index:** 应用约束的顺序.
>
`boolean` **skin required:** 如果为true, 该约束只有在活动皮肤涉及该约束时才会应用.
>
`varint+` **bone count:** 附加的骨骼数量.
>
对于每根骨骼:
>>
`varint+` **bone index:** 旋转和/或位移将被约束限制的骨骼的索引.
>
`varint+` **target index:** 目标槽位的索引值.
>
`PATH_POSITION_*` **position mode:** 决定路径位置的计算方式.
>
`PATH_SPACING_*` **spacing mode:** 决定骨骼间间距的计算方式.
>
`PATH_ROTATE_*` **rotate mode:** 决定骨骼旋转角度的计算方式.
>
`float` **offset rotation:** 路径旋转中的旋转偏移量.
>
`float` **position:** 路径位置.
>
`float` **spacing:** 骨骼间距.
>
`float` **rotate mix:** 一个从0到1的值, 表示约束对骨骼的影响. 其中0表示没有影响, 1表示完全约束, 中间值表示正常姿势和约束的混合.
>
`float` **translate mix:** 参见**rotate mix**.

---

[Skin](#Skin格式) **default skin:** 默认的皮肤附件, 它包含Spine中没有分配给皮肤的附件. 请注意, 默认皮肤不包含名称、骨骼、IK约束、transform(变换)约束或path(路径)约束!

`varint+` **skin count:** 附加的皮肤数量.

对于每个皮肤:
>
`ref string` **name:** 皮肤的名称. 该参数在一个skeleton中是唯一的.
>
`varint+` **bones count:** 皮肤涉及的骨骼数量.
>
对于每根骨骼:
>>
`varint+` **bone index:** 骨骼的索引值.
>
`varint+` **ik constraint count:** 皮肤中IK约束的数量.
>
对于每个IK约束:
>>
`varint+` **ik constraint index:** IK约束的索引值.
>
`varint+` **transform constraint count:** 皮肤的transform约束数量.
>
对于每个transform约束:
>>
`varint+` **transform constraint index:** tranform约束的索引值.
>
`varint+` **path constraint count:** 皮肤的路径约束数量.
>
对于每个路径约束:
>>
`varint+` **path constraint index:** 路径约束的索引值.
>
[Skin](#Skin格式) **skin:** 皮肤的附件.

---

`varint+` **event count:** 附加的事件数量.

对于每个事件:
>
`ref string` **name:** 事件的名称. 该参数在一个skeleton中是唯一的.
>
`varint-` **int:** 事件的int值.
>
`float` **float:** 事件的float值.
>
`string` **string:** 事件的string值.
>
`string` **audio:** 若该事件可用于播放音频, 则该参数指定了音频文件的路径.
>
`float` **volume:** 播放音频文件的音量.
>
`float` **balance:** 播放音频文件的立体声均衡值.

---

`varint+` **animation count:** 附加的动画数量.

对于每个动画:
>
`varint+` **slot count:** 附加的槽位数量.
>
对于每个槽位:
>>
`varint+` **slot index:** 槽位的索引值.
>>
`varint+` **timeline count:** 附加的时间轴数量.
>>
对于每个时间轴:
>>>
`SLOT_*` **timeline type:** 槽位时间轴的类型.
>>>
`varint+` **frame count:** 时间轴内的关键帧数量.
>>>
For `SLOT_ATTACHMENT`:
>>>>
对于每个关键帧(keyframe):
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`ref string` **attachment name:** 要设置在槽上的附件的名称, 为空(null)表示清除槽位中的附件.
>>>
对于 `SLOT_COLOR`:
>>>>
对于每个关键帧:
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`color` **color:** 为关键帧设置的槽位颜色.
>>>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>>>
对于 `SLOT_TWO_COLOR`:
>>>>
对于每个关键帧:
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`color` **light:** 关键帧的浅槽位色.
>>>>>
`color` **dark:** 关键帧的深槽位色.
>>>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>
`varint+` **bone count:** 附件的骨骼数量.
>
对于每根骨骼:
>>
`varint+` **bone index:** 骨骼的索引值.
>>
`varint+` **timeline count:** 附加的时间轴数量.
>>
对于每个时间轴:
>>>
`BONE_*` **timeline type:** 骨骼时间轴的类型.
>>>
`varint+` **frame count:** 时间轴内关键帧的数量.
>>>
对于 `BONE_ROTATE`:
>>>>
对于每个关键帧:
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`float` **rotation:** 关键帧的旋转.
>>>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>>>
对于 `BONE_TRANSLATE`, `BONE_SCALE`, 和 `BONE_SHEAR`:
>>>>
对于每个关键帧:
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`float` **x:** 关键帧的平移, 缩放或斜切的X分量.
>>>>>
`float` **y:** 关键帧的平移, 缩放或斜切的Y分量.
>>>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>
`varint+` **ik constraint timeline count:** 附加的IK约束时间轴.
>
对于每个IK约束时间轴:
>>
`varint+` **ik constraint index:** IK约束的索引值.
>>
`varint+` **frame count:** 时间轴内的关键帧数量.
>>
对于每个关键帧:
>>>
`float` **time:** 关键帧时长(以秒计).
>>>
`float` **mix:** IK约束的mix.
>>>
`byte` **bend direction:** IK约束的弯曲方向 (1 or -1).
>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>
`varint+` **transform constraint timeline count:** 附加的transform约束时间轴的数量.
>
对于每个transform约束时间轴:
>>
`varint+` **transform constraint index:** transform约束的索引值.
>>
`varint+` **frame count:** 时间轴内关键帧的数量.
>>
对于每个关键帧:
>>>
`float` **time:** 关键帧时长(以秒计).
>>>
`float` **rotate mix:** transform约束的旋转mix.
>>>
`float` **translate mix:** transform约束的平移mix.
>>>
`float` **scale mix:** transform约束的缩放mix.
>>>
`float` **shear mix:** transform约束的斜切mix.
>
`varint+` **path constraint entry count:** 附加的路径约束条目的数量.
>
对于每个路径约束条目:
>>
`varint+` **path constraint index:** 路径约束的索引值.
>>
`varint+` **path constraint timeline count:** 附加的路径约束时间轴的数量.
>>
对于每个路径约束时间轴:
>>>
`PATH_*` **path constraint timeline type:** 路径约束时间轴的类型.
>>>
`varint+` **frame count:** 时间轴内的关键帧数量.
>>>
对于每个关键帧:
>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>
For `PATH_POSITION`:
>>>>>
`float` **position:** 路径约束位置.
>>>>
For `PATH_SPACING`:
>>>>>
`float` **spacing:** 路径约束间隔.
>>>>
For `PATH_MIX`:
>>>>>
`float` **rotate mix:** 路径约束的旋转mix.
>>>>>
`float` **translate mix:** 路径约束的平移mix.
>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>
`varint+` **skin count:** 附加的皮肤数量.
>
对于每个皮肤:
>>
`varint+` **skin index:** 皮肤的索引值.
>>
`varint+` **slot count:** 附加的槽位的数量.
>>
对于每个槽位:
>>>
`varint+` **slot index:** 槽位的索引值.
>>>
`varint+` **deform timeline count:** 附加的变形(deform)时间轴数量.
>>>
对于每个变形时间轴:
>>>>
`ref string` **name:** 皮肤和槽位的附件名称.
>>>>
`varint+` **frame count:** 变形时间轴中的关键帧数量.
>>>>
对于每个关键帧:
>>>>>
`float` **time:** 关键帧时长(以秒计).
>>>>>
`varint+` **end vertex:** 最后一个顶点值的索引. 若为0, **起始顶点(start vertex)** 和其顶点值将被忽略.
>>>>>
`varint+` **start vertex:** 起始的顶点值的索引.
>>>>>
对于每个介于起始(包含)和最终(不含)顶点之间的顶点值:
>>>>>>
`float` **value:** 相对于附件的setup pose要调整顶点的量.
>>>>>
[Curve](#曲线格式) **curve:** 关键帧的曲线. 最后一帧将忽略曲线.
>
`varint+` **draw order count:** 附加的绘制顺序关键帧.
>
对于每个绘制顺序关键帧:
>>
`float` **time:** 关键帧时长(以秒计).
>>
`varint+` **change count:** 附加的绘制顺序变更数量.
>>
对月每次变更(change):
>>>
`varint+` **slot index:** 在绘制顺序中要修改的槽位的索引.
>>>
`varint+` **amount:** 在绘制顺序中要修改的槽位的移动量.
>
`varint+` **event count:** 附加的事件关键帧的数量.
>
对于每个事件关键帧:
>>
`float` **time:** 关键帧时长(以秒计).
>>
`varint+` **event index:** 关键帧的事件索引.
>>
`varint-` **int:** 关键帧的int值.
>>
`float` **float:** 关键帧的float值.
>>
`boolean` **has string:** 若为false, **string** 则被忽略.
>>
`string` **string:** 关键帧的string值.
>>
`float` **volume:** 播放音频文件的音量.
>>
`float` **balance:** 播放音频文件的立体声均衡值.

# Skin格式

`varint+` **slot count:** 附加的皮肤内槽位数量.

对于每个槽位:
>
`varint+` **slot index:** 属于该皮肤且包含以下附件的槽位的索引.
>
`varint+` **attachment count:** 槽位中的附件数量.
>
对于每个附件:
>>
`ref string` **placeholder name:** 可用于存储附件的皮肤中的占位符名称.
>>
`ref string` **name:** 附件名称. 若为空(null), 则使用 **placeholder name**. 该参数在一个skeleton中是唯一的. 对于图片附件, 该值是一个用于查找texture区域的键, 例如在磁盘或texture atlas中查找texture.
>>
`ATTACHMENT_*` **attachment type:** 附件的类型.
>>
对于 `ATTACHMENT_REGION`:
>>>
`ref string` **path:** 如果为非空值, 该参数将代替附件名称用于查texture区域.
>>>
`float` **rotation:** 图片相对于槽位骨骼的旋转角度.
>>>
`float` **x:** 图片相对于槽位骨骼的位置X分量.
>>>
`float` **y:** 图片相对于槽位骨骼的位置Y分量.
>>>
`float` **scaleX:** 图片在X方向的缩放值.
>>>
`float` **scaleY:** 图片在Y方向的缩放值.
>>>
`float` **width:** 图片宽度.
>>>
`float` **height:** 图片高度.
>>>
`color` **color:** 附件被tint时的颜色.
>>
对于 `ATTACHMENT_BOUNDING_BOX`:
>>>
`varint+` **vertex count:** 包围盒的顶点数量.
>>>
[Vertices](#顶点格式) **vertices:** 包围盒顶点.
>>>
`color` **color:** Spine中的包围盒颜色. 非必要的参数.
>>
对于 `ATTACHMENT_MESH`:
>>>
`ref string` **path:** 如果为非空值, 则该值将替代附件名称来查找texture区域.
>>>
`color` **color:** 附件被tint时的颜色.
>>>
`varint+` **uv count:** 网格的UV数量.
>>>
对于每个UV:
>>>>
`float` **x:** 顶点纹理的X坐标.
>>>>
`float` **y:** 顶点纹理的Y坐标.
>>>
`varint+` **triangle count:** 附加的网格中三角形端点数量.
>>>
对于每个三角形端点:
>>>>
`short` **vertex index:** 该点的顶点索引值.
>>>
[Vertices](#顶点格式) **vertices:** 网格顶点.
>>>
`varint+` **hull count:** 构成多面体包面的顶点数量. 包面顶点总是在**vertices**列表的首项.
>>>
`varint+` **edge count:** 连接顶点的边上包含的边点数量. 非必要的参数.
>>>
对于每个边的端点:
>>>>
`short` **vertex index:** 该点的顶点索引值. 非必要的参数.
>>>
`float` **width:** 网格图像的宽度. 非必要的参数.
>>>
`float` **height:** 网格图像的高度. 非必要的参数.
>>
对于 `ATTACHMENT_LINKED_MESH`:
>>>
`ref string` **path:** 如果为非空值, 则该值将替代附件名称来查找texture区域.
>>>
`color` **color:** 附件被tint时的颜色.
>>>
`ref string` **skin:** 包含源网格的皮肤的名称. 如果为空, 则源网格在默认皮肤中.
>>>
`ref string` **parent:** 源网格的名称, 它总是同该网格在同一槽位中. 如果源网格不在默认的皮肤中, 则将使用该名称查找皮肤中的实际附件.
>>>
`boolean` **deform:** 若为false, 则源网格的变形时间轴将不会应用于该网格.
>>>
`float` **width:** 网格图像的宽度. 非必要的参数.
>>>
`float` **height:** 网格图像的高度. 非必要的参数.
>>
对于 `ATTACHMENT_PATH`:
>>>
`boolean` **closed:** 若首尾顶点相连则为True.
>>>
`boolean` **constantSpeed:** 若使用恒定速度沿路径移动, 则为True.
>>>
>>>
`varint+` **vertex count:** 路径上的顶点数量.
>>>
[Vertices](#顶点格式) **vertices:** 路径顶点.
>>>
对于 **vertex count** / 3 的长度:
>>>>
`float` **length:** 在setup pose中从路径的起点到每条曲线的终点的长度.
>>>
`color` **color:** Spine中路径的颜色. 非必要的参数.
>>
对于 `ATTACHMENT_POINT`:
>>>
`float` **rotation:** 该点相对于槽位骨骼的旋转角度.
>>>
`float` **x:** 该点相对于槽位骨骼的位置的X分量.
>>>
`float` **y:** 该点相对于槽位骨骼的位置的Y分量.
>>>
`color` **color:**Spine中该点的颜色. 非必要的参数.
>>
对于 `ATTACHMENT_CLIPPING`:
>>>
`int` **end slot index:** 裁剪边缘的槽位索引.
>>>
`varint+` **vertex count:** 裁剪多边形的顶点数量.
>>>
[Vertices](#顶点格式) **vertices:** 裁剪多边形的顶点.
>>>
`color` **color:** Spine中裁剪附件的颜色. 非必要的参数.

# 曲线格式

曲线定义了该关键帧和下一关键帧之间使用的插值方法: 线性、分段或贝塞尔曲线.

贝塞尔曲线有4个参数值, 定义了控制点：cx1, cy1, cx2, cy2. X范围为0到1, 表示了两个关键帧之间的时长百分比. Y范围也是从0到1, 代表了关键帧数值间的差异百分比.

`CURVE_*` **curve type:** 曲线类型.

对于 `CURVE_BEZIER`:
>
`float` **c1**
>
`float` **c2**
>
`float` **c3**
>
`float` **c4**

# 顶点格式

`boolean` **weighted:** 若为True表示顶点带有权重.

当 **weighted** 为true:
>
对于每个顶点:
>>
`float` **x:** 顶点相对于槽位骨骼的位置的X分量.
>>
`float` **y:** 顶点相对于槽位骨骼的位置的Y分量.

当 **weighted** 为false:
>
对于每个顶点:
>>
`float` **bone count:** 影响顶点的骨骼数量.
>>
对于多个骨骼:
>>>
`float` **bone index:** 影响顶点的骨骼索引.
>>>
`float` **bind position X:** 顶点相对于槽位骨骼的位置的X分量.
>>>
`float` **bind position Y:** 顶点相对于槽位骨骼的位置的Y分量.
>>>
`float` **weight:** 骨骼的权重.