/** * The MIT License (MIT) * * Copyright (c) 2012-2017 DragonBones team and other contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; namespace DragonBones { /// /// public class ObjectDataParser : DataParser { protected static bool _GetBoolean(Dictionary rawData, string key, bool defaultValue) { if (rawData.ContainsKey(key)) { var value = rawData[key]; if (value is bool) { return (bool)value; } else if (value is string) { switch (value as string) { case "0": case "NaN": case "": case "false": case "null": case "undefined": return false; default: return true; } } else { return Convert.ToBoolean(value); } } return defaultValue; } protected static uint _GetNumber(Dictionary rawData, string key, uint defaultValue) { if (rawData.ContainsKey(key)) { var value = rawData[key]; if (value == null) { return defaultValue; } if (value is uint) { return (uint)value; } return Convert.ToUInt32(value); } return defaultValue; } protected static int _GetNumber(Dictionary rawData, string key, int defaultValue) { if (rawData.ContainsKey(key)) { var value = rawData[key]; if (value == null) { return defaultValue; } if (value is int) { return (int)value; } return Convert.ToInt32(value); } return defaultValue; } protected static float _GetNumber(Dictionary rawData, string key, float defaultValue) { if (rawData.ContainsKey(key)) { var value = rawData[key]; if (value == null) { return defaultValue; } if (value is float) { return (float)value; } return Convert.ToSingle(value); } return defaultValue; } protected static string _GetString(Dictionary rawData, string key, string defaultValue) { if (rawData.ContainsKey(key)) { var value = rawData[key]; var res = Convert.ToString(value); if (value is string) { res = (string)value; } if (!string.IsNullOrEmpty(res)) { return res; } } return defaultValue; } protected int _rawTextureAtlasIndex = 0; protected readonly List _rawBones = new List(); protected DragonBonesData _data = null; // protected ArmatureData _armature = null; // protected BoneData _bone = null; // protected SlotData _slot = null; // protected SkinData _skin = null; // protected MeshDisplayData _mesh = null; // protected AnimationData _animation = null; // protected TimelineData _timeline = null; // protected List _rawTextureAtlases = null; private int _defaultColorOffset = -1; private int _prevClockwise = 0; private float _prevRotation = 0.0f; private readonly Matrix _helpMatrixA = new Matrix(); private readonly Matrix _helpMatrixB = new Matrix(); private readonly TransformDB _helpTransform = new TransformDB(); private readonly ColorTransform _helpColorTransform = new ColorTransform(); private readonly Point _helpPoint = new Point(); private readonly List _helpArray = new List(); private readonly List _intArray = new List(); private readonly List _floatArray = new List(); private readonly List _frameIntArray = new List(); private readonly List _frameFloatArray = new List(); private readonly List _frameArray = new List(); private readonly List _timelineArray = new List(); private readonly List _cacheRawMeshes = new List(); private readonly List _cacheMeshes = new List(); private readonly List _actionFrames = new List(); private readonly Dictionary> _weightSlotPose = new Dictionary>(); private readonly Dictionary> _weightBonePoses = new Dictionary>(); private readonly Dictionary> _weightBoneIndices = new Dictionary>(); private readonly Dictionary> _cacheBones = new Dictionary>(); private readonly Dictionary> _slotChildActions = new Dictionary>(); public ObjectDataParser() { } private void _GetCurvePoint(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float t, Point result) { var l_t = 1.0f - t; var powA = l_t * l_t; var powB = t * t; var kA = l_t * powA; var kB = 3.0f * t * powA; var kC = 3.0f * l_t * powB; var kD = t * powB; result.x = kA * x1 + kB * x2 + kC * x3 + kD * x4; result.y = kA * y1 + kB * y2 + kC * y3 + kD * y4; } private void _SamplingEasingCurve(float[] curve, List samples) { var curveCount = curve.Length; var stepIndex = -2; for (int i = 0, l = samples.Count; i < l; ++i) { var t = ((float)i + 1.0f) / ((float)l + 1.0f); while ((stepIndex + 6 < curveCount ? curve[stepIndex + 6] : 1) < t) { // stepIndex + 3 * 2 stepIndex += 6; } var isInCurve = stepIndex >= 0 && stepIndex + 6 < curveCount; var x1 = isInCurve ? curve[stepIndex] : 0.0f; var y1 = isInCurve ? curve[stepIndex + 1] : 0.0f; var x2 = curve[stepIndex + 2]; var y2 = curve[stepIndex + 3]; var x3 = curve[stepIndex + 4]; var y3 = curve[stepIndex + 5]; var x4 = isInCurve ? curve[stepIndex + 6] : 1.0f; var y4 = isInCurve ? curve[stepIndex + 7] : 1.0f; var lower = 0.0f; var higher = 1.0f; while (higher - lower > 0.0001f) { var percentage = (higher + lower) * 0.5f; this._GetCurvePoint(x1, y1, x2, y2, x3, y3, x4, y4, percentage, this._helpPoint); if (t - this._helpPoint.x > 0.0) { lower = percentage; } else { higher = percentage; } } samples[i] = this._helpPoint.y; } } //private int _SortActionFrame(ActionFrame a, ActionFrame b) //{ // return a.frameStart > b.frameStart? 1 : -1; //} private void _ParseActionDataInFrame(object rawData, int frameStart, BoneData bone = null, SlotData slot = null) { Dictionary rawDic = rawData as Dictionary; if (rawDic == null) { return; } if (rawDic.ContainsKey(ObjectDataParser.EVENT)) { this._MergeActionFrame(rawDic[ObjectDataParser.EVENT], frameStart, ActionType.Frame, bone, slot); } if (rawDic.ContainsKey(ObjectDataParser.SOUND)) { this._MergeActionFrame(rawDic[ObjectDataParser.SOUND], frameStart, ActionType.Sound, bone, slot); } if (rawDic.ContainsKey(ObjectDataParser.ACTION)) { this._MergeActionFrame(rawDic[ObjectDataParser.ACTION], frameStart, ActionType.Play, bone, slot); } if (rawDic.ContainsKey(ObjectDataParser.EVENTS)) { this._MergeActionFrame(rawDic[ObjectDataParser.EVENTS], frameStart, ActionType.Frame, bone, slot); } if (rawDic.ContainsKey(ObjectDataParser.ACTIONS)) { this._MergeActionFrame(rawDic[ObjectDataParser.ACTIONS], frameStart, ActionType.Play, bone, slot); } } private void _MergeActionFrame(object rawData, int frameStart, ActionType type, BoneData bone = null, SlotData slot = null) { var actionOffset = this._armature.actions.Count; var actions = this._ParseActionData(rawData, type, bone, slot); var frameIndex = 0; ActionFrame frame = null; foreach (var action in actions) { this._armature.AddAction(action, false); } if (this._actionFrames.Count == 0) { // First frame. frame = new ActionFrame(); frame.frameStart = 0; this._actionFrames.Add(frame); frame = null; } foreach (var eachFrame in this._actionFrames) { // Get same frame. if (eachFrame.frameStart == frameStart) { frame = eachFrame; break; } else if (eachFrame.frameStart > frameStart) { break; } frameIndex++; } if (frame == null) { // Create and cache frame. frame = new ActionFrame(); frame.frameStart = frameStart; if (frameIndex + 1 < this._actionFrames.Count) { this._actionFrames.Insert(frameIndex + 1, frame); } else { this._actionFrames.Add(frame); } } for (var i = 0; i < actions.Count; ++i) { // Cache action offsets. frame.actions.Add(actionOffset + i); } } private int _ParseCacheActionFrame(ActionFrame frame) { var frameOffset = this._frameArray.Count; var actionCount = frame.actions.Count; this._frameArray.ResizeList(this._frameArray.Count + 1 + 1 + actionCount, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FramePosition] = (short)frame.frameStart; this._frameArray[frameOffset + (int)BinaryOffset.FramePosition + 1] = (short)actionCount; // Action count. for (var i = 0; i < actionCount; ++i) { // Action offsets. this._frameArray[frameOffset + (int)BinaryOffset.FramePosition + 2 + i] = (short)frame.actions[i]; } return frameOffset; } private ArmatureData _ParseArmature(Dictionary rawData, float scale) { var armature = BaseObject.BorrowObject(); armature.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); armature.frameRate = ObjectDataParser._GetNumber(rawData, ObjectDataParser.FRAME_RATE, this._data.frameRate); armature.scale = scale; if (rawData.ContainsKey(ObjectDataParser.TYPE) && rawData[ObjectDataParser.TYPE] is string) { armature.type = ObjectDataParser._GetArmatureType((string)rawData[ObjectDataParser.TYPE]); } else { armature.type = (ArmatureType)ObjectDataParser._GetNumber(rawData, ObjectDataParser.TYPE.ToString(), (int)ArmatureType.Armature); } if (armature.frameRate == 0) { // Data error. armature.frameRate = 24; } this._armature = armature; //CANVAS功能为完全实现,这里先注释 if (rawData != null && rawData.ContainsKey(ObjectDataParser.CANVAS)) { var rawCanvas = rawData[ObjectDataParser.CANVAS] as Dictionary; var canvas = BaseObject.BorrowObject(); if (rawData.ContainsKey(ObjectDataParser.COLOR)) { canvas.hasBackground = true; } else { canvas.hasBackground = false; } canvas.color = ObjectDataParser._GetNumber(rawCanvas, ObjectDataParser.COLOR, 0); canvas.x = ObjectDataParser._GetNumber(rawCanvas, ObjectDataParser.X, 0) * armature.scale; canvas.y = ObjectDataParser._GetNumber(rawCanvas, ObjectDataParser.Y, 0) * armature.scale; canvas.width = ObjectDataParser._GetNumber(rawCanvas, ObjectDataParser.WIDTH, 0) * armature.scale; canvas.height = ObjectDataParser._GetNumber(rawCanvas, ObjectDataParser.HEIGHT, 0) * armature.scale; armature.canvas = canvas; } if (rawData.ContainsKey(ObjectDataParser.AABB)) { var rawAABB = rawData[AABB] as Dictionary; armature.aabb.x = ObjectDataParser._GetNumber(rawAABB, ObjectDataParser.X, 0.0f) * armature.scale; armature.aabb.y = ObjectDataParser._GetNumber(rawAABB, ObjectDataParser.Y, 0.0f) * armature.scale; armature.aabb.width = ObjectDataParser._GetNumber(rawAABB, ObjectDataParser.WIDTH, 0.0f) * armature.scale; armature.aabb.height = ObjectDataParser._GetNumber(rawAABB, ObjectDataParser.HEIGHT, 0.0f) * armature.scale; } if (rawData.ContainsKey(ObjectDataParser.BONE)) { var rawBones = rawData[ObjectDataParser.BONE] as List; foreach (Dictionary rawBone in rawBones) { var parentName = ObjectDataParser._GetString(rawBone, ObjectDataParser.PARENT, ""); var bone = this._ParseBone(rawBone); if (parentName.Length > 0) { // Get bone parent. var parent = armature.GetBone(parentName); if (parent != null) { bone.parent = parent; } else { // Cache. if (!this._cacheBones.ContainsKey(parentName)) { this._cacheBones[parentName] = new List(); } this._cacheBones[parentName].Add(bone); } } if (this._cacheBones.ContainsKey(bone.name)) { foreach (var child in this._cacheBones[bone.name]) { child.parent = bone; } this._cacheBones[bone.name].Clear(); } armature.AddBone(bone); this._rawBones.Add(bone); // Cache raw bones sort. } } if (rawData.ContainsKey(ObjectDataParser.IK)) { var rawIKS = rawData[ObjectDataParser.IK] as List; foreach (Dictionary rawIK in rawIKS) { var constraint = this._ParseIKConstraint(rawIK); if (constraint != null) { armature.AddConstraint(constraint); } } } armature.SortBones(); if (rawData.ContainsKey(ObjectDataParser.SLOT)) { var zOrder = 0; var rawSlots = rawData[ObjectDataParser.SLOT] as List; foreach (Dictionary rawSlot in rawSlots) { armature.AddSlot(this._ParseSlot(rawSlot, zOrder++)); } } if (rawData.ContainsKey(ObjectDataParser.SKIN)) { var rawSkins = rawData[ObjectDataParser.SKIN] as List; foreach (Dictionary rawSkin in rawSkins) { armature.AddSkin(this._ParseSkin(rawSkin)); } } for (int i = 0, l = this._cacheRawMeshes.Count; i < l; i++) { var shareName = ObjectDataParser._GetString(rawData, DataParser.SHARE, ""); if (shareName.Length == 0) { continue; } var skinName = ObjectDataParser._GetString(rawData, DataParser.SKIN, DataParser.DEFAULT_NAME); if (skinName.Length == 0) { // skinName = DataParser.DEFAULT_NAME; } var shareMesh = armature.GetMesh(skinName, "", shareName) as MeshDisplayData; // TODO slot; if (shareMesh == null) { continue; // Error. } var mesh = this._cacheMeshes[i]; mesh.vertices.ShareFrom(shareMesh.vertices); } if (rawData.ContainsKey(ObjectDataParser.ANIMATION)) { var rawAnimations = rawData[ObjectDataParser.ANIMATION] as List; foreach (Dictionary rawAnimation in rawAnimations) { var animation = this._ParseAnimation(rawAnimation); armature.AddAnimation(animation); } } if (rawData.ContainsKey(ObjectDataParser.DEFAULT_ACTIONS)) { var actions = this._ParseActionData(rawData[ObjectDataParser.DEFAULT_ACTIONS], ActionType.Play, null, null); foreach (var action in actions) { armature.AddAction(action, true); if (action.type == ActionType.Play) { // Set default animation from default action. var animation = armature.GetAnimation(action.name); if (animation != null) { armature.defaultAnimation = animation; } } } } if (rawData.ContainsKey(ObjectDataParser.ACTIONS)) { var actions = this._ParseActionData(rawData[ObjectDataParser.ACTIONS], ActionType.Play, null, null); foreach (var action in actions) { armature.AddAction(action, false); } } // Clear helper. this._rawBones.Clear(); this._cacheRawMeshes.Clear(); this._cacheMeshes.Clear(); this._armature = null; this._cacheBones.Clear(); this._slotChildActions.Clear(); this._weightSlotPose.Clear(); this._weightBonePoses.Clear(); this._weightBoneIndices.Clear(); return armature; } protected BoneData _ParseBone(Dictionary rawData) { var scale = this._armature.scale; var bone = BaseObject.BorrowObject(); bone.inheritTranslation = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.INHERIT_TRANSLATION, true); bone.inheritRotation = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.INHERIT_ROTATION, true); bone.inheritScale = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.INHERIT_SCALE, true); bone.inheritReflection = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.INHERIT_REFLECTION, true); bone.length = ObjectDataParser._GetNumber(rawData, ObjectDataParser.LENGTH, 0) * scale; bone.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); if (rawData.ContainsKey(ObjectDataParser.TRANSFORM)) { this._ParseTransform(rawData[ObjectDataParser.TRANSFORM] as Dictionary, bone.transform, scale); } return bone; } protected ConstraintData _ParseIKConstraint(Dictionary rawData) { var bone = _armature.GetBone(_GetString(rawData, BONE, "")); if (bone == null) { return null; } var target = this._armature.GetBone(ObjectDataParser._GetString(rawData, ObjectDataParser.TARGET, "")); if (target == null) { return null; } var constraint = BaseObject.BorrowObject(); constraint.scaleEnabled = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.SCALE, false); constraint.bendPositive = ObjectDataParser._GetBoolean(rawData, ObjectDataParser.BEND_POSITIVE, true); constraint.weight = ObjectDataParser._GetNumber(rawData, ObjectDataParser.WEIGHT, 1.0f); constraint.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); constraint.bone = bone; constraint.target = target; var chain = ObjectDataParser._GetNumber(rawData, ObjectDataParser.CHAIN, 0); if (chain > 0 && bone.parent != null) { constraint.root = bone.parent; constraint.bone = bone; } else { constraint.root = bone; constraint.bone = null; } return constraint; } private SlotData _ParseSlot(Dictionary rawData, int zOrder) { var slot = BaseObject.BorrowObject(); slot.displayIndex = ObjectDataParser._GetNumber(rawData, ObjectDataParser.DISPLAY_INDEX, 0); slot.zOrder = zOrder; slot.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); slot.parent = this._armature.GetBone(ObjectDataParser._GetString(rawData, ObjectDataParser.PARENT, "")); // if (rawData.ContainsKey(ObjectDataParser.BLEND_MODE) && rawData[ObjectDataParser.BLEND_MODE] is string) { slot.blendMode = ObjectDataParser._GetBlendMode((string)rawData[ObjectDataParser.BLEND_MODE]); } else { slot.blendMode = (BlendMode)ObjectDataParser._GetNumber(rawData, ObjectDataParser.BLEND_MODE, (int)BlendMode.Normal); } if (rawData.ContainsKey(ObjectDataParser.COLOR)) { slot.color = SlotData.CreateColor(); this._ParseColorTransform(rawData[ObjectDataParser.COLOR] as Dictionary, slot.color); } else { slot.color = SlotData.DEFAULT_COLOR; } if (rawData.ContainsKey(ObjectDataParser.ACTIONS)) { this._slotChildActions[slot.name] = this._ParseActionData(rawData[ObjectDataParser.ACTIONS], ActionType.Play, null, null); } return slot; } protected SkinData _ParseSkin(Dictionary rawData) { var skin = BaseObject.BorrowObject(); skin.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ObjectDataParser.DEFAULT_NAME); if (rawData.ContainsKey(ObjectDataParser.SLOT)) { var rawSlots = rawData[ObjectDataParser.SLOT] as List; this._skin = skin; foreach (Dictionary rawSlot in rawSlots) { var slotName = ObjectDataParser._GetString(rawSlot, ObjectDataParser.NAME, ""); var slot = this._armature.GetSlot(slotName); if (slot != null) { this._slot = slot; if (rawSlot.ContainsKey(ObjectDataParser.DISPLAY)) { var rawDisplays = rawSlot[ObjectDataParser.DISPLAY] as List; foreach (Dictionary rawDisplay in rawDisplays) { skin.AddDisplay(slotName, this._ParseDisplay(rawDisplay)); } } this._slot = null; // } } this._skin = null; } return skin; } protected DisplayData _ParseDisplay(Dictionary rawData) { var name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); var path = ObjectDataParser._GetString(rawData, ObjectDataParser.PATH, ""); var type = DisplayType.Image; DisplayData display = null; if (rawData.ContainsKey(ObjectDataParser.TYPE) && rawData[ObjectDataParser.TYPE] is string) { type = ObjectDataParser._GetDisplayType((string)rawData[ObjectDataParser.TYPE]); } else { type = (DisplayType)ObjectDataParser._GetNumber(rawData, ObjectDataParser.TYPE, (int)type); } switch (type) { case DisplayType.Image: var imageDisplay = BaseObject.BorrowObject(); display = imageDisplay; imageDisplay.name = name; imageDisplay.path = path.Length > 0 ? path : name; this._ParsePivot(rawData, imageDisplay); break; case DisplayType.Armature: var armatureDisplay = BaseObject.BorrowObject(); display = armatureDisplay; armatureDisplay.name = name; armatureDisplay.path = path.Length > 0 ? path : name; armatureDisplay.inheritAnimation = true; if (rawData.ContainsKey(ObjectDataParser.ACTIONS)) { var actions = this._ParseActionData(rawData[ObjectDataParser.ACTIONS], ActionType.Play, null, null); foreach (var action in actions) { armatureDisplay.AddAction(action); } } else if (this._slotChildActions.ContainsKey(this._slot.name)) { var displays = this._skin.GetDisplays(this._slot.name); if (displays == null ? this._slot.displayIndex == 0 : this._slot.displayIndex == displays.Count) { foreach (var action in this._slotChildActions[this._slot.name]) { armatureDisplay.AddAction(action); } this._slotChildActions[this._slot.name].Clear(); } } break; case DisplayType.Mesh: var meshDisplay = BaseObject.BorrowObject(); display = meshDisplay; meshDisplay.vertices.inheritDeform = ObjectDataParser._GetBoolean(rawData, DataParser.INHERIT_DEFORM, true); meshDisplay.name = name; meshDisplay.path = path.Length > 0 ? path : name; meshDisplay.vertices.data = this._data; if (rawData.ContainsKey(DataParser.SHARE)) { this._cacheRawMeshes.Add(rawData); this._cacheMeshes.Add(meshDisplay); } else { this._ParseMesh(rawData, meshDisplay); } break; case DisplayType.BoundingBox: var boundingBox = this._ParseBoundingBox(rawData); if (boundingBox != null) { var boundingBoxDisplay = BaseObject.BorrowObject(); display = boundingBoxDisplay; boundingBoxDisplay.name = name; boundingBoxDisplay.path = path.Length > 0 ? path : name; boundingBoxDisplay.boundingBox = boundingBox; } break; } if (display != null && rawData.ContainsKey(ObjectDataParser.TRANSFORM)) { this._ParseTransform(rawData[ObjectDataParser.TRANSFORM] as Dictionary, display.transform, this._armature.scale); } return display; } protected void _ParsePivot(Dictionary rawData, ImageDisplayData display) { if (rawData.ContainsKey(ObjectDataParser.PIVOT)) { var rawPivot = rawData[ObjectDataParser.PIVOT] as Dictionary; display.pivot.x = ObjectDataParser._GetNumber(rawPivot, ObjectDataParser.X, 0.0f); display.pivot.y = ObjectDataParser._GetNumber(rawPivot, ObjectDataParser.Y, 0.0f); } else { display.pivot.x = 0.5f; display.pivot.y = 0.5f; } } protected virtual void _ParseMesh(Dictionary rawData, MeshDisplayData mesh) { var rawVertices = (rawData[ObjectDataParser.VERTICES] as List).ConvertAll(Convert.ToSingle);//float var rawUVs = (rawData[ObjectDataParser.UVS] as List).ConvertAll(Convert.ToSingle);//float var rawTriangles = (rawData[ObjectDataParser.TRIANGLES] as List).ConvertAll(Convert.ToInt16);//uint var vertexCount = (rawVertices.Count / 2); // uint var triangleCount = (rawTriangles.Count / 3); // uint var vertexOffset = this._floatArray.Count; var uvOffset = vertexOffset + vertexCount * 2; var meshOffset = this._intArray.Count; var meshName = this._skin.name + "_" + this._slot.name + "_" + mesh.name; // Cache pose data. mesh.vertices.offset = meshOffset; this._intArray.ResizeList(this._intArray.Count + 1 + 1 + 1 + 1 + triangleCount * 3, (short)0); this._intArray[meshOffset + (int)BinaryOffset.MeshVertexCount] = (short)vertexCount; this._intArray[meshOffset + (int)BinaryOffset.MeshTriangleCount] = (short)triangleCount; this._intArray[meshOffset + (int)BinaryOffset.MeshFloatOffset] = (short)vertexOffset; for (int i = 0, l = triangleCount * 3; i < l; ++i) { this._intArray[meshOffset + (int)BinaryOffset.MeshVertexIndices + i] = rawTriangles[i]; } this._floatArray.ResizeList(this._floatArray.Count + vertexCount * 2 + vertexCount * 2, 0.0f); for (int i = 0, l = vertexCount * 2; i < l; ++i) { this._floatArray[vertexOffset + i] = rawVertices[i]; this._floatArray[uvOffset + i] = rawUVs[i]; } if (rawData.ContainsKey(ObjectDataParser.WEIGHTS)) { var rawWeights = (rawData[ObjectDataParser.WEIGHTS] as List).ConvertAll(Convert.ToSingle); // float; var rawSlotPose = (rawData[ObjectDataParser.SLOT_POSE] as List).ConvertAll(Convert.ToSingle); // float; var rawBonePoses = (rawData[ObjectDataParser.BONE_POSE] as List).ConvertAll(Convert.ToSingle); //float ; //var sortedBones = this._armature.sortedBones; var weightBoneIndices = new List(); var weightBoneCount = rawBonePoses.Count / 7; // uint var floatOffset = this._floatArray.Count; var weightCount = (int)Math.Floor((double)rawWeights.Count - (double)vertexCount) / 2; // uint var weightOffset = this._intArray.Count; var weight = BaseObject.BorrowObject(); weight.count = weightCount; weight.offset = weightOffset; weightBoneIndices.ResizeList(weightBoneCount, uint.MinValue); this._intArray.ResizeList(this._intArray.Count + 1 + 1 + weightBoneCount + vertexCount + weight.count, (short)0); this._intArray[weightOffset + (int)BinaryOffset.WeigthFloatOffset] = (short)floatOffset; for (var i = 0; i < weightBoneCount; ++i) { var rawBoneIndex = (int)rawBonePoses[i * 7]; // uint var bone = this._rawBones[(int)rawBoneIndex]; weight.AddBone(bone); weightBoneIndices[i] = (uint)rawBoneIndex; this._intArray[weightOffset + (int)BinaryOffset.WeigthBoneIndices + i] = (short)this._armature.sortedBones.IndexOf(bone); } this._floatArray.ResizeList(this._floatArray.Count + (weightCount * 3), 0.0f); this._helpMatrixA.CopyFromArray(rawSlotPose, 0); for (int i = 0, iW = 0, iB = weightOffset + (int)BinaryOffset.WeigthBoneIndices + weightBoneCount, iV = floatOffset; i < vertexCount; ++i) { var iD = i * 2; var vertexBoneCount = this._intArray[iB++] = short.Parse(rawWeights[iW++].ToString()); // uint var x = this._floatArray[vertexOffset + iD]; var y = this._floatArray[vertexOffset + iD + 1]; this._helpMatrixA.TransformPoint(x, y, this._helpPoint); x = this._helpPoint.x; y = this._helpPoint.y; for (var j = 0; j < vertexBoneCount; ++j) { var rawBoneIndex = (uint)rawWeights[iW++]; // uint var boneIndex = weightBoneIndices.IndexOf(rawBoneIndex); this._helpMatrixB.CopyFromArray(rawBonePoses, weightBoneIndices.IndexOf(rawBoneIndex) * 7 + 1); this._helpMatrixB.Invert(); this._helpMatrixB.TransformPoint(x, y, this._helpPoint); this._intArray[iB++] = (short)boneIndex; this._floatArray[iV++] = rawWeights[iW++]; this._floatArray[iV++] = this._helpPoint.x; this._floatArray[iV++] = this._helpPoint.y; } } mesh.vertices.weight = weight; this._weightSlotPose[meshName] = rawSlotPose; this._weightBonePoses[meshName] = rawBonePoses; } } protected BoundingBoxData _ParseBoundingBox(Dictionary rawData) { BoundingBoxData boundingBox = null; var type = BoundingBoxType.Rectangle; if (rawData.ContainsKey(ObjectDataParser.SUB_TYPE) && rawData[ObjectDataParser.SUB_TYPE] is string) { type = ObjectDataParser._GetBoundingBoxType((string)rawData[ObjectDataParser.SUB_TYPE]); } else { type = (BoundingBoxType)ObjectDataParser._GetNumber(rawData, ObjectDataParser.SUB_TYPE, (uint)type); } switch (type) { case BoundingBoxType.Rectangle: boundingBox = BaseObject.BorrowObject(); break; case BoundingBoxType.Ellipse: boundingBox = BaseObject.BorrowObject(); break; case BoundingBoxType.Polygon: boundingBox = this._ParsePolygonBoundingBox(rawData); break; } if (boundingBox != null) { boundingBox.color = ObjectDataParser._GetNumber(rawData, ObjectDataParser.COLOR, (uint)0x000000); if (boundingBox.type == BoundingBoxType.Rectangle || boundingBox.type == BoundingBoxType.Ellipse) { boundingBox.width = ObjectDataParser._GetNumber(rawData, ObjectDataParser.WIDTH, 0.0f); boundingBox.height = ObjectDataParser._GetNumber(rawData, ObjectDataParser.HEIGHT, 0.0f); } } return boundingBox; } protected PolygonBoundingBoxData _ParsePolygonBoundingBox(Dictionary rawData) { var polygonBoundingBox = BaseObject.BorrowObject(); if (rawData.ContainsKey(ObjectDataParser.VERTICES)) { float scale = this._armature.scale; var rawVertices = (rawData[ObjectDataParser.VERTICES] as List).ConvertAll(Convert.ToSingle); var vertices = polygonBoundingBox.vertices; vertices.ResizeList(rawVertices.Count, 0.0f); for (int i = 0, l = rawVertices.Count; i < l; i += 2) { var x = rawVertices[i] * scale; var y = rawVertices[i + 1] * scale; vertices[i] = x; vertices[i + 1] = y; if (i == 0) { polygonBoundingBox.x = x; polygonBoundingBox.y = y; polygonBoundingBox.width = x; polygonBoundingBox.height = y; } else { if (x < polygonBoundingBox.x) { polygonBoundingBox.x = x; } else if (x > polygonBoundingBox.width) { polygonBoundingBox.width = x; } if (y < polygonBoundingBox.y) { polygonBoundingBox.y = y; } else if (y > polygonBoundingBox.height) { polygonBoundingBox.height = y; } } } polygonBoundingBox.width -= polygonBoundingBox.x; polygonBoundingBox.height -= polygonBoundingBox.y; } else { Helper.Assert(false, "Data error.\n Please reexport DragonBones Data to fixed the bug."); } return polygonBoundingBox; } protected virtual AnimationData _ParseAnimation(Dictionary rawData) { var animation = BaseObject.BorrowObject(); animation.frameCount = (uint)Math.Max(ObjectDataParser._GetNumber(rawData, ObjectDataParser.DURATION, 1), 1); animation.playTimes = (uint)ObjectDataParser._GetNumber(rawData, ObjectDataParser.PLAY_TIMES, 1); animation.duration = (float)animation.frameCount / (float)this._armature.frameRate;// float animation.fadeInTime = ObjectDataParser._GetNumber(rawData, ObjectDataParser.FADE_IN_TIME, 0.0f); animation.scale = ObjectDataParser._GetNumber(rawData, ObjectDataParser.SCALE, 1.0f); animation.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ObjectDataParser.DEFAULT_NAME); if (animation.name.Length == 0) { animation.name = ObjectDataParser.DEFAULT_NAME; } animation.frameIntOffset = (uint)this._frameIntArray.Count; animation.frameFloatOffset = (uint)this._frameFloatArray.Count; animation.frameOffset = (uint)this._frameArray.Count; this._animation = animation; if (rawData.ContainsKey(ObjectDataParser.FRAME)) { var rawFrames = rawData[ObjectDataParser.FRAME] as List; var keyFrameCount = rawFrames.Count; if (keyFrameCount > 0) { for (int i = 0, frameStart = 0; i < keyFrameCount; ++i) { var rawFrame = rawFrames[i] as Dictionary; this._ParseActionDataInFrame(rawFrame, frameStart, null, null); frameStart += ObjectDataParser._GetNumber(rawFrame, ObjectDataParser.DURATION, 1); } } } if (rawData.ContainsKey(ObjectDataParser.Z_ORDER)) { this._animation.zOrderTimeline = this._ParseTimeline( rawData[ObjectDataParser.Z_ORDER] as Dictionary, null, ObjectDataParser.FRAME, TimelineType.ZOrder, false, false, 0, this._ParseZOrderFrame ); } if (rawData.ContainsKey(ObjectDataParser.BONE)) { var rawTimelines = rawData[ObjectDataParser.BONE] as List; foreach (Dictionary rawTimeline in rawTimelines) { this._ParseBoneTimeline(rawTimeline); } } if (rawData.ContainsKey(ObjectDataParser.SLOT)) { var rawTimelines = rawData[ObjectDataParser.SLOT] as List; foreach (Dictionary rawTimeline in rawTimelines) { this._ParseSlotTimeline(rawTimeline); } } if (rawData.ContainsKey(ObjectDataParser.FFD)) { var rawTimelines = rawData[ObjectDataParser.FFD] as List; foreach (Dictionary rawTimeline in rawTimelines) { var skinName = ObjectDataParser._GetString(rawTimeline, DataParser.SKIN, DataParser.DEFAULT_NAME); var slotName = ObjectDataParser._GetString(rawTimeline, DataParser.SLOT, ""); var displayName = ObjectDataParser._GetString(rawTimeline, DataParser.NAME, ""); if (skinName.Length == 0) { skinName = ObjectDataParser.DEFAULT_NAME; } this._slot = this._armature.GetSlot(slotName); this._mesh = this._armature.GetMesh(skinName, slotName, displayName) as MeshDisplayData; if (this._slot == null || this._mesh == null) { continue; } var timeline = this._ParseTimeline( rawTimeline, null, ObjectDataParser.FRAME, TimelineType.SlotDeform, false, true, 0, this._ParseSlotFFDFrame ); if (timeline != null) { this._animation.AddSlotTimeline(this._slot, timeline); } this._slot = null; // this._mesh = null; // } } if (rawData.ContainsKey(ObjectDataParser.IK)) { var rawTimelines = rawData[ObjectDataParser.IK] as List; foreach (Dictionary rawTimeline in rawTimelines) { var constraintName = ObjectDataParser._GetString(rawTimeline, ObjectDataParser.NAME, ""); var constraint = this._armature.GetConstraint(constraintName); if (constraint == null) { continue; } var timeline = this._ParseTimeline( rawTimeline, null, ObjectDataParser.FRAME, TimelineType.IKConstraint, true, false, 2, this._ParseIKConstraintFrame ); if (timeline != null) { this._animation.AddConstraintTimeline(constraint, timeline); } } } if (this._actionFrames.Count > 0) { var timeline = this._animation.actionTimeline = BaseObject.BorrowObject(); var keyFrameCount = this._actionFrames.Count; timeline.type = TimelineType.Action; timeline.offset = (uint)this._timelineArray.Count; this._timelineArray.ResizeList(this._timelineArray.Count + 1 + 1 + 1 + 1 + 1 + keyFrameCount, (ushort)0); this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineScale] = 100; this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineOffset] = 0; this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineKeyFrameCount] = (ushort)keyFrameCount; this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameValueCount] = 0; this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameValueOffset] = 0; this._timeline = timeline; if (keyFrameCount == 1) { timeline.frameIndicesOffset = -1; this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameOffset + 0] = (ushort)(this._ParseCacheActionFrame(this._actionFrames[0]) - this._animation.frameOffset); } else { var totalFrameCount = this._animation.frameCount + 1; // One more frame than animation. var frameIndices = this._data.frameIndices; timeline.frameIndicesOffset = frameIndices.Count; frameIndices.ResizeList(frameIndices.Count + (int)totalFrameCount, uint.MinValue); for ( int i = 0, iK = 0, frameStart = 0, frameCount = 0; i < totalFrameCount; ++i ) { if (frameStart + frameCount <= i && iK < keyFrameCount) { var frame = this._actionFrames[iK]; frameStart = frame.frameStart; if (iK == keyFrameCount - 1) { frameCount = (int)this._animation.frameCount - frameStart; } else { frameCount = this._actionFrames[iK + 1].frameStart - frameStart; } this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameOffset + iK] = (ushort)(this._ParseCacheActionFrame(frame) - (int)this._animation.frameOffset); iK++; } frameIndices[timeline.frameIndicesOffset + i] = (uint)iK - 1; } } this._timeline = null; // this._actionFrames.Clear(); } this._animation = null; // return animation; } protected TimelineData _ParseTimeline( Dictionary rawData, List rawFrames, string framesKey, TimelineType type, bool addIntOffset, bool addFloatOffset, uint frameValueCount, Func, int, int, int> frameParser) { if (rawData != null && framesKey.Length > 0 && rawData.ContainsKey(framesKey)) { rawFrames = rawData[framesKey] as List; } if (rawFrames == null) { return null; } var keyFrameCount = rawFrames.Count; if (keyFrameCount == 0) { return null; } var frameIntArrayLength = this._frameIntArray.Count; var frameFloatArrayLength = this._frameFloatArray.Count; var timeline = BaseObject.BorrowObject(); var timelineOffset = this._timelineArray.Count; this._timelineArray.ResizeList(this._timelineArray.Count + 1 + 1 + 1 + 1 + 1 + keyFrameCount, (ushort)0); if (rawData != null) { this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineScale] = (ushort)Math.Round(ObjectDataParser._GetNumber(rawData, ObjectDataParser.SCALE, 1.0f) * 100); this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineOffset] = (ushort)Math.Round(ObjectDataParser._GetNumber(rawData, ObjectDataParser.OFFSET, 0.0f) * 100); } else { this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineScale] = 100; this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineOffset] = 0; } this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineKeyFrameCount] = (ushort)keyFrameCount; this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineFrameValueCount] = (ushort)frameValueCount; if (addIntOffset) { this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineFrameValueOffset] = (ushort)(frameIntArrayLength - this._animation.frameIntOffset); } else if (addFloatOffset) { this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineFrameValueOffset] = (ushort)(frameFloatArrayLength - (int)this._animation.frameFloatOffset); } else { this._timelineArray[timelineOffset + (int)BinaryOffset.TimelineFrameValueOffset] = 0; } this._timeline = timeline; this._timeline.type = type; this._timeline.offset = (uint)timelineOffset; if (keyFrameCount == 1) { // Only one frame. timeline.frameIndicesOffset = -1; int frameParserResult = frameParser(rawFrames[0] as Dictionary, 0, 0); this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameOffset + 0] = (ushort)(frameParserResult - this._animation.frameOffset); } else { var frameIndices = this._data.frameIndices; var totalFrameCount = this._animation.frameCount + 1; // One more frame than animation. timeline.frameIndicesOffset = frameIndices.Count; frameIndices.ResizeList(frameIndices.Count + (int)totalFrameCount, uint.MinValue); for ( int i = 0, iK = 0, frameStart = 0, frameCount = 0; i < totalFrameCount; ++i ) { if (frameStart + frameCount <= i && iK < keyFrameCount) { var rawFrame = rawFrames[iK] as Dictionary; frameStart = i; frameCount = ObjectDataParser._GetNumber(rawFrame, ObjectDataParser.DURATION, 1); if (iK == keyFrameCount - 1) { frameCount = (int)this._animation.frameCount - frameStart; } int frameParserResult = frameParser(rawFrame, frameStart, frameCount); this._timelineArray[(int)timeline.offset + (int)BinaryOffset.TimelineFrameOffset + iK] = (ushort)(frameParserResult - this._animation.frameOffset); iK++; } frameIndices[timeline.frameIndicesOffset + i] = (uint)iK - 1; } } this._timeline = null; // return timeline; } protected void _ParseBoneTimeline(Dictionary rawData) { var bone = this._armature.GetBone(ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, "")); if (bone == null) { return; } this._bone = bone; this._slot = this._armature.GetSlot(this._bone.name); if (rawData.ContainsKey(ObjectDataParser.TRANSLATE_FRAME)) { var timeline = this._ParseTimeline( rawData, null, ObjectDataParser.TRANSLATE_FRAME, TimelineType.BoneTranslate, false, true, 2, this._ParseBoneTranslateFrame ); if (timeline != null) { this._animation.AddBoneTimeline(bone, timeline); } } if (rawData.ContainsKey(ObjectDataParser.ROTATE_FRAME)) { var timeline = this._ParseTimeline( rawData, null, ObjectDataParser.ROTATE_FRAME, TimelineType.BoneRotate, false, true, 2, this._ParseBoneRotateFrame ); if (timeline != null) { this._animation.AddBoneTimeline(bone, timeline); } } if (rawData.ContainsKey(ObjectDataParser.SCALE_FRAME)) { var timeline = this._ParseTimeline( rawData, null, ObjectDataParser.SCALE_FRAME, TimelineType.BoneScale, false, true, 2, this._ParseBoneScaleFrame ); if (timeline != null) { this._animation.AddBoneTimeline(bone, timeline); } } if (rawData.ContainsKey(ObjectDataParser.FRAME)) { var timeline = this._ParseTimeline( rawData, null, ObjectDataParser.FRAME, TimelineType.BoneAll, false, true, 6, this._ParseBoneAllFrame ); if (timeline != null) { this._animation.AddBoneTimeline(bone, timeline); } } this._bone = null; // this._slot = null; // } protected void _ParseSlotTimeline(Dictionary rawData) { var slot = this._armature.GetSlot(ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, "")); if (slot == null) { return; } this._slot = slot; // Display timeline. TimelineData displayTimeline = null; if (rawData.ContainsKey(ObjectDataParser.DISPLAY_FRAME)) { displayTimeline = this._ParseTimeline( rawData, null, ObjectDataParser.DISPLAY_FRAME, TimelineType.SlotDisplay, false, false, 0, this._ParseSlotDisplayFrame ); } else { displayTimeline = this._ParseTimeline( rawData, null, ObjectDataParser.FRAME, TimelineType.SlotDisplay, false, false, 0, this._ParseSlotDisplayFrame ); } if (displayTimeline != null) { this._animation.AddSlotTimeline(slot, displayTimeline); } TimelineData colorTimeline = null; if (rawData.ContainsKey(ObjectDataParser.COLOR_FRAME)) { colorTimeline = this._ParseTimeline( rawData, null, ObjectDataParser.COLOR_FRAME, TimelineType.SlotColor, true, false, 1, this._ParseSlotColorFrame ); } else { colorTimeline = this._ParseTimeline( rawData, null, ObjectDataParser.FRAME, TimelineType.SlotColor, true, false, 1, this._ParseSlotColorFrame ); } if (colorTimeline != null) { this._animation.AddSlotTimeline(slot, colorTimeline); } this._slot = null; // } protected int _ParseFrame(Dictionary rawData, int frameStart, int frameCount) { //rawData没用到 var frameOffset = this._frameArray.Count; this._frameArray.ResizeList(this._frameArray.Count + 1, (short)0); this._frameArray[(int)frameOffset + (int)BinaryOffset.FramePosition] = (short)frameStart; return frameOffset; } protected int _ParseTweenFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseFrame(rawData, frameStart, frameCount); if (frameCount > 0) { if (rawData.ContainsKey(ObjectDataParser.CURVE)) { var sampleCount = frameCount + 1; this._helpArray.ResizeList(sampleCount, 0.0f); var rawCurve = rawData[ObjectDataParser.CURVE] as List; var curve = new float[rawCurve.Count]; for (int i = 0, l = rawCurve.Count; i < l; ++i) { curve[i] = Convert.ToSingle(rawCurve[i]); } this._SamplingEasingCurve(curve, this._helpArray); this._frameArray.ResizeList(this._frameArray.Count + 1 + 1 + this._helpArray.Count, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.Curve; this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenEasingOrCurveSampleCount] = (short)sampleCount; for (var i = 0; i < sampleCount; ++i) { this._frameArray[frameOffset + (int)BinaryOffset.FrameCurveSamples + i] = (short)Math.Round(this._helpArray[i] * 10000.0f); } } else { var noTween = -2.0f; var tweenEasing = noTween; if (rawData.ContainsKey(ObjectDataParser.TWEEN_EASING)) { tweenEasing = ObjectDataParser._GetNumber(rawData, ObjectDataParser.TWEEN_EASING, noTween); } if (tweenEasing == noTween) { this._frameArray.ResizeList(this._frameArray.Count + 1, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.None; } else if (tweenEasing == 0.0f) { this._frameArray.ResizeList(this._frameArray.Count + 1, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.Line; } else if (tweenEasing < 0.0f) { this._frameArray.ResizeList(this._frameArray.Count + 1 + 1, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.QuadIn; this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenEasingOrCurveSampleCount] = (short)Math.Round(-tweenEasing * 100.0f); } else if (tweenEasing <= 1.0f) { this._frameArray.ResizeList(this._frameArray.Count + 1 + 1, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.QuadOut; this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenEasingOrCurveSampleCount] = (short)Math.Round(tweenEasing * 100.0f); } else { this._frameArray.ResizeList(this._frameArray.Count + 1 + 1, (short)0); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.QuadInOut; this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenEasingOrCurveSampleCount] = (short)Math.Round(tweenEasing * 100.0f - 100.0f); } } } else { this._frameArray.ResizeList(this._frameArray.Count + 1); this._frameArray[frameOffset + (int)BinaryOffset.FrameTweenType] = (int)TweenType.None; } return frameOffset; } private int _ParseZOrderFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseFrame(rawData, frameStart, frameCount); if (rawData.ContainsKey(ObjectDataParser.Z_ORDER)) { var rawZOrder = (rawData[ObjectDataParser.Z_ORDER] as List).ConvertAll(Convert.ToInt32); if (rawZOrder.Count > 0) { int slotCount = this._armature.sortedSlots.Count; int[] unchanged = new int[slotCount - rawZOrder.Count / 2]; int[] zOrders = new int[slotCount]; for (var i = 0; i < unchanged.Length; ++i) { unchanged[i] = 0; } for (var i = 0; i < slotCount; ++i) { zOrders[i] = -1; } var originalIndex = 0; var unchangedIndex = 0; for (int i = 0, l = rawZOrder.Count; i < l; i += 2) { var slotIndex = rawZOrder[i]; var zOrderOffset = rawZOrder[i + 1]; while (originalIndex != slotIndex) { unchanged[unchangedIndex++] = originalIndex++; } //兼容错误格式zorder索引负值 if (originalIndex + zOrderOffset >= 0) { var tempIndex = originalIndex + zOrderOffset; zOrders[tempIndex] = originalIndex++; } else { originalIndex++; } } while (originalIndex < slotCount) { unchanged[unchangedIndex++] = originalIndex++; } this._frameArray.ResizeList(this._frameArray.Count + 1 + slotCount); this._frameArray[frameOffset + 1] = (short)slotCount; var index = slotCount; while (index-- > 0) { var value = 0; if (zOrders[index] == -1) { if (unchangedIndex > 0) { value = unchanged[--unchangedIndex]; } this._frameArray[frameOffset + 2 + index] = (short)(value > 0 ? value : 0); } else { value = zOrders[index]; this._frameArray[frameOffset + 2 + index] = (short)(value > 0 ? value : 0); } } return frameOffset; } } this._frameArray.ResizeList(this._frameArray.Count + 1); this._frameArray[frameOffset + 1] = 0; return frameOffset; } protected int _ParseBoneAllFrame(Dictionary rawData, int frameStart, int frameCount) { this._helpTransform.Identity(); if (rawData.ContainsKey(ObjectDataParser.TRANSFORM)) { this._ParseTransform(rawData[ObjectDataParser.TRANSFORM] as Dictionary, this._helpTransform, 1.0f); } // Modify rotation. var rotation = this._helpTransform.rotation; if (frameStart != 0) { if (this._prevClockwise == 0) { rotation = this._prevRotation + TransformDB.NormalizeRadian(rotation - this._prevRotation); } else { if (this._prevClockwise > 0 ? rotation >= this._prevRotation : rotation <= this._prevRotation) { this._prevClockwise = this._prevClockwise > 0 ? this._prevClockwise - 1 : this._prevClockwise + 1; } rotation = this._prevRotation + rotation - this._prevRotation + TransformDB.PI_D * this._prevClockwise; } } this._prevClockwise = ObjectDataParser._GetNumber(rawData, ObjectDataParser.TWEEN_ROTATE, 0); this._prevRotation = rotation; var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var frameFloatOffset = this._frameFloatArray.Count; this._frameFloatArray.ResizeList(this._frameFloatArray.Count + 6); this._frameFloatArray[frameFloatOffset++] = this._helpTransform.x; this._frameFloatArray[frameFloatOffset++] = this._helpTransform.y; this._frameFloatArray[frameFloatOffset++] = rotation; this._frameFloatArray[frameFloatOffset++] = this._helpTransform.skew; this._frameFloatArray[frameFloatOffset++] = this._helpTransform.scaleX; this._frameFloatArray[frameFloatOffset++] = this._helpTransform.scaleY; this._ParseActionDataInFrame(rawData, frameStart, this._bone, this._slot); return frameOffset; } protected int _ParseBoneTranslateFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var frameFloatOffset = this._frameFloatArray.Count; this._frameFloatArray.ResizeList(this._frameFloatArray.Count + 2); this._frameFloatArray[frameFloatOffset++] = ObjectDataParser._GetNumber(rawData, ObjectDataParser.X, 0.0f); this._frameFloatArray[frameFloatOffset++] = ObjectDataParser._GetNumber(rawData, ObjectDataParser.Y, 0.0f); return frameOffset; } protected int _ParseBoneRotateFrame(Dictionary rawData, int frameStart, int frameCount) { // Modify rotation. var rotation = ObjectDataParser._GetNumber(rawData, ObjectDataParser.ROTATE, 0.0f) * TransformDB.DEG_RAD; if (frameStart != 0) { if (this._prevClockwise == 0) { rotation = this._prevRotation + TransformDB.NormalizeRadian(rotation - this._prevRotation); } else { if (this._prevClockwise > 0 ? rotation >= this._prevRotation : rotation <= this._prevRotation) { this._prevClockwise = this._prevClockwise > 0 ? this._prevClockwise - 1 : this._prevClockwise + 1; } rotation = this._prevRotation + rotation - this._prevRotation + TransformDB.PI_D * this._prevClockwise; } } this._prevClockwise = ObjectDataParser._GetNumber(rawData, ObjectDataParser.CLOCK_WISE, 0); this._prevRotation = rotation; var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var frameFloatOffset = this._frameFloatArray.Count; this._frameFloatArray.ResizeList(this._frameFloatArray.Count + 2); this._frameFloatArray[frameFloatOffset++] = rotation; this._frameFloatArray[frameFloatOffset++] = ObjectDataParser._GetNumber(rawData, ObjectDataParser.SKEW, 0.0f) * TransformDB.DEG_RAD; return frameOffset; } protected int _ParseBoneScaleFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var frameFloatOffset = this._frameFloatArray.Count; this._frameFloatArray.ResizeList(this._frameFloatArray.Count + 2); this._frameFloatArray[frameFloatOffset++] = ObjectDataParser._GetNumber(rawData, ObjectDataParser.X, 1.0f); this._frameFloatArray[frameFloatOffset++] = ObjectDataParser._GetNumber(rawData, ObjectDataParser.Y, 1.0f); return frameOffset; } protected int _ParseSlotDisplayFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseFrame(rawData, frameStart, frameCount); this._frameArray.ResizeList(this._frameArray.Count + 1); if (rawData.ContainsKey(ObjectDataParser.VALUE)) { this._frameArray[frameOffset + 1] = (short)ObjectDataParser._GetNumber(rawData, ObjectDataParser.VALUE, 0); } else { this._frameArray[frameOffset + 1] = (short)ObjectDataParser._GetNumber(rawData, ObjectDataParser.DISPLAY_INDEX, 0); } this._ParseActionDataInFrame(rawData, frameStart, this._slot.parent, this._slot); return frameOffset; } protected int _ParseSlotColorFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var colorOffset = -1; if (rawData.ContainsKey(ObjectDataParser.VALUE) || rawData.ContainsKey(ObjectDataParser.COLOR)) { var rawColor = rawData.ContainsKey(ObjectDataParser.VALUE) ? rawData[ObjectDataParser.VALUE] as Dictionary : rawData[ObjectDataParser.COLOR] as Dictionary; foreach (var k in rawColor) { // Detects the presence of color. this._ParseColorTransform(rawColor, this._helpColorTransform); colorOffset = this._intArray.Count; this._intArray.ResizeList(this._intArray.Count + 8); this._intArray[colorOffset++] = (short)Math.Round(this._helpColorTransform.alphaMultiplier * 100); this._intArray[colorOffset++] = (short)Math.Round(this._helpColorTransform.redMultiplier * 100); this._intArray[colorOffset++] = (short)Math.Round(this._helpColorTransform.greenMultiplier * 100); this._intArray[colorOffset++] = (short)Math.Round(this._helpColorTransform.blueMultiplier * 100); this._intArray[colorOffset++] = (short)Math.Round((float)this._helpColorTransform.alphaOffset); this._intArray[colorOffset++] = (short)Math.Round((float)this._helpColorTransform.redOffset); this._intArray[colorOffset++] = (short)Math.Round((float)this._helpColorTransform.greenOffset); this._intArray[colorOffset++] = (short)Math.Round((float)this._helpColorTransform.blueOffset); colorOffset -= 8; break; } } if (colorOffset < 0) { if (this._defaultColorOffset < 0) { this._defaultColorOffset = colorOffset = this._intArray.Count; this._intArray.ResizeList(this._intArray.Count + 8); this._intArray[colorOffset++] = 100; this._intArray[colorOffset++] = 100; this._intArray[colorOffset++] = 100; this._intArray[colorOffset++] = 100; this._intArray[colorOffset++] = 0; this._intArray[colorOffset++] = 0; this._intArray[colorOffset++] = 0; this._intArray[colorOffset++] = 0; } colorOffset = this._defaultColorOffset; } var frameIntOffset = this._frameIntArray.Count; this._frameIntArray.ResizeList(this._frameIntArray.Count + 1); this._frameIntArray[frameIntOffset] = (short)colorOffset; return frameOffset; } protected int _ParseSlotFFDFrame(Dictionary rawData, int frameStart, int frameCount) { var frameFloatOffset = this._frameFloatArray.Count; var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var rawVertices = rawData.ContainsKey(ObjectDataParser.VERTICES) ? (rawData[ObjectDataParser.VERTICES] as List).ConvertAll(Convert.ToSingle) : null; var offset = ObjectDataParser._GetNumber(rawData, ObjectDataParser.OFFSET, 0); // uint var vertexCount = this._intArray[this._mesh.vertices.offset + (int)BinaryOffset.MeshVertexCount]; var meshName = this._mesh.parent.name + "_" + this._slot.name + "_" + this._mesh.name; var weight = this._mesh.vertices.weight; var x = 0.0f; var y = 0.0f; var iB = 0; var iV = 0; if (weight != null) { var rawSlotPose = this._weightSlotPose[meshName]; this._helpMatrixA.CopyFromArray(rawSlotPose, 0); this._frameFloatArray.ResizeList(this._frameFloatArray.Count + (weight.count * 2)); iB = weight.offset + (int)BinaryOffset.WeigthBoneIndices + weight.bones.Count; } else { this._frameFloatArray.ResizeList(this._frameFloatArray.Count + (vertexCount * 2)); } for (var i = 0; i < vertexCount * 2; i += 2) { if (rawVertices == null) { // Fill 0. x = 0.0f; y = 0.0f; } else { if (i < offset || i - offset >= rawVertices.Count) { x = 0.0f; } else { x = rawVertices[i - offset]; } if (i + 1 < offset || i + 1 - offset >= rawVertices.Count) { y = 0.0f; } else { y = rawVertices[i + 1 - offset]; } } if (weight != null) { // If mesh is skinned, transform point by bone bind pose. var rawBonePoses = this._weightBonePoses[meshName]; var vertexBoneCount = this._intArray[iB++]; this._helpMatrixA.TransformPoint(x, y, this._helpPoint, true); x = this._helpPoint.x; y = this._helpPoint.y; for (var j = 0; j < vertexBoneCount; ++j) { var boneIndex = this._intArray[iB++]; this._helpMatrixB.CopyFromArray(rawBonePoses, boneIndex * 7 + 1); this._helpMatrixB.Invert(); this._helpMatrixB.TransformPoint(x, y, this._helpPoint, true); this._frameFloatArray[frameFloatOffset + iV++] = this._helpPoint.x; this._frameFloatArray[frameFloatOffset + iV++] = this._helpPoint.y; } } else { this._frameFloatArray[frameFloatOffset + i] = x; this._frameFloatArray[frameFloatOffset + i + 1] = y; } } if (frameStart == 0) { var frameIntOffset = this._frameIntArray.Count; this._frameIntArray.ResizeList(this._frameIntArray.Count + 1 + 1 + 1 + 1 + 1); this._frameIntArray[frameIntOffset + (int)BinaryOffset.DeformVertexOffset] = (short)this._mesh.vertices.offset; this._frameIntArray[frameIntOffset + (int)BinaryOffset.DeformCount] = (short)(this._frameFloatArray.Count - frameFloatOffset); this._frameIntArray[frameIntOffset + (int)BinaryOffset.DeformValueCount] = (short)(this._frameFloatArray.Count - frameFloatOffset); this._frameIntArray[frameIntOffset + (int)BinaryOffset.DeformValueOffset] = 0; this._frameIntArray[frameIntOffset + (int)BinaryOffset.DeformFloatOffset] = (short)(frameFloatOffset - this._animation.frameFloatOffset);// fixed ffd timeline mesh bound this._timelineArray[(int)this._timeline.offset + (int)BinaryOffset.TimelineFrameValueCount] = (ushort)(frameIntOffset - this._animation.frameIntOffset); } return frameOffset; } protected int _ParseIKConstraintFrame(Dictionary rawData, int frameStart, int frameCount) { var frameOffset = this._ParseTweenFrame(rawData, frameStart, frameCount); var frameIntOffset = this._frameIntArray.Count; this._frameIntArray.ResizeList(this._frameIntArray.Count + 2); this._frameIntArray[frameIntOffset++] = (short)(ObjectDataParser._GetBoolean(rawData, ObjectDataParser.BEND_POSITIVE, true) ? 1 : 0); this._frameIntArray[frameIntOffset++] = (short)Math.Round(ObjectDataParser._GetNumber(rawData, ObjectDataParser.WEIGHT, 1.0f) * 100.0); return frameOffset; } protected List _ParseActionData(object rawData, ActionType type, BoneData bone = null, SlotData slot = null) { var actions = new List(); if (rawData is string) { var action = BaseObject.BorrowObject(); action.type = type; action.name = (string)rawData; action.bone = bone; action.slot = slot; actions.Add(action); } else if (rawData is IList) { var actionsObject = rawData as List; foreach (Dictionary rawAction in actionsObject) { var action = BaseObject.BorrowObject(); if (rawAction.ContainsKey(ObjectDataParser.GOTO_AND_PLAY)) { action.type = ActionType.Play; action.name = ObjectDataParser._GetString(rawAction, ObjectDataParser.GOTO_AND_PLAY, ""); } else { if (rawAction.ContainsKey(ObjectDataParser.TYPE) && rawAction[ObjectDataParser.TYPE] is string) { action.type = (ActionType)ObjectDataParser._GetActionType((string)rawAction[ObjectDataParser.TYPE]); } else { action.type = (ActionType)ObjectDataParser._GetNumber(rawAction, ObjectDataParser.TYPE, (uint)type); } action.name = ObjectDataParser._GetString(rawAction, ObjectDataParser.NAME, ""); } if (rawAction.ContainsKey(ObjectDataParser.BONE)) { var boneName = ObjectDataParser._GetString(rawAction, ObjectDataParser.BONE, ""); action.bone = this._armature.GetBone(boneName); } else { action.bone = bone; } if (rawAction.ContainsKey(ObjectDataParser.SLOT)) { var slotName = ObjectDataParser._GetString(rawAction, ObjectDataParser.SLOT, ""); action.slot = this._armature.GetSlot(slotName); } else { action.slot = slot; } UserData userData = null; if (rawAction.ContainsKey(ObjectDataParser.INTS)) { if (userData == null) { userData = BaseObject.BorrowObject(); } var rawInts = (rawAction[ObjectDataParser.INTS] as List).ConvertAll(Convert.ToInt32); foreach (var rawValue in rawInts) { userData.AddInt(rawValue); } } if (rawAction.ContainsKey(ObjectDataParser.FLOATS)) { if (userData == null) { userData = BaseObject.BorrowObject(); } var rawFloats = (rawAction[ObjectDataParser.FLOATS] as List).ConvertAll(Convert.ToSingle); foreach (var rawValue in rawFloats) { userData.AddFloat(rawValue); } } if (rawAction.ContainsKey(ObjectDataParser.STRINGS)) { if (userData == null) { userData = BaseObject.BorrowObject(); } var rawStrings = (rawAction[ObjectDataParser.STRINGS] as List).ConvertAll(Convert.ToString); foreach (var rawValue in rawStrings) { userData.AddString(rawValue); } } action.data = userData; actions.Add(action); } } return actions; } protected void _ParseTransform(Dictionary rawData, TransformDB transform, float scale) { transform.x = ObjectDataParser._GetNumber(rawData, ObjectDataParser.X, 0.0f) * scale; transform.y = ObjectDataParser._GetNumber(rawData, ObjectDataParser.Y, 0.0f) * scale; if (rawData.ContainsKey(ObjectDataParser.ROTATE) || rawData.ContainsKey(ObjectDataParser.SKEW)) { transform.rotation = TransformDB.NormalizeRadian(ObjectDataParser._GetNumber(rawData, ObjectDataParser.ROTATE, 0.0f) * TransformDB.DEG_RAD); transform.skew = TransformDB.NormalizeRadian(ObjectDataParser._GetNumber(rawData, ObjectDataParser.SKEW, 0.0f) * TransformDB.DEG_RAD); } else if (rawData.ContainsKey(ObjectDataParser.SKEW_X) || rawData.ContainsKey(ObjectDataParser.SKEW_Y)) { transform.rotation = TransformDB.NormalizeRadian(ObjectDataParser._GetNumber(rawData, ObjectDataParser.SKEW_Y, 0.0f) * TransformDB.DEG_RAD); transform.skew = TransformDB.NormalizeRadian(ObjectDataParser._GetNumber(rawData, ObjectDataParser.SKEW_X, 0.0f) * TransformDB.DEG_RAD) - transform.rotation; } transform.scaleX = ObjectDataParser._GetNumber(rawData, ObjectDataParser.SCALE_X, 1.0f); transform.scaleY = ObjectDataParser._GetNumber(rawData, ObjectDataParser.SCALE_Y, 1.0f); } protected void _ParseColorTransform(Dictionary rawData, ColorTransform color) { color.alphaMultiplier = ObjectDataParser._GetNumber(rawData, ObjectDataParser.ALPHA_MULTIPLIER, 100) * 0.01f; color.redMultiplier = ObjectDataParser._GetNumber(rawData, ObjectDataParser.RED_MULTIPLIER, 100) * 0.01f; color.greenMultiplier = ObjectDataParser._GetNumber(rawData, ObjectDataParser.GREEN_MULTIPLIER, 100) * 0.01f; color.blueMultiplier = ObjectDataParser._GetNumber(rawData, ObjectDataParser.BLUE_MULTIPLIER, 100) * 0.01f; color.alphaOffset = ObjectDataParser._GetNumber(rawData, ObjectDataParser.ALPHA_OFFSET, 0); color.redOffset = ObjectDataParser._GetNumber(rawData, ObjectDataParser.RED_OFFSET, 0); color.greenOffset = ObjectDataParser._GetNumber(rawData, ObjectDataParser.GREEN_OFFSET, 0); color.blueOffset = ObjectDataParser._GetNumber(rawData, ObjectDataParser.BLUE_OFFSET, 0); } protected virtual void _ParseArray(Dictionary rawData) { this._intArray.Clear(); this._floatArray.Clear(); this._frameIntArray.Clear(); this._frameFloatArray.Clear(); this._frameArray.Clear(); this._timelineArray.Clear(); } protected void _ModifyArray() { // Align. if ((this._intArray.Count % Helper.INT16_SIZE) != 0) { this._intArray.Add(0); } if ((this._frameIntArray.Count % Helper.INT16_SIZE) != 0) { this._frameIntArray.Add(0); } if ((this._frameArray.Count % Helper.INT16_SIZE) != 0) { this._frameArray.Add(0); } if ((this._timelineArray.Count % Helper.UINT16_SIZE) != 0) { this._timelineArray.Add(0); } var l1 = this._intArray.Count * Helper.INT16_SIZE; var l2 = this._floatArray.Count * Helper.FLOAT_SIZE; var l3 = this._frameIntArray.Count * Helper.INT16_SIZE; var l4 = this._frameFloatArray.Count * Helper.FLOAT_SIZE; var l5 = this._frameArray.Count * Helper.INT16_SIZE; var l6 = this._timelineArray.Count * Helper.UINT16_SIZE; var lTotal = l1 + l2 + l3 + l4 + l5 + l6; using (MemoryStream ms = new MemoryStream(lTotal)) using (BinaryDataWriter writer = new BinaryDataWriter(ms)) using (BinaryDataReader reader = new BinaryDataReader(ms)) { //ToWrite writer.Write(_intArray.ToArray()); writer.Write(_floatArray.ToArray()); writer.Write(_frameIntArray.ToArray()); writer.Write(_frameFloatArray.ToArray()); writer.Write(_frameArray.ToArray()); writer.Write(_timelineArray.ToArray()); ms.Position = 0; //ToRead this._data.binary = ms.GetBuffer(); this._data.intArray = reader.ReadInt16s(0, this._intArray.Count); this._data.floatArray = reader.ReadSingles(0, this._floatArray.Count); this._data.frameIntArray = reader.ReadInt16s(0, this._frameIntArray.Count); this._data.frameFloatArray = reader.ReadSingles(0, this._frameFloatArray.Count); this._data.frameArray = reader.ReadInt16s(0, this._frameArray.Count); this._data.timelineArray = reader.ReadUInt16s(0, this._timelineArray.Count); ms.Close(); } this._defaultColorOffset = -1; } public override DragonBonesData ParseDragonBonesData(object rawObj, float scale = 1.0f) { var rawData = rawObj as Dictionary; Helper.Assert(rawData != null, "Data error."); var version = ObjectDataParser._GetString(rawData, ObjectDataParser.VERSION, ""); var compatibleVersion = ObjectDataParser._GetString(rawData, ObjectDataParser.COMPATIBLE_VERSION, ""); if (ObjectDataParser.DATA_VERSIONS.IndexOf(version) >= 0 || ObjectDataParser.DATA_VERSIONS.IndexOf(compatibleVersion) >= 0) { var data = BaseObject.BorrowObject(); data.version = version; data.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); data.frameRate = ObjectDataParser._GetNumber(rawData, ObjectDataParser.FRAME_RATE, (uint)24); if (data.frameRate == 0) { // Data error. data.frameRate = 24; } if (rawData.ContainsKey(ObjectDataParser.ARMATURE)) { this._data = data; this._ParseArray(rawData); var rawArmatures = rawData[ObjectDataParser.ARMATURE] as List; foreach (Dictionary rawArmature in rawArmatures) { data.AddArmature(this._ParseArmature(rawArmature, scale)); } if (this._data.binary == null) { this._ModifyArray(); } if (rawData.ContainsKey(ObjectDataParser.STAGE)) { data.stage = data.GetArmature(ObjectDataParser._GetString(rawData, ObjectDataParser.STAGE, "")); } else if (data.armatureNames.Count > 0) { data.stage = data.GetArmature(data.armatureNames[0]); } this._data = null; } if (rawData.ContainsKey(ObjectDataParser.TEXTURE_ATLAS)) { this._rawTextureAtlases = rawData[ObjectDataParser.TEXTURE_ATLAS] as List; } return data; } else { Helper.Assert( false, "Nonsupport data version: " + version + "\n" + "Please convert DragonBones data to support version.\n" + "Read more: https://github.com/DragonBones/Tools/" ); } return null; } public override bool ParseTextureAtlasData(object rawObj, TextureAtlasData textureAtlasData, float scale = 1.0f) { var rawData = rawObj as Dictionary; if (rawData == null) { if (this._rawTextureAtlases == null || this._rawTextureAtlases.Count == 0) { return false; } var rawTextureAtlas = this._rawTextureAtlases[this._rawTextureAtlasIndex++]; this.ParseTextureAtlasData(rawTextureAtlas, textureAtlasData, scale); if (this._rawTextureAtlasIndex >= this._rawTextureAtlases.Count) { this._rawTextureAtlasIndex = 0; this._rawTextureAtlases = null; } return true; } // Texture format. textureAtlasData.width = ObjectDataParser._GetNumber(rawData, ObjectDataParser.WIDTH, uint.MinValue); textureAtlasData.height = ObjectDataParser._GetNumber(rawData, ObjectDataParser.HEIGHT, uint.MinValue); textureAtlasData.scale = scale == 1.0f ? (1.0f / ObjectDataParser._GetNumber(rawData, ObjectDataParser.SCALE, 1.0f)) : scale; textureAtlasData.name = ObjectDataParser._GetString(rawData, ObjectDataParser.NAME, ""); textureAtlasData.imagePath = ObjectDataParser._GetString(rawData, ObjectDataParser.IMAGE_PATH, ""); if (rawData.ContainsKey(ObjectDataParser.SUB_TEXTURE)) { var rawTextures = rawData[ObjectDataParser.SUB_TEXTURE] as List; for (int i = 0, l = rawTextures.Count; i < l; ++i) { var rawTexture = rawTextures[i] as Dictionary; var textureData = textureAtlasData.CreateTexture(); textureData.rotated = ObjectDataParser._GetBoolean(rawTexture, ObjectDataParser.ROTATED, false); textureData.name = ObjectDataParser._GetString(rawTexture, ObjectDataParser.NAME, ""); textureData.region.x = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.X, 0.0f); textureData.region.y = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.Y, 0.0f); textureData.region.width = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.WIDTH, 0.0f); textureData.region.height = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.HEIGHT, 0.0f); var frameWidth = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.FRAME_WIDTH, -1.0f); var frameHeight = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.FRAME_HEIGHT, -1.0f); if (frameWidth > 0.0 && frameHeight > 0.0) { textureData.frame = TextureData.CreateRectangle(); textureData.frame.x = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.FRAME_X, 0.0f); textureData.frame.y = ObjectDataParser._GetNumber(rawTexture, ObjectDataParser.FRAME_Y, 0.0f); textureData.frame.width = frameWidth; textureData.frame.height = frameHeight; } textureAtlasData.AddTexture(textureData); } } return true; } } /// /// class ActionFrame { public int frameStart = 0; public readonly List actions = new List(); } }