mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[ts] Port of sequence attachments, see #1956
SkeletonJson parsing of sequence timelines incomplete. Untested.
This commit is contained in:
parent
7876897c59
commit
81927051ff
3
.gitignore
vendored
3
.gitignore
vendored
@ -152,3 +152,6 @@ spine-ts/spine-canvas/dist
|
|||||||
spine-ts/spine-webgl/dist
|
spine-ts/spine-webgl/dist
|
||||||
spine-ts/spine-player/dist
|
spine-ts/spine-player/dist
|
||||||
spine-ts/spine-threejs/dist
|
spine-ts/spine-threejs/dist
|
||||||
|
spine-libgdx/gradle
|
||||||
|
spine-libgdx/gradlew
|
||||||
|
spine-libgdx/gradlew.bat
|
||||||
|
|||||||
@ -241,7 +241,7 @@ export class SkeletonRenderer {
|
|||||||
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
||||||
alpha);
|
alpha);
|
||||||
|
|
||||||
region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
|
region.computeWorldVertices(slot, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
|
||||||
|
|
||||||
let vertices = this.vertices;
|
let vertices = this.vertices;
|
||||||
let uvs = region.uvs;
|
let uvs = region.uvs;
|
||||||
|
|||||||
@ -35,6 +35,8 @@ import { Slot } from "./Slot";
|
|||||||
import { TransformConstraint } from "./TransformConstraint";
|
import { TransformConstraint } from "./TransformConstraint";
|
||||||
import { StringSet, Utils, MathUtils, NumberArrayLike } from "./Utils";
|
import { StringSet, Utils, MathUtils, NumberArrayLike } from "./Utils";
|
||||||
import { Event } from "./Event";
|
import { Event } from "./Event";
|
||||||
|
import { HasTextureRegion } from "./attachments/HasTextureRegion";
|
||||||
|
import { SequenceMode, SequenceModeValues } from "./attachments/Sequence";
|
||||||
|
|
||||||
/** A simple container for a list of timelines and a name. */
|
/** A simple container for a list of timelines and a name. */
|
||||||
export class Animation {
|
export class Animation {
|
||||||
@ -146,7 +148,9 @@ const Property = {
|
|||||||
|
|
||||||
pathConstraintPosition: 16,
|
pathConstraintPosition: 16,
|
||||||
pathConstraintSpacing: 17,
|
pathConstraintSpacing: 17,
|
||||||
pathConstraintMix: 18
|
pathConstraintMix: 18,
|
||||||
|
|
||||||
|
sequence: 19
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The interface for all timelines. */
|
/** The interface for all timelines. */
|
||||||
@ -1505,7 +1509,7 @@ export class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
|||||||
let slot: Slot = skeleton.slots[this.slotIndex];
|
let slot: Slot = skeleton.slots[this.slotIndex];
|
||||||
if (!slot.bone.active) return;
|
if (!slot.bone.active) return;
|
||||||
let slotAttachment: Attachment = slot.getAttachment();
|
let slotAttachment: Attachment = slot.getAttachment();
|
||||||
if (!(slotAttachment instanceof VertexAttachment) || (<VertexAttachment>slotAttachment).deformAttachment != this.attachment) return;
|
if (!(slotAttachment instanceof VertexAttachment) || (<VertexAttachment>slotAttachment).timelineAttahment != this.attachment) return;
|
||||||
|
|
||||||
let deform: Array<number> = slot.deform;
|
let deform: Array<number> = slot.deform;
|
||||||
if (deform.length == 0) blend = MixBlend.setup;
|
if (deform.length == 0) blend = MixBlend.setup;
|
||||||
@ -1515,7 +1519,6 @@ export class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
|||||||
|
|
||||||
let frames = this.frames;
|
let frames = this.frames;
|
||||||
if (time < frames[0]) {
|
if (time < frames[0]) {
|
||||||
let vertexAttachment = <VertexAttachment>slotAttachment;
|
|
||||||
switch (blend) {
|
switch (blend) {
|
||||||
case MixBlend.setup:
|
case MixBlend.setup:
|
||||||
deform.length = 0;
|
deform.length = 0;
|
||||||
@ -1526,6 +1529,7 @@ export class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
deform.length = vertexCount;
|
deform.length = vertexCount;
|
||||||
|
let vertexAttachment = <VertexAttachment>slotAttachment;
|
||||||
if (!vertexAttachment.bones) {
|
if (!vertexAttachment.bones) {
|
||||||
// Unweighted vertex positions.
|
// Unweighted vertex positions.
|
||||||
let setupVertices = vertexAttachment.vertices;
|
let setupVertices = vertexAttachment.vertices;
|
||||||
@ -2141,3 +2145,91 @@ export class PathConstraintMixTimeline extends CurveTimeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Changes a slot's {@link Slot#getSequenceIndex()} for an attachment's {@link Sequence}. */
|
||||||
|
export class SequenceTimeline extends Timeline implements SlotTimeline {
|
||||||
|
static ENTRIES = 3;
|
||||||
|
static MODE = 1;
|
||||||
|
static DELAY = 2;
|
||||||
|
|
||||||
|
slotIndex: number;
|
||||||
|
attachment: HasTextureRegion;
|
||||||
|
|
||||||
|
constructor (frameCount: number, slotIndex: number, attachment: HasTextureRegion) {
|
||||||
|
super(frameCount, [
|
||||||
|
Property.sequence + "|" + slotIndex + "|" + attachment.sequence.id
|
||||||
|
]);
|
||||||
|
this.slotIndex = slotIndex;
|
||||||
|
this.attachment = attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFrameEntries () {
|
||||||
|
return SequenceTimeline.ENTRIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSlotIndex () {
|
||||||
|
return this.slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttachment () {
|
||||||
|
return this.attachment as unknown as Attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time, mode, index, and frame time for the specified frame.
|
||||||
|
* @param frame Between 0 and <code>frameCount</code>, inclusive.
|
||||||
|
* @param time Seconds between frames. */
|
||||||
|
setFrame (frame: number, time: number, mode: SequenceMode, index: number, delay: number) {
|
||||||
|
let frames = this.frames;
|
||||||
|
frame *= SequenceTimeline.ENTRIES;
|
||||||
|
frames[frame] = time;
|
||||||
|
frames[frame + SequenceTimeline.MODE] = mode | (index << 4);
|
||||||
|
frames[frame + SequenceTimeline.DELAY] = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply (skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection) {
|
||||||
|
let slot = skeleton.slots[this.slotIndex];
|
||||||
|
if (!slot.bone.active) return;
|
||||||
|
let slotAttachment = slot.attachment;
|
||||||
|
let attachment = this.attachment as unknown as Attachment;
|
||||||
|
if (slotAttachment != attachment) {
|
||||||
|
if (!(slotAttachment instanceof VertexAttachment)
|
||||||
|
|| (slotAttachment as VertexAttachment).timelineAttahment != attachment) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let frames = this.frames;
|
||||||
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
|
if (blend == MixBlend.setup || blend == MixBlend.first) slot.sequenceIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = Timeline.search(frames, time, SequenceTimeline.ENTRIES);
|
||||||
|
let before = frames[i];
|
||||||
|
let modeAndIndex = frames[i + SequenceTimeline.MODE];
|
||||||
|
let delay = frames[i + SequenceTimeline.DELAY];
|
||||||
|
|
||||||
|
let index = modeAndIndex >> 4, count = this.attachment.sequence.regions.length;
|
||||||
|
let mode = SequenceModeValues[modeAndIndex & 0xf];
|
||||||
|
if (mode != SequenceMode.hold) {
|
||||||
|
index += (time - before) / delay + 0.00001;
|
||||||
|
switch (mode) {
|
||||||
|
case SequenceMode.once:
|
||||||
|
index = Math.min(count - 1, index);
|
||||||
|
break;
|
||||||
|
case SequenceMode.loop:
|
||||||
|
index %= count;
|
||||||
|
break;
|
||||||
|
case SequenceMode.pingpong:
|
||||||
|
let n = (count << 1) - 2;
|
||||||
|
index %= n;
|
||||||
|
if (index >= count) index = n - index;
|
||||||
|
break;
|
||||||
|
case SequenceMode.onceReverse:
|
||||||
|
index = Math.max(count - 1 - index, 0);
|
||||||
|
break;
|
||||||
|
case SequenceMode.loopReverse:
|
||||||
|
index = count - 1 - (index % count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slot.sequenceIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,6 +36,7 @@ import { PointAttachment } from "./attachments/PointAttachment";
|
|||||||
import { RegionAttachment } from "./attachments/RegionAttachment";
|
import { RegionAttachment } from "./attachments/RegionAttachment";
|
||||||
import { Skin } from "./Skin";
|
import { Skin } from "./Skin";
|
||||||
import { TextureAtlas } from "./TextureAtlas";
|
import { TextureAtlas } from "./TextureAtlas";
|
||||||
|
import { Sequence } from "./attachments/Sequence"
|
||||||
|
|
||||||
/** An {@link AttachmentLoader} that configures attachments using texture regions from an {@link TextureAtlas}.
|
/** An {@link AttachmentLoader} that configures attachments using texture regions from an {@link TextureAtlas}.
|
||||||
*
|
*
|
||||||
@ -48,21 +49,39 @@ export class AtlasAttachmentLoader implements AttachmentLoader {
|
|||||||
this.atlas = atlas;
|
this.atlas = atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment {
|
loadSequence (name: string, basePath: string, sequence: Sequence) {
|
||||||
let region = this.atlas.findRegion(path);
|
let regions = sequence.regions;
|
||||||
if (!region) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
for (let i = 0, n = regions.length; i < n; i++) {
|
||||||
region.renderObject = region;
|
let path = sequence.getPath(basePath, i);
|
||||||
|
regions[i] = this.atlas.findRegion(path);
|
||||||
|
regions[i].renderObject = regions[i];
|
||||||
|
if (regions[i] == null) throw new Error("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newRegionAttachment (skin: Skin, name: string, path: string, sequence: Sequence): RegionAttachment {
|
||||||
let attachment = new RegionAttachment(name);
|
let attachment = new RegionAttachment(name);
|
||||||
attachment.setRegion(region);
|
if (sequence != null) {
|
||||||
|
this.loadSequence(name, path, sequence);
|
||||||
|
} else {
|
||||||
|
let region = this.atlas.findRegion(path);
|
||||||
|
if (!region) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||||
|
region.renderObject = region;
|
||||||
|
attachment.region = region;
|
||||||
|
}
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
newMeshAttachment (skin: Skin, name: string, path: string): MeshAttachment {
|
newMeshAttachment (skin: Skin, name: string, path: string, sequence: Sequence): MeshAttachment {
|
||||||
let region = this.atlas.findRegion(path);
|
|
||||||
if (!region) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
|
||||||
region.renderObject = region;
|
|
||||||
let attachment = new MeshAttachment(name);
|
let attachment = new MeshAttachment(name);
|
||||||
attachment.region = region;
|
if (sequence != null) {
|
||||||
|
this.loadSequence(name, path, sequence);
|
||||||
|
} else {
|
||||||
|
let region = this.atlas.findRegion(path);
|
||||||
|
if (!region) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||||
|
region.renderObject = region;
|
||||||
|
attachment.region = region;
|
||||||
|
}
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,11 +75,6 @@ export class Skeleton {
|
|||||||
/** The color to tint all the skeleton's attachments. */
|
/** The color to tint all the skeleton's attachments. */
|
||||||
color: Color;
|
color: Color;
|
||||||
|
|
||||||
/** Returns the skeleton's time. This can be used for tracking, such as with Slot {@link Slot#attachmentTime}.
|
|
||||||
* <p>
|
|
||||||
* See {@link #update()}. */
|
|
||||||
time = 0;
|
|
||||||
|
|
||||||
/** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale
|
/** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale
|
||||||
* inheritance. */
|
* inheritance. */
|
||||||
scaleX = 1;
|
scaleX = 1;
|
||||||
@ -603,7 +598,7 @@ export class Skeleton {
|
|||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
verticesLength = 8;
|
verticesLength = 8;
|
||||||
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
||||||
(<RegionAttachment>attachment).computeWorldVertices(slot.bone, vertices, 0, 2);
|
(<RegionAttachment>attachment).computeWorldVertices(slot, vertices, 0, 2);
|
||||||
} else if (attachment instanceof MeshAttachment) {
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
let mesh = (<MeshAttachment>attachment);
|
let mesh = (<MeshAttachment>attachment);
|
||||||
verticesLength = mesh.worldVerticesLength;
|
verticesLength = mesh.worldVerticesLength;
|
||||||
@ -623,9 +618,4 @@ export class Skeleton {
|
|||||||
offset.set(minX, minY);
|
offset.set(minX, minY);
|
||||||
size.set(maxX - minX, maxY - minY);
|
size.set(maxX - minX, maxY - minY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Increments the skeleton's {@link #time}. */
|
|
||||||
update (delta: number) {
|
|
||||||
this.time += delta;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,10 +27,12 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { Animation, Timeline, AttachmentTimeline, RGBATimeline, RGBTimeline, RGBA2Timeline, RGB2Timeline, AlphaTimeline, RotateTimeline, TranslateTimeline, TranslateXTimeline, TranslateYTimeline, ScaleTimeline, ScaleXTimeline, ScaleYTimeline, ShearTimeline, ShearXTimeline, ShearYTimeline, IkConstraintTimeline, TransformConstraintTimeline, PathConstraintPositionTimeline, PathConstraintSpacingTimeline, PathConstraintMixTimeline, DeformTimeline, DrawOrderTimeline, EventTimeline, CurveTimeline1, CurveTimeline2, CurveTimeline } from "./Animation";
|
import { Animation, Timeline, AttachmentTimeline, RGBATimeline, RGBTimeline, RGBA2Timeline, RGB2Timeline, AlphaTimeline, RotateTimeline, TranslateTimeline, TranslateXTimeline, TranslateYTimeline, ScaleTimeline, ScaleXTimeline, ScaleYTimeline, ShearTimeline, ShearXTimeline, ShearYTimeline, IkConstraintTimeline, TransformConstraintTimeline, PathConstraintPositionTimeline, PathConstraintSpacingTimeline, PathConstraintMixTimeline, DeformTimeline, DrawOrderTimeline, EventTimeline, CurveTimeline1, CurveTimeline2, CurveTimeline, SequenceTimeline } from "./Animation";
|
||||||
import { VertexAttachment, Attachment } from "./attachments/Attachment";
|
import { VertexAttachment, Attachment } from "./attachments/Attachment";
|
||||||
import { AttachmentLoader } from "./attachments/AttachmentLoader";
|
import { AttachmentLoader } from "./attachments/AttachmentLoader";
|
||||||
|
import { HasTextureRegion } from "./attachments/HasTextureRegion";
|
||||||
import { MeshAttachment } from "./attachments/MeshAttachment";
|
import { MeshAttachment } from "./attachments/MeshAttachment";
|
||||||
|
import { Sequence, SequenceModeValues } from "./attachments/Sequence";
|
||||||
import { BoneData } from "./BoneData";
|
import { BoneData } from "./BoneData";
|
||||||
import { Event } from "./Event";
|
import { Event } from "./Event";
|
||||||
import { EventData } from "./EventData";
|
import { EventData } from "./EventData";
|
||||||
@ -219,9 +221,9 @@ export class SkeletonBinary {
|
|||||||
let linkedMesh = this.linkedMeshes[i];
|
let linkedMesh = this.linkedMeshes[i];
|
||||||
let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
||||||
let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||||
linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent as VertexAttachment : linkedMesh.mesh;
|
linkedMesh.mesh.timelineAttahment = linkedMesh.inheritTimeline ? parent as VertexAttachment : linkedMesh.mesh;
|
||||||
linkedMesh.mesh.setParentMesh(parent as MeshAttachment);
|
linkedMesh.mesh.setParentMesh(parent as MeshAttachment);
|
||||||
linkedMesh.mesh.updateUVs();
|
if (linkedMesh.mesh.region != null) linkedMesh.mesh.updateRegion();
|
||||||
}
|
}
|
||||||
this.linkedMeshes.length = 0;
|
this.linkedMeshes.length = 0;
|
||||||
|
|
||||||
@ -299,9 +301,10 @@ export class SkeletonBinary {
|
|||||||
let width = input.readFloat();
|
let width = input.readFloat();
|
||||||
let height = input.readFloat();
|
let height = input.readFloat();
|
||||||
let color = input.readInt32();
|
let color = input.readInt32();
|
||||||
|
let sequence = this.readSequence(input);
|
||||||
|
|
||||||
if (!path) path = name;
|
if (!path) path = name;
|
||||||
let region = this.attachmentLoader.newRegionAttachment(skin, name, path);
|
let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||||
if (!region) return null;
|
if (!region) return null;
|
||||||
region.path = path;
|
region.path = path;
|
||||||
region.x = x * scale;
|
region.x = x * scale;
|
||||||
@ -312,7 +315,8 @@ export class SkeletonBinary {
|
|||||||
region.width = width * scale;
|
region.width = width * scale;
|
||||||
region.height = height * scale;
|
region.height = height * scale;
|
||||||
Color.rgba8888ToColor(region.color, color);
|
Color.rgba8888ToColor(region.color, color);
|
||||||
region.updateOffset();
|
region.sequence = sequence;
|
||||||
|
if (sequence == null) region.updateRegion();
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
case AttachmentType.BoundingBox: {
|
case AttachmentType.BoundingBox: {
|
||||||
@ -336,6 +340,7 @@ export class SkeletonBinary {
|
|||||||
let triangles = this.readShortArray(input);
|
let triangles = this.readShortArray(input);
|
||||||
let vertices = this.readVertices(input, vertexCount);
|
let vertices = this.readVertices(input, vertexCount);
|
||||||
let hullLength = input.readInt(true);
|
let hullLength = input.readInt(true);
|
||||||
|
let sequence = this.readSequence(input);
|
||||||
let edges = null;
|
let edges = null;
|
||||||
let width = 0, height = 0;
|
let width = 0, height = 0;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
@ -345,7 +350,7 @@ export class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!path) path = name;
|
if (!path) path = name;
|
||||||
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
|
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (!mesh) return null;
|
if (!mesh) return null;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
Color.rgba8888ToColor(mesh.color, color);
|
Color.rgba8888ToColor(mesh.color, color);
|
||||||
@ -354,8 +359,9 @@ export class SkeletonBinary {
|
|||||||
mesh.worldVerticesLength = vertexCount << 1;
|
mesh.worldVerticesLength = vertexCount << 1;
|
||||||
mesh.triangles = triangles;
|
mesh.triangles = triangles;
|
||||||
mesh.regionUVs = uvs;
|
mesh.regionUVs = uvs;
|
||||||
mesh.updateUVs();
|
if (sequence == null) mesh.updateRegion();
|
||||||
mesh.hullLength = hullLength << 1;
|
mesh.hullLength = hullLength << 1;
|
||||||
|
mesh.sequence = sequence;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.edges = edges;
|
mesh.edges = edges;
|
||||||
mesh.width = width * scale;
|
mesh.width = width * scale;
|
||||||
@ -368,7 +374,8 @@ export class SkeletonBinary {
|
|||||||
let color = input.readInt32();
|
let color = input.readInt32();
|
||||||
let skinName = input.readStringRef();
|
let skinName = input.readStringRef();
|
||||||
let parent = input.readStringRef();
|
let parent = input.readStringRef();
|
||||||
let inheritDeform = input.readBoolean();
|
let inheritTimelines = input.readBoolean();
|
||||||
|
let sequence = this.readSequence(input);
|
||||||
let width = 0, height = 0;
|
let width = 0, height = 0;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
width = input.readFloat();
|
width = input.readFloat();
|
||||||
@ -376,15 +383,16 @@ export class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!path) path = name;
|
if (!path) path = name;
|
||||||
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
|
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (!mesh) return null;
|
if (!mesh) return null;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
Color.rgba8888ToColor(mesh.color, color);
|
Color.rgba8888ToColor(mesh.color, color);
|
||||||
|
mesh.sequence = sequence;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.width = width * scale;
|
mesh.width = width * scale;
|
||||||
mesh.height = height * scale;
|
mesh.height = height * scale;
|
||||||
}
|
}
|
||||||
this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritDeform));
|
this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritTimelines));
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
case AttachmentType.Path: {
|
case AttachmentType.Path: {
|
||||||
@ -441,6 +449,15 @@ export class SkeletonBinary {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readSequence (input: BinaryInput) {
|
||||||
|
if (!input.readBoolean()) return null;
|
||||||
|
let sequence = new Sequence(input.readInt(true));
|
||||||
|
sequence.start = input.readInt(true);
|
||||||
|
sequence.digits = input.readInt(true);
|
||||||
|
sequence.setupIndex = input.readInt(true);
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
private readVertices (input: BinaryInput, vertexCount: number): Vertices {
|
private readVertices (input: BinaryInput, vertexCount: number): Vertices {
|
||||||
let scale = this.scale;
|
let scale = this.scale;
|
||||||
let verticesLength = vertexCount << 1;
|
let verticesLength = vertexCount << 1;
|
||||||
@ -697,7 +714,6 @@ export class SkeletonBinary {
|
|||||||
a = a2;
|
a = a2;
|
||||||
}
|
}
|
||||||
timelines.push(timeline);
|
timelines.push(timeline);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -850,112 +866,130 @@ export class SkeletonBinary {
|
|||||||
let slotIndex = input.readInt(true);
|
let slotIndex = input.readInt(true);
|
||||||
for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
|
for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
|
||||||
let attachmentName = input.readStringRef();
|
let attachmentName = input.readStringRef();
|
||||||
let attachment = skin.getAttachment(slotIndex, attachmentName) as VertexAttachment;
|
let attachment = skin.getAttachment(slotIndex, attachmentName);
|
||||||
let weighted = attachment.bones;
|
let timelineType = input.readByte();
|
||||||
let vertices = attachment.vertices;
|
|
||||||
let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
|
||||||
|
|
||||||
let frameCount = input.readInt(true);
|
let frameCount = input.readInt(true);
|
||||||
let frameLast = frameCount - 1;
|
let frameLast = frameCount - 1;
|
||||||
let bezierCount = input.readInt(true);
|
|
||||||
let timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, attachment);
|
|
||||||
|
|
||||||
let time = input.readFloat();
|
switch (timelineType) {
|
||||||
for (let frame = 0, bezier = 0; ; frame++) {
|
case ATTACHMENT_DEFORM: {
|
||||||
let deform;
|
let vertexAttachment = attachment as VertexAttachment;
|
||||||
let end = input.readInt(true);
|
let weighted = vertexAttachment.bones;
|
||||||
if (end == 0)
|
let vertices = vertexAttachment.vertices;
|
||||||
deform = weighted ? Utils.newFloatArray(deformLength) : vertices;
|
let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
||||||
else {
|
|
||||||
deform = Utils.newFloatArray(deformLength);
|
|
||||||
let start = input.readInt(true);
|
|
||||||
end += start;
|
|
||||||
if (scale == 1) {
|
|
||||||
for (let v = start; v < end; v++)
|
|
||||||
deform[v] = input.readFloat();
|
|
||||||
} else {
|
|
||||||
for (let v = start; v < end; v++)
|
|
||||||
deform[v] = input.readFloat() * scale;
|
|
||||||
}
|
|
||||||
if (!weighted) {
|
|
||||||
for (let v = 0, vn = deform.length; v < vn; v++)
|
|
||||||
deform[v] += vertices[v];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timeline.setFrame(frame, time, deform);
|
|
||||||
if (frame == frameLast) break;
|
let bezierCount = input.readInt(true);
|
||||||
let time2 = input.readFloat();
|
let timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, vertexAttachment);
|
||||||
switch (input.readByte()) {
|
|
||||||
case CURVE_STEPPED:
|
let time = input.readFloat();
|
||||||
timeline.setStepped(frame);
|
for (let frame = 0, bezier = 0; ; frame++) {
|
||||||
break;
|
let deform;
|
||||||
case CURVE_BEZIER:
|
let end = input.readInt(true);
|
||||||
setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
if (end == 0)
|
||||||
|
deform = weighted ? Utils.newFloatArray(deformLength) : vertices;
|
||||||
|
else {
|
||||||
|
deform = Utils.newFloatArray(deformLength);
|
||||||
|
let start = input.readInt(true);
|
||||||
|
end += start;
|
||||||
|
if (scale == 1) {
|
||||||
|
for (let v = start; v < end; v++)
|
||||||
|
deform[v] = input.readFloat();
|
||||||
|
} else {
|
||||||
|
for (let v = start; v < end; v++)
|
||||||
|
deform[v] = input.readFloat() * scale;
|
||||||
|
}
|
||||||
|
if (!weighted) {
|
||||||
|
for (let v = 0, vn = deform.length; v < vn; v++)
|
||||||
|
deform[v] += vertices[v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timeline.setFrame(frame, time, deform);
|
||||||
|
if (frame == frameLast) break;
|
||||||
|
let time2 = input.readFloat();
|
||||||
|
switch (input.readByte()) {
|
||||||
|
case CURVE_STEPPED:
|
||||||
|
timeline.setStepped(frame);
|
||||||
|
break;
|
||||||
|
case CURVE_BEZIER:
|
||||||
|
setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
||||||
|
}
|
||||||
|
time = time2;
|
||||||
|
}
|
||||||
|
timelines.push(timeline);
|
||||||
|
}
|
||||||
|
case ATTACHMENT_SEQUENCE: {
|
||||||
|
let timeline = new SequenceTimeline(frameCount, slotIndex, attachment as unknown as HasTextureRegion);
|
||||||
|
for (let frame = 0; frame < frameCount; frame++) {
|
||||||
|
let time = input.readFloat();
|
||||||
|
let modeAndIndex = input.readInt32();
|
||||||
|
timeline.setFrame(frame, time, SequenceModeValues[modeAndIndex & 0xf], modeAndIndex >> 4,
|
||||||
|
input.readFloat());
|
||||||
|
}
|
||||||
|
timelines.push(timeline);
|
||||||
}
|
}
|
||||||
time = time2;
|
|
||||||
}
|
}
|
||||||
timelines.push(timeline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw order timeline.
|
// Draw order timeline.
|
||||||
let drawOrderCount = input.readInt(true);
|
let drawOrderCount = input.readInt(true);
|
||||||
if (drawOrderCount > 0) {
|
if (drawOrderCount > 0) {
|
||||||
let timeline = new DrawOrderTimeline(drawOrderCount);
|
let timeline = new DrawOrderTimeline(drawOrderCount);
|
||||||
let slotCount = skeletonData.slots.length;
|
let slotCount = skeletonData.slots.length;
|
||||||
for (let i = 0; i < drawOrderCount; i++) {
|
for (let i = 0; i < drawOrderCount; i++) {
|
||||||
let time = input.readFloat();
|
let time = input.readFloat();
|
||||||
let offsetCount = input.readInt(true);
|
let offsetCount = input.readInt(true);
|
||||||
let drawOrder = Utils.newArray(slotCount, 0);
|
let drawOrder = Utils.newArray(slotCount, 0);
|
||||||
for (let ii = slotCount - 1; ii >= 0; ii--)
|
for (let ii = slotCount - 1; ii >= 0; ii--)
|
||||||
drawOrder[ii] = -1;
|
drawOrder[ii] = -1;
|
||||||
let unchanged = Utils.newArray(slotCount - offsetCount, 0);
|
let unchanged = Utils.newArray(slotCount - offsetCount, 0);
|
||||||
let originalIndex = 0, unchangedIndex = 0;
|
let originalIndex = 0, unchangedIndex = 0;
|
||||||
for (let ii = 0; ii < offsetCount; ii++) {
|
for (let ii = 0; ii < offsetCount; ii++) {
|
||||||
let slotIndex = input.readInt(true);
|
let slotIndex = input.readInt(true);
|
||||||
// Collect unchanged items.
|
// Collect unchanged items.
|
||||||
while (originalIndex != slotIndex)
|
while (originalIndex != slotIndex)
|
||||||
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
|
// Set changed items.
|
||||||
|
drawOrder[originalIndex + input.readInt(true)] = originalIndex++;
|
||||||
|
}
|
||||||
|
// Collect remaining unchanged items.
|
||||||
|
while (originalIndex < slotCount)
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
// Set changed items.
|
// Fill in unchanged items.
|
||||||
drawOrder[originalIndex + input.readInt(true)] = originalIndex++;
|
for (let ii = slotCount - 1; ii >= 0; ii--)
|
||||||
|
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
|
||||||
|
timeline.setFrame(i, time, drawOrder);
|
||||||
}
|
}
|
||||||
// Collect remaining unchanged items.
|
timelines.push(timeline);
|
||||||
while (originalIndex < slotCount)
|
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
|
||||||
// Fill in unchanged items.
|
|
||||||
for (let ii = slotCount - 1; ii >= 0; ii--)
|
|
||||||
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
|
|
||||||
timeline.setFrame(i, time, drawOrder);
|
|
||||||
}
|
}
|
||||||
timelines.push(timeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event timeline.
|
// Event timeline.
|
||||||
let eventCount = input.readInt(true);
|
let eventCount = input.readInt(true);
|
||||||
if (eventCount > 0) {
|
if (eventCount > 0) {
|
||||||
let timeline = new EventTimeline(eventCount);
|
let timeline = new EventTimeline(eventCount);
|
||||||
for (let i = 0; i < eventCount; i++) {
|
for (let i = 0; i < eventCount; i++) {
|
||||||
let time = input.readFloat();
|
let time = input.readFloat();
|
||||||
let eventData = skeletonData.events[input.readInt(true)];
|
let eventData = skeletonData.events[input.readInt(true)];
|
||||||
let event = new Event(time, eventData);
|
let event = new Event(time, eventData);
|
||||||
event.intValue = input.readInt(false);
|
event.intValue = input.readInt(false);
|
||||||
event.floatValue = input.readFloat();
|
event.floatValue = input.readFloat();
|
||||||
event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue;
|
event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue;
|
||||||
if (event.data.audioPath) {
|
if (event.data.audioPath) {
|
||||||
event.volume = input.readFloat();
|
event.volume = input.readFloat();
|
||||||
event.balance = input.readFloat();
|
event.balance = input.readFloat();
|
||||||
|
}
|
||||||
|
timeline.setFrame(i, event);
|
||||||
}
|
}
|
||||||
timeline.setFrame(i, event);
|
timelines.push(timeline);
|
||||||
}
|
}
|
||||||
timelines.push(timeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
let duration = 0;
|
let duration = 0;
|
||||||
for (let i = 0, n = timelines.length; i < n; i++)
|
for (let i = 0, n = timelines.length; i < n; i++)
|
||||||
duration = Math.max(duration, timelines[i].getDuration());
|
duration = Math.max(duration, timelines[i].getDuration());
|
||||||
return new Animation(name, timelines, duration);
|
return new Animation(name, timelines, duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,14 +1090,14 @@ class LinkedMesh {
|
|||||||
parent: string; skin: string;
|
parent: string; skin: string;
|
||||||
slotIndex: number;
|
slotIndex: number;
|
||||||
mesh: MeshAttachment;
|
mesh: MeshAttachment;
|
||||||
inheritDeform: boolean;
|
inheritTimeline: boolean;
|
||||||
|
|
||||||
constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string, inheritDeform: boolean) {
|
constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string, inheritDeform: boolean) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
this.slotIndex = slotIndex;
|
this.slotIndex = slotIndex;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.inheritDeform = inheritDeform;
|
this.inheritTimeline = inheritDeform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,6 +1170,9 @@ const SLOT_RGBA2 = 3;
|
|||||||
const SLOT_RGB2 = 4;
|
const SLOT_RGB2 = 4;
|
||||||
const SLOT_ALPHA = 5;
|
const SLOT_ALPHA = 5;
|
||||||
|
|
||||||
|
const ATTACHMENT_DEFORM = 0;
|
||||||
|
const ATTACHMENT_SEQUENCE = 1;
|
||||||
|
|
||||||
const PATH_POSITION = 0;
|
const PATH_POSITION = 0;
|
||||||
const PATH_SPACING = 1;
|
const PATH_SPACING = 1;
|
||||||
const PATH_MIX = 2;
|
const PATH_MIX = 2;
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import { Skin } from "./Skin";
|
|||||||
import { SlotData, BlendMode } from "./SlotData";
|
import { SlotData, BlendMode } from "./SlotData";
|
||||||
import { TransformConstraintData } from "./TransformConstraintData";
|
import { TransformConstraintData } from "./TransformConstraintData";
|
||||||
import { Utils, Color, NumberArrayLike } from "./Utils";
|
import { Utils, Color, NumberArrayLike } from "./Utils";
|
||||||
|
import { Sequence } from "./attachments/Sequence";
|
||||||
|
|
||||||
/** Loads skeleton data in the Spine JSON format.
|
/** Loads skeleton data in the Spine JSON format.
|
||||||
*
|
*
|
||||||
@ -257,9 +258,9 @@ export class SkeletonJson {
|
|||||||
let linkedMesh = this.linkedMeshes[i];
|
let linkedMesh = this.linkedMeshes[i];
|
||||||
let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
||||||
let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||||
linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? <VertexAttachment>parent : <VertexAttachment>linkedMesh.mesh;
|
linkedMesh.mesh.timelineAttahment = linkedMesh.inheritTimeline ? <VertexAttachment>parent : <VertexAttachment>linkedMesh.mesh;
|
||||||
linkedMesh.mesh.setParentMesh(<MeshAttachment>parent);
|
linkedMesh.mesh.setParentMesh(<MeshAttachment>parent);
|
||||||
linkedMesh.mesh.updateUVs();
|
if (linkedMesh.mesh.region != null) linkedMesh.mesh.updateRegion();
|
||||||
}
|
}
|
||||||
this.linkedMeshes.length = 0;
|
this.linkedMeshes.length = 0;
|
||||||
|
|
||||||
@ -298,7 +299,8 @@ export class SkeletonJson {
|
|||||||
switch (getValue(map, "type", "region")) {
|
switch (getValue(map, "type", "region")) {
|
||||||
case "region": {
|
case "region": {
|
||||||
let path = getValue(map, "path", name);
|
let path = getValue(map, "path", name);
|
||||||
let region = this.attachmentLoader.newRegionAttachment(skin, name, path);
|
let sequence = this.readSequence(getValue(map, "sequence", null));
|
||||||
|
let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||||
if (!region) return null;
|
if (!region) return null;
|
||||||
region.path = path;
|
region.path = path;
|
||||||
region.x = getValue(map, "x", 0) * scale;
|
region.x = getValue(map, "x", 0) * scale;
|
||||||
@ -308,11 +310,12 @@ export class SkeletonJson {
|
|||||||
region.rotation = getValue(map, "rotation", 0);
|
region.rotation = getValue(map, "rotation", 0);
|
||||||
region.width = map.width * scale;
|
region.width = map.width * scale;
|
||||||
region.height = map.height * scale;
|
region.height = map.height * scale;
|
||||||
|
region.sequence = sequence;
|
||||||
|
|
||||||
let color: string = getValue(map, "color", null);
|
let color: string = getValue(map, "color", null);
|
||||||
if (color) region.color.setFromString(color);
|
if (color) region.color.setFromString(color);
|
||||||
|
|
||||||
region.updateOffset();
|
if (region.region != null) region.updateRegion();
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
case "boundingbox": {
|
case "boundingbox": {
|
||||||
@ -326,7 +329,8 @@ export class SkeletonJson {
|
|||||||
case "mesh":
|
case "mesh":
|
||||||
case "linkedmesh": {
|
case "linkedmesh": {
|
||||||
let path = getValue(map, "path", name);
|
let path = getValue(map, "path", name);
|
||||||
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
|
let sequence = this.readSequence(getValue(map, "sequence", null));
|
||||||
|
let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (!mesh) return null;
|
if (!mesh) return null;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
|
|
||||||
@ -335,10 +339,11 @@ export class SkeletonJson {
|
|||||||
|
|
||||||
mesh.width = getValue(map, "width", 0) * scale;
|
mesh.width = getValue(map, "width", 0) * scale;
|
||||||
mesh.height = getValue(map, "height", 0) * scale;
|
mesh.height = getValue(map, "height", 0) * scale;
|
||||||
|
mesh.sequence = sequence;
|
||||||
|
|
||||||
let parent: string = getValue(map, "parent", null);
|
let parent: string = getValue(map, "parent", null);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
this.linkedMeshes.push(new LinkedMesh(mesh, <string>getValue(map, "skin", null), slotIndex, parent, getValue(map, "deform", true)));
|
this.linkedMeshes.push(new LinkedMesh(mesh, <string>getValue(map, "skin", null), slotIndex, parent, getValue(map, "timelines", true)));
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +351,7 @@ export class SkeletonJson {
|
|||||||
this.readVertices(map, mesh, uvs.length);
|
this.readVertices(map, mesh, uvs.length);
|
||||||
mesh.triangles = map.triangles;
|
mesh.triangles = map.triangles;
|
||||||
mesh.regionUVs = uvs;
|
mesh.regionUVs = uvs;
|
||||||
mesh.updateUVs();
|
if (mesh.region != null) mesh.updateRegion();
|
||||||
|
|
||||||
mesh.edges = getValue(map, "edges", null);
|
mesh.edges = getValue(map, "edges", null);
|
||||||
mesh.hullLength = getValue(map, "hull", 0) * 2;
|
mesh.hullLength = getValue(map, "hull", 0) * 2;
|
||||||
@ -399,6 +404,15 @@ export class SkeletonJson {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readSequence (map: any) {
|
||||||
|
if (map == null) return null;
|
||||||
|
let sequence = new Sequence(getValue(map, "count", 0));
|
||||||
|
sequence.start = getValue(map, "start", 1);
|
||||||
|
sequence.digits = getValue(map, "digits", 0);
|
||||||
|
sequence.setupIndex = getValue(map, "setup", 0);
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
readVertices (map: any, attachment: VertexAttachment, verticesLength: number) {
|
readVertices (map: any, attachment: VertexAttachment, verticesLength: number) {
|
||||||
let scale = this.scale;
|
let scale = this.scale;
|
||||||
attachment.worldVerticesLength = verticesLength;
|
attachment.worldVerticesLength = verticesLength;
|
||||||
@ -445,7 +459,7 @@ export class SkeletonJson {
|
|||||||
let timeline = new AttachmentTimeline(frames, slotIndex);
|
let timeline = new AttachmentTimeline(frames, slotIndex);
|
||||||
for (let frame = 0; frame < frames; frame++) {
|
for (let frame = 0; frame < frames; frame++) {
|
||||||
let keyMap = timelineMap[frame];
|
let keyMap = timelineMap[frame];
|
||||||
timeline.setFrame(frame, getValue(keyMap, "time", 0), keyMap.name);
|
timeline.setFrame(frame, getValue(keyMap, "time", 0), getValue(keyMap, "name", null));
|
||||||
}
|
}
|
||||||
timelines.push(timeline);
|
timelines.push(timeline);
|
||||||
|
|
||||||
@ -778,17 +792,18 @@ export class SkeletonJson {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deform timelines.
|
// Attachment timelines.
|
||||||
if (map.deform) {
|
if (map.attachments) {
|
||||||
for (let deformName in map.deform) {
|
for (let attachmentsName in map.attachments) {
|
||||||
let deformMap = map.deform[deformName];
|
let attachmentsMap = map.attachments[attachmentsName];
|
||||||
let skin = skeletonData.findSkin(deformName);
|
let skin = skeletonData.findSkin(attachmentsName);
|
||||||
for (let slotName in deformMap) {
|
for (let slotName in attachmentsMap) {
|
||||||
let slotMap = deformMap[slotName];
|
let slotMap = attachmentsMap[slotName];
|
||||||
let slotIndex = skeletonData.findSlot(slotName).index;
|
let slotIndex = skeletonData.findSlot(slotName).index;
|
||||||
for (let timelineName in slotMap) {
|
for (let timelineName in slotMap) {
|
||||||
let timelineMap = slotMap[timelineName];
|
let attachmentMap = slotMap[timelineName];
|
||||||
let keyMap = timelineMap[0];
|
let attachmentMapName = timelineName;
|
||||||
|
let keyMap = attachmentMap[0];
|
||||||
if (!keyMap) continue;
|
if (!keyMap) continue;
|
||||||
|
|
||||||
let attachment = <VertexAttachment>skin.getAttachment(slotIndex, timelineName);
|
let attachment = <VertexAttachment>skin.getAttachment(slotIndex, timelineName);
|
||||||
@ -796,7 +811,7 @@ export class SkeletonJson {
|
|||||||
let vertices = attachment.vertices;
|
let vertices = attachment.vertices;
|
||||||
let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
||||||
|
|
||||||
let timeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment);
|
let timeline = new DeformTimeline(attachmentMap.length, attachmentMap.length, slotIndex, attachment);
|
||||||
let time = getValue(keyMap, "time", 0);
|
let time = getValue(keyMap, "time", 0);
|
||||||
for (let frame = 0, bezier = 0; ; frame++) {
|
for (let frame = 0, bezier = 0; ; frame++) {
|
||||||
let deform: NumberArrayLike;
|
let deform: NumberArrayLike;
|
||||||
@ -818,7 +833,7 @@ export class SkeletonJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeline.setFrame(frame, time, deform);
|
timeline.setFrame(frame, time, deform);
|
||||||
let nextMap = timelineMap[frame + 1];
|
let nextMap = attachmentMap[frame + 1];
|
||||||
if (!nextMap) {
|
if (!nextMap) {
|
||||||
timeline.shrink(bezier);
|
timeline.shrink(bezier);
|
||||||
break;
|
break;
|
||||||
@ -900,14 +915,14 @@ class LinkedMesh {
|
|||||||
parent: string; skin: string;
|
parent: string; skin: string;
|
||||||
slotIndex: number;
|
slotIndex: number;
|
||||||
mesh: MeshAttachment;
|
mesh: MeshAttachment;
|
||||||
inheritDeform: boolean;
|
inheritTimeline: boolean;
|
||||||
|
|
||||||
constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string, inheritDeform: boolean) {
|
constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string, inheritDeform: boolean) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
this.slotIndex = slotIndex;
|
this.slotIndex = slotIndex;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.inheritDeform = inheritDeform;
|
this.inheritTimeline = inheritDeform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,10 +53,12 @@ export class Slot {
|
|||||||
|
|
||||||
attachment: Attachment;
|
attachment: Attachment;
|
||||||
|
|
||||||
private attachmentTime: number;
|
|
||||||
|
|
||||||
attachmentState: number;
|
attachmentState: number;
|
||||||
|
|
||||||
|
/** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the
|
||||||
|
* {@link Sequence#getSetupIndex()}. */
|
||||||
|
sequenceIndex: number;
|
||||||
|
|
||||||
/** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a
|
/** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a
|
||||||
* weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions.
|
* weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions.
|
||||||
*
|
*
|
||||||
@ -83,28 +85,17 @@ export class Slot {
|
|||||||
return this.attachment;
|
return this.attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the slot's attachment and, if the attachment changed, resets {@link #attachmentTime} and clears the {@link #deform}.
|
/** Sets the slot's attachment and, if the attachment changed, resets {@link #sequenceIndex} and clears the {@link #deform}.
|
||||||
* The deform is not cleared if the old attachment has the same {@link VertexAttachment#getDeformAttachment()} as the specified
|
* The deform is not cleared if the old attachment has the same {@link VertexAttachment#getTimelineAttachment()} as the
|
||||||
* attachment.
|
* specified attachment. */
|
||||||
* @param attachment May be null. */
|
|
||||||
setAttachment (attachment: Attachment) {
|
setAttachment (attachment: Attachment) {
|
||||||
if (this.attachment == attachment) return;
|
if (this.attachment == attachment) return;
|
||||||
if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment)
|
if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment)
|
||||||
|| (<VertexAttachment>attachment).deformAttachment != (<VertexAttachment>this.attachment).deformAttachment) {
|
|| (<VertexAttachment>attachment).timelineAttahment != (<VertexAttachment>this.attachment).timelineAttahment) {
|
||||||
this.deform.length = 0;
|
this.deform.length = 0;
|
||||||
}
|
}
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
this.attachmentTime = this.bone.skeleton.time;
|
this.sequenceIndex = -1;
|
||||||
}
|
|
||||||
|
|
||||||
setAttachmentTime (time: number) {
|
|
||||||
this.attachmentTime = this.bone.skeleton.time - time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The time that has elapsed since the last time the attachment was set or cleared. Relies on Skeleton
|
|
||||||
* {@link Skeleton#time}. */
|
|
||||||
getAttachmentTime (): number {
|
|
||||||
return this.bone.skeleton.time - this.attachmentTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets this slot to the setup pose. */
|
/** Sets this slot to the setup pose. */
|
||||||
|
|||||||
@ -64,8 +64,9 @@ export abstract class VertexAttachment extends Attachment {
|
|||||||
* {@link #computeWorldVertices()} using the `count` parameter. */
|
* {@link #computeWorldVertices()} using the `count` parameter. */
|
||||||
worldVerticesLength = 0;
|
worldVerticesLength = 0;
|
||||||
|
|
||||||
/** Deform keys for the deform attachment are also applied to this attachment. May be null if no deform keys should be applied. */
|
/** Timelines for the timeline attachment are also applied to this attachment.
|
||||||
deformAttachment: VertexAttachment = this;
|
* May be null if no attachment-specific timelines should be applied. */
|
||||||
|
timelineAttahment: Attachment = this;
|
||||||
|
|
||||||
constructor (name: string) {
|
constructor (name: string) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -155,6 +156,6 @@ export abstract class VertexAttachment extends Attachment {
|
|||||||
attachment.vertices = null;
|
attachment.vertices = null;
|
||||||
|
|
||||||
attachment.worldVerticesLength = this.worldVerticesLength;
|
attachment.worldVerticesLength = this.worldVerticesLength;
|
||||||
attachment.deformAttachment = this.deformAttachment;
|
attachment.timelineAttahment = this.timelineAttahment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import { MeshAttachment } from "./MeshAttachment";
|
|||||||
import { PathAttachment } from "./PathAttachment";
|
import { PathAttachment } from "./PathAttachment";
|
||||||
import { PointAttachment } from "./PointAttachment";
|
import { PointAttachment } from "./PointAttachment";
|
||||||
import { RegionAttachment } from "./RegionAttachment";
|
import { RegionAttachment } from "./RegionAttachment";
|
||||||
|
import { Sequence } from "./Sequence";
|
||||||
|
|
||||||
/** The interface which can be implemented to customize creating and populating attachments.
|
/** The interface which can be implemented to customize creating and populating attachments.
|
||||||
*
|
*
|
||||||
@ -41,10 +42,10 @@ import { RegionAttachment } from "./RegionAttachment";
|
|||||||
* Runtimes Guide. */
|
* Runtimes Guide. */
|
||||||
export interface AttachmentLoader {
|
export interface AttachmentLoader {
|
||||||
/** @return May be null to not load an attachment. */
|
/** @return May be null to not load an attachment. */
|
||||||
newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment;
|
newRegionAttachment (skin: Skin, name: string, path: string, sequence: Sequence): RegionAttachment;
|
||||||
|
|
||||||
/** @return May be null to not load an attachment. */
|
/** @return May be null to not load an attachment. */
|
||||||
newMeshAttachment (skin: Skin, name: string, path: string): MeshAttachment;
|
newMeshAttachment (skin: Skin, name: string, path: string, sequence: Sequence): MeshAttachment;
|
||||||
|
|
||||||
/** @return May be null to not load an attachment. */
|
/** @return May be null to not load an attachment. */
|
||||||
newBoundingBoxAttachment (skin: Skin, name: string): BoundingBoxAttachment;
|
newBoundingBoxAttachment (skin: Skin, name: string): BoundingBoxAttachment;
|
||||||
|
|||||||
50
spine-ts/spine-core/src/attachments/HasTextureRegion.ts
Normal file
50
spine-ts/spine-core/src/attachments/HasTextureRegion.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated September 24, 2021. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import { TextureRegion } from "../Texture"
|
||||||
|
import { Color } from "../Utils"
|
||||||
|
import { Sequence } from "./Sequence"
|
||||||
|
|
||||||
|
export interface HasTextureRegion {
|
||||||
|
/** The name used to find the {@link #region()}. */
|
||||||
|
path: string;
|
||||||
|
|
||||||
|
/** The region used to draw the attachment. After setting the region or if the region's properties are changed,
|
||||||
|
* {@link #updateRegion()} must be called. */
|
||||||
|
region: TextureRegion;
|
||||||
|
|
||||||
|
/** Updates any values the attachment calculates using the {@link #getRegion()}. Must be called after setting the
|
||||||
|
* {@link #getRegion()} or if the region's properties are changed. */
|
||||||
|
updateRegion (): void;
|
||||||
|
|
||||||
|
/** The color to tint the attachment. */
|
||||||
|
color: Color;
|
||||||
|
|
||||||
|
sequence: Sequence;
|
||||||
|
}
|
||||||
@ -31,12 +31,15 @@ import { TextureRegion } from "../Texture";
|
|||||||
import { TextureAtlasRegion } from "../TextureAtlas";
|
import { TextureAtlasRegion } from "../TextureAtlas";
|
||||||
import { Color, NumberArrayLike, Utils } from "../Utils";
|
import { Color, NumberArrayLike, Utils } from "../Utils";
|
||||||
import { VertexAttachment, Attachment } from "./Attachment";
|
import { VertexAttachment, Attachment } from "./Attachment";
|
||||||
|
import { HasTextureRegion } from "./HasTextureRegion";
|
||||||
|
import { Sequence } from "./Sequence";
|
||||||
|
import { Slot } from "../Slot";
|
||||||
|
|
||||||
/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not
|
/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not
|
||||||
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
||||||
*
|
*
|
||||||
* See [Mesh attachments](http://esotericsoftware.com/spine-meshes) in the Spine User Guide. */
|
* See [Mesh attachments](http://esotericsoftware.com/spine-meshes) in the Spine User Guide. */
|
||||||
export class MeshAttachment extends VertexAttachment {
|
export class MeshAttachment extends VertexAttachment implements HasTextureRegion {
|
||||||
region: TextureRegion;
|
region: TextureRegion;
|
||||||
|
|
||||||
/** The name of the texture region for this attachment. */
|
/** The name of the texture region for this attachment. */
|
||||||
@ -70,15 +73,18 @@ export class MeshAttachment extends VertexAttachment {
|
|||||||
edges: Array<number>;
|
edges: Array<number>;
|
||||||
|
|
||||||
private parentMesh: MeshAttachment;
|
private parentMesh: MeshAttachment;
|
||||||
|
|
||||||
|
sequence: Sequence;
|
||||||
|
|
||||||
tempColor = new Color(0, 0, 0, 0);
|
tempColor = new Color(0, 0, 0, 0);
|
||||||
|
|
||||||
constructor (name: string) {
|
constructor (name: string) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates {@link #uvs} using {@link #regionUVs} and the {@link #region}. Must be called after changing the region UVs or
|
/** Calculates {@link #uvs} using the {@link #regionUVs} and region. Must be called if the region, the region's properties, or
|
||||||
* region. */
|
* the {@link #regionUVs} are changed. */
|
||||||
updateUVs () {
|
updateRegion () {
|
||||||
let regionUVs = this.regionUVs;
|
let regionUVs = this.regionUVs;
|
||||||
if (!this.uvs || this.uvs.length != regionUVs.length) this.uvs = Utils.newFloatArray(regionUVs.length);
|
if (!this.uvs || this.uvs.length != regionUVs.length) this.uvs = Utils.newFloatArray(regionUVs.length);
|
||||||
let uvs = this.uvs;
|
let uvs = this.uvs;
|
||||||
@ -175,6 +181,8 @@ export class MeshAttachment extends VertexAttachment {
|
|||||||
Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length);
|
Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length);
|
||||||
copy.hullLength = this.hullLength;
|
copy.hullLength = this.hullLength;
|
||||||
|
|
||||||
|
copy.sequence = this.sequence.copy();
|
||||||
|
|
||||||
// Nonessential.
|
// Nonessential.
|
||||||
if (this.edges) {
|
if (this.edges) {
|
||||||
copy.edges = new Array<number>(this.edges.length);
|
copy.edges = new Array<number>(this.edges.length);
|
||||||
@ -186,15 +194,20 @@ export class MeshAttachment extends VertexAttachment {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeWorldVertices (slot: Slot, start: number, count: number, worldVertices: NumberArrayLike, offset: number, stride: number) {
|
||||||
|
if (this.sequence != null) this.sequence.apply(slot, this);
|
||||||
|
super.computeWorldVertices(slot, start, count, worldVertices, offset, stride);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. **/
|
/** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. **/
|
||||||
newLinkedMesh (): MeshAttachment {
|
newLinkedMesh (): MeshAttachment {
|
||||||
let copy = new MeshAttachment(this.name);
|
let copy = new MeshAttachment(this.name);
|
||||||
copy.region = this.region;
|
copy.region = this.region;
|
||||||
copy.path = this.path;
|
copy.path = this.path;
|
||||||
copy.color.setFromColor(this.color);
|
copy.color.setFromColor(this.color);
|
||||||
copy.deformAttachment = this.deformAttachment;
|
copy.timelineAttahment = this.timelineAttahment;
|
||||||
copy.setParentMesh(this.parentMesh ? this.parentMesh : this);
|
copy.setParentMesh(this.parentMesh ? this.parentMesh : this);
|
||||||
copy.updateUVs();
|
if (copy.region != null) copy.updateRegion();
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,11 +31,14 @@ import { Bone } from "../Bone";
|
|||||||
import { TextureRegion } from "../Texture";
|
import { TextureRegion } from "../Texture";
|
||||||
import { Color, NumberArrayLike, Utils } from "../Utils";
|
import { Color, NumberArrayLike, Utils } from "../Utils";
|
||||||
import { Attachment } from "./Attachment";
|
import { Attachment } from "./Attachment";
|
||||||
|
import { HasTextureRegion } from "./HasTextureRegion";
|
||||||
|
import { Sequence } from "./Sequence";
|
||||||
|
import { Slot } from "../Slot";
|
||||||
|
|
||||||
/** An attachment that displays a textured quadrilateral.
|
/** An attachment that displays a textured quadrilateral.
|
||||||
*
|
*
|
||||||
* See [Region attachments](http://esotericsoftware.com/spine-regions) in the Spine User Guide. */
|
* See [Region attachments](http://esotericsoftware.com/spine-regions) in the Spine User Guide. */
|
||||||
export class RegionAttachment extends Attachment {
|
export class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||||
/** The local x translation. */
|
/** The local x translation. */
|
||||||
x = 0;
|
x = 0;
|
||||||
|
|
||||||
@ -63,8 +66,9 @@ export class RegionAttachment extends Attachment {
|
|||||||
/** The name of the texture region for this attachment. */
|
/** The name of the texture region for this attachment. */
|
||||||
path: string;
|
path: string;
|
||||||
|
|
||||||
rendererObject: any;
|
private rendererObject: any;
|
||||||
region: TextureRegion;
|
region: TextureRegion;
|
||||||
|
sequence: Sequence;
|
||||||
|
|
||||||
/** For each of the 4 vertices, a pair of <code>x,y</code> values that is the local position of the vertex.
|
/** For each of the 4 vertices, a pair of <code>x,y</code> values that is the local position of the vertex.
|
||||||
*
|
*
|
||||||
@ -80,7 +84,7 @@ export class RegionAttachment extends Attachment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates the {@link #offset} using the region settings. Must be called after changing region settings. */
|
/** Calculates the {@link #offset} using the region settings. Must be called after changing region settings. */
|
||||||
updateOffset (): void {
|
updateRegion (): void {
|
||||||
let region = this.region;
|
let region = this.region;
|
||||||
let regionScaleX = this.width / this.region.originalWidth * this.scaleX;
|
let regionScaleX = this.width / this.region.originalWidth * this.scaleX;
|
||||||
let regionScaleY = this.height / this.region.originalHeight * this.scaleY;
|
let regionScaleY = this.height / this.region.originalHeight * this.scaleY;
|
||||||
@ -109,10 +113,7 @@ export class RegionAttachment extends Attachment {
|
|||||||
offset[5] = localY2Cos + localX2Sin;
|
offset[5] = localY2Cos + localX2Sin;
|
||||||
offset[6] = localX2Cos - localYSin;
|
offset[6] = localX2Cos - localYSin;
|
||||||
offset[7] = localYCos + localX2Sin;
|
offset[7] = localYCos + localX2Sin;
|
||||||
}
|
|
||||||
|
|
||||||
setRegion (region: TextureRegion): void {
|
|
||||||
this.region = region;
|
|
||||||
let uvs = this.uvs;
|
let uvs = this.uvs;
|
||||||
if (region.degrees == 90) {
|
if (region.degrees == 90) {
|
||||||
uvs[2] = region.u;
|
uvs[2] = region.u;
|
||||||
@ -135,14 +136,18 @@ export class RegionAttachment extends Attachment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transforms the attachment's four vertices to world coordinates.
|
/** Transforms the attachment's four vertices to world coordinates. If the attachment has a {@link #sequence}, the region may
|
||||||
*
|
* be changed.
|
||||||
* See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine
|
* <p>
|
||||||
|
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||||
* Runtimes Guide.
|
* Runtimes Guide.
|
||||||
* @param worldVertices The output world vertices. Must have a length >= `offset` + 8.
|
* @param worldVertices The output world vertices. Must have a length >= <code>offset</code> + 8.
|
||||||
* @param offset The `worldVertices` index to begin writing values.
|
* @param offset The <code>worldVertices</code> index to begin writing values.
|
||||||
* @param stride The number of `worldVertices` entries between the value pairs written. */
|
* @param stride The number of <code>worldVertices</code> entries between the value pairs written. */
|
||||||
computeWorldVertices (bone: Bone, worldVertices: NumberArrayLike, offset: number, stride: number) {
|
computeWorldVertices (slot: Slot, worldVertices: NumberArrayLike, offset: number, stride: number) {
|
||||||
|
if (this.sequence != null) this.sequence.apply(slot, this);
|
||||||
|
|
||||||
|
let bone = slot.bone;
|
||||||
let vertexOffset = this.offset;
|
let vertexOffset = this.offset;
|
||||||
let x = bone.worldX, y = bone.worldY;
|
let x = bone.worldX, y = bone.worldY;
|
||||||
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||||
@ -187,6 +192,7 @@ export class RegionAttachment extends Attachment {
|
|||||||
Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8);
|
Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8);
|
||||||
Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8);
|
Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8);
|
||||||
copy.color.setFromColor(this.color);
|
copy.color.setFromColor(this.color);
|
||||||
|
copy.sequence = this.sequence.copy();
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
102
spine-ts/spine-core/src/attachments/Sequence.ts
Normal file
102
spine-ts/spine-core/src/attachments/Sequence.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated September 24, 2021. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import { TextureRegion } from "../Texture";
|
||||||
|
import { Slot } from "../Slot";
|
||||||
|
import { HasTextureRegion } from "./HasTextureRegion";
|
||||||
|
import { Utils } from "src";
|
||||||
|
|
||||||
|
|
||||||
|
export class Sequence {
|
||||||
|
private static _nextID = 0;
|
||||||
|
|
||||||
|
id = Sequence.nextID();
|
||||||
|
regions: TextureRegion[];
|
||||||
|
start = 0;
|
||||||
|
digits = 0;
|
||||||
|
/** The index of the region to show for the setup pose. */
|
||||||
|
setupIndex = 0;
|
||||||
|
|
||||||
|
constructor (count: number) {
|
||||||
|
this.regions = new Array<TextureRegion>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy (): Sequence {
|
||||||
|
let copy = new Sequence(this.regions.length);
|
||||||
|
Utils.arrayCopy(this.regions, 0, copy.regions, 0, this.regions.length);
|
||||||
|
copy.start = this.start;
|
||||||
|
copy.digits = this.digits;
|
||||||
|
copy.setupIndex = this.setupIndex;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply (slot: Slot, attachment: HasTextureRegion) {
|
||||||
|
let index = slot.sequenceIndex;
|
||||||
|
if (index == -1) index = this.setupIndex;
|
||||||
|
if (index >= this.regions.length) index = this.regions.length - 1;
|
||||||
|
let region = this.regions[index];
|
||||||
|
if (attachment.region != region) {
|
||||||
|
attachment.region = region;
|
||||||
|
attachment.updateRegion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPath (basePath: string, index: number): string {
|
||||||
|
let result = basePath;
|
||||||
|
let frame = (this.start + index).toString();
|
||||||
|
for (let i = this.digits - frame.length; i > 0; i--)
|
||||||
|
result += "0";
|
||||||
|
result += frame;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static nextID (): number {
|
||||||
|
return Sequence._nextID++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SequenceMode {
|
||||||
|
hold = 0,
|
||||||
|
once = 1,
|
||||||
|
loop = 2,
|
||||||
|
pingpong = 3,
|
||||||
|
onceReverse = 4,
|
||||||
|
loopReverse = 5,
|
||||||
|
pingpongReverse = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SequenceModeValues = [
|
||||||
|
SequenceMode.hold,
|
||||||
|
SequenceMode.once,
|
||||||
|
SequenceMode.loop,
|
||||||
|
SequenceMode.pingpong,
|
||||||
|
SequenceMode.onceReverse,
|
||||||
|
SequenceMode.loopReverse,
|
||||||
|
SequenceMode.pingpongReverse
|
||||||
|
];
|
||||||
@ -176,7 +176,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
|||||||
attachmentColor = region.color;
|
attachmentColor = region.color;
|
||||||
vertices = this.vertices;
|
vertices = this.vertices;
|
||||||
numFloats = vertexSize * 4;
|
numFloats = vertexSize * 4;
|
||||||
region.computeWorldVertices(slot.bone, vertices, 0, vertexSize);
|
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||||
triangles = SkeletonMesh.QUAD_TRIANGLES;
|
triangles = SkeletonMesh.QUAD_TRIANGLES;
|
||||||
uvs = region.uvs;
|
uvs = region.uvs;
|
||||||
texture = <ThreeJsTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
texture = <ThreeJsTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
||||||
|
|||||||
@ -92,7 +92,7 @@ export class SkeletonDebugRenderer implements Disposable {
|
|||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
let regionAttachment = <RegionAttachment>attachment;
|
let regionAttachment = <RegionAttachment>attachment;
|
||||||
let vertices = this.vertices;
|
let vertices = this.vertices;
|
||||||
regionAttachment.computeWorldVertices(slot.bone, vertices, 0, 2);
|
regionAttachment.computeWorldVertices(slot, vertices, 0, 2);
|
||||||
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
||||||
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||||
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
||||||
|
|||||||
@ -109,7 +109,7 @@ export class SkeletonRenderer {
|
|||||||
renderable.vertices = this.vertices;
|
renderable.vertices = this.vertices;
|
||||||
renderable.numVertices = 4;
|
renderable.numVertices = 4;
|
||||||
renderable.numFloats = clippedVertexSize << 2;
|
renderable.numFloats = clippedVertexSize << 2;
|
||||||
region.computeWorldVertices(slot.bone, renderable.vertices, 0, clippedVertexSize);
|
region.computeWorldVertices(slot, renderable.vertices, 0, clippedVertexSize);
|
||||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||||
uvs = region.uvs;
|
uvs = region.uvs;
|
||||||
texture = <GLTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
texture = <GLTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
||||||
|
|||||||
@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
// Create the Spine canvas which runs the app
|
// Create the Spine canvas which runs the app
|
||||||
new spine.SpineCanvas(document.getElementById("canvas"), {
|
new spine.SpineCanvas(document.getElementById("canvas"), {
|
||||||
pathPrefix: "assets/",
|
pathPrefix: "../example/assets/",
|
||||||
app: new App()
|
app: new App()
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user