@pixi-spine/runtime-3.8
Version:
Pixi runtime for spine 3.8 models
806 lines (802 loc) • 36.7 kB
JavaScript
'use strict';
var Event = require('./Event.js');
var SkeletonData = require('./SkeletonData.js');
var SlotData = require('./SlotData.js');
var BoneData = require('./BoneData.js');
var IkConstraintData = require('./IkConstraintData.js');
var TransformConstraintData = require('./TransformConstraintData.js');
var PathConstraintData = require('./PathConstraintData.js');
var Skin = require('./Skin.js');
var EventData = require('./EventData.js');
var Animation = require('./Animation.js');
var base = require('@pixi-spine/base');
var core = require('@pixi/core');
class SkeletonJson {
constructor(attachmentLoader) {
this.scale = 1;
this.linkedMeshes = new Array();
this.attachmentLoader = attachmentLoader;
}
readSkeletonData(json) {
const scale = this.scale;
const skeletonData = new SkeletonData.SkeletonData();
const root = typeof json === "string" ? JSON.parse(json) : json;
const skeletonMap = root.skeleton;
if (skeletonMap != null) {
skeletonData.hash = skeletonMap.hash;
skeletonData.version = skeletonMap.spine;
if (skeletonData.version.substr(0, 3) !== "3.8") {
const error = `Spine 3.8 loader cant load version ${skeletonMap.spine}. Please configure your pixi-spine bundle`;
console.error(error);
}
if (skeletonData.version === "3.8.75") {
const error = `Unsupported skeleton data, 3.8.75 is deprecated, please export with a newer version of Spine.`;
console.error(error);
}
skeletonData.x = skeletonMap.x;
skeletonData.y = skeletonMap.y;
skeletonData.width = skeletonMap.width;
skeletonData.height = skeletonMap.height;
skeletonData.fps = skeletonMap.fps;
skeletonData.imagesPath = skeletonMap.images;
}
if (root.bones) {
for (let i = 0; i < root.bones.length; i++) {
const boneMap = root.bones[i];
let parent = null;
const parentName = this.getValue(boneMap, "parent", null);
if (parentName != null) {
parent = skeletonData.findBone(parentName);
if (parent == null)
throw new Error(`Parent bone not found: ${parentName}`);
}
const data = new BoneData.BoneData(skeletonData.bones.length, boneMap.name, parent);
data.length = this.getValue(boneMap, "length", 0) * scale;
data.x = this.getValue(boneMap, "x", 0) * scale;
data.y = this.getValue(boneMap, "y", 0) * scale;
data.rotation = this.getValue(boneMap, "rotation", 0);
data.scaleX = this.getValue(boneMap, "scaleX", 1);
data.scaleY = this.getValue(boneMap, "scaleY", 1);
data.shearX = this.getValue(boneMap, "shearX", 0);
data.shearY = this.getValue(boneMap, "shearY", 0);
data.transformMode = SkeletonJson.transformModeFromString(this.getValue(boneMap, "transform", "normal"));
data.skinRequired = this.getValue(boneMap, "skin", false);
skeletonData.bones.push(data);
}
}
if (root.slots) {
for (let i = 0; i < root.slots.length; i++) {
const slotMap = root.slots[i];
const slotName = slotMap.name;
const boneName = slotMap.bone;
const boneData = skeletonData.findBone(boneName);
if (boneData == null)
throw new Error(`Slot bone not found: ${boneName}`);
const data = new SlotData.SlotData(skeletonData.slots.length, slotName, boneData);
const color = this.getValue(slotMap, "color", null);
if (color != null)
data.color.setFromString(color);
const dark = this.getValue(slotMap, "dark", null);
if (dark != null) {
data.darkColor = new base.Color(1, 1, 1, 1);
data.darkColor.setFromString(dark);
}
data.attachmentName = this.getValue(slotMap, "attachment", null);
data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal"));
skeletonData.slots.push(data);
}
}
if (root.ik) {
for (let i = 0; i < root.ik.length; i++) {
const constraintMap = root.ik[i];
const data = new IkConstraintData.IkConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
data.skinRequired = this.getValue(constraintMap, "skin", false);
for (let j = 0; j < constraintMap.bones.length; j++) {
const boneName = constraintMap.bones[j];
const bone = skeletonData.findBone(boneName);
if (bone == null)
throw new Error(`IK bone not found: ${boneName}`);
data.bones.push(bone);
}
const targetName = constraintMap.target;
data.target = skeletonData.findBone(targetName);
if (data.target == null)
throw new Error(`IK target bone not found: ${targetName}`);
data.mix = this.getValue(constraintMap, "mix", 1);
data.softness = this.getValue(constraintMap, "softness", 0) * scale;
data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
data.compress = this.getValue(constraintMap, "compress", false);
data.stretch = this.getValue(constraintMap, "stretch", false);
data.uniform = this.getValue(constraintMap, "uniform", false);
skeletonData.ikConstraints.push(data);
}
}
if (root.transform) {
for (let i = 0; i < root.transform.length; i++) {
const constraintMap = root.transform[i];
const data = new TransformConstraintData.TransformConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
data.skinRequired = this.getValue(constraintMap, "skin", false);
for (let j = 0; j < constraintMap.bones.length; j++) {
const boneName = constraintMap.bones[j];
const bone = skeletonData.findBone(boneName);
if (bone == null)
throw new Error(`Transform constraint bone not found: ${boneName}`);
data.bones.push(bone);
}
const targetName = constraintMap.target;
data.target = skeletonData.findBone(targetName);
if (data.target == null)
throw new Error(`Transform constraint target bone not found: ${targetName}`);
data.local = this.getValue(constraintMap, "local", false);
data.relative = this.getValue(constraintMap, "relative", false);
data.offsetRotation = this.getValue(constraintMap, "rotation", 0);
data.offsetX = this.getValue(constraintMap, "x", 0) * scale;
data.offsetY = this.getValue(constraintMap, "y", 0) * scale;
data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0);
data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0);
data.offsetShearY = this.getValue(constraintMap, "shearY", 0);
data.rotateMix = this.getValue(constraintMap, "rotateMix", 1);
data.translateMix = this.getValue(constraintMap, "translateMix", 1);
data.scaleMix = this.getValue(constraintMap, "scaleMix", 1);
data.shearMix = this.getValue(constraintMap, "shearMix", 1);
skeletonData.transformConstraints.push(data);
}
}
if (root.path) {
for (let i = 0; i < root.path.length; i++) {
const constraintMap = root.path[i];
const data = new PathConstraintData.PathConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
data.skinRequired = this.getValue(constraintMap, "skin", false);
for (let j = 0; j < constraintMap.bones.length; j++) {
const boneName = constraintMap.bones[j];
const bone = skeletonData.findBone(boneName);
if (bone == null)
throw new Error(`Transform constraint bone not found: ${boneName}`);
data.bones.push(bone);
}
const targetName = constraintMap.target;
data.target = skeletonData.findSlot(targetName);
if (data.target == null)
throw new Error(`Path target slot not found: ${targetName}`);
data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent"));
data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length"));
data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent"));
data.offsetRotation = this.getValue(constraintMap, "rotation", 0);
data.position = this.getValue(constraintMap, "position", 0);
if (data.positionMode == base.PositionMode.Fixed)
data.position *= scale;
data.spacing = this.getValue(constraintMap, "spacing", 0);
if (data.spacingMode == PathConstraintData.SpacingMode.Length || data.spacingMode == PathConstraintData.SpacingMode.Fixed)
data.spacing *= scale;
data.rotateMix = this.getValue(constraintMap, "rotateMix", 1);
data.translateMix = this.getValue(constraintMap, "translateMix", 1);
skeletonData.pathConstraints.push(data);
}
}
if (root.skins) {
for (let i = 0; i < root.skins.length; i++) {
const skinMap = root.skins[i];
const skin = new Skin.Skin(skinMap.name);
if (skinMap.bones) {
for (let ii = 0; ii < skinMap.bones.length; ii++) {
const bone = skeletonData.findBone(skinMap.bones[ii]);
if (bone == null)
throw new Error(`Skin bone not found: ${skinMap.bones[i]}`);
skin.bones.push(bone);
}
}
if (skinMap.ik) {
for (let ii = 0; ii < skinMap.ik.length; ii++) {
const constraint = skeletonData.findIkConstraint(skinMap.ik[ii]);
if (constraint == null)
throw new Error(`Skin IK constraint not found: ${skinMap.ik[i]}`);
skin.constraints.push(constraint);
}
}
if (skinMap.transform) {
for (let ii = 0; ii < skinMap.transform.length; ii++) {
const constraint = skeletonData.findTransformConstraint(skinMap.transform[ii]);
if (constraint == null)
throw new Error(`Skin transform constraint not found: ${skinMap.transform[i]}`);
skin.constraints.push(constraint);
}
}
if (skinMap.path) {
for (let ii = 0; ii < skinMap.path.length; ii++) {
const constraint = skeletonData.findPathConstraint(skinMap.path[ii]);
if (constraint == null)
throw new Error(`Skin path constraint not found: ${skinMap.path[i]}`);
skin.constraints.push(constraint);
}
}
for (const slotName in skinMap.attachments) {
const slot = skeletonData.findSlot(slotName);
if (slot == null)
throw new Error(`Slot not found: ${slotName}`);
const slotMap = skinMap.attachments[slotName];
for (const entryName in slotMap) {
const attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData);
if (attachment != null)
skin.setAttachment(slot.index, entryName, attachment);
}
}
skeletonData.skins.push(skin);
if (skin.name == "default")
skeletonData.defaultSkin = skin;
}
}
for (let i = 0, n = this.linkedMeshes.length; i < n; i++) {
const linkedMesh = this.linkedMeshes[i];
const skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
if (skin == null)
throw new Error(`Skin not found: ${linkedMesh.skin}`);
const parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
if (parent == null)
throw new Error(`Parent mesh not found: ${linkedMesh.parent}`);
linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent : linkedMesh.mesh;
linkedMesh.mesh.setParentMesh(parent);
}
this.linkedMeshes.length = 0;
if (root.events) {
for (const eventName in root.events) {
const eventMap = root.events[eventName];
const data = new EventData.EventData(eventName);
data.intValue = this.getValue(eventMap, "int", 0);
data.floatValue = this.getValue(eventMap, "float", 0);
data.stringValue = this.getValue(eventMap, "string", "");
data.audioPath = this.getValue(eventMap, "audio", null);
if (data.audioPath != null) {
data.volume = this.getValue(eventMap, "volume", 1);
data.balance = this.getValue(eventMap, "balance", 0);
}
skeletonData.events.push(data);
}
}
if (root.animations) {
for (const animationName in root.animations) {
const animationMap = root.animations[animationName];
this.readAnimation(animationMap, animationName, skeletonData);
}
}
return skeletonData;
}
readAttachment(map, skin, slotIndex, name, skeletonData) {
const scale = this.scale;
name = this.getValue(map, "name", name);
const type = this.getValue(map, "type", "region");
switch (type) {
case "region": {
const path = this.getValue(map, "path", name);
const region = this.attachmentLoader.newRegionAttachment(skin, name, path);
if (region == null)
return null;
region.path = path;
region.x = this.getValue(map, "x", 0) * scale;
region.y = this.getValue(map, "y", 0) * scale;
region.scaleX = this.getValue(map, "scaleX", 1);
region.scaleY = this.getValue(map, "scaleY", 1);
region.rotation = this.getValue(map, "rotation", 0);
region.width = map.width * scale;
region.height = map.height * scale;
const color = this.getValue(map, "color", null);
if (color != null)
region.color.setFromString(color);
return region;
}
case "boundingbox": {
const box = this.attachmentLoader.newBoundingBoxAttachment(skin, name);
if (box == null)
return null;
this.readVertices(map, box, map.vertexCount << 1);
const color = this.getValue(map, "color", null);
if (color != null)
box.color.setFromString(color);
return box;
}
case "mesh":
case "linkedmesh": {
const path = this.getValue(map, "path", name);
const mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
if (mesh == null)
return null;
mesh.path = path;
const color = this.getValue(map, "color", null);
if (color != null)
mesh.color.setFromString(color);
mesh.width = this.getValue(map, "width", 0) * scale;
mesh.height = this.getValue(map, "height", 0) * scale;
const parent = this.getValue(map, "parent", null);
if (parent != null) {
this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent, this.getValue(map, "deform", true)));
return mesh;
}
const uvs = map.uvs;
this.readVertices(map, mesh, uvs.length);
mesh.triangles = map.triangles;
mesh.regionUVs = new Float32Array(uvs);
mesh.edges = this.getValue(map, "edges", null);
mesh.hullLength = this.getValue(map, "hull", 0) * 2;
return mesh;
}
case "path": {
const path = this.attachmentLoader.newPathAttachment(skin, name);
if (path == null)
return null;
path.closed = this.getValue(map, "closed", false);
path.constantSpeed = this.getValue(map, "constantSpeed", true);
const vertexCount = map.vertexCount;
this.readVertices(map, path, vertexCount << 1);
const lengths = base.Utils.newArray(vertexCount / 3, 0);
for (let i = 0; i < map.lengths.length; i++)
lengths[i] = map.lengths[i] * scale;
path.lengths = lengths;
const color = this.getValue(map, "color", null);
if (color != null)
path.color.setFromString(color);
return path;
}
case "point": {
const point = this.attachmentLoader.newPointAttachment(skin, name);
if (point == null)
return null;
point.x = this.getValue(map, "x", 0) * scale;
point.y = this.getValue(map, "y", 0) * scale;
point.rotation = this.getValue(map, "rotation", 0);
const color = this.getValue(map, "color", null);
if (color != null)
point.color.setFromString(color);
return point;
}
case "clipping": {
const clip = this.attachmentLoader.newClippingAttachment(skin, name);
if (clip == null)
return null;
const end = this.getValue(map, "end", null);
if (end != null) {
const slot = skeletonData.findSlot(end);
if (slot == null)
throw new Error(`Clipping end slot not found: ${end}`);
clip.endSlot = slot;
}
const vertexCount = map.vertexCount;
this.readVertices(map, clip, vertexCount << 1);
const color = this.getValue(map, "color", null);
if (color != null)
clip.color.setFromString(color);
return clip;
}
}
return null;
}
readVertices(map, attachment, verticesLength) {
const scale = this.scale;
attachment.worldVerticesLength = verticesLength;
const vertices = map.vertices;
if (verticesLength == vertices.length) {
const scaledVertices = base.Utils.toFloatArray(vertices);
if (scale != 1) {
for (let i = 0, n = vertices.length; i < n; i++)
scaledVertices[i] *= scale;
}
attachment.vertices = scaledVertices;
return;
}
const weights = new Array();
const bones = new Array();
for (let i = 0, n = vertices.length; i < n; ) {
const boneCount = vertices[i++];
bones.push(boneCount);
for (let nn = i + boneCount * 4; i < nn; i += 4) {
bones.push(vertices[i]);
weights.push(vertices[i + 1] * scale);
weights.push(vertices[i + 2] * scale);
weights.push(vertices[i + 3]);
}
}
attachment.bones = bones;
attachment.vertices = base.Utils.toFloatArray(weights);
}
readAnimation(map, name, skeletonData) {
const scale = this.scale;
const timelines = new Array();
let duration = 0;
if (map.slots) {
for (const slotName in map.slots) {
const slotMap = map.slots[slotName];
const slotIndex = skeletonData.findSlotIndex(slotName);
if (slotIndex == -1)
throw new Error(`Slot not found: ${slotName}`);
for (const timelineName in slotMap) {
const timelineMap = slotMap[timelineName];
if (timelineName == "attachment") {
const timeline = new Animation.AttachmentTimeline(timelineMap.length);
timeline.slotIndex = slotIndex;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
timeline.setFrame(frameIndex++, this.getValue(valueMap, "time", 0), valueMap.name);
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
} else if (timelineName == "color") {
const timeline = new Animation.ColorTimeline(timelineMap.length);
timeline.slotIndex = slotIndex;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
const color = new base.Color();
color.setFromString(valueMap.color || "ffffffff");
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), color.r, color.g, color.b, color.a);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES]);
} else if (timelineName == "twoColor") {
const timeline = new Animation.TwoColorTimeline(timelineMap.length);
timeline.slotIndex = slotIndex;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
const light = new base.Color();
const dark = new base.Color();
light.setFromString(valueMap.light);
dark.setFromString(valueMap.dark);
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.TwoColorTimeline.ENTRIES]);
} else
throw new Error(`Invalid timeline type for a slot: ${timelineName} (${slotName})`);
}
}
}
if (map.bones) {
for (const boneName in map.bones) {
const boneMap = map.bones[boneName];
const boneIndex = skeletonData.findBoneIndex(boneName);
if (boneIndex == -1)
throw new Error(`Bone not found: ${boneName}`);
for (const timelineName in boneMap) {
const timelineMap = boneMap[timelineName];
if (timelineName === "rotate") {
const timeline = new Animation.RotateTimeline(timelineMap.length);
timeline.boneIndex = boneIndex;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "angle", 0));
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.RotateTimeline.ENTRIES]);
} else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") {
let timeline = null;
let timelineScale = 1;
let defaultValue = 0;
if (timelineName === "scale") {
timeline = new Animation.ScaleTimeline(timelineMap.length);
defaultValue = 1;
} else if (timelineName === "shear")
timeline = new Animation.ShearTimeline(timelineMap.length);
else {
timeline = new Animation.TranslateTimeline(timelineMap.length);
timelineScale = scale;
}
timeline.boneIndex = boneIndex;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
const x = this.getValue(valueMap, "x", defaultValue);
const y = this.getValue(valueMap, "y", defaultValue);
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), x * timelineScale, y * timelineScale);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.TranslateTimeline.ENTRIES]);
} else
throw new Error(`Invalid timeline type for a bone: ${timelineName} (${boneName})`);
}
}
}
if (map.ik) {
for (const constraintName in map.ik) {
const constraintMap = map.ik[constraintName];
const constraint = skeletonData.findIkConstraint(constraintName);
const timeline = new Animation.IkConstraintTimeline(constraintMap.length);
timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint);
let frameIndex = 0;
for (let i = 0; i < constraintMap.length; i++) {
const valueMap = constraintMap[i];
timeline.setFrame(
frameIndex,
this.getValue(valueMap, "time", 0),
this.getValue(valueMap, "mix", 1),
this.getValue(valueMap, "softness", 0) * scale,
this.getValue(valueMap, "bendPositive", true) ? 1 : -1,
this.getValue(valueMap, "compress", false),
this.getValue(valueMap, "stretch", false)
);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.IkConstraintTimeline.ENTRIES]);
}
}
if (map.transform) {
for (const constraintName in map.transform) {
const constraintMap = map.transform[constraintName];
const constraint = skeletonData.findTransformConstraint(constraintName);
const timeline = new Animation.TransformConstraintTimeline(constraintMap.length);
timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint);
let frameIndex = 0;
for (let i = 0; i < constraintMap.length; i++) {
const valueMap = constraintMap[i];
timeline.setFrame(
frameIndex,
this.getValue(valueMap, "time", 0),
this.getValue(valueMap, "rotateMix", 1),
this.getValue(valueMap, "translateMix", 1),
this.getValue(valueMap, "scaleMix", 1),
this.getValue(valueMap, "shearMix", 1)
);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.TransformConstraintTimeline.ENTRIES]);
}
}
if (map.path) {
for (const constraintName in map.path) {
const constraintMap = map.path[constraintName];
const index = skeletonData.findPathConstraintIndex(constraintName);
if (index == -1)
throw new Error(`Path constraint not found: ${constraintName}`);
const data = skeletonData.pathConstraints[index];
for (const timelineName in constraintMap) {
const timelineMap = constraintMap[timelineName];
if (timelineName === "position" || timelineName === "spacing") {
let timeline = null;
let timelineScale = 1;
if (timelineName === "spacing") {
timeline = new Animation.PathConstraintSpacingTimeline(timelineMap.length);
if (data.spacingMode == PathConstraintData.SpacingMode.Length || data.spacingMode == PathConstraintData.SpacingMode.Fixed)
timelineScale = scale;
} else {
timeline = new Animation.PathConstraintPositionTimeline(timelineMap.length);
if (data.positionMode == base.PositionMode.Fixed)
timelineScale = scale;
}
timeline.pathConstraintIndex = index;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, timelineName, 0) * timelineScale);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.PathConstraintPositionTimeline.ENTRIES]);
} else if (timelineName === "mix") {
const timeline = new Animation.PathConstraintMixTimeline(timelineMap.length);
timeline.pathConstraintIndex = index;
let frameIndex = 0;
for (let i = 0; i < timelineMap.length; i++) {
const valueMap = timelineMap[i];
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1));
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * Animation.PathConstraintMixTimeline.ENTRIES]);
}
}
}
}
if (map.deform) {
for (const deformName in map.deform) {
const deformMap = map.deform[deformName];
const skin = skeletonData.findSkin(deformName);
if (skin == null) {
if (base.settings.FAIL_ON_NON_EXISTING_SKIN) {
throw new Error(`Skin not found: ${deformName}`);
} else {
continue;
}
}
for (const slotName in deformMap) {
const slotMap = deformMap[slotName];
const slotIndex = skeletonData.findSlotIndex(slotName);
if (slotIndex == -1)
throw new Error(`Slot not found: ${slotMap.name}`);
for (const timelineName in slotMap) {
const timelineMap = slotMap[timelineName];
const attachment = skin.getAttachment(slotIndex, timelineName);
if (attachment == null)
throw new Error(`Deform attachment not found: ${timelineMap.name}`);
const weighted = attachment.bones != null;
const vertices = attachment.vertices;
const deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
const timeline = new Animation.DeformTimeline(timelineMap.length);
timeline.slotIndex = slotIndex;
timeline.attachment = attachment;
let frameIndex = 0;
for (let j = 0; j < timelineMap.length; j++) {
const valueMap = timelineMap[j];
let deform;
const verticesValue = this.getValue(valueMap, "vertices", null);
if (verticesValue == null)
deform = weighted ? base.Utils.newFloatArray(deformLength) : vertices;
else {
deform = base.Utils.newFloatArray(deformLength);
const start = this.getValue(valueMap, "offset", 0);
base.Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length);
if (scale != 1) {
for (let i = start, n = i + verticesValue.length; i < n; i++)
deform[i] *= scale;
}
if (!weighted) {
for (let i = 0; i < deformLength; i++)
deform[i] += vertices[i];
}
}
timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), deform);
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
}
}
}
}
let drawOrderNode = map.drawOrder;
if (drawOrderNode == null)
drawOrderNode = map.draworder;
if (drawOrderNode != null) {
const timeline = new Animation.DrawOrderTimeline(drawOrderNode.length);
const slotCount = skeletonData.slots.length;
let frameIndex = 0;
for (let j = 0; j < drawOrderNode.length; j++) {
const drawOrderMap = drawOrderNode[j];
let drawOrder = null;
const offsets = this.getValue(drawOrderMap, "offsets", null);
if (offsets != null) {
drawOrder = base.Utils.newArray(slotCount, -1);
const unchanged = base.Utils.newArray(slotCount - offsets.length, 0);
let originalIndex = 0;
let unchangedIndex = 0;
for (let i = 0; i < offsets.length; i++) {
const offsetMap = offsets[i];
const slotIndex = skeletonData.findSlotIndex(offsetMap.slot);
if (slotIndex == -1)
throw new Error(`Slot not found: ${offsetMap.slot}`);
while (originalIndex != slotIndex)
unchanged[unchangedIndex++] = originalIndex++;
drawOrder[originalIndex + offsetMap.offset] = originalIndex++;
}
while (originalIndex < slotCount)
unchanged[unchangedIndex++] = originalIndex++;
for (let i = slotCount - 1; i >= 0; i--)
if (drawOrder[i] == -1)
drawOrder[i] = unchanged[--unchangedIndex];
}
timeline.setFrame(frameIndex++, this.getValue(drawOrderMap, "time", 0), drawOrder);
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
}
if (map.events) {
const timeline = new Animation.EventTimeline(map.events.length);
let frameIndex = 0;
for (let i = 0; i < map.events.length; i++) {
const eventMap = map.events[i];
const eventData = skeletonData.findEvent(eventMap.name);
if (eventData == null)
throw new Error(`Event not found: ${eventMap.name}`);
const event = new Event.Event(base.Utils.toSinglePrecision(this.getValue(eventMap, "time", 0)), eventData);
event.intValue = this.getValue(eventMap, "int", eventData.intValue);
event.floatValue = this.getValue(eventMap, "float", eventData.floatValue);
event.stringValue = this.getValue(eventMap, "string", eventData.stringValue);
if (event.data.audioPath != null) {
event.volume = this.getValue(eventMap, "volume", 1);
event.balance = this.getValue(eventMap, "balance", 0);
}
timeline.setFrame(frameIndex++, event);
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
}
if (isNaN(duration)) {
throw new Error("Error while parsing animation, duration is NaN");
}
skeletonData.animations.push(new Animation.Animation(name, timelines, duration));
}
readCurve(map, timeline, frameIndex) {
if (!map.hasOwnProperty("curve"))
return;
if (map.curve === "stepped")
timeline.setStepped(frameIndex);
else {
const curve = map.curve;
timeline.setCurve(frameIndex, curve, this.getValue(map, "c2", 0), this.getValue(map, "c3", 1), this.getValue(map, "c4", 1));
}
}
getValue(map, prop, defaultValue) {
return map[prop] !== void 0 ? map[prop] : defaultValue;
}
static blendModeFromString(str) {
str = str.toLowerCase();
if (str == "normal")
return core.BLEND_MODES.NORMAL;
if (str == "additive")
return core.BLEND_MODES.ADD;
if (str == "multiply")
return core.BLEND_MODES.MULTIPLY;
if (str == "screen")
return core.BLEND_MODES.SCREEN;
throw new Error(`Unknown blend mode: ${str}`);
}
static positionModeFromString(str) {
str = str.toLowerCase();
if (str == "fixed")
return base.PositionMode.Fixed;
if (str == "percent")
return base.PositionMode.Percent;
throw new Error(`Unknown position mode: ${str}`);
}
static spacingModeFromString(str) {
str = str.toLowerCase();
if (str == "length")
return PathConstraintData.SpacingMode.Length;
if (str == "fixed")
return PathConstraintData.SpacingMode.Fixed;
if (str == "percent")
return PathConstraintData.SpacingMode.Percent;
throw new Error(`Unknown position mode: ${str}`);
}
static rotateModeFromString(str) {
str = str.toLowerCase();
if (str == "tangent")
return base.RotateMode.Tangent;
if (str == "chain")
return base.RotateMode.Chain;
if (str == "chainscale")
return base.RotateMode.ChainScale;
throw new Error(`Unknown rotate mode: ${str}`);
}
static transformModeFromString(str) {
str = str.toLowerCase();
if (str == "normal")
return base.TransformMode.Normal;
if (str == "onlytranslation")
return base.TransformMode.OnlyTranslation;
if (str == "norotationorreflection")
return base.TransformMode.NoRotationOrReflection;
if (str == "noscale")
return base.TransformMode.NoScale;
if (str == "noscaleorreflection")
return base.TransformMode.NoScaleOrReflection;
throw new Error(`Unknown transform mode: ${str}`);
}
}
class LinkedMesh {
constructor(mesh, skin, slotIndex, parent, inheritDeform) {
this.mesh = mesh;
this.skin = skin;
this.slotIndex = slotIndex;
this.parent = parent;
this.inheritDeform = inheritDeform;
}
}
exports.SkeletonJson = SkeletonJson;
//# sourceMappingURL=SkeletonJson.js.map