SkeletonBinary.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, 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
  13. * or 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
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #if (UNITY_5 || UNITY_5_3_OR_NEWER || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1)
  30. #define IS_UNITY
  31. #endif
  32. using System;
  33. using System.Collections.Generic;
  34. using System.IO;
  35. using System.Runtime.Serialization;
  36. #if WINDOWS_STOREAPP
  37. using System.Threading.Tasks;
  38. using Windows.Storage;
  39. #endif
  40. namespace Spine {
  41. public class SkeletonBinary : SkeletonLoader {
  42. public const int BONE_ROTATE = 0;
  43. public const int BONE_TRANSLATE = 1;
  44. public const int BONE_TRANSLATEX = 2;
  45. public const int BONE_TRANSLATEY = 3;
  46. public const int BONE_SCALE = 4;
  47. public const int BONE_SCALEX = 5;
  48. public const int BONE_SCALEY = 6;
  49. public const int BONE_SHEAR = 7;
  50. public const int BONE_SHEARX = 8;
  51. public const int BONE_SHEARY = 9;
  52. public const int SLOT_ATTACHMENT = 0;
  53. public const int SLOT_RGBA = 1;
  54. public const int SLOT_RGB = 2;
  55. public const int SLOT_RGBA2 = 3;
  56. public const int SLOT_RGB2 = 4;
  57. public const int SLOT_ALPHA = 5;
  58. public const int PATH_POSITION = 0;
  59. public const int PATH_SPACING = 1;
  60. public const int PATH_MIX = 2;
  61. public const int CURVE_LINEAR = 0;
  62. public const int CURVE_STEPPED = 1;
  63. public const int CURVE_BEZIER = 2;
  64. public SkeletonBinary (AttachmentLoader attachmentLoader)
  65. : base(attachmentLoader) {
  66. }
  67. public SkeletonBinary (params Atlas[] atlasArray)
  68. : base(atlasArray) {
  69. }
  70. #if !ISUNITY && WINDOWS_STOREAPP
  71. private async Task<SkeletonData> ReadFile(string path) {
  72. var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
  73. using (var input = new BufferedStream(await folder.GetFileAsync(path).AsTask().ConfigureAwait(false))) {
  74. SkeletonData skeletonData = ReadSkeletonData(input);
  75. skeletonData.Name = Path.GetFileNameWithoutExtension(path);
  76. return skeletonData;
  77. }
  78. }
  79. public override SkeletonData ReadSkeletonData (string path) {
  80. return this.ReadFile(path).Result;
  81. }
  82. #else
  83. public override SkeletonData ReadSkeletonData (string path) {
  84. #if WINDOWS_PHONE
  85. using (var input = new BufferedStream(Microsoft.Xna.Framework.TitleContainer.OpenStream(path))) {
  86. #else
  87. using (var input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) {
  88. #endif
  89. SkeletonData skeletonData = ReadSkeletonData(input);
  90. skeletonData.name = Path.GetFileNameWithoutExtension(path);
  91. return skeletonData;
  92. }
  93. }
  94. #endif // WINDOWS_STOREAPP
  95. public static readonly TransformMode[] TransformModeValues = {
  96. TransformMode.Normal,
  97. TransformMode.OnlyTranslation,
  98. TransformMode.NoRotationOrReflection,
  99. TransformMode.NoScale,
  100. TransformMode.NoScaleOrReflection
  101. };
  102. /// <summary>Returns the version string of binary skeleton data.</summary>
  103. public static string GetVersionString (Stream file) {
  104. if (file == null) throw new ArgumentNullException("file");
  105. SkeletonInput input = new SkeletonInput(file);
  106. return input.GetVersionString();
  107. }
  108. public SkeletonData ReadSkeletonData (Stream file) {
  109. if (file == null) throw new ArgumentNullException("file");
  110. float scale = this.scale;
  111. var skeletonData = new SkeletonData();
  112. SkeletonInput input = new SkeletonInput(file);
  113. long hash = input.ReadLong();
  114. skeletonData.hash = hash == 0 ? null : hash.ToString();
  115. skeletonData.version = input.ReadString();
  116. if (skeletonData.version.Length == 0) skeletonData.version = null;
  117. // early return for old 3.8 format instead of reading past the end
  118. if (skeletonData.version.Length > 13) return null;
  119. skeletonData.x = input.ReadFloat();
  120. skeletonData.y = input.ReadFloat();
  121. skeletonData.width = input.ReadFloat();
  122. skeletonData.height = input.ReadFloat();
  123. bool nonessential = input.ReadBoolean();
  124. if (nonessential) {
  125. skeletonData.fps = input.ReadFloat();
  126. skeletonData.imagesPath = input.ReadString();
  127. if (string.IsNullOrEmpty(skeletonData.imagesPath)) skeletonData.imagesPath = null;
  128. skeletonData.audioPath = input.ReadString();
  129. if (string.IsNullOrEmpty(skeletonData.audioPath)) skeletonData.audioPath = null;
  130. }
  131. int n;
  132. Object[] o;
  133. // Strings.
  134. o = input.strings = new String[n = input.ReadInt(true)];
  135. for (int i = 0; i < n; i++)
  136. o[i] = input.ReadString();
  137. // Bones.
  138. var bones = skeletonData.bones.Resize(n = input.ReadInt(true)).Items;
  139. for (int i = 0; i < n; i++) {
  140. String name = input.ReadString();
  141. BoneData parent = i == 0 ? null : bones[input.ReadInt(true)];
  142. BoneData data = new BoneData(i, name, parent);
  143. data.rotation = input.ReadFloat();
  144. data.x = input.ReadFloat() * scale;
  145. data.y = input.ReadFloat() * scale;
  146. data.scaleX = input.ReadFloat();
  147. data.scaleY = input.ReadFloat();
  148. data.shearX = input.ReadFloat();
  149. data.shearY = input.ReadFloat();
  150. data.Length = input.ReadFloat() * scale;
  151. data.transformMode = TransformModeValues[input.ReadInt(true)];
  152. data.skinRequired = input.ReadBoolean();
  153. if (nonessential) input.ReadInt(); // Skip bone color.
  154. bones[i] = data;
  155. }
  156. // Slots.
  157. var slots = skeletonData.slots.Resize(n = input.ReadInt(true)).Items;
  158. for (int i = 0; i < n; i++) {
  159. String slotName = input.ReadString();
  160. BoneData boneData = bones[input.ReadInt(true)];
  161. SlotData slotData = new SlotData(i, slotName, boneData);
  162. int color = input.ReadInt();
  163. slotData.r = ((color & 0xff000000) >> 24) / 255f;
  164. slotData.g = ((color & 0x00ff0000) >> 16) / 255f;
  165. slotData.b = ((color & 0x0000ff00) >> 8) / 255f;
  166. slotData.a = ((color & 0x000000ff)) / 255f;
  167. int darkColor = input.ReadInt(); // 0x00rrggbb
  168. if (darkColor != -1) {
  169. slotData.hasSecondColor = true;
  170. slotData.r2 = ((darkColor & 0x00ff0000) >> 16) / 255f;
  171. slotData.g2 = ((darkColor & 0x0000ff00) >> 8) / 255f;
  172. slotData.b2 = ((darkColor & 0x000000ff)) / 255f;
  173. }
  174. slotData.attachmentName = input.ReadStringRef();
  175. slotData.blendMode = (BlendMode)input.ReadInt(true);
  176. slots[i] = slotData;
  177. }
  178. // IK constraints.
  179. o = skeletonData.ikConstraints.Resize(n = input.ReadInt(true)).Items;
  180. for (int i = 0, nn; i < n; i++) {
  181. IkConstraintData data = new IkConstraintData(input.ReadString());
  182. data.order = input.ReadInt(true);
  183. data.skinRequired = input.ReadBoolean();
  184. var constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
  185. for (int ii = 0; ii < nn; ii++)
  186. constraintBones[ii] = bones[input.ReadInt(true)];
  187. data.target = bones[input.ReadInt(true)];
  188. data.mix = input.ReadFloat();
  189. data.softness = input.ReadFloat() * scale;
  190. data.bendDirection = input.ReadSByte();
  191. data.compress = input.ReadBoolean();
  192. data.stretch = input.ReadBoolean();
  193. data.uniform = input.ReadBoolean();
  194. o[i] = data;
  195. }
  196. // Transform constraints.
  197. o = skeletonData.transformConstraints.Resize(n = input.ReadInt(true)).Items;
  198. for (int i = 0, nn; i < n; i++) {
  199. TransformConstraintData data = new TransformConstraintData(input.ReadString());
  200. data.order = input.ReadInt(true);
  201. data.skinRequired = input.ReadBoolean();
  202. var constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
  203. for (int ii = 0; ii < nn; ii++)
  204. constraintBones[ii] = bones[input.ReadInt(true)];
  205. data.target = bones[input.ReadInt(true)];
  206. data.local = input.ReadBoolean();
  207. data.relative = input.ReadBoolean();
  208. data.offsetRotation = input.ReadFloat();
  209. data.offsetX = input.ReadFloat() * scale;
  210. data.offsetY = input.ReadFloat() * scale;
  211. data.offsetScaleX = input.ReadFloat();
  212. data.offsetScaleY = input.ReadFloat();
  213. data.offsetShearY = input.ReadFloat();
  214. data.mixRotate = input.ReadFloat();
  215. data.mixX = input.ReadFloat();
  216. data.mixY = input.ReadFloat();
  217. data.mixScaleX = input.ReadFloat();
  218. data.mixScaleY = input.ReadFloat();
  219. data.mixShearY = input.ReadFloat();
  220. o[i] = data;
  221. }
  222. // Path constraints
  223. o = skeletonData.pathConstraints.Resize(n = input.ReadInt(true)).Items;
  224. for (int i = 0, nn; i < n; i++) {
  225. PathConstraintData data = new PathConstraintData(input.ReadString());
  226. data.order = input.ReadInt(true);
  227. data.skinRequired = input.ReadBoolean();
  228. Object[] constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
  229. for (int ii = 0; ii < nn; ii++)
  230. constraintBones[ii] = bones[input.ReadInt(true)];
  231. data.target = slots[input.ReadInt(true)];
  232. data.positionMode = (PositionMode)Enum.GetValues(typeof(PositionMode)).GetValue(input.ReadInt(true));
  233. data.spacingMode = (SpacingMode)Enum.GetValues(typeof(SpacingMode)).GetValue(input.ReadInt(true));
  234. data.rotateMode = (RotateMode)Enum.GetValues(typeof(RotateMode)).GetValue(input.ReadInt(true));
  235. data.offsetRotation = input.ReadFloat();
  236. data.position = input.ReadFloat();
  237. if (data.positionMode == PositionMode.Fixed) data.position *= scale;
  238. data.spacing = input.ReadFloat();
  239. if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale;
  240. data.mixRotate = input.ReadFloat();
  241. data.mixX = input.ReadFloat();
  242. data.mixY = input.ReadFloat();
  243. o[i] = data;
  244. }
  245. // Default skin.
  246. Skin defaultSkin = ReadSkin(input, skeletonData, true, nonessential);
  247. if (defaultSkin != null) {
  248. skeletonData.defaultSkin = defaultSkin;
  249. skeletonData.skins.Add(defaultSkin);
  250. }
  251. // Skins.
  252. {
  253. int i = skeletonData.skins.Count;
  254. o = skeletonData.skins.Resize(n = i + input.ReadInt(true)).Items;
  255. for (; i < n; i++)
  256. o[i] = ReadSkin(input, skeletonData, false, nonessential);
  257. }
  258. // Linked meshes.
  259. n = linkedMeshes.Count;
  260. for (int i = 0; i < n; i++) {
  261. LinkedMesh linkedMesh = linkedMeshes[i];
  262. Skin skin = linkedMesh.skin == null ? skeletonData.DefaultSkin : skeletonData.FindSkin(linkedMesh.skin);
  263. if (skin == null) throw new Exception("Skin not found: " + linkedMesh.skin);
  264. Attachment parent = skin.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent);
  265. if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent);
  266. linkedMesh.mesh.DeformAttachment = linkedMesh.inheritDeform ? (VertexAttachment)parent : linkedMesh.mesh;
  267. linkedMesh.mesh.ParentMesh = (MeshAttachment)parent;
  268. linkedMesh.mesh.UpdateUVs();
  269. }
  270. linkedMeshes.Clear();
  271. // Events.
  272. o = skeletonData.events.Resize(n = input.ReadInt(true)).Items;
  273. for (int i = 0; i < n; i++) {
  274. EventData data = new EventData(input.ReadStringRef());
  275. data.Int = input.ReadInt(false);
  276. data.Float = input.ReadFloat();
  277. data.String = input.ReadString();
  278. data.AudioPath = input.ReadString();
  279. if (data.AudioPath != null) {
  280. data.Volume = input.ReadFloat();
  281. data.Balance = input.ReadFloat();
  282. }
  283. o[i] = data;
  284. }
  285. // Animations.
  286. o = skeletonData.animations.Resize(n = input.ReadInt(true)).Items;
  287. for (int i = 0; i < n; i++)
  288. o[i] = ReadAnimation(input.ReadString(), input, skeletonData);
  289. return skeletonData;
  290. }
  291. /// <returns>May be null.</returns>
  292. private Skin ReadSkin (SkeletonInput input, SkeletonData skeletonData, bool defaultSkin, bool nonessential) {
  293. Skin skin;
  294. int slotCount;
  295. if (defaultSkin) {
  296. slotCount = input.ReadInt(true);
  297. if (slotCount == 0) return null;
  298. skin = new Skin("default");
  299. } else {
  300. skin = new Skin(input.ReadStringRef());
  301. Object[] bones = skin.bones.Resize(input.ReadInt(true)).Items;
  302. var bonesItems = skeletonData.bones.Items;
  303. for (int i = 0, n = skin.bones.Count; i < n; i++)
  304. bones[i] = bonesItems[input.ReadInt(true)];
  305. var ikConstraintsItems = skeletonData.ikConstraints.Items;
  306. for (int i = 0, n = input.ReadInt(true); i < n; i++)
  307. skin.constraints.Add(ikConstraintsItems[input.ReadInt(true)]);
  308. var transformConstraintsItems = skeletonData.transformConstraints.Items;
  309. for (int i = 0, n = input.ReadInt(true); i < n; i++)
  310. skin.constraints.Add(transformConstraintsItems[input.ReadInt(true)]);
  311. var pathConstraintsItems = skeletonData.pathConstraints.Items;
  312. for (int i = 0, n = input.ReadInt(true); i < n; i++)
  313. skin.constraints.Add(pathConstraintsItems[input.ReadInt(true)]);
  314. skin.constraints.TrimExcess();
  315. slotCount = input.ReadInt(true);
  316. }
  317. for (int i = 0; i < slotCount; i++) {
  318. int slotIndex = input.ReadInt(true);
  319. for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
  320. String name = input.ReadStringRef();
  321. Attachment attachment = ReadAttachment(input, skeletonData, skin, slotIndex, name, nonessential);
  322. if (attachment != null) skin.SetAttachment(slotIndex, name, attachment);
  323. }
  324. }
  325. return skin;
  326. }
  327. private Attachment ReadAttachment (SkeletonInput input, SkeletonData skeletonData, Skin skin, int slotIndex,
  328. String attachmentName, bool nonessential) {
  329. float scale = this.scale;
  330. String name = input.ReadStringRef();
  331. if (name == null) name = attachmentName;
  332. switch ((AttachmentType)input.ReadByte()) {
  333. case AttachmentType.Region: {
  334. String path = input.ReadStringRef();
  335. float rotation = input.ReadFloat();
  336. float x = input.ReadFloat();
  337. float y = input.ReadFloat();
  338. float scaleX = input.ReadFloat();
  339. float scaleY = input.ReadFloat();
  340. float width = input.ReadFloat();
  341. float height = input.ReadFloat();
  342. int color = input.ReadInt();
  343. if (path == null) path = name;
  344. RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path);
  345. if (region == null) return null;
  346. region.Path = path;
  347. region.x = x * scale;
  348. region.y = y * scale;
  349. region.scaleX = scaleX;
  350. region.scaleY = scaleY;
  351. region.rotation = rotation;
  352. region.width = width * scale;
  353. region.height = height * scale;
  354. region.r = ((color & 0xff000000) >> 24) / 255f;
  355. region.g = ((color & 0x00ff0000) >> 16) / 255f;
  356. region.b = ((color & 0x0000ff00) >> 8) / 255f;
  357. region.a = ((color & 0x000000ff)) / 255f;
  358. region.UpdateOffset();
  359. return region;
  360. }
  361. case AttachmentType.Boundingbox: {
  362. int vertexCount = input.ReadInt(true);
  363. Vertices vertices = ReadVertices(input, vertexCount);
  364. if (nonessential) input.ReadInt(); //int color = nonessential ? input.ReadInt() : 0; // Avoid unused local warning.
  365. BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name);
  366. if (box == null) return null;
  367. box.worldVerticesLength = vertexCount << 1;
  368. box.vertices = vertices.vertices;
  369. box.bones = vertices.bones;
  370. // skipped porting: if (nonessential) Color.rgba8888ToColor(box.getColor(), color);
  371. return box;
  372. }
  373. case AttachmentType.Mesh: {
  374. String path = input.ReadStringRef();
  375. int color = input.ReadInt();
  376. int vertexCount = input.ReadInt(true);
  377. float[] uvs = ReadFloatArray(input, vertexCount << 1, 1);
  378. int[] triangles = ReadShortArray(input);
  379. Vertices vertices = ReadVertices(input, vertexCount);
  380. int hullLength = input.ReadInt(true);
  381. int[] edges = null;
  382. float width = 0, height = 0;
  383. if (nonessential) {
  384. edges = ReadShortArray(input);
  385. width = input.ReadFloat();
  386. height = input.ReadFloat();
  387. }
  388. if (path == null) path = name;
  389. MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path);
  390. if (mesh == null) return null;
  391. mesh.Path = path;
  392. mesh.r = ((color & 0xff000000) >> 24) / 255f;
  393. mesh.g = ((color & 0x00ff0000) >> 16) / 255f;
  394. mesh.b = ((color & 0x0000ff00) >> 8) / 255f;
  395. mesh.a = ((color & 0x000000ff)) / 255f;
  396. mesh.bones = vertices.bones;
  397. mesh.vertices = vertices.vertices;
  398. mesh.WorldVerticesLength = vertexCount << 1;
  399. mesh.triangles = triangles;
  400. mesh.regionUVs = uvs;
  401. mesh.UpdateUVs();
  402. mesh.HullLength = hullLength << 1;
  403. if (nonessential) {
  404. mesh.Edges = edges;
  405. mesh.Width = width * scale;
  406. mesh.Height = height * scale;
  407. }
  408. return mesh;
  409. }
  410. case AttachmentType.Linkedmesh: {
  411. String path = input.ReadStringRef();
  412. int color = input.ReadInt();
  413. String skinName = input.ReadStringRef();
  414. String parent = input.ReadStringRef();
  415. bool inheritDeform = input.ReadBoolean();
  416. float width = 0, height = 0;
  417. if (nonessential) {
  418. width = input.ReadFloat();
  419. height = input.ReadFloat();
  420. }
  421. if (path == null) path = name;
  422. MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path);
  423. if (mesh == null) return null;
  424. mesh.Path = path;
  425. mesh.r = ((color & 0xff000000) >> 24) / 255f;
  426. mesh.g = ((color & 0x00ff0000) >> 16) / 255f;
  427. mesh.b = ((color & 0x0000ff00) >> 8) / 255f;
  428. mesh.a = ((color & 0x000000ff)) / 255f;
  429. if (nonessential) {
  430. mesh.Width = width * scale;
  431. mesh.Height = height * scale;
  432. }
  433. linkedMeshes.Add(new SkeletonJson.LinkedMesh(mesh, skinName, slotIndex, parent, inheritDeform));
  434. return mesh;
  435. }
  436. case AttachmentType.Path: {
  437. bool closed = input.ReadBoolean();
  438. bool constantSpeed = input.ReadBoolean();
  439. int vertexCount = input.ReadInt(true);
  440. Vertices vertices = ReadVertices(input, vertexCount);
  441. float[] lengths = new float[vertexCount / 3];
  442. for (int i = 0, n = lengths.Length; i < n; i++)
  443. lengths[i] = input.ReadFloat() * scale;
  444. if (nonessential) input.ReadInt(); //int color = nonessential ? input.ReadInt() : 0;
  445. PathAttachment path = attachmentLoader.NewPathAttachment(skin, name);
  446. if (path == null) return null;
  447. path.closed = closed;
  448. path.constantSpeed = constantSpeed;
  449. path.worldVerticesLength = vertexCount << 1;
  450. path.vertices = vertices.vertices;
  451. path.bones = vertices.bones;
  452. path.lengths = lengths;
  453. // skipped porting: if (nonessential) Color.rgba8888ToColor(path.getColor(), color);
  454. return path;
  455. }
  456. case AttachmentType.Point: {
  457. float rotation = input.ReadFloat();
  458. float x = input.ReadFloat();
  459. float y = input.ReadFloat();
  460. if (nonessential) input.ReadInt(); //int color = nonessential ? input.ReadInt() : 0;
  461. PointAttachment point = attachmentLoader.NewPointAttachment(skin, name);
  462. if (point == null) return null;
  463. point.x = x * scale;
  464. point.y = y * scale;
  465. point.rotation = rotation;
  466. // skipped porting: if (nonessential) point.color = color;
  467. return point;
  468. }
  469. case AttachmentType.Clipping: {
  470. int endSlotIndex = input.ReadInt(true);
  471. int vertexCount = input.ReadInt(true);
  472. Vertices vertices = ReadVertices(input, vertexCount);
  473. if (nonessential) input.ReadInt();
  474. ClippingAttachment clip = attachmentLoader.NewClippingAttachment(skin, name);
  475. if (clip == null) return null;
  476. clip.EndSlot = skeletonData.slots.Items[endSlotIndex];
  477. clip.worldVerticesLength = vertexCount << 1;
  478. clip.vertices = vertices.vertices;
  479. clip.bones = vertices.bones;
  480. // skipped porting: if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
  481. return clip;
  482. }
  483. }
  484. return null;
  485. }
  486. private Vertices ReadVertices (SkeletonInput input, int vertexCount) {
  487. float scale = this.scale;
  488. int verticesLength = vertexCount << 1;
  489. Vertices vertices = new Vertices();
  490. if (!input.ReadBoolean()) {
  491. vertices.vertices = ReadFloatArray(input, verticesLength, scale);
  492. return vertices;
  493. }
  494. var weights = new ExposedList<float>(verticesLength * 3 * 3);
  495. var bonesArray = new ExposedList<int>(verticesLength * 3);
  496. for (int i = 0; i < vertexCount; i++) {
  497. int boneCount = input.ReadInt(true);
  498. bonesArray.Add(boneCount);
  499. for (int ii = 0; ii < boneCount; ii++) {
  500. bonesArray.Add(input.ReadInt(true));
  501. weights.Add(input.ReadFloat() * scale);
  502. weights.Add(input.ReadFloat() * scale);
  503. weights.Add(input.ReadFloat());
  504. }
  505. }
  506. vertices.vertices = weights.ToArray();
  507. vertices.bones = bonesArray.ToArray();
  508. return vertices;
  509. }
  510. private float[] ReadFloatArray (SkeletonInput input, int n, float scale) {
  511. float[] array = new float[n];
  512. if (scale == 1) {
  513. for (int i = 0; i < n; i++)
  514. array[i] = input.ReadFloat();
  515. } else {
  516. for (int i = 0; i < n; i++)
  517. array[i] = input.ReadFloat() * scale;
  518. }
  519. return array;
  520. }
  521. private int[] ReadShortArray (SkeletonInput input) {
  522. int n = input.ReadInt(true);
  523. int[] array = new int[n];
  524. for (int i = 0; i < n; i++)
  525. array[i] = (input.ReadByte() << 8) | input.ReadByte();
  526. return array;
  527. }
  528. /// <exception cref="SerializationException">SerializationException will be thrown when a Vertex attachment is not found.</exception>
  529. /// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
  530. private Animation ReadAnimation (String name, SkeletonInput input, SkeletonData skeletonData) {
  531. var timelines = new ExposedList<Timeline>(input.ReadInt(true));
  532. float scale = this.scale;
  533. // Slot timelines.
  534. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  535. int slotIndex = input.ReadInt(true);
  536. for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
  537. int timelineType = input.ReadByte(), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
  538. switch (timelineType) {
  539. case SLOT_ATTACHMENT: {
  540. AttachmentTimeline timeline = new AttachmentTimeline(frameCount, slotIndex);
  541. for (int frame = 0; frame < frameCount; frame++)
  542. timeline.SetFrame(frame, input.ReadFloat(), input.ReadStringRef());
  543. timelines.Add(timeline);
  544. break;
  545. }
  546. case SLOT_RGBA: {
  547. RGBATimeline timeline = new RGBATimeline(frameCount, input.ReadInt(true), slotIndex);
  548. float time = input.ReadFloat();
  549. float r = input.Read() / 255f, g = input.Read() / 255f;
  550. float b = input.Read() / 255f, a = input.Read() / 255f;
  551. for (int frame = 0, bezier = 0; ; frame++) {
  552. timeline.SetFrame(frame, time, r, g, b, a);
  553. if (frame == frameLast) break;
  554. float time2 = input.ReadFloat();
  555. float r2 = input.Read() / 255f, g2 = input.Read() / 255f;
  556. float b2 = input.Read() / 255f, a2 = input.Read() / 255f;
  557. switch (input.ReadByte()) {
  558. case CURVE_STEPPED:
  559. timeline.SetStepped(frame);
  560. break;
  561. case CURVE_BEZIER:
  562. SetBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1);
  563. SetBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1);
  564. SetBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1);
  565. SetBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1);
  566. break;
  567. }
  568. time = time2;
  569. r = r2;
  570. g = g2;
  571. b = b2;
  572. a = a2;
  573. }
  574. timelines.Add(timeline);
  575. break;
  576. }
  577. case SLOT_RGB: {
  578. RGBTimeline timeline = new RGBTimeline(frameCount, input.ReadInt(true), slotIndex);
  579. float time = input.ReadFloat();
  580. float r = input.Read() / 255f, g = input.Read() / 255f, b = input.Read() / 255f;
  581. for (int frame = 0, bezier = 0; ; frame++) {
  582. timeline.SetFrame(frame, time, r, g, b);
  583. if (frame == frameLast) break;
  584. float time2 = input.ReadFloat();
  585. float r2 = input.Read() / 255f, g2 = input.Read() / 255f, b2 = input.Read() / 255f;
  586. switch (input.ReadByte()) {
  587. case CURVE_STEPPED:
  588. timeline.SetStepped(frame);
  589. break;
  590. case CURVE_BEZIER:
  591. SetBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1);
  592. SetBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1);
  593. SetBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1);
  594. break;
  595. }
  596. time = time2;
  597. r = r2;
  598. g = g2;
  599. b = b2;
  600. }
  601. timelines.Add(timeline);
  602. break;
  603. }
  604. case SLOT_RGBA2: {
  605. RGBA2Timeline timeline = new RGBA2Timeline(frameCount, input.ReadInt(true), slotIndex);
  606. float time = input.ReadFloat();
  607. float r = input.Read() / 255f, g = input.Read() / 255f;
  608. float b = input.Read() / 255f, a = input.Read() / 255f;
  609. float r2 = input.Read() / 255f, g2 = input.Read() / 255f, b2 = input.Read() / 255f;
  610. for (int frame = 0, bezier = 0; ; frame++) {
  611. timeline.SetFrame(frame, time, r, g, b, a, r2, g2, b2);
  612. if (frame == frameLast) break;
  613. float time2 = input.ReadFloat();
  614. float nr = input.Read() / 255f, ng = input.Read() / 255f;
  615. float nb = input.Read() / 255f, na = input.Read() / 255f;
  616. float nr2 = input.Read() / 255f, ng2 = input.Read() / 255f, nb2 = input.Read() / 255f;
  617. switch (input.ReadByte()) {
  618. case CURVE_STEPPED:
  619. timeline.SetStepped(frame);
  620. break;
  621. case CURVE_BEZIER:
  622. SetBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1);
  623. SetBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1);
  624. SetBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1);
  625. SetBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1);
  626. SetBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1);
  627. SetBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1);
  628. SetBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1);
  629. break;
  630. }
  631. time = time2;
  632. r = nr;
  633. g = ng;
  634. b = nb;
  635. a = na;
  636. r2 = nr2;
  637. g2 = ng2;
  638. b2 = nb2;
  639. }
  640. timelines.Add(timeline);
  641. break;
  642. }
  643. case SLOT_RGB2: {
  644. RGB2Timeline timeline = new RGB2Timeline(frameCount, input.ReadInt(true), slotIndex);
  645. float time = input.ReadFloat();
  646. float r = input.Read() / 255f, g = input.Read() / 255f, b = input.Read() / 255f;
  647. float r2 = input.Read() / 255f, g2 = input.Read() / 255f, b2 = input.Read() / 255f;
  648. for (int frame = 0, bezier = 0; ; frame++) {
  649. timeline.SetFrame(frame, time, r, g, b, r2, g2, b2);
  650. if (frame == frameLast) break;
  651. float time2 = input.ReadFloat();
  652. float nr = input.Read() / 255f, ng = input.Read() / 255f, nb = input.Read() / 255f;
  653. float nr2 = input.Read() / 255f, ng2 = input.Read() / 255f, nb2 = input.Read() / 255f;
  654. switch (input.ReadByte()) {
  655. case CURVE_STEPPED:
  656. timeline.SetStepped(frame);
  657. break;
  658. case CURVE_BEZIER:
  659. SetBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1);
  660. SetBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1);
  661. SetBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1);
  662. SetBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1);
  663. SetBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1);
  664. SetBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1);
  665. break;
  666. }
  667. time = time2;
  668. r = nr;
  669. g = ng;
  670. b = nb;
  671. r2 = nr2;
  672. g2 = ng2;
  673. b2 = nb2;
  674. }
  675. timelines.Add(timeline);
  676. break;
  677. }
  678. case SLOT_ALPHA: {
  679. AlphaTimeline timeline = new AlphaTimeline(frameCount, input.ReadInt(true), slotIndex);
  680. float time = input.ReadFloat(), a = input.Read() / 255f;
  681. for (int frame = 0, bezier = 0; ; frame++) {
  682. timeline.SetFrame(frame, time, a);
  683. if (frame == frameLast) break;
  684. float time2 = input.ReadFloat();
  685. float a2 = input.Read() / 255f;
  686. switch (input.ReadByte()) {
  687. case CURVE_STEPPED:
  688. timeline.SetStepped(frame);
  689. break;
  690. case CURVE_BEZIER:
  691. SetBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1);
  692. break;
  693. }
  694. time = time2;
  695. a = a2;
  696. }
  697. timelines.Add(timeline);
  698. break;
  699. }
  700. }
  701. }
  702. }
  703. // Bone timelines.
  704. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  705. int boneIndex = input.ReadInt(true);
  706. for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
  707. int type = input.ReadByte(), frameCount = input.ReadInt(true), bezierCount = input.ReadInt(true);
  708. switch (type) {
  709. case BONE_ROTATE:
  710. timelines.Add(ReadTimeline(input, new RotateTimeline(frameCount, bezierCount, boneIndex), 1));
  711. break;
  712. case BONE_TRANSLATE:
  713. timelines.Add(ReadTimeline(input, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale));
  714. break;
  715. case BONE_TRANSLATEX:
  716. timelines.Add(ReadTimeline(input, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale));
  717. break;
  718. case BONE_TRANSLATEY:
  719. timelines.Add(ReadTimeline(input, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale));
  720. break;
  721. case BONE_SCALE:
  722. timelines.Add(ReadTimeline(input, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1));
  723. break;
  724. case BONE_SCALEX:
  725. timelines.Add(ReadTimeline(input, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1));
  726. break;
  727. case BONE_SCALEY:
  728. timelines.Add(ReadTimeline(input, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1));
  729. break;
  730. case BONE_SHEAR:
  731. timelines.Add(ReadTimeline(input, new ShearTimeline(frameCount, bezierCount, boneIndex), 1));
  732. break;
  733. case BONE_SHEARX:
  734. timelines.Add(ReadTimeline(input, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1));
  735. break;
  736. case BONE_SHEARY:
  737. timelines.Add(ReadTimeline(input, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1));
  738. break;
  739. }
  740. }
  741. }
  742. // IK constraint timelines.
  743. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  744. int index = input.ReadInt(true), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
  745. IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.ReadInt(true), index);
  746. float time = input.ReadFloat(), mix = input.ReadFloat(), softness = input.ReadFloat() * scale;
  747. for (int frame = 0, bezier = 0; ; frame++) {
  748. timeline.SetFrame(frame, time, mix, softness, input.ReadSByte(), input.ReadBoolean(), input.ReadBoolean());
  749. if (frame == frameLast) break;
  750. float time2 = input.ReadFloat(), mix2 = input.ReadFloat(), softness2 = input.ReadFloat() * scale;
  751. switch (input.ReadByte()) {
  752. case CURVE_STEPPED:
  753. timeline.SetStepped(frame);
  754. break;
  755. case CURVE_BEZIER:
  756. SetBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1);
  757. SetBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale);
  758. break;
  759. }
  760. time = time2;
  761. mix = mix2;
  762. softness = softness2;
  763. }
  764. timelines.Add(timeline);
  765. }
  766. // Transform constraint timelines.
  767. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  768. int index = input.ReadInt(true), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
  769. TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.ReadInt(true), index);
  770. float time = input.ReadFloat(), mixRotate = input.ReadFloat(), mixX = input.ReadFloat(), mixY = input.ReadFloat(),
  771. mixScaleX = input.ReadFloat(), mixScaleY = input.ReadFloat(), mixShearY = input.ReadFloat();
  772. for (int frame = 0, bezier = 0; ; frame++) {
  773. timeline.SetFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY);
  774. if (frame == frameLast) break;
  775. float time2 = input.ReadFloat(), mixRotate2 = input.ReadFloat(), mixX2 = input.ReadFloat(), mixY2 = input.ReadFloat(),
  776. mixScaleX2 = input.ReadFloat(), mixScaleY2 = input.ReadFloat(), mixShearY2 = input.ReadFloat();
  777. switch (input.ReadByte()) {
  778. case CURVE_STEPPED:
  779. timeline.SetStepped(frame);
  780. break;
  781. case CURVE_BEZIER:
  782. SetBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
  783. SetBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
  784. SetBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1);
  785. SetBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1);
  786. SetBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1);
  787. SetBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1);
  788. break;
  789. }
  790. time = time2;
  791. mixRotate = mixRotate2;
  792. mixX = mixX2;
  793. mixY = mixY2;
  794. mixScaleX = mixScaleX2;
  795. mixScaleY = mixScaleY2;
  796. mixShearY = mixShearY2;
  797. }
  798. timelines.Add(timeline);
  799. }
  800. // Path constraint timelines.
  801. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  802. int index = input.ReadInt(true);
  803. PathConstraintData data = skeletonData.pathConstraints.Items[index];
  804. for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
  805. switch (input.ReadByte()) {
  806. case PATH_POSITION:
  807. timelines
  808. .Add(ReadTimeline(input, new PathConstraintPositionTimeline(input.ReadInt(true), input.ReadInt(true), index),
  809. data.positionMode == PositionMode.Fixed ? scale : 1));
  810. break;
  811. case PATH_SPACING:
  812. timelines
  813. .Add(ReadTimeline(input, new PathConstraintSpacingTimeline(input.ReadInt(true), input.ReadInt(true), index),
  814. data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed ? scale : 1));
  815. break;
  816. case PATH_MIX:
  817. PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(input.ReadInt(true), input.ReadInt(true),
  818. index);
  819. float time = input.ReadFloat(), mixRotate = input.ReadFloat(), mixX = input.ReadFloat(), mixY = input.ReadFloat();
  820. for (int frame = 0, bezier = 0, frameLast = timeline.FrameCount - 1; ; frame++) {
  821. timeline.SetFrame(frame, time, mixRotate, mixX, mixY);
  822. if (frame == frameLast) break;
  823. float time2 = input.ReadFloat(), mixRotate2 = input.ReadFloat(), mixX2 = input.ReadFloat(),
  824. mixY2 = input.ReadFloat();
  825. switch (input.ReadByte()) {
  826. case CURVE_STEPPED:
  827. timeline.SetStepped(frame);
  828. break;
  829. case CURVE_BEZIER:
  830. SetBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
  831. SetBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
  832. SetBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1);
  833. break;
  834. }
  835. time = time2;
  836. mixRotate = mixRotate2;
  837. mixX = mixX2;
  838. mixY = mixY2;
  839. }
  840. timelines.Add(timeline);
  841. break;
  842. }
  843. }
  844. }
  845. // Deform timelines.
  846. for (int i = 0, n = input.ReadInt(true); i < n; i++) {
  847. Skin skin = skeletonData.skins.Items[input.ReadInt(true)];
  848. for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
  849. int slotIndex = input.ReadInt(true);
  850. for (int iii = 0, nnn = input.ReadInt(true); iii < nnn; iii++) {
  851. String attachmentName = input.ReadStringRef();
  852. VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, attachmentName);
  853. if (attachment == null) throw new SerializationException("Vertex attachment not found: " + attachmentName);
  854. bool weighted = attachment.Bones != null;
  855. float[] vertices = attachment.Vertices;
  856. int deformLength = weighted ? (vertices.Length / 3) << 1 : vertices.Length;
  857. int frameCount = input.ReadInt(true), frameLast = frameCount - 1;
  858. DeformTimeline timeline = new DeformTimeline(frameCount, input.ReadInt(true), slotIndex, attachment);
  859. float time = input.ReadFloat();
  860. for (int frame = 0, bezier = 0; ; frame++) {
  861. float[] deform;
  862. int end = input.ReadInt(true);
  863. if (end == 0)
  864. deform = weighted ? new float[deformLength] : vertices;
  865. else {
  866. deform = new float[deformLength];
  867. int start = input.ReadInt(true);
  868. end += start;
  869. if (scale == 1) {
  870. for (int v = start; v < end; v++)
  871. deform[v] = input.ReadFloat();
  872. } else {
  873. for (int v = start; v < end; v++)
  874. deform[v] = input.ReadFloat() * scale;
  875. }
  876. if (!weighted) {
  877. for (int v = 0, vn = deform.Length; v < vn; v++)
  878. deform[v] += vertices[v];
  879. }
  880. }
  881. timeline.SetFrame(frame, time, deform);
  882. if (frame == frameLast) break;
  883. float time2 = input.ReadFloat();
  884. switch (input.ReadByte()) {
  885. case CURVE_STEPPED:
  886. timeline.SetStepped(frame);
  887. break;
  888. case CURVE_BEZIER:
  889. SetBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
  890. break;
  891. }
  892. time = time2;
  893. }
  894. timelines.Add(timeline);
  895. }
  896. }
  897. }
  898. // Draw order timeline.
  899. int drawOrderCount = input.ReadInt(true);
  900. if (drawOrderCount > 0) {
  901. DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount);
  902. int slotCount = skeletonData.slots.Count;
  903. for (int i = 0; i < drawOrderCount; i++) {
  904. float time = input.ReadFloat();
  905. int offsetCount = input.ReadInt(true);
  906. int[] drawOrder = new int[slotCount];
  907. for (int ii = slotCount - 1; ii >= 0; ii--)
  908. drawOrder[ii] = -1;
  909. int[] unchanged = new int[slotCount - offsetCount];
  910. int originalIndex = 0, unchangedIndex = 0;
  911. for (int ii = 0; ii < offsetCount; ii++) {
  912. int slotIndex = input.ReadInt(true);
  913. // Collect unchanged items.
  914. while (originalIndex != slotIndex)
  915. unchanged[unchangedIndex++] = originalIndex++;
  916. // Set changed items.
  917. drawOrder[originalIndex + input.ReadInt(true)] = originalIndex++;
  918. }
  919. // Collect remaining unchanged items.
  920. while (originalIndex < slotCount)
  921. unchanged[unchangedIndex++] = originalIndex++;
  922. // Fill in unchanged items.
  923. for (int ii = slotCount - 1; ii >= 0; ii--)
  924. if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
  925. timeline.SetFrame(i, time, drawOrder);
  926. }
  927. timelines.Add(timeline);
  928. }
  929. // Event timeline.
  930. int eventCount = input.ReadInt(true);
  931. if (eventCount > 0) {
  932. EventTimeline timeline = new EventTimeline(eventCount);
  933. for (int i = 0; i < eventCount; i++) {
  934. float time = input.ReadFloat();
  935. EventData eventData = skeletonData.events.Items[input.ReadInt(true)];
  936. Event e = new Event(time, eventData);
  937. e.intValue = input.ReadInt(false);
  938. e.floatValue = input.ReadFloat();
  939. e.stringValue = input.ReadBoolean() ? input.ReadString() : eventData.String;
  940. if (e.Data.AudioPath != null) {
  941. e.volume = input.ReadFloat();
  942. e.balance = input.ReadFloat();
  943. }
  944. timeline.SetFrame(i, e);
  945. }
  946. timelines.Add(timeline);
  947. }
  948. float duration = 0;
  949. var items = timelines.Items;
  950. for (int i = 0, n = timelines.Count; i < n; i++)
  951. duration = Math.Max(duration, items[i].Duration);
  952. return new Animation(name, timelines, duration);
  953. }
  954. /// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
  955. private Timeline ReadTimeline (SkeletonInput input, CurveTimeline1 timeline, float scale) {
  956. float time = input.ReadFloat(), value = input.ReadFloat() * scale;
  957. for (int frame = 0, bezier = 0, frameLast = timeline.FrameCount - 1; ; frame++) {
  958. timeline.SetFrame(frame, time, value);
  959. if (frame == frameLast) break;
  960. float time2 = input.ReadFloat(), value2 = input.ReadFloat() * scale;
  961. switch (input.ReadByte()) {
  962. case CURVE_STEPPED:
  963. timeline.SetStepped(frame);
  964. break;
  965. case CURVE_BEZIER:
  966. SetBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale);
  967. break;
  968. }
  969. time = time2;
  970. value = value2;
  971. }
  972. return timeline;
  973. }
  974. /// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
  975. private Timeline ReadTimeline (SkeletonInput input, CurveTimeline2 timeline, float scale) {
  976. float time = input.ReadFloat(), value1 = input.ReadFloat() * scale, value2 = input.ReadFloat() * scale;
  977. for (int frame = 0, bezier = 0, frameLast = timeline.FrameCount - 1; ; frame++) {
  978. timeline.SetFrame(frame, time, value1, value2);
  979. if (frame == frameLast) break;
  980. float time2 = input.ReadFloat(), nvalue1 = input.ReadFloat() * scale, nvalue2 = input.ReadFloat() * scale;
  981. switch (input.ReadByte()) {
  982. case CURVE_STEPPED:
  983. timeline.SetStepped(frame);
  984. break;
  985. case CURVE_BEZIER:
  986. SetBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale);
  987. SetBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale);
  988. break;
  989. }
  990. time = time2;
  991. value1 = nvalue1;
  992. value2 = nvalue2;
  993. }
  994. return timeline;
  995. }
  996. /// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
  997. void SetBezier (SkeletonInput input, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
  998. float value1, float value2, float scale) {
  999. timeline.SetBezier(bezier, frame, value, time1, value1, input.ReadFloat(), input.ReadFloat() * scale, input.ReadFloat(),
  1000. input.ReadFloat() * scale, time2, value2);
  1001. }
  1002. internal class Vertices {
  1003. public int[] bones;
  1004. public float[] vertices;
  1005. }
  1006. internal class SkeletonInput {
  1007. private byte[] chars = new byte[32];
  1008. private byte[] bytesBigEndian = new byte[8];
  1009. internal string[] strings;
  1010. Stream input;
  1011. public SkeletonInput (Stream input) {
  1012. this.input = input;
  1013. }
  1014. public int Read () {
  1015. return input.ReadByte();
  1016. }
  1017. public byte ReadByte () {
  1018. return (byte)input.ReadByte();
  1019. }
  1020. public sbyte ReadSByte () {
  1021. int value = input.ReadByte();
  1022. if (value == -1) throw new EndOfStreamException();
  1023. return (sbyte)value;
  1024. }
  1025. public bool ReadBoolean () {
  1026. return input.ReadByte() != 0;
  1027. }
  1028. public float ReadFloat () {
  1029. input.Read(bytesBigEndian, 0, 4);
  1030. chars[3] = bytesBigEndian[0];
  1031. chars[2] = bytesBigEndian[1];
  1032. chars[1] = bytesBigEndian[2];
  1033. chars[0] = bytesBigEndian[3];
  1034. return BitConverter.ToSingle(chars, 0);
  1035. }
  1036. public int ReadInt () {
  1037. input.Read(bytesBigEndian, 0, 4);
  1038. return (bytesBigEndian[0] << 24)
  1039. + (bytesBigEndian[1] << 16)
  1040. + (bytesBigEndian[2] << 8)
  1041. + bytesBigEndian[3];
  1042. }
  1043. public long ReadLong () {
  1044. input.Read(bytesBigEndian, 0, 8);
  1045. return ((long)(bytesBigEndian[0]) << 56)
  1046. + ((long)(bytesBigEndian[1]) << 48)
  1047. + ((long)(bytesBigEndian[2]) << 40)
  1048. + ((long)(bytesBigEndian[3]) << 32)
  1049. + ((long)(bytesBigEndian[4]) << 24)
  1050. + ((long)(bytesBigEndian[5]) << 16)
  1051. + ((long)(bytesBigEndian[6]) << 8)
  1052. + (long)(bytesBigEndian[7]);
  1053. }
  1054. public int ReadInt (bool optimizePositive) {
  1055. int b = input.ReadByte();
  1056. int result = b & 0x7F;
  1057. if ((b & 0x80) != 0) {
  1058. b = input.ReadByte();
  1059. result |= (b & 0x7F) << 7;
  1060. if ((b & 0x80) != 0) {
  1061. b = input.ReadByte();
  1062. result |= (b & 0x7F) << 14;
  1063. if ((b & 0x80) != 0) {
  1064. b = input.ReadByte();
  1065. result |= (b & 0x7F) << 21;
  1066. if ((b & 0x80) != 0) result |= (input.ReadByte() & 0x7F) << 28;
  1067. }
  1068. }
  1069. }
  1070. return optimizePositive ? result : ((result >> 1) ^ -(result & 1));
  1071. }
  1072. public string ReadString () {
  1073. int byteCount = ReadInt(true);
  1074. switch (byteCount) {
  1075. case 0:
  1076. return null;
  1077. case 1:
  1078. return "";
  1079. }
  1080. byteCount--;
  1081. byte[] buffer = this.chars;
  1082. if (buffer.Length < byteCount) buffer = new byte[byteCount];
  1083. ReadFully(buffer, 0, byteCount);
  1084. return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount);
  1085. }
  1086. ///<return>May be null.</return>
  1087. public String ReadStringRef () {
  1088. int index = ReadInt(true);
  1089. return index == 0 ? null : strings[index - 1];
  1090. }
  1091. public void ReadFully (byte[] buffer, int offset, int length) {
  1092. while (length > 0) {
  1093. int count = input.Read(buffer, offset, length);
  1094. if (count <= 0) throw new EndOfStreamException();
  1095. offset += count;
  1096. length -= count;
  1097. }
  1098. }
  1099. /// <summary>Returns the version string of binary skeleton data.</summary>
  1100. public string GetVersionString () {
  1101. try {
  1102. // try reading 4.0+ format
  1103. var initialPosition = input.Position;
  1104. ReadLong(); // long hash
  1105. var stringPosition = input.Position;
  1106. int stringByteCount = ReadInt(true);
  1107. input.Position = stringPosition;
  1108. if (stringByteCount <= 13) {
  1109. string version = ReadString();
  1110. if (char.IsDigit(version[0]))
  1111. return version;
  1112. }
  1113. // fallback to old version format
  1114. input.Position = initialPosition;
  1115. return GetVersionStringOld3X();
  1116. } catch (Exception e) {
  1117. throw new ArgumentException("Stream does not contain valid binary Skeleton Data.\n" + e, "input");
  1118. }
  1119. }
  1120. /// <summary>Returns old 3.8 and earlier format version string of binary skeleton data.</summary>
  1121. public string GetVersionStringOld3X () {
  1122. // Hash.
  1123. int byteCount = ReadInt(true);
  1124. if (byteCount > 1) input.Position += byteCount - 1;
  1125. // Version.
  1126. byteCount = ReadInt(true);
  1127. if (byteCount > 1 && byteCount <= 13) {
  1128. byteCount--;
  1129. var buffer = new byte[byteCount];
  1130. ReadFully(buffer, 0, byteCount);
  1131. return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount);
  1132. }
  1133. throw new ArgumentException("Stream does not contain valid binary Skeleton Data.");
  1134. }
  1135. }
  1136. }
  1137. }