diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f08549f8..b97a56973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,9 @@ * **Breaking changes** * **Additions** + * `BoneFollower` and `BoneFollowerGraphic` now provide an additional `Follow Parent World Scale` parameter to allow following simple scale of parent bones (rotated/skewed scale can't be supported). + * `SpineAtlasAsset.CreateRuntimeInstance` methods now provide an optional `newCustomTextureLoader` parameter (defaults to `null`) which can be set to e.g. `(a) => new YourCustomTextureLoader(a)` to use your own `TextureLoader` subclass instead of `MaterialsTextureLoader`. + * Improved `Advanced - Fix Prefab Override MeshFilter` property for `SkeletonRenderer` (and subclasses`SkeletonAnimation` and `SkeletonMecanim`), now providing an additional option to use a global value which can be set in `Edit - Preferences - Spine`. * **Changes of default values** @@ -246,6 +249,8 @@ * Prefabs containing `SkeletonRenderer`, `SkeletonAnimation` and `SkeletonMecanim` now provide a proper Editor preview, including the preview thumbnail. * `SkeletonRenderer` (and subclasses`SkeletonAnimation` and `SkeletonMecanim`) now provide a property `Advanced - Fix Prefab Override MeshFilter`, which when enabled fixes the prefab always being marked as changed. It sets the MeshFilter's hide flags to `DontSaveInEditor`. Unfortunately this comes at the cost of references to the `MeshFilter` by other components being lost, therefore this parameter defaults to `false` to keep the safe existing behaviour. * `BoundingBoxFollower` and `BoundingBoxFollowerGraphic` now provide previously missing `usedByEffector` and `usedByComposite` parameters to be set at all generated colliders. + * `BoneFollower` and `BoneFollowerGraphic` now provide an additional `Follow Parent World Scale` parameter to allow following simple scale of parent bones (rotated/skewed scale can't be supported). + * Improved `Advanced - Fix Prefab Override MeshFilter` property for `SkeletonRenderer` (and subclasses`SkeletonAnimation` and `SkeletonMecanim`), now providing an additional option to use a global value which can be set in `Edit - Preferences - Spine`. * **Changes of default values** diff --git a/spine-c/spine-c/include/spine/Atlas.h b/spine-c/spine-c/include/spine/Atlas.h index 9279170c5..0aef18dd6 100644 --- a/spine-c/spine-c/include/spine/Atlas.h +++ b/spine-c/spine-c/include/spine/Atlas.h @@ -32,6 +32,7 @@ #include #include +#include "TextureRegion.h" #ifdef __cplusplus extern "C" { @@ -96,13 +97,10 @@ _SP_ARRAY_DECLARE_TYPE(spKeyValueArray, spKeyValue) /**/ typedef struct spAtlasRegion spAtlasRegion; struct spAtlasRegion { + spTextureRegion super; const char *name; - int x, y, width, height; - float u, v, u2, v2; - int offsetX, offsetY; - int originalWidth, originalHeight; + int x, y; int index; - int degrees; int *splits; int *pads; spKeyValueArray *keyValues; diff --git a/spine-c/spine-c/include/spine/AttachmentLoader.h b/spine-c/spine-c/include/spine/AttachmentLoader.h index bc3cfdb6a..eea153fe1 100644 --- a/spine-c/spine-c/include/spine/AttachmentLoader.h +++ b/spine-c/spine-c/include/spine/AttachmentLoader.h @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -51,7 +52,7 @@ SP_API void spAttachmentLoader_dispose(spAttachmentLoader *self); * called, an error occurred. */ SP_API spAttachment * spAttachmentLoader_createAttachment(spAttachmentLoader *self, spSkin *skin, spAttachmentType type, const char *name, - const char *path); + const char *path, spSequence *sequence); /* Called after the attachment has been fully configured. */ SP_API void spAttachmentLoader_configureAttachment(spAttachmentLoader *self, spAttachment *attachment); /* Called just before the attachment is disposed. This can release allocations made in spAttachmentLoader_configureAttachment. */ diff --git a/spine-c/spine-c/include/spine/MeshAttachment.h b/spine-c/spine-c/include/spine/MeshAttachment.h index e884842f8..df2bae846 100644 --- a/spine-c/spine-c/include/spine/MeshAttachment.h +++ b/spine-c/spine-c/include/spine/MeshAttachment.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -45,11 +46,8 @@ struct spMeshAttachment { spVertexAttachment super; void *rendererObject; - int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ - int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ - int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ - float regionU, regionV, regionU2, regionV2; - int regionDegrees; + spTextureRegion *region; + spSequence *sequence; const char *path; @@ -73,7 +71,7 @@ struct spMeshAttachment { SP_API spMeshAttachment *spMeshAttachment_create(const char *name); -SP_API void spMeshAttachment_updateUVs(spMeshAttachment *self); +SP_API void spMeshAttachment_updateRegion(spMeshAttachment *self); SP_API void spMeshAttachment_setParentMesh(spMeshAttachment *self, spMeshAttachment *parentMesh); diff --git a/spine-c/spine-c/include/spine/RegionAttachment.h b/spine-c/spine-c/include/spine/RegionAttachment.h index d0a78db00..4a526785f 100644 --- a/spine-c/spine-c/include/spine/RegionAttachment.h +++ b/spine-c/spine-c/include/spine/RegionAttachment.h @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -46,9 +47,8 @@ typedef struct spRegionAttachment { spColor color; void *rendererObject; - int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ - int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ - int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ + spTextureRegion *region; + spSequence *sequence; float offset[8]; float uvs[8]; @@ -56,11 +56,9 @@ typedef struct spRegionAttachment { SP_API spRegionAttachment *spRegionAttachment_create(const char *name); -SP_API void spRegionAttachment_setUVs(spRegionAttachment *self, float u, float v, float u2, float v2, float degrees); +SP_API void spRegionAttachment_updateRegion(spRegionAttachment *self); -SP_API void spRegionAttachment_updateOffset(spRegionAttachment *self); - -SP_API void spRegionAttachment_computeWorldVertices(spRegionAttachment *self, spBone *bone, float *vertices, int offset, +SP_API void spRegionAttachment_computeWorldVertices(spRegionAttachment *self, spSlot *slot, float *vertices, int offset, int stride); #ifdef __cplusplus diff --git a/spine-c/spine-c/include/spine/Sequence.h b/spine-c/spine-c/include/spine/Sequence.h new file mode 100644 index 000000000..2692ddc4f --- /dev/null +++ b/spine-c/spine-c/include/spine/Sequence.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef SPINE_SEQUENCE_H +#define SPINE_SEQUENCE_H + +#include +#include +#include +#include "Attachment.h" +#include "Slot.h" + +#ifdef __cplusplus +extern "C" { +#endif + +_SP_ARRAY_DECLARE_TYPE(spTextureRegionArray, spTextureRegion*) + +typedef struct spSequence { + int id; + int start; + int digits; + int setupIndex; + spTextureRegionArray *regions; +} spSequence; + +SP_API spSequence *spSequence_create(int start, int digits, int setupIndex, int numRegions); + +SP_API void spSequence_dispose(spSequence *self); + +SP_API spSequence *spSequence_copy(spSequence *self); + +SP_API void spSequence_apply(spSequence *self, spSlot *slot, spAttachment *attachment); + +SP_API void spSequence_getPath(const char* basePath, int index, char *path); + +#define SP_SEQUENCE_MODE_HOLD 0 +#define SP_SEQUENCE_MODE_ONCE 1 +#define SP_SEQUENCE_MODE_LOOP 2 +#define SP_SEQUENCE_MODE_PINGPONG 3 +#define SP_SEQUENCE_MODE_ONCEREVERSE 4 +#define SP_SEQUENCE_MODE_LOOPREVERSE 5 +#define SP_SEQUENCE_MODE_PINGPONGREVERSE 6 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/spine-c/spine-c/include/spine/Skeleton.h b/spine-c/spine-c/include/spine/Skeleton.h index 8fe55806e..bb9d842ef 100644 --- a/spine-c/spine-c/include/spine/Skeleton.h +++ b/spine-c/spine-c/include/spine/Skeleton.h @@ -64,7 +64,6 @@ typedef struct spSkeleton { spSkin *const skin; spColor color; - float time; float scaleX, scaleY; float x, y; } spSkeleton; @@ -120,8 +119,6 @@ SP_API spTransformConstraint *spSkeleton_findTransformConstraint(const spSkeleto /* Returns 0 if the path constraint was not found. */ SP_API spPathConstraint *spSkeleton_findPathConstraint(const spSkeleton *self, const char *constraintName); -SP_API void spSkeleton_update(spSkeleton *self, float deltaTime); - #ifdef __cplusplus } #endif diff --git a/spine-c/spine-c/include/spine/Slot.h b/spine-c/spine-c/include/spine/Slot.h index c464eb92b..40d52c98b 100644 --- a/spine-c/spine-c/include/spine/Slot.h +++ b/spine-c/spine-c/include/spine/Slot.h @@ -50,6 +50,8 @@ typedef struct spSlot { int deformCapacity; int deformCount; float *deform; + + int sequenceIndex; } spSlot; SP_API spSlot *spSlot_create(spSlotData *data, spBone *bone); @@ -59,10 +61,6 @@ SP_API void spSlot_dispose(spSlot *self); /* @param attachment May be 0 to clear the attachment for the slot. */ SP_API void spSlot_setAttachment(spSlot *self, spAttachment *attachment); -SP_API void spSlot_setAttachmentTime(spSlot *self, float time); - -SP_API float spSlot_getAttachmentTime(const spSlot *self); - SP_API void spSlot_setToSetupPose(spSlot *self); #ifdef __cplusplus diff --git a/spine-c/spine-c/include/spine/TextureRegion.h b/spine-c/spine-c/include/spine/TextureRegion.h new file mode 100644 index 000000000..f672297c3 --- /dev/null +++ b/spine-c/spine-c/include/spine/TextureRegion.h @@ -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. + *****************************************************************************/ + +#ifndef SPINE_TEXTURE_REGION_H +#define SPINE_TEXTURE_REGION_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spTextureRegion { + void *rendererObject; + float u, v, u2, v2; + int degrees; + float offsetX, offsetY; + int width, height; + int originalWidth, originalHeight; +} spTextureRegion; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/spine-c/spine-c/include/spine/VertexAttachment.h b/spine-c/spine-c/include/spine/VertexAttachment.h index 6539e01df..91d6b49b1 100644 --- a/spine-c/spine-c/include/spine/VertexAttachment.h +++ b/spine-c/spine-c/include/spine/VertexAttachment.h @@ -50,7 +50,7 @@ struct spVertexAttachment { int worldVerticesLength; - spVertexAttachment *deformAttachment; + spAttachment *timelineAttachment; int id; }; diff --git a/spine-c/spine-c/include/spine/extension.h b/spine-c/spine-c/include/spine/extension.h index 553fd2ace..ac5dd8971 100644 --- a/spine-c/spine-c/include/spine/extension.h +++ b/spine-c/spine-c/include/spine/extension.h @@ -246,7 +246,7 @@ void _spAttachmentLoader_init(spAttachmentLoader *self, void (*dispose)(spAttachmentLoader *self), spAttachment *(*createAttachment)(spAttachmentLoader *self, spSkin *skin, spAttachmentType type, const char *name, - const char *path), + const char *path, spSequence *sequence), void (*configureAttachment)(spAttachmentLoader *self, spAttachment *), void (*disposeAttachment)(spAttachmentLoader *self, spAttachment *) ); diff --git a/spine-c/spine-c/src/spine/Animation.c b/spine-c/spine-c/src/spine/Animation.c index 8d768a12e..27c963cd7 100644 --- a/spine-c/spine-c/src/spine/Animation.c +++ b/spine-c/spine-c/src/spine/Animation.c @@ -1775,7 +1775,7 @@ void _spDeformTimeline_apply( case SP_ATTACHMENT_MESH: case SP_ATTACHMENT_PATH: { spVertexAttachment *vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment); - if (vertexAttachment->deformAttachment != SUB_CAST(spVertexAttachment, self->attachment)) return; + if (vertexAttachment->timelineAttachment != self->attachment) return; break; } default: diff --git a/spine-c/spine-c/src/spine/Atlas.c b/spine-c/spine-c/src/spine/Atlas.c index 112a500ca..c71c321ba 100644 --- a/spine-c/spine-c/src/spine/Atlas.c +++ b/spine-c/spine-c/src/spine/Atlas.c @@ -356,29 +356,29 @@ spAtlas *spAtlas_create(const char *begin, int length, const char *dir, void *re region->x = ss_toInt(&entry[1]); region->y = ss_toInt(&entry[2]); } else if (ss_equals(&entry[0], "size")) { - region->width = ss_toInt(&entry[1]); - region->height = ss_toInt(&entry[2]); + region->super.width = ss_toInt(&entry[1]); + region->super.height = ss_toInt(&entry[2]); } else if (ss_equals(&entry[0], "bounds")) { region->x = ss_toInt(&entry[1]); region->y = ss_toInt(&entry[2]); - region->width = ss_toInt(&entry[3]); - region->height = ss_toInt(&entry[4]); + region->super.width = ss_toInt(&entry[3]); + region->super.height = ss_toInt(&entry[4]); } else if (ss_equals(&entry[0], "offset")) { - region->offsetX = ss_toInt(&entry[1]); - region->offsetY = ss_toInt(&entry[2]); + region->super.offsetX = ss_toInt(&entry[1]); + region->super.offsetY = ss_toInt(&entry[2]); } else if (ss_equals(&entry[0], "orig")) { - region->originalWidth = ss_toInt(&entry[1]); - region->originalHeight = ss_toInt(&entry[2]); + region->super.originalWidth = ss_toInt(&entry[1]); + region->super.originalHeight = ss_toInt(&entry[2]); } else if (ss_equals(&entry[0], "offsets")) { - region->offsetX = ss_toInt(&entry[1]); - region->offsetY = ss_toInt(&entry[2]); - region->originalWidth = ss_toInt(&entry[3]); - region->originalHeight = ss_toInt(&entry[4]); + region->super.offsetX = ss_toInt(&entry[1]); + region->super.offsetY = ss_toInt(&entry[2]); + region->super.originalWidth = ss_toInt(&entry[3]); + region->super.originalHeight = ss_toInt(&entry[4]); } else if (ss_equals(&entry[0], "rotate")) { if (ss_equals(&entry[1], "true")) { - region->degrees = 90; + region->super.degrees = 90; } else if (!ss_equals(&entry[1], "false")) { - region->degrees = ss_toInt(&entry[1]); + region->super.degrees = ss_toInt(&entry[1]); } } else if (ss_equals(&entry[0], "index")) { region->index = ss_toInt(&entry[1]); @@ -392,19 +392,19 @@ spAtlas *spAtlas_create(const char *begin, int length, const char *dir, void *re spKeyValueArray_add(region->keyValues, keyValue); } } - if (region->originalWidth == 0 && region->originalHeight == 0) { - region->originalWidth = region->width; - region->originalHeight = region->height; + if (region->super.originalWidth == 0 && region->super.originalHeight == 0) { + region->super.originalWidth = region->super.width; + region->super.originalHeight = region->super.height; } - region->u = (float) region->x / page->width; - region->v = (float) region->y / page->height; - if (region->degrees == 90) { - region->u2 = (float) (region->x + region->height) / page->width; - region->v2 = (float) (region->y + region->width) / page->height; + region->super.u = (float) region->x / page->width; + region->super.v = (float) region->y / page->height; + if (region->super.degrees == 90) { + region->super.u2 = (float) (region->x + region->super.height) / page->width; + region->super.v2 = (float) (region->y + region->super.width) / page->height; } else { - region->u2 = (float) (region->x + region->width) / page->width; - region->v2 = (float) (region->y + region->height) / page->height; + region->super.u2 = (float) (region->x + region->super.width) / page->width; + region->super.v2 = (float) (region->y + region->super.height) / page->height; } } } diff --git a/spine-c/spine-c/src/spine/AtlasAttachmentLoader.c b/spine-c/spine-c/src/spine/AtlasAttachmentLoader.c index 17954b98e..6055b30e8 100644 --- a/spine-c/spine-c/src/spine/AtlasAttachmentLoader.c +++ b/spine-c/spine-c/src/spine/AtlasAttachmentLoader.c @@ -29,50 +29,68 @@ #include #include +#include + +static int /*bool*/ loadSequence(spAtlas *atlas, const char *basePath, spSequence *sequence) { + spTextureRegionArray *regions = sequence->regions; + char *path = CALLOC(char, strlen(basePath) + sequence->digits + 1); + int i ; + for (i = 0; i < regions->size; i++) { + spSequence_getPath(basePath, i, path); + regions->items[i] = SUPER(spAtlas_findRegion(atlas, path)); + if (!regions->items[i]) { + FREE(path); + return 0; + } + regions->items[i]->rendererObject = regions->items[i]; + } + FREE(path); + return -1; +} spAttachment *_spAtlasAttachmentLoader_createAttachment(spAttachmentLoader *loader, spSkin *skin, spAttachmentType type, - const char *name, const char *path) { + const char *name, const char *path, spSequence *sequence) { spAtlasAttachmentLoader *self = SUB_CAST(spAtlasAttachmentLoader, loader); switch (type) { case SP_ATTACHMENT_REGION: { - spRegionAttachment *attachment; - spAtlasRegion *region = spAtlas_findRegion(self->atlas, path); - if (!region) { - _spAttachmentLoader_setError(loader, "Region not found: ", path); - return 0; + spRegionAttachment *attachment = spRegionAttachment_create(name); + if (sequence) { + if (!loadSequence(self->atlas, path, sequence)) { + spAttachment_dispose(SUPER(attachment)); + _spAttachmentLoader_setError(loader, "Couldn't load sequence for region attachment: ", path); + return 0; + } + } else { + spAtlasRegion *region = spAtlas_findRegion(self->atlas, path); + if (!region) { + spAttachment_dispose(SUPER(attachment)); + _spAttachmentLoader_setError(loader, "Region not found: ", path); + return 0; + } + attachment->rendererObject = region; + attachment->region = SUPER(region); } - attachment = spRegionAttachment_create(name); - attachment->rendererObject = region; - spRegionAttachment_setUVs(attachment, region->u, region->v, region->u2, region->v2, region->degrees); - attachment->regionOffsetX = region->offsetX; - attachment->regionOffsetY = region->offsetY; - attachment->regionWidth = region->width; - attachment->regionHeight = region->height; - attachment->regionOriginalWidth = region->originalWidth; - attachment->regionOriginalHeight = region->originalHeight; return SUPER(attachment); } case SP_ATTACHMENT_MESH: case SP_ATTACHMENT_LINKED_MESH: { - spMeshAttachment *attachment; - spAtlasRegion *region = spAtlas_findRegion(self->atlas, path); - if (!region) { - _spAttachmentLoader_setError(loader, "Region not found: ", path); - return 0; + spMeshAttachment *attachment = spMeshAttachment_create(name); + + if (sequence) { + if (!loadSequence(self->atlas, path, sequence)) { + spAttachment_dispose(SUPER(SUPER(attachment))); + _spAttachmentLoader_setError(loader, "Couldn't load sequence for mesh attachment: ", path); + return 0; + } + } else { + spAtlasRegion *region = spAtlas_findRegion(self->atlas, path); + if (!region) { + _spAttachmentLoader_setError(loader, "Region not found: ", path); + return 0; + } + attachment->rendererObject = region; + attachment->region = SUPER(region); } - attachment = spMeshAttachment_create(name); - attachment->rendererObject = region; - attachment->regionU = region->u; - attachment->regionV = region->v; - attachment->regionU2 = region->u2; - attachment->regionV2 = region->v2; - attachment->regionDegrees = region->degrees; - attachment->regionOffsetX = region->offsetX; - attachment->regionOffsetY = region->offsetY; - attachment->regionWidth = region->width; - attachment->regionHeight = region->height; - attachment->regionOriginalWidth = region->originalWidth; - attachment->regionOriginalHeight = region->originalHeight; return SUPER(SUPER(attachment)); } case SP_ATTACHMENT_BOUNDING_BOX: diff --git a/spine-c/spine-c/src/spine/AttachmentLoader.c b/spine-c/spine-c/src/spine/AttachmentLoader.c index 3fae52a94..de23cb280 100644 --- a/spine-c/spine-c/src/spine/AttachmentLoader.c +++ b/spine-c/spine-c/src/spine/AttachmentLoader.c @@ -33,7 +33,7 @@ typedef struct _spAttachmentLoaderVtable { spAttachment *(*createAttachment)(spAttachmentLoader *self, spSkin *skin, spAttachmentType type, const char *name, - const char *path); + const char *path, spSequence *sequence); void (*configureAttachment)(spAttachmentLoader *self, spAttachment *); @@ -46,7 +46,7 @@ void _spAttachmentLoader_init(spAttachmentLoader *self, void (*dispose)(spAttachmentLoader *self), spAttachment *(*createAttachment)(spAttachmentLoader *self, spSkin *skin, spAttachmentType type, const char *name, - const char *path), + const char *path, spSequence *sequence), void (*configureAttachment)(spAttachmentLoader *self, spAttachment *), void (*disposeAttachment)(spAttachmentLoader *self, spAttachment *)) { CONST_CAST(_spAttachmentLoaderVtable *, self->vtable) = NEW(_spAttachmentLoaderVtable); @@ -69,12 +69,12 @@ void spAttachmentLoader_dispose(spAttachmentLoader *self) { spAttachment * spAttachmentLoader_createAttachment(spAttachmentLoader *self, spSkin *skin, spAttachmentType type, const char *name, - const char *path) { + const char *path, spSequence *sequence) { FREE(self->error1); FREE(self->error2); self->error1 = 0; self->error2 = 0; - return VTABLE(spAttachmentLoader, self)->createAttachment(self, skin, type, name, path); + return VTABLE(spAttachmentLoader, self)->createAttachment(self, skin, type, name, path, sequence); } void spAttachmentLoader_configureAttachment(spAttachmentLoader *self, spAttachment *attachment) { diff --git a/spine-c/spine-c/src/spine/MeshAttachment.c b/spine-c/spine-c/src/spine/MeshAttachment.c index 55f1808e4..718909e04 100644 --- a/spine-c/spine-c/src/spine/MeshAttachment.c +++ b/spine-c/spine-c/src/spine/MeshAttachment.c @@ -42,6 +42,7 @@ void _spMeshAttachment_dispose(spAttachment *attachment) { FREE(self->edges); } else _spAttachment_deinit(attachment); + if (self->sequence) FREE(self->sequence); FREE(self); } @@ -52,17 +53,8 @@ spAttachment *_spMeshAttachment_copy(spAttachment *attachment) { return SUPER(SUPER(spMeshAttachment_newLinkedMesh(self))); copy = spMeshAttachment_create(attachment->name); copy->rendererObject = self->rendererObject; - copy->regionU = self->regionU; - copy->regionV = self->regionV; - copy->regionU2 = self->regionU2; - copy->regionV2 = self->regionV2; - copy->regionDegrees = self->regionDegrees; - copy->regionOffsetX = self->regionOffsetX; - copy->regionOffsetY = self->regionOffsetY; - copy->regionWidth = self->regionWidth; - copy->regionHeight = self->regionHeight; - copy->regionOriginalWidth = self->regionOriginalWidth; - copy->regionOriginalHeight = self->regionOriginalHeight; + copy->region = self->region; + copy->sequence = self->sequence != NULL ? spSequence_copy(self->sequence) : NULL; MALLOC_STR(copy->path, self->path); spColor_setFromColor(©->color, &self->color); @@ -90,22 +82,12 @@ spMeshAttachment *spMeshAttachment_newLinkedMesh(spMeshAttachment *self) { spMeshAttachment *copy = spMeshAttachment_create(self->super.super.name); copy->rendererObject = self->rendererObject; - copy->regionU = self->regionU; - copy->regionV = self->regionV; - copy->regionU2 = self->regionU2; - copy->regionV2 = self->regionV2; - copy->regionDegrees = self->regionDegrees; - copy->regionOffsetX = self->regionOffsetX; - copy->regionOffsetY = self->regionOffsetY; - copy->regionWidth = self->regionWidth; - copy->regionHeight = self->regionHeight; - copy->regionOriginalWidth = self->regionOriginalWidth; - copy->regionOriginalHeight = self->regionOriginalHeight; + copy->region = self->region; MALLOC_STR(copy->path, self->path); spColor_setFromColor(©->color, &self->color); - copy->super.deformAttachment = self->super.deformAttachment; + copy->super.timelineAttachment = self->super.timelineAttachment; spMeshAttachment_setParentMesh(copy, self->parentMesh ? self->parentMesh : self); - spMeshAttachment_updateUVs(copy); + if (copy->region) spMeshAttachment_updateRegion(copy); return copy; } @@ -117,7 +99,7 @@ spMeshAttachment *spMeshAttachment_create(const char *name) { return self; } -void spMeshAttachment_updateUVs(spMeshAttachment *self) { +void spMeshAttachment_updateRegion(spMeshAttachment *self) { int i, n; float *uvs; float u, v, width, height; @@ -125,17 +107,17 @@ void spMeshAttachment_updateUVs(spMeshAttachment *self) { FREE(self->uvs); uvs = self->uvs = MALLOC(float, verticesLength); n = verticesLength; - u = self->regionU; - v = self->regionV; + u = self->region->u; + v = self->region->v; - switch (self->regionDegrees) { + switch (self->region->degrees) { case 90: { - float textureWidth = self->regionHeight / (self->regionU2 - self->regionU); - float textureHeight = self->regionWidth / (self->regionV2 - self->regionV); - u -= (self->regionOriginalHeight - self->regionOffsetY - self->regionHeight) / textureWidth; - v -= (self->regionOriginalWidth - self->regionOffsetX - self->regionWidth) / textureHeight; - width = self->regionOriginalHeight / textureWidth; - height = self->regionOriginalWidth / textureHeight; + float textureWidth = self->region->height / (self->region->u2 - self->region->u); + float textureHeight = self->region->width / (self->region->v2 - self->region->v); + u -= (self->region->originalHeight - self->region->offsetY - self->region->height) / textureWidth; + v -= (self->region->originalWidth - self->region->offsetX - self->region->width) / textureHeight; + width = self->region->originalHeight / textureWidth; + height = self->region->originalWidth / textureHeight; for (i = 0; i < n; i += 2) { uvs[i] = u + self->regionUVs[i + 1] * width; uvs[i + 1] = v + (1 - self->regionUVs[i]) * height; @@ -143,12 +125,12 @@ void spMeshAttachment_updateUVs(spMeshAttachment *self) { return; } case 180: { - float textureWidth = self->regionWidth / (self->regionU2 - self->regionU); - float textureHeight = self->regionHeight / (self->regionV2 - self->regionV); - u -= (self->regionOriginalWidth - self->regionOffsetX - self->regionWidth) / textureWidth; - v -= self->regionOffsetY / textureHeight; - width = self->regionOriginalWidth / textureWidth; - height = self->regionOriginalHeight / textureHeight; + float textureWidth = self->region->width / (self->region->u2 - self->region->u); + float textureHeight = self->region->height / (self->region->v2 - self->region->v); + u -= (self->region->originalWidth - self->region->offsetX - self->region->width) / textureWidth; + v -= self->region->offsetY / textureHeight; + width = self->region->originalWidth / textureWidth; + height = self->region->originalHeight / textureHeight; for (i = 0; i < n; i += 2) { uvs[i] = u + (1 - self->regionUVs[i]) * width; uvs[i + 1] = v + (1 - self->regionUVs[i + 1]) * height; @@ -156,12 +138,12 @@ void spMeshAttachment_updateUVs(spMeshAttachment *self) { return; } case 270: { - float textureHeight = self->regionHeight / (self->regionV2 - self->regionV); - float textureWidth = self->regionWidth / (self->regionU2 - self->regionU); - u -= self->regionOffsetY / textureWidth; - v -= self->regionOffsetX / textureHeight; - width = self->regionOriginalHeight / textureWidth; - height = self->regionOriginalWidth / textureHeight; + float textureHeight = self->region->height / (self->region->v2 - self->region->v); + float textureWidth = self->region->width / (self->region->u2 - self->region->u); + u -= self->region->offsetY / textureWidth; + v -= self->region->offsetX / textureHeight; + width = self->region->originalHeight / textureWidth; + height = self->region->originalWidth / textureHeight; for (i = 0; i < n; i += 2) { uvs[i] = u + (1 - self->regionUVs[i + 1]) * width; uvs[i + 1] = v + self->regionUVs[i] * height; @@ -169,12 +151,12 @@ void spMeshAttachment_updateUVs(spMeshAttachment *self) { return; } default: { - float textureWidth = self->regionWidth / (self->regionU2 - self->regionU); - float textureHeight = self->regionHeight / (self->regionV2 - self->regionV); - u -= self->regionOffsetX / textureWidth; - v -= (self->regionOriginalHeight - self->regionOffsetY - self->regionHeight) / textureHeight; - width = self->regionOriginalWidth / textureWidth; - height = self->regionOriginalHeight / textureHeight; + float textureWidth = self->region->width / (self->region->u2 - self->region->u); + float textureHeight = self->region->height / (self->region->v2 - self->region->v); + u -= self->region->offsetX / textureWidth; + v -= (self->region->originalHeight - self->region->offsetY - self->region->height) / textureHeight; + width = self->region->originalWidth / textureWidth; + height = self->region->originalHeight / textureHeight; for (i = 0; i < n; i += 2) { uvs[i] = u + self->regionUVs[i] * width; uvs[i + 1] = v + self->regionUVs[i + 1] * height; diff --git a/spine-c/spine-c/src/spine/RegionAttachment.c b/spine-c/spine-c/src/spine/RegionAttachment.c index 664873f9b..ba5f89536 100644 --- a/spine-c/spine-c/src/spine/RegionAttachment.c +++ b/spine-c/spine-c/src/spine/RegionAttachment.c @@ -51,12 +51,7 @@ void _spRegionAttachment_dispose(spAttachment *attachment) { spAttachment *_spRegionAttachment_copy(spAttachment *attachment) { spRegionAttachment *self = SUB_CAST(spRegionAttachment, attachment); spRegionAttachment *copy = spRegionAttachment_create(attachment->name); - copy->regionWidth = self->regionWidth; - copy->regionHeight = self->regionHeight; - copy->regionOffsetX = self->regionOffsetX; - copy->regionOffsetY = self->regionOffsetY; - copy->regionOriginalWidth = self->regionOriginalWidth; - copy->regionOriginalHeight = self->regionOriginalHeight; + copy->region = self->region; copy->rendererObject = self->rendererObject; MALLOC_STR(copy->path, self->path); copy->x = self->x; @@ -69,6 +64,7 @@ spAttachment *_spRegionAttachment_copy(spAttachment *attachment) { memcpy(copy->uvs, self->uvs, sizeof(float) * 8); memcpy(copy->offset, self->offset, sizeof(float) * 8); spColor_setFromColor(©->color, &self->color); + copy->sequence = self->sequence ? spSequence_copy(self->sequence) : NULL; return SUPER(copy); } @@ -81,35 +77,13 @@ spRegionAttachment *spRegionAttachment_create(const char *name) { return self; } -void spRegionAttachment_setUVs(spRegionAttachment *self, float u, float v, float u2, float v2, float degrees) { - if (degrees == 90) { - self->uvs[URX] = u; - self->uvs[URY] = v2; - self->uvs[BRX] = u; - self->uvs[BRY] = v; - self->uvs[BLX] = u2; - self->uvs[BLY] = v; - self->uvs[ULX] = u2; - self->uvs[ULY] = v2; - } else { - self->uvs[ULX] = u; - self->uvs[ULY] = v2; - self->uvs[URX] = u; - self->uvs[URY] = v; - self->uvs[BRX] = u2; - self->uvs[BRY] = v; - self->uvs[BLX] = u2; - self->uvs[BLY] = v2; - } -} - -void spRegionAttachment_updateOffset(spRegionAttachment *self) { - float regionScaleX = self->width / self->regionOriginalWidth * self->scaleX; - float regionScaleY = self->height / self->regionOriginalHeight * self->scaleY; - float localX = -self->width / 2 * self->scaleX + self->regionOffsetX * regionScaleX; - float localY = -self->height / 2 * self->scaleY + self->regionOffsetY * regionScaleY; - float localX2 = localX + self->regionWidth * regionScaleX; - float localY2 = localY + self->regionHeight * regionScaleY; +void spRegionAttachment_updateRegion(spRegionAttachment *self) { + float regionScaleX = self->width / self->region->originalWidth * self->scaleX; + float regionScaleY = self->height / self->region->originalHeight * self->scaleY; + float localX = -self->width / 2 * self->scaleX + self->region->offsetX * regionScaleX; + float localY = -self->height / 2 * self->scaleY + self->region->offsetY * regionScaleY; + float localX2 = localX + self->region->width * regionScaleX; + float localY2 = localY + self->region->height * regionScaleY; float radians = self->rotation * DEG_RAD; float cosine = COS(radians), sine = SIN(radians); float localXCos = localX * cosine + self->x; @@ -128,14 +102,37 @@ void spRegionAttachment_updateOffset(spRegionAttachment *self) { self->offset[URY] = localY2Cos + localX2Sin; self->offset[BRX] = localX2Cos - localYSin; self->offset[BRY] = localYCos + localX2Sin; + + if (self->region->degrees == 90) { + self->uvs[URX] = self->region->u; + self->uvs[URY] = self->region->v2; + self->uvs[BRX] = self->region->u; + self->uvs[BRY] = self->region->v; + self->uvs[BLX] = self->region->u2; + self->uvs[BLY] = self->region->v; + self->uvs[ULX] = self->region->u2; + self->uvs[ULY] = self->region->v2; + } else { + self->uvs[ULX] = self->region->u; + self->uvs[ULY] = self->region->v2; + self->uvs[URX] = self->region->u; + self->uvs[URY] = self->region->v; + self->uvs[BRX] = self->region->u2; + self->uvs[BRY] = self->region->v; + self->uvs[BLX] = self->region->u2; + self->uvs[BLY] = self->region->v2; + } } -void spRegionAttachment_computeWorldVertices(spRegionAttachment *self, spBone *bone, float *vertices, int offset, +void spRegionAttachment_computeWorldVertices(spRegionAttachment *self, spSlot *slot, float *vertices, int offset, int stride) { const float *offsets = self->offset; + spBone *bone = slot->bone; float x = bone->worldX, y = bone->worldY; float offsetX, offsetY; + if (self->sequence) spSequence_apply(self->sequence, slot, SUPER(self)); + offsetX = offsets[BRX]; offsetY = offsets[BRY]; vertices[offset] = offsetX * bone->a + offsetY * bone->b + x; /* br */ diff --git a/spine-c/spine-c/src/spine/Sequence.c b/spine-c/spine-c/src/spine/Sequence.c new file mode 100644 index 000000000..2811fbfdd --- /dev/null +++ b/spine-c/spine-c/src/spine/Sequence.c @@ -0,0 +1,92 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#include +#include + +_SP_ARRAY_IMPLEMENT_TYPE(spTextureRegionArray, spTextureRegion*) + +static int nextSequenceId = 0; + +spSequence *spSequence_create(int start, int digits, int setupIndex, int numRegions) { + spSequence *self = NEW(spSequence); + self->id = nextSequenceId++; + self->start = start; + self->digits = digits; + self->setupIndex = setupIndex; + self->regions = spTextureRegionArray_create(numRegions); + spTextureRegionArray_setSize(self->regions, numRegions); + return self; +} + +void spSequence_dispose(spSequence *self) { + FREE(self->regions); + FREE(self); +} + +spSequence *spSequence_copy(spSequence *self) { + int i = 0; + spSequence *copy = spSequence_create(self->start, self->digits, self->setupIndex, self->regions->size); + for (; i < self->regions->size; i++) + copy->regions->items[i] = self->regions->items[i]; + copy->start = self->start; + copy->digits = self->digits; + copy->setupIndex = self->setupIndex; + return copy; +} + +void spSequence_apply(spSequence *self, spSlot *slot, spAttachment *attachment) { + int index = slot->sequenceIndex; + spTextureRegion *region = NULL; + if (index == -1) index = self->setupIndex; + if (index >= (int) self->regions->size) index = self->regions->size - 1; + region = self->regions->items[index]; + + if (attachment->type == SP_ATTACHMENT_REGION) { + spRegionAttachment *regionAttachment = (spRegionAttachment*)attachment; + if (regionAttachment->region != region) { + regionAttachment->rendererObject = region; + regionAttachment->region = region; + spRegionAttachment_updateRegion(regionAttachment); + } + } + + if (attachment->type == SP_ATTACHMENT_MESH) { + spMeshAttachment *meshAttachment = (spMeshAttachment*)attachment; + if (meshAttachment->region != region) { + meshAttachment->rendererObject = region; + meshAttachment->region = region; + spMeshAttachment_updateRegion(meshAttachment); + } + } +} + +void spSequence_getPath(const char* basePath, int index, char* path) { + fix me +} diff --git a/spine-c/spine-c/src/spine/Skeleton.c b/spine-c/spine-c/src/spine/Skeleton.c index 84f2bf70d..f85bfe1b5 100644 --- a/spine-c/spine-c/src/spine/Skeleton.c +++ b/spine-c/spine-c/src/spine/Skeleton.c @@ -629,7 +629,3 @@ spPathConstraint *spSkeleton_findPathConstraint(const spSkeleton *self, const ch if (strcmp(self->pathConstraints[i]->data->name, constraintName) == 0) return self->pathConstraints[i]; return 0; } - -void spSkeleton_update(spSkeleton *self, float deltaTime) { - self->time += deltaTime; -} diff --git a/spine-c/spine-c/src/spine/SkeletonBinary.c b/spine-c/spine-c/src/spine/SkeletonBinary.c index 7a31ffdc0..b7d2b7b64 100644 --- a/spine-c/spine-c/src/spine/SkeletonBinary.c +++ b/spine-c/spine-c/src/spine/SkeletonBinary.c @@ -991,13 +991,13 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput region->width = readFloat(input) * self->scale; region->height = readFloat(input) * self->scale; readColor(input, ®ion->color.r, ®ion->color.g, ®ion->color.b, ®ion->color.a); - spRegionAttachment_updateOffset(region); + spRegionAttachment_updateRegion(region); spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); return attachment; } case SP_ATTACHMENT_BOUNDING_BOX: { int vertexCount = readVarint(input, 1); - spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0); + spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0, NULL); _readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount); if (nonessential) { spBoundingBoxAttachment *bbox = SUB_CAST(spBoundingBoxAttachment, attachment); @@ -1025,7 +1025,7 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput mesh->regionUVs = _readFloatArray(input, vertexCount << 1, 1); mesh->triangles = (unsigned short *) _readShortArray(input, &mesh->trianglesCount); _readVertices(self, input, SUPER(mesh), vertexCount); - spMeshAttachment_updateUVs(mesh); + spMeshAttachment_updateRegion(mesh); mesh->hullLength = readVarint(input, 1) << 1; if (nonessential) { mesh->edges = (int *) _readShortArray(input, &mesh->edgesCount); @@ -1067,7 +1067,7 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput return attachment; } case SP_ATTACHMENT_PATH: { - spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0); + spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0, NULL); spPathAttachment *path = SUB_CAST(spPathAttachment, attachment); int vertexCount = 0; path->closed = readBoolean(input); @@ -1086,7 +1086,7 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput return attachment; } case SP_ATTACHMENT_POINT: { - spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0); + spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0, NULL); spPointAttachment *point = SUB_CAST(spPointAttachment, attachment); point->rotation = readFloat(input); point->x = readFloat(input) * self->scale; @@ -1101,7 +1101,7 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput case SP_ATTACHMENT_CLIPPING: { int endSlotIndex = readVarint(input, 1); int vertexCount = readVarint(input, 1); - spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0); + spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0, NULL); spClippingAttachment *clip = SUB_CAST(spClippingAttachment, attachment); _readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount); if (nonessential) { @@ -1418,11 +1418,10 @@ spSkeletonData *spSkeletonBinary_readSkeletonData(spSkeletonBinary *self, const _spSkeletonBinary_setError(self, "Parent mesh not found: ", linkedMesh->parent); return NULL; } - linkedMesh->mesh->super.deformAttachment = linkedMesh->inheritDeform ? SUB_CAST(spVertexAttachment, parent) - : SUB_CAST(spVertexAttachment, - linkedMesh->mesh); + linkedMesh->mesh->super.timelineAttachment = linkedMesh->inheritDeform ? parent + : SUPER(SUPER(linkedMesh->mesh)); spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); - spMeshAttachment_updateUVs(linkedMesh->mesh); + spMeshAttachment_updateRegion(linkedMesh->mesh); spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); } diff --git a/spine-c/spine-c/src/spine/SkeletonJson.c b/spine-c/spine-c/src/spine/SkeletonJson.c index 2136fc83c..a0a94ec1b 100644 --- a/spine-c/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/spine-c/src/spine/SkeletonJson.c @@ -1352,7 +1352,7 @@ spSkeletonData *spSkeletonJson_readSkeletonData(spSkeletonJson *self, const char toColor(color, 3)); } - spRegionAttachment_updateOffset(region); + spRegionAttachment_updateRegion(region); spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); break; @@ -1392,7 +1392,7 @@ spSkeletonData *spSkeletonJson_readSkeletonData(spSkeletonJson *self, const char _readVertices(self, attachmentMap, SUPER(mesh), verticesLength); - spMeshAttachment_updateUVs(mesh); + spMeshAttachment_updateRegion(mesh); mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); @@ -1514,11 +1514,10 @@ spSkeletonData *spSkeletonJson_readSkeletonData(spSkeletonJson *self, const char _spSkeletonJson_setError(self, 0, "Parent mesh not found: ", linkedMesh->parent); return NULL; } - linkedMesh->mesh->super.deformAttachment = linkedMesh->inheritDeform ? SUB_CAST(spVertexAttachment, parent) - : SUB_CAST(spVertexAttachment, - linkedMesh->mesh); + linkedMesh->mesh->super.timelineAttachment = linkedMesh->inheritDeform ? parent + : SUPER(SUPER(linkedMesh->mesh)); spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); - spMeshAttachment_updateUVs(linkedMesh->mesh); + spMeshAttachment_updateRegion(linkedMesh->mesh); spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); } diff --git a/spine-c/spine-c/src/spine/Slot.c b/spine-c/spine-c/src/spine/Slot.c index bc39699e3..3973d775e 100644 --- a/spine-c/spine-c/src/spine/Slot.c +++ b/spine-c/spine-c/src/spine/Slot.c @@ -30,13 +30,8 @@ #include #include -typedef struct { - spSlot super; - float attachmentTime; -} _spSlot; - spSlot *spSlot_create(spSlotData *data, spBone *bone) { - spSlot *self = SUPER(NEW(_spSlot)); + spSlot *self = NEW(spSlot); CONST_CAST(spSlotData *, self->data) = data; CONST_CAST(spBone *, self->bone) = bone; spColor_setFromFloats(&self->color, 1, 1, 1, 1); @@ -68,20 +63,12 @@ void spSlot_setAttachment(spSlot *self, spAttachment *attachment) { if (attachment == self->attachment) return; if (!isVertexAttachment(attachment) || - !isVertexAttachment(self->attachment) || (SUB_CAST(spVertexAttachment, attachment)->deformAttachment != SUB_CAST(spVertexAttachment, self->attachment)->deformAttachment)) { + !isVertexAttachment(self->attachment) || (SUB_CAST(spVertexAttachment, attachment)->timelineAttachment != SUB_CAST(spVertexAttachment, self->attachment)->timelineAttachment)) { self->deformCount = 0; } CONST_CAST(spAttachment *, self->attachment) = attachment; - SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time; -} - -void spSlot_setAttachmentTime(spSlot *self, float time) { - SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time - time; -} - -float spSlot_getAttachmentTime(const spSlot *self) { - return self->bone->skeleton->time - SUB_CAST(_spSlot, self)->attachmentTime; + self->sequenceIndex = -1; } void spSlot_setToSetupPose(spSlot *self) { diff --git a/spine-c/spine-c/src/spine/VertexAttachment.c b/spine-c/spine-c/src/spine/VertexAttachment.c index e6c83f878..23ac0a4ad 100644 --- a/spine-c/spine-c/src/spine/VertexAttachment.c +++ b/spine-c/spine-c/src/spine/VertexAttachment.c @@ -35,7 +35,7 @@ static int nextID = 0; void _spVertexAttachment_init(spVertexAttachment *attachment) { attachment->id = nextID++; - attachment->deformAttachment = attachment; + attachment->timelineAttachment = SUPER(attachment); } void _spVertexAttachment_deinit(spVertexAttachment *attachment) { @@ -52,6 +52,11 @@ void spVertexAttachment_computeWorldVertices(spVertexAttachment *self, spSlot *s float *vertices; int *bones; + if (self->super.type == SP_ATTACHMENT_MESH || self->super.type == SP_ATTACHMENT_LINKED_MESH) { + spMeshAttachment *mesh = SUB_CAST(spMeshAttachment, self); + if (mesh->sequence) spSequence_apply(mesh->sequence, slot, SUPER(self)); + } + count = offset + (count >> 1) * stride; skeleton = slot->bone->skeleton; deformLength = slot->deformCount; diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index b87d667f9..fcd3819f0 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -249,7 +249,6 @@ namespace spine { void SkeletonRenderer::update(float deltaTime) { Node::update(deltaTime); - if (_ownsSkeleton) _skeleton->update(deltaTime * _timeScale); } void SkeletonRenderer::draw(Renderer *renderer, const Mat4 &transform, uint32_t transformFlags) { @@ -657,7 +656,7 @@ namespace spine { RegionAttachment *attachment = (RegionAttachment *) slot->getAttachment(); float worldVertices[8]; - attachment->computeWorldVertices(slot->getBone(), worldVertices, 0, 2); + attachment->computeWorldVertices(*slot, worldVertices, 0, 2); const Vec2 points[4] = { {worldVertices[0], worldVertices[1]}, @@ -958,7 +957,7 @@ namespace spine { if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { RegionAttachment *const regionAttachment = static_cast(attachment); assert(dstPtr + 8 <= dstEnd); - regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2); + regionAttachment->computeWorldVertices(slot, dstPtr, 0, 2); dstPtr += 8; } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { MeshAttachment *const mesh = static_cast(attachment); diff --git a/spine-cpp/spine-cpp/include/spine/Animation.h b/spine-cpp/spine-cpp/include/spine/Animation.h index cc9b35a49..a670c3bca 100644 --- a/spine-cpp/spine-cpp/include/spine/Animation.h +++ b/spine-cpp/spine-cpp/include/spine/Animation.h @@ -116,16 +116,15 @@ namespace spine { void setDuration(float inValue); + /// @param target After the first and before the last entry. + static int search(Vector &values, float target); + + static int search(Vector &values, float target, int step); private: Vector _timelines; HashMap _timelineIds; float _duration; String _name; - - /// @param target After the first and before the last entry. - static int search(Vector &values, float target); - - static int search(Vector &values, float target, int step); }; } diff --git a/spine-cpp/spine-cpp/include/spine/LinkedMesh.h b/spine-cpp/spine-cpp/include/spine/LinkedMesh.h index 8b6271d07..3af86be72 100644 --- a/spine-cpp/spine-cpp/include/spine/LinkedMesh.h +++ b/spine-cpp/spine-cpp/include/spine/LinkedMesh.h @@ -43,14 +43,14 @@ namespace spine { public: LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent, - bool inheritDeform); + bool inheritTimeline); private: MeshAttachment *_mesh; String _skin; size_t _slotIndex; String _parent; - bool _inheritDeform; + bool _inheritTimeline; }; } diff --git a/spine-cpp/spine-cpp/include/spine/Property.h b/spine-cpp/spine-cpp/include/spine/Property.h index c51063ced..1d5a1e419 100644 --- a/spine-cpp/spine-cpp/include/spine/Property.h +++ b/spine-cpp/spine-cpp/include/spine/Property.h @@ -51,7 +51,8 @@ namespace spine { Property_TransformConstraint = 1 << 15, Property_PathConstraintPosition = 1 << 16, Property_PathConstraintSpacing = 1 << 17, - Property_PathConstraintMix = 1 << 18 + Property_PathConstraintMix = 1 << 18, + Property_Sequence = 1 << 19 }; } diff --git a/spine-cpp/spine-cpp/include/spine/RegionAttachment.h b/spine-cpp/spine-cpp/include/spine/RegionAttachment.h index 00d613ab5..bd8cc1827 100644 --- a/spine-cpp/spine-cpp/include/spine/RegionAttachment.h +++ b/spine-cpp/spine-cpp/include/spine/RegionAttachment.h @@ -60,8 +60,6 @@ namespace spine { void updateRegion(); - void setUVs(float u, float v, float u2, float v2, float degrees); - /// Transforms the attachment's four vertices to world coordinates. /// @param bone The parent bone. /// @param worldVertices The output world vertices. Must have a length greater than or equal to offset + 8. diff --git a/spine-cpp/spine-cpp/include/spine/Sequence.h b/spine-cpp/spine-cpp/include/spine/Sequence.h index e697eb891..41f53ecbc 100644 --- a/spine-cpp/spine-cpp/include/spine/Sequence.h +++ b/spine-cpp/spine-cpp/include/spine/Sequence.h @@ -39,12 +39,14 @@ namespace spine { class Attachment; + class SkeletonBinary; + class SkeletonJson; + class SP_API Sequence : public SpineObject { - + friend class SkeletonBinary; + friend class SkeletonJson; public: - explicit Sequence(); - - Sequence(int id, const Vector ®ions, int start, int digits, int setupIndex); + Sequence(int count); ~Sequence(); diff --git a/spine-cpp/spine-cpp/include/spine/SequenceTimeline.h b/spine-cpp/spine-cpp/include/spine/SequenceTimeline.h new file mode 100644 index 000000000..ed5e7c8aa --- /dev/null +++ b/spine-cpp/spine-cpp/include/spine/SequenceTimeline.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef Spine_SequenceTimeline_h +#define Spine_SequenceTimeline_h + +#ifdef SPINE_UE4 +#include "SpinePluginPrivatePCH.h" +#endif + +#include +#include + +namespace spine { + class Attachment; + + class SP_API SequenceTimeline : public Timeline { + friend class SkeletonBinary; + + friend class SkeletonJson; + + RTTI_DECL + + public: + explicit SequenceTimeline(size_t frameCount, int slotIndex, spine::Attachment *attachment); + + virtual ~SequenceTimeline(); + + virtual void + apply(Skeleton &skeleton, float lastTime, float time, Vector *pEvents, float alpha, MixBlend blend, + MixDirection direction); + + void setFrame(int frame, float time, SequenceMode mode, int index, float delay); + + int getSlotIndex() { return _slotIndex; }; + + void setSlotIndex(int inValue) { _slotIndex = inValue; } + + Attachment *getAttachment() { return _attachment; } + + protected: + int _slotIndex; + Attachment *_attachment; + + static const int ENTRIES = 3; + static const int MODE = 1; + static const int DELAY = 2; + }; +} + +#endif /* Spine_SequenceTimeline_h */ \ No newline at end of file diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h b/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h index 3ffe1d21b..e5078f1be 100644 --- a/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h +++ b/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h @@ -61,6 +61,8 @@ namespace spine { class CurveTimeline2; + class Sequence; + class SP_API SkeletonBinary : public SpineObject { public: static const int BONE_ROTATE = 0; @@ -81,6 +83,9 @@ namespace spine { static const int SLOT_RGB2 = 4; static const int SLOT_ALPHA = 5; + static const int ATTACHMENT_DEFORM = 0; + static const int ATTACHMENT_SEQUENCE = 1; + static const int PATH_POSITION = 0; static const int PATH_SPACING = 1; static const int PATH_MIX = 2; @@ -137,10 +142,12 @@ namespace spine { Skin *readSkin(DataInput *input, bool defaultSkin, SkeletonData *skeletonData, bool nonessential); + Sequence *readSequence(DataInput *input); + Attachment *readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName, SkeletonData *skeletonData, bool nonessential); - void readVertices(DataInput *input, VertexAttachment *attachment, int vertexCount); + void readVertices(DataInput *input, Vector &vertices, Vector &bones, int vertexCount); void readFloatArray(DataInput *input, int n, float scale, Vector &array); diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonJson.h b/spine-cpp/spine-cpp/include/spine/SkeletonJson.h index 8f3fd925e..9af35439e 100644 --- a/spine-cpp/spine-cpp/include/spine/SkeletonJson.h +++ b/spine-cpp/spine-cpp/include/spine/SkeletonJson.h @@ -59,6 +59,8 @@ namespace spine { class String; + class Sequence; + class SP_API SkeletonJson : public SpineObject { public: explicit SkeletonJson(Atlas *atlas); @@ -82,6 +84,8 @@ namespace spine { const bool _ownsLoader; String _error; + static Sequence *readSequence(Json *sequence); + static void setBezier(CurveTimeline *timeline, int frame, int value, int bezier, float time1, float value1, float cx1, float cy1, diff --git a/spine-cpp/spine-cpp/src/spine/AtlasAttachmentLoader.cpp b/spine-cpp/spine-cpp/src/spine/AtlasAttachmentLoader.cpp index f195bd47c..1a31f5e32 100644 --- a/spine-cpp/spine-cpp/src/spine/AtlasAttachmentLoader.cpp +++ b/spine-cpp/spine-cpp/src/spine/AtlasAttachmentLoader.cpp @@ -48,7 +48,7 @@ namespace spine { AtlasAttachmentLoader::AtlasAttachmentLoader(Atlas *atlas) : AttachmentLoader(), _atlas(atlas) { } - bool loadSequence (Atlas *atlas, const String &basePath, Sequence *sequence) { + bool loadSequence(Atlas *atlas, const String &basePath, Sequence *sequence) { Vector ®ions = sequence->getRegions(); for (int i = 0, n = regions.size(); i < n; i++) { String path = sequence->getPath(basePath, i); @@ -61,7 +61,7 @@ namespace spine { RegionAttachment *AtlasAttachmentLoader::newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) { SP_UNUSED(skin); - RegionAttachment *attachment = new(__FILE__, __LINE__) RegionAttachment(name); + RegionAttachment *attachment = new (__FILE__, __LINE__) RegionAttachment(name); if (sequence) { if (!loadSequence(_atlas, path, sequence)) return NULL; } else { diff --git a/spine-cpp/spine-cpp/src/spine/LinkedMesh.cpp b/spine-cpp/spine-cpp/src/spine/LinkedMesh.cpp index d240f79a3..ed70ec900 100644 --- a/spine-cpp/spine-cpp/src/spine/LinkedMesh.cpp +++ b/spine-cpp/spine-cpp/src/spine/LinkedMesh.cpp @@ -38,9 +38,9 @@ using namespace spine; LinkedMesh::LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent, - bool inheritDeform) : _mesh(mesh), - _skin(skin), - _slotIndex(slotIndex), - _parent(parent), - _inheritDeform(inheritDeform) { + bool inheritTimeline) : _mesh(mesh), + _skin(skin), + _slotIndex(slotIndex), + _parent(parent), + _inheritTimeline(inheritTimeline) { } diff --git a/spine-cpp/spine-cpp/src/spine/MeshAttachment.cpp b/spine-cpp/spine-cpp/src/spine/MeshAttachment.cpp index 987709876..0e0d1ce53 100644 --- a/spine-cpp/spine-cpp/src/spine/MeshAttachment.cpp +++ b/spine-cpp/spine-cpp/src/spine/MeshAttachment.cpp @@ -144,6 +144,22 @@ void MeshAttachment::setPath(const String &inValue) { _path = inValue; } +TextureRegion *MeshAttachment::getRegion() { + return _region; +} + +void MeshAttachment::setRegion(TextureRegion *region) { + _region = region; +} + +Sequence *MeshAttachment::getSequence() { + return _sequence; +} + +void MeshAttachment::setSequence(Sequence *sequence) { + _sequence = sequence; +} + MeshAttachment *MeshAttachment::getParentMesh() { return _parentMesh; } diff --git a/spine-cpp/spine-cpp/src/spine/Sequence.cpp b/spine-cpp/spine-cpp/src/spine/Sequence.cpp index 77794d49a..e43850e34 100644 --- a/spine-cpp/spine-cpp/src/spine/Sequence.cpp +++ b/spine-cpp/spine-cpp/src/spine/Sequence.cpp @@ -35,22 +35,21 @@ using namespace spine; -Sequence::Sequence() : _id(Sequence::getNextID()), - _regions(), - _start(0), - _digits(0), - _setupIndex(0) { - +Sequence::Sequence(int count) : _id(Sequence::getNextID()), + _regions(), + _start(0), + _digits(0), + _setupIndex(0) { + _regions.setSize(count, NULL); } Sequence::~Sequence() { - } Sequence *Sequence::copy() { - Sequence *copy = new (__FILE__, __LINE__) Sequence(); + Sequence *copy = new (__FILE__, __LINE__) Sequence(_regions.size()); for (size_t i = 0; i < _regions.size(); i++) { - copy->_regions.add(_regions[i]); + copy->_regions[i] = _regions[i]; } copy->_start = _start; copy->_digits = _digits; @@ -61,12 +60,13 @@ Sequence *Sequence::copy() { void Sequence::apply(Slot *slot, Attachment *attachment) { int index = slot->getSequenceIndex(); if (index == -1) index = _setupIndex; - if (index >= (int)_regions.size()) index = _regions.size() - 1; + if (index >= (int) _regions.size()) index = _regions.size() - 1; TextureRegion *region = _regions[index]; if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { RegionAttachment *regionAttachment = static_cast(attachment); if (regionAttachment->getRegion() != region) { + regionAttachment->setRendererObject(region); regionAttachment->setRegion(region); regionAttachment->updateRegion(); } @@ -75,6 +75,7 @@ void Sequence::apply(Slot *slot, Attachment *attachment) { if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { MeshAttachment *meshAttachment = static_cast(attachment); if (meshAttachment->getRegion() != region) { + meshAttachment->setRendererObject(region); meshAttachment->setRegion(region); meshAttachment->updateRegion(); } diff --git a/spine-cpp/spine-cpp/src/spine/SequenceTimeline.cpp b/spine-cpp/spine-cpp/src/spine/SequenceTimeline.cpp new file mode 100644 index 000000000..374f81eed --- /dev/null +++ b/spine-cpp/spine-cpp/src/spine/SequenceTimeline.cpp @@ -0,0 +1,129 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifdef SPINE_UE4 +#include "SpinePluginPrivatePCH.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace spine; + +RTTI_IMPL(SequenceTimeline, Timeline) + +SequenceTimeline::SequenceTimeline(size_t frameCount, int slotIndex, Attachment *attachment) : Timeline(frameCount, ENTRIES), _slotIndex(slotIndex), _attachment(attachment) { + int sequenceId = 0; + if (attachment->getRTTI().instanceOf(RegionAttachment::rtti)) sequenceId = ((RegionAttachment *) attachment)->getSequence()->getId(); + if (attachment->getRTTI().instanceOf(MeshAttachment::rtti)) sequenceId = ((MeshAttachment *) attachment)->getSequence()->getId(); + PropertyId ids[] = {((PropertyId) Property_Sequence << 32) | ((slotIndex << 16 | sequenceId) & 0xffffffff)}; + setPropertyIds(ids, 1); +} + +SequenceTimeline::~SequenceTimeline() { +} + +void SequenceTimeline::setFrame(int frame, float time, SequenceMode mode, int index, float delay) { + Vector &frames = this->_frames; + frame *= ENTRIES; + frames[frame] = time; + frames[frame + MODE] = mode | (index << 4); + frames[frame + DELAY] = delay; +} + +void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector *pEvents, + float alpha, MixBlend blend, MixDirection direction) { + SP_UNUSED(alpha); + SP_UNUSED(lastTime); + SP_UNUSED(pEvents); + SP_UNUSED(direction); + + Slot *slot = skeleton.getSlots()[_slotIndex]; + if (!slot->getBone().isActive()) return; + Attachment *slotAttachment = slot->getAttachment(); + if (slotAttachment != _attachment) { + if (!slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti) || ((VertexAttachment *) slotAttachment)->getTimelineAttachment() != _attachment) return; + } + + Vector &frames = this->_frames; + if (time < frames[0]) {// Time is before first frame. + if (blend == MixBlend_Setup || blend == MixBlend_First) slot->setSequenceIndex(-1); + return; + } + + int i = Animation::search(frames, time, ENTRIES); + float before = frames[i]; + int modeAndIndex = (int) frames[i + MODE]; + float delay = frames[i + DELAY]; + + Sequence *sequence = NULL; + if (_attachment->getRTTI().instanceOf(RegionAttachment::rtti)) sequence = ((RegionAttachment *) _attachment)->getSequence(); + if (_attachment->getRTTI().instanceOf(MeshAttachment::rtti)) sequence = ((MeshAttachment *) _attachment)->getSequence(); + int index = modeAndIndex >> 4, count = sequence->getRegions().size(); + int mode = modeAndIndex & 0xf; + if (mode != SequenceMode::hold) { + index += (int) (((time - before) / delay + 0.00001)); + switch (mode) { + case SequenceMode::once: + index = MathUtil::min(count - 1, index); + break; + case SequenceMode::loop: + index %= count; + break; + case SequenceMode::pingpong: { + int n = (count << 1) - 2; + index %= n; + if (index >= count) index = n - index; + break; + } + case SequenceMode::onceReverse: + index = MathUtil::max(count - 1 - index, 0); + break; + case SequenceMode::loopReverse: + index = count - 1 - (index % count); + break; + case SequenceMode::pingpongReverse: { + int n = (count << 1) - 2; + index = (index + count - 1) % n; + if (index >= count) index = n - index; + } + } + } + slot->setSequenceIndex(index); +} \ No newline at end of file diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp index 47d70fd4a..a2f636a8a 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp @@ -72,6 +72,7 @@ #include #include #include +#include "spine/SequenceTimeline.h" using namespace spine; @@ -298,10 +299,10 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons setError("Parent mesh not found: ", linkedMesh->_parent.buffer()); return NULL; } - linkedMesh->_mesh->_timelineAttachment = linkedMesh->_inheritDeform ? static_cast(parent) - : linkedMesh->_mesh; + linkedMesh->_mesh->_timelineAttachment = linkedMesh->_inheritTimeline ? static_cast(parent) + : linkedMesh->_mesh; linkedMesh->_mesh->setParentMesh(static_cast(parent)); - linkedMesh->_mesh->updateRegion(); + if (linkedMesh->_mesh->_region) linkedMesh->_mesh->updateRegion(); _attachmentLoader->configureAttachment(linkedMesh->_mesh); } ContainerUtil::cleanUpVectorOfPointers(_linkedMeshes); @@ -478,6 +479,15 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData return skin; } +Sequence *SkeletonBinary::readSequence(DataInput *input) { + if (!readBoolean(input)) return NULL; + Sequence *sequence = new (__FILE__, __LINE__) Sequence(readVarint(input, true)); + sequence->_start = readVarint(input, true); + sequence->_digits = readVarint(input, true); + sequence->_setupIndex = readVarint(input, true); + return sequence; +} + Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName, SkeletonData *skeletonData, bool nonessential) { String name(readStringRef(input, skeletonData)); @@ -488,21 +498,32 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo case AttachmentType_Region: { String path(readStringRef(input, skeletonData)); if (path.isEmpty()) path = name; - RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path)); + float rotation = readFloat(input); + float x = readFloat(input) * _scale; + float y = readFloat(input) * _scale; + float scaleX = readFloat(input); + float scaleY = readFloat(input); + float width = readFloat(input) * _scale; + float height = readFloat(input) * _scale; + Color color; + readColor(input, color); + Sequence *sequence = readSequence(input); + RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence); if (!region) { setError("Error reading attachment: ", name.buffer()); return nullptr; } region->_path = path; - region->_rotation = readFloat(input); - region->_x = readFloat(input) * _scale; - region->_y = readFloat(input) * _scale; - region->_scaleX = readFloat(input); - region->_scaleY = readFloat(input); - region->_width = readFloat(input) * _scale; - region->_height = readFloat(input) * _scale; - readColor(input, region->getColor()); - region->updateRegion(); + region->_rotation = rotation; + region->_x = x; + region->_y = y; + region->_scaleX = scaleX; + region->_scaleY = scaleY; + region->_width = width; + region->_height = height; + region->getColor().set(color); + region->_sequence = sequence; + if (sequence == NULL) region->updateRegion(); _attachmentLoader->configureAttachment(region); return region; } @@ -513,7 +534,8 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo setError("Error reading attachment: ", name.buffer()); return nullptr; } - readVertices(input, static_cast(box), vertexCount); + readVertices(input, box->getVertices(), box->getBones(), vertexCount); + box->setWorldVerticesLength(vertexCount << 1); if (nonessential) { readColor(input, box->getColor()); } @@ -521,31 +543,52 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo return box; } case AttachmentType_Mesh: { + Color color; int vertexCount; - MeshAttachment *mesh; + Vector uvs; + Vector triangles; + Vector vertices; + Vector bones; + int hullLength; + Sequence *sequence; + float width = 0; + float height = 0; + Vector edges; + String path(readStringRef(input, skeletonData)); if (path.isEmpty()) path = name; + readColor(input, color); + vertexCount = readVarint(input, true); + readFloatArray(input, vertexCount << 1, 1, uvs); + readShortArray(input, triangles); + readVertices(input, vertices, bones, vertexCount); + hullLength = readVarint(input, true) << 1; + sequence = readSequence(input); + if (nonessential) { + readShortArray(input, edges); + width = readFloat(input) * _scale; + height = readFloat(input) * _scale; + } - mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path)); + MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence); if (!mesh) { setError("Error reading attachment: ", name.buffer()); return nullptr; } mesh->_path = path; - readColor(input, mesh->getColor()); - vertexCount = readVarint(input, true); - readFloatArray(input, vertexCount << 1, 1, mesh->getRegionUVs()); - readShortArray(input, mesh->getTriangles()); - readVertices(input, static_cast(mesh), vertexCount); - mesh->updateRegion(); - mesh->_hullLength = readVarint(input, true) << 1; + mesh->_color.set(color); + mesh->_bones.addAll(bones); + mesh->_vertices.addAll(vertices); + mesh->setWorldVerticesLength(vertexCount << 1); + mesh->_triangles.addAll(triangles); + mesh->_regionUVs.addAll(uvs); + if (sequence == NULL) mesh->updateRegion(); + mesh->_hullLength = hullLength; + mesh->_sequence = sequence; if (nonessential) { - readShortArray(input, mesh->getEdges()); - mesh->_width = readFloat(input) * _scale; - mesh->_height = readFloat(input) * _scale; - } else { - mesh->_width = 0; - mesh->_height = 0; + mesh->_edges.addAll(edges); + mesh->_width = width; + mesh->_height = height; } _attachmentLoader->configureAttachment(mesh); return mesh; @@ -554,23 +597,33 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo String path(readStringRef(input, skeletonData)); if (path.isEmpty()) path = name; - MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path)); + Color color; + float width, height; + readColor(input, color); + String skinName(readStringRef(input, skeletonData)); + String parent(readStringRef(input, skeletonData)); + bool inheritTimelines = readBoolean(input); + Sequence *sequence = readSequence(input); + if (nonessential) { + width = readFloat(input) * _scale; + height = readFloat(input) * _scale; + } + + MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence); if (!mesh) { setError("Error reading attachment: ", name.buffer()); return nullptr; } mesh->_path = path; - readColor(input, mesh->getColor()); - String skinName(readStringRef(input, skeletonData)); - String parent(readStringRef(input, skeletonData)); - bool inheritDeform = readBoolean(input); + mesh->_color.set(color); + mesh->_sequence = sequence; if (nonessential) { - mesh->_width = readFloat(input) * _scale; - mesh->_height = readFloat(input) * _scale; + mesh->_width = width; + mesh->_height = height; } LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, String(skinName), slotIndex, - String(parent), inheritDeform); + String(parent), inheritTimelines); _linkedMeshes.add(linkedMesh); return mesh; } @@ -583,7 +636,8 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo path->_closed = readBoolean(input); path->_constantSpeed = readBoolean(input); int vertexCount = readVarint(input, true); - readVertices(input, static_cast(path), vertexCount); + readVertices(input, path->getVertices(), path->getBones(), vertexCount); + path->setWorldVerticesLength(vertexCount << 1); int lengthsLength = vertexCount / 3; path->_lengths.setSize(lengthsLength, 0); for (int i = 0; i < lengthsLength; ++i) { @@ -619,7 +673,8 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo setError("Error reading attachment: ", name.buffer()); return nullptr; } - readVertices(input, static_cast(clip), vertexCount); + readVertices(input, clip->getVertices(), clip->getBones(), vertexCount); + clip->setWorldVerticesLength(vertexCount << 1); clip->_endSlot = skeletonData->_slots[endSlotIndex]; if (nonessential) { readColor(input, clip->getColor()); @@ -631,18 +686,15 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo return nullptr; } -void SkeletonBinary::readVertices(DataInput *input, VertexAttachment *attachment, int vertexCount) { +void SkeletonBinary::readVertices(DataInput *input, Vector &vertices, Vector &bones, int vertexCount) { float scale = _scale; int verticesLength = vertexCount << 1; - attachment->setWorldVerticesLength(vertexCount << 1); if (!readBoolean(input)) { - readFloatArray(input, verticesLength, scale, attachment->getVertices()); + readFloatArray(input, verticesLength, scale, vertices); return; } - Vector &vertices = attachment->getVertices(); - Vector &bones = attachment->getBones(); vertices.ensureCapacity(verticesLength * 3 * 3); bones.ensureCapacity(verticesLength * 3); @@ -1176,69 +1228,84 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S for (int iii = 0, nnn = readVarint(input, true); iii < nnn; iii++) { const char *attachmentName = readStringRef(input, skeletonData); Attachment *baseAttachment = skin->getAttachment(slotIndex, String(attachmentName)); - if (!baseAttachment) { ContainerUtil::cleanUpVectorOfPointers(timelines); setError("Attachment not found: ", attachmentName); return NULL; } - VertexAttachment *attachment = static_cast(baseAttachment); - - bool weighted = attachment->_bones.size() > 0; - Vector &vertices = attachment->_vertices; - int deformLength = weighted ? vertices.size() / 3 * 2 : vertices.size(); - + unsigned int timelineType = readByte(input); int frameCount = readVarint(input, true); int frameLast = frameCount - 1; - int bezierCount = readVarint(input, true); - DeformTimeline *timeline = new (__FILE__, __LINE__) DeformTimeline(frameCount, bezierCount, slotIndex, - attachment); - float time = readFloat(input); - for (int frame = 0, bezier = 0;; ++frame) { - Vector deform; - size_t end = (size_t) readVarint(input, true); - if (end == 0) { - if (weighted) { - deform.setSize(deformLength, 0); - for (int iiii = 0; iiii < deformLength; ++iiii) - deform[iiii] = 0; - } else { - deform.clearAndAddAll(vertices); - } - } else { - deform.setSize(deformLength, 0); - size_t start = (size_t) readVarint(input, true); - end += start; - if (scale == 1) { - for (size_t v = start; v < end; ++v) - deform[v] = readFloat(input); - } else { - for (size_t v = start; v < end; ++v) - deform[v] = readFloat(input) * scale; + switch (timelineType) { + case ATTACHMENT_DEFORM: { + bool weighted = attachment->_bones.size() > 0; + Vector &vertices = attachment->_vertices; + int deformLength = weighted ? vertices.size() / 3 * 2 : vertices.size(); + + int bezierCount = readVarint(input, true); + DeformTimeline *timeline = new (__FILE__, __LINE__) DeformTimeline(frameCount, bezierCount, slotIndex, + attachment); + + float time = readFloat(input); + for (int frame = 0, bezier = 0;; ++frame) { + Vector deform; + size_t end = (size_t) readVarint(input, true); + if (end == 0) { + if (weighted) { + deform.setSize(deformLength, 0); + for (int iiii = 0; iiii < deformLength; ++iiii) + deform[iiii] = 0; + } else { + deform.clearAndAddAll(vertices); + } + } else { + deform.setSize(deformLength, 0); + size_t start = (size_t) readVarint(input, true); + end += start; + if (scale == 1) { + for (size_t v = start; v < end; ++v) + deform[v] = readFloat(input); + } else { + for (size_t v = start; v < end; ++v) + deform[v] = readFloat(input) * scale; + } + + if (!weighted) { + for (size_t v = 0, vn = deform.size(); v < vn; ++v) + deform[v] += vertices[v]; + } + } + + timeline->setFrame(frame, time, deform); + if (frame == frameLast) break; + float time2 = readFloat(input); + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; } - if (!weighted) { - for (size_t v = 0, vn = deform.size(); v < vn; ++v) - deform[v] += vertices[v]; - } + timelines.add(timeline); + break; } - - timeline->setFrame(frame, time, deform); - if (frame == frameLast) break; - float time2 = readFloat(input); - switch (readSByte(input)) { - case CURVE_STEPPED: - timeline->setStepped(frame); - break; - case CURVE_BEZIER: - setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + case ATTACHMENT_SEQUENCE: { + SequenceTimeline *timeline = new (__FILE__, __LINE__) SequenceTimeline(frameCount, slotIndex, attachment); + for (int frame = 0; frame < frameCount; frame++) { + float time = readFloat(input); + int modeAndIndex = readInt(input); + float delay = readFloat(input); + timeline->setFrame(frame, time, (spine::SequenceMode)(modeAndIndex & 0xf), modeAndIndex >> 4, delay); + } + timelines.add(timeline); + break; } - time = time2; } - - timelines.add(timeline); } } } diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index 8fb442c09..4ef30094f 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -72,6 +72,7 @@ #include #include #include +#include "spine/SequenceTimeline.h" #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) #define strdup _strdup @@ -548,7 +549,8 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { switch (type) { case AttachmentType_Region: { - attachment = _attachmentLoader->newRegionAttachment(*skin, attachmentName, attachmentPath); + Sequence *sequence = readSequence(Json::getItem(attachmentMap, "sequence")); + attachment = _attachmentLoader->newRegionAttachment(*skin, attachmentName, attachmentPath, sequence); if (!attachment) { delete skeletonData; setError(root, "Error reading attachment: ", skinAttachmentName); @@ -565,17 +567,19 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { region->_rotation = Json::getFloat(attachmentMap, "rotation", 0); region->_width = Json::getFloat(attachmentMap, "width", 32) * _scale; region->_height = Json::getFloat(attachmentMap, "height", 32) * _scale; + region->_sequence = sequence; color = Json::getString(attachmentMap, "color", 0); if (color) toColor(region->getColor(), color, true); - region->updateRegion(); + if (region->_region != NULL) region->updateRegion(); _attachmentLoader->configureAttachment(region); break; } case AttachmentType_Mesh: case AttachmentType_Linkedmesh: { - attachment = _attachmentLoader->newMeshAttachment(*skin, attachmentName, attachmentPath); + Sequence *sequence = readSequence(Json::getItem(attachmentMap, "sequence")); + attachment = _attachmentLoader->newMeshAttachment(*skin, attachmentName, attachmentPath, sequence); if (!attachment) { delete skeletonData; @@ -591,6 +595,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { mesh->_width = Json::getFloat(attachmentMap, "width", 32) * _scale; mesh->_height = Json::getFloat(attachmentMap, "height", 32) * _scale; + mesh->_sequence = sequence; entry = Json::getItem(attachmentMap, "parent"); if (!entry) { @@ -610,7 +615,7 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { readVertices(attachmentMap, mesh, verticesLength); - mesh->updateRegion(); + if (mesh->_region != NULL) mesh->updateRegion(); mesh->_hullLength = Json::getInt(attachmentMap, "hull", 0); @@ -623,14 +628,14 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { } _attachmentLoader->configureAttachment(mesh); } else { - bool inheritDeform = Json::getInt(attachmentMap, "deform", 1) ? true : false; + bool inheritTimelines = Json::getInt(attachmentMap, "timelines", 1) ? true : false; LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, String(Json::getString( attachmentMap, "skin", 0)), slot->getIndex(), String(entry->_valueString), - inheritDeform); + inheritTimelines); _linkedMeshes.add(linkedMesh); } break; @@ -722,10 +727,10 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { setError(root, "Parent mesh not found: ", linkedMesh->_parent.buffer()); return NULL; } - linkedMesh->_mesh->_timelineAttachment = linkedMesh->_inheritDeform ? static_cast(parent) - : linkedMesh->_mesh; + linkedMesh->_mesh->_timelineAttachment = linkedMesh->_inheritTimeline ? static_cast(parent) + : linkedMesh->_mesh; linkedMesh->_mesh->setParentMesh(static_cast(parent)); - linkedMesh->_mesh->updateRegion(); + if (linkedMesh->_mesh->_region != NULL) linkedMesh->_mesh->updateRegion(); _attachmentLoader->configureAttachment(linkedMesh->_mesh); } ContainerUtil::cleanUpVectorOfPointers(_linkedMeshes); @@ -777,6 +782,15 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { return skeletonData; } +Sequence *SkeletonJson::readSequence(Json *item) { + if (item == NULL) return NULL; + Sequence *sequence = new Sequence(Json::getInt(item, "count", 0)); + sequence->_start = Json::getInt(item, "start", 1); + sequence->_digits = Json::getInt(item, "digits", 0); + sequence->_setupIndex = Json::getInt(item, "setupIndex", 0); + return sequence; +} + void SkeletonJson::setBezier(CurveTimeline *timeline, int frame, int value, int bezier, float time1, float value1, float cx1, float cy1, float cx2, float cy2, float time2, float value2) { @@ -865,10 +879,10 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { Json *ik = Json::getItem(root, "ik"); Json *transform = Json::getItem(root, "transform"); Json *paths = Json::getItem(root, "path"); - Json *deform = Json::getItem(root, "deform"); + Json *attachments = Json::getItem(root, "attachments"); Json *drawOrder = Json::getItem(root, "drawOrder"); Json *events = Json::getItem(root, "events"); - Json *boneMap, *slotMap, *constraintMap, *keyMap, *nextMap, *curve; + Json *boneMap, *slotMap, *keyMap, *nextMap, *curve; int frame, bezier; Color color, color2, newColor, newColor2; @@ -883,7 +897,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { AttachmentTimeline *timeline = new (__FILE__, __LINE__) AttachmentTimeline(frames, slotIndex); for (keyMap = timelineMap->_child, frame = 0; keyMap; keyMap = keyMap->_next, ++frame) { timeline->setFrame(frame, Json::getFloat(keyMap, "time", 0), - Json::getItem(keyMap, "name")->_valueString); + Json::getItem(keyMap, "name") ? Json::getItem(keyMap, "name")->_valueString : NULL); } timelines.add(timeline); @@ -1079,7 +1093,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { } /** IK constraint timelines. */ - for (constraintMap = ik ? ik->_child : 0; constraintMap; constraintMap = constraintMap->_next) { + for (Json *constraintMap = ik ? ik->_child : 0; constraintMap; constraintMap = constraintMap->_next) { keyMap = constraintMap->_child; if (keyMap == NULL) continue; @@ -1122,7 +1136,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { } /** Transform constraint timelines. */ - for (constraintMap = transform ? transform->_child : 0; constraintMap; constraintMap = constraintMap->_next) { + for (Json *constraintMap = transform ? transform->_child : 0; constraintMap; constraintMap = constraintMap->_next) { keyMap = constraintMap->_child; if (keyMap == NULL) continue; @@ -1178,7 +1192,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { } /** Path constraint timelines. */ - for (constraintMap = paths ? paths->_child : 0; constraintMap; constraintMap = constraintMap->_next) { + for (Json *constraintMap = paths ? paths->_child : 0; constraintMap; constraintMap = constraintMap->_next) { PathConstraintData *constraint = skeletonData->findPathConstraint(constraintMap->_name); if (!constraint) { ContainerUtil::cleanUpVectorOfPointers(timelines); @@ -1239,77 +1253,99 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { } } - /** Deform timelines. */ - for (constraintMap = deform ? deform->_child : NULL; constraintMap; constraintMap = constraintMap->_next) { - Skin *skin = skeletonData->findSkin(constraintMap->_name); - for (slotMap = constraintMap->_child; slotMap; slotMap = slotMap->_next) { + /** Attachment timelines. */ + for (Json *attachmenstMap = attachments ? attachments->_child : NULL; attachmenstMap; attachmenstMap = attachmenstMap->_next) { + Skin *skin = skeletonData->findSkin(attachmenstMap->_name); + for (slotMap = attachmenstMap->_child; slotMap; slotMap = slotMap->_next) { int slotIndex = findSlotIndex(skeletonData, slotMap->_name, timelines); if (slotIndex == -1) return NULL; - for (Json *timelineMap = slotMap->_child; timelineMap; timelineMap = timelineMap->_next) { - keyMap = timelineMap->_child; - if (keyMap == NULL) continue; - - Attachment *baseAttachment = skin->getAttachment(slotIndex, timelineMap->_name); - if (!baseAttachment) { + for (Json *attachmentMap = slotMap->_child; attachmentMap; attachmentMap = attachmentMap->_next) { + Attachment *attachment = skin->getAttachment(slotIndex, attachmentMap->_name); + if (!attachment) { ContainerUtil::cleanUpVectorOfPointers(timelines); - setError(NULL, "Attachment not found: ", timelineMap->_name); + setError(NULL, "Attachment not found: ", attachmentMap->_name); return NULL; } - VertexAttachment *attachment = static_cast(baseAttachment); - bool weighted = attachment->_bones.size() != 0; - Vector &verts = attachment->_vertices; - int deformLength = weighted ? verts.size() / 3 * 2 : verts.size(); + for (Json *timelineMap = attachmentMap->_child; timelineMap; timelineMap = timelineMap->_next) { + keyMap = timelineMap->_child; + if (keyMap == NULL) continue; + int frames = timelineMap->_size; + String timelineName = timelineMap->_name; + if (timelineName == "deform") { + VertexAttachment *vertexAttachment = static_cast(attachment); + bool weighted = vertexAttachment->_bones.size() != 0; + Vector &verts = vertexAttachment->_vertices; + int deformLength = weighted ? verts.size() / 3 * 2 : verts.size(); - DeformTimeline *timeline = new (__FILE__, __LINE__) DeformTimeline(timelineMap->_size, - timelineMap->_size, slotIndex, - attachment); - float time = Json::getFloat(keyMap, "time", 0); - for (frame = 0, bezier = 0;; frame++) { - Json *vertices = Json::getItem(keyMap, "vertices"); - Vector deformed; - if (!vertices) { - if (weighted) { - deformed.setSize(deformLength, 0); - } else { - deformed.clearAndAddAll(attachment->_vertices); - } - } else { - int v, start = Json::getInt(keyMap, "offset", 0); - Json *vertex; - deformed.setSize(deformLength, 0); - if (_scale == 1) { - for (vertex = vertices->_child, v = start; vertex; vertex = vertex->_next, ++v) { - deformed[v] = vertex->_valueFloat; + DeformTimeline *timeline = new (__FILE__, __LINE__) DeformTimeline(frames, + frames, slotIndex, vertexAttachment); + float time = Json::getFloat(keyMap, "time", 0); + for (frame = 0, bezier = 0;; frame++) { + Json *vertices = Json::getItem(keyMap, "vertices"); + Vector deformed; + if (!vertices) { + if (weighted) { + deformed.setSize(deformLength, 0); + } else { + deformed.clearAndAddAll(vertexAttachment->_vertices); + } + } else { + deformed.setSize(deformLength, 0); + int v, start = Json::getInt(keyMap, "offset", 0); + Json *vertex; + if (_scale == 1) { + for (vertex = vertices->_child, v = start; vertex; vertex = vertex->_next, ++v) { + deformed[v] = vertex->_valueFloat; + } + } else { + for (vertex = vertices->_child, v = start; vertex; vertex = vertex->_next, ++v) { + deformed[v] = vertex->_valueFloat * _scale; + } + } + if (!weighted) { + Vector &verticesAttachment = vertexAttachment->_vertices; + for (v = 0; v < deformLength; ++v) { + deformed[v] += verticesAttachment[v]; + } + } } - } else { - for (vertex = vertices->_child, v = start; vertex; vertex = vertex->_next, ++v) { - deformed[v] = vertex->_valueFloat * _scale; + timeline->setFrame(frame, time, deformed); + nextMap = keyMap->_next; + if (!nextMap) { + // timeline.shrink(); // BOZO + break; } - } - if (!weighted) { - Vector &verticesAttachment = attachment->_vertices; - for (v = 0; v < deformLength; ++v) { - deformed[v] += verticesAttachment[v]; + float time2 = Json::getFloat(nextMap, "time", 0); + curve = Json::getItem(keyMap, "curve"); + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); } + time = time2; + keyMap = nextMap; } + timelines.add(timeline); + } else if (timelineName == "sequence") { + SequenceTimeline *timeline = new SequenceTimeline(frames, slotIndex, attachment); + float lastDelay = 0; + for (frame = 0; keyMap != NULL; keyMap = keyMap->_next, frame++) { + float delay = Json::getFloat(keyMap, "delay", lastDelay); + float time = Json::getFloat(keyMap, "time", 0); + String modeString = Json::getString(keyMap, "mode", "hold"); + int index = Json::getInt(keyMap, "index", 0); + SequenceMode mode = SequenceMode::hold; + if (modeString == "once") mode = SequenceMode::once; + if (modeString == "loop") mode = SequenceMode::loop; + if (modeString == "pingpong") mode = SequenceMode::pingpong; + if (modeString == "onceReverse") mode = SequenceMode::onceReverse; + if (modeString == "loopReverse") mode = SequenceMode::loopReverse; + if (modeString == "pingpongReverse") mode = SequenceMode::pingpongReverse; + timeline->setFrame(frame, time, mode, index, delay); + } + timelines.add(timeline); } - timeline->setFrame(frame, time, deformed); - nextMap = keyMap->_next; - if (!nextMap) { - // timeline.shrink(); // BOZO - break; - } - float time2 = Json::getFloat(nextMap, "time", 0); - curve = Json::getItem(keyMap, "curve"); - if (curve) { - bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); - } - time = time2; - keyMap = nextMap; } - timelines.add(timeline); } } } diff --git a/spine-cpp/spine-cpp/src/spine/Slot.cpp b/spine-cpp/spine-cpp/src/spine/Slot.cpp index d9c08bf80..1918c4981 100644 --- a/spine-cpp/spine-cpp/src/spine/Slot.cpp +++ b/spine-cpp/spine-cpp/src/spine/Slot.cpp @@ -103,8 +103,8 @@ void Slot::setAttachment(Attachment *inValue) { !_attachment || !inValue->getRTTI().instanceOf(VertexAttachment::rtti) || !_attachment->getRTTI().instanceOf(VertexAttachment::rtti) || - static_cast(inValue)->getTimelineAttachment() != - static_cast(_attachment)->getTimelineAttachment()) { + static_cast(inValue)->getTimelineAttachment() != + static_cast(_attachment)->getTimelineAttachment()) { _deform.clear(); } diff --git a/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp b/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp index d2570e49e..c8898663f 100644 --- a/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp +++ b/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp @@ -150,7 +150,7 @@ void VertexAttachment::setWorldVerticesLength(size_t inValue) { _worldVerticesLength = inValue; } -Attachment * VertexAttachment::getTimelineAttachment() { +Attachment *VertexAttachment::getTimelineAttachment() { return _timelineAttachment; } diff --git a/spine-csharp/src/Animation.cs b/spine-csharp/src/Animation.cs index ca956d5b2..2492e9dca 100644 --- a/spine-csharp/src/Animation.cs +++ b/spine-csharp/src/Animation.cs @@ -2665,17 +2665,24 @@ namespace Spine { case SequenceMode.Loop: index %= count; break; - case SequenceMode.Pingpong: + case SequenceMode.Pingpong: { int 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); break; + case SequenceMode.PingpongReverse: { + int n = (count << 1) - 2; + index = (index + count - 1) % n; + if (index >= count) index = n - index; + break; + } // end case } } slot.SequenceIndex = index; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index 444fbdad1..f23bc1109 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -2494,16 +2494,22 @@ public class Animation { case loop: index %= count; break; - case pingpong: + case pingpong: { int n = (count << 1) - 2; index %= n; if (index >= count) index = n - index; break; + } case onceReverse: index = Math.max(count - 1 - index, 0); break; case loopReverse: index = count - 1 - (index % count); + break; + case pingpongReverse: + int n = (count << 1) - 2; + index = (index + count - 1) % n; + if (index >= count) index = n - index; } } slot.setSequenceIndex(index); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index a8f4e3ea7..90384dd41 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -1351,6 +1351,9 @@ public class AnimationState { /** The interface to implement for receiving TrackEntry events. It is always safe to call AnimationState methods when receiving * events. *

+ * TrackEntry events are collected during {@link AnimationState#update(float)} and {@link AnimationState#apply(Skeleton)} and + * fired only after those methods are finished. + *

* See TrackEntry {@link TrackEntry#setListener(AnimationStateListener)} and AnimationState * {@link AnimationState#addListener(AnimationStateListener)}. */ static public interface AnimationStateListener { diff --git a/spine-sfml/cpp/example/main.cpp b/spine-sfml/cpp/example/main.cpp index c9ab57bb7..fd7aa445a 100644 --- a/spine-sfml/cpp/example/main.cpp +++ b/spine-sfml/cpp/example/main.cpp @@ -645,13 +645,13 @@ int main() { SpineExtension::setInstance(&dbgExtension); testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f); + testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f); + testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f); testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f); testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f); testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f); - testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f); testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f); testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor-pma.atlas", 0.5f); - testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f); testcase(tank, "data/tank-pro.json", "data/tank-pro.skel", "data/tank-pma.atlas", 0.2f); testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor-pma.atlas", 0.5f); testcase(goblins, "data/goblins-pro.json", "data/goblins-pro.skel", "data/goblins-pma.atlas", 1.4f); diff --git a/spine-sfml/cpp/src/spine/spine-sfml.cpp b/spine-sfml/cpp/src/spine/spine-sfml.cpp index ce3c51839..4c6ca494b 100644 --- a/spine-sfml/cpp/src/spine/spine-sfml.cpp +++ b/spine-sfml/cpp/src/spine/spine-sfml.cpp @@ -77,7 +77,6 @@ namespace spine { } void SkeletonDrawable::update(float deltaTime) { - skeleton->update(deltaTime); state->update(deltaTime * timeScale); state->apply(*skeleton); skeleton->updateWorldTransform(); @@ -123,7 +122,7 @@ namespace spine { } worldVertices.setSize(8, 0); - regionAttachment->computeWorldVertices(slot.getBone(), worldVertices, 0, 2); + regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2); verticesCount = 4; uvs = ®ionAttachment->getUVs(); indices = &quadIndices; @@ -142,7 +141,7 @@ namespace spine { worldVertices.setSize(mesh->getWorldVerticesLength(), 0); texture = (Texture *) ((AtlasRegion *) mesh->getRendererObject())->page->getRendererObject(); - mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices, 0, 2); + mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2); verticesCount = mesh->getWorldVerticesLength() >> 1; uvs = &mesh->getUVs(); indices = &mesh->getTriangles(); diff --git a/spine-ts/README.md b/spine-ts/README.md index ed7be5faa..a799500d2 100644 --- a/spine-ts/README.md +++ b/spine-ts/README.md @@ -7,7 +7,7 @@ up into multiple modules: 1. `spine-webgl/`, a self-contained WebGL backend, built on the core classes. 1. `spine-canvas/`, a self-contained Canvas backend, built on the core classes. 1. `spine-threejs/`, a self-contained THREE.JS backend, built on the core classes. -1. `spine-player/`, a self-contained player to easily display Spine animations on your website, built on core the classes and WebGL backend. +1. `spine-player/`, a self-contained player to easily display Spine animations on your website, built on the core classes and WebGL backend. In most cases, the `spine-player` module is best suited for your needs. Please refer to the [Spine Web Player documentation](https://esotericsoftware.com/spine-player) for more information. @@ -104,6 +104,7 @@ spine-ts is developed with TypeScript, we thus recommend the following developme 3. Open a terminal and execute ``` git clone https://github.com/esotericsoftware/spine-runtimes +cd spine-runtimes/spine-ts npm install npm run dev ``` diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json index 9994a1738..a857b5e98 100644 --- a/spine-ts/package-lock.json +++ b/spine-ts/package-lock.json @@ -1,12 +1,12 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.1.4", + "version": "4.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@esotericsoftware/spine-ts", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE", "workspaces": [ "spine-core", @@ -519,9 +519,9 @@ "dev": true }, "node_modules/concurrently": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.3.0.tgz", - "integrity": "sha512-k4k1jQGHHKsfbqzkUszVf29qECBrkvBKkcPJEUDTyVR7tZd1G/JOfnst4g1sYbFvJ4UjHZisj1aWQR8yLKpGPw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.4.0.tgz", + "integrity": "sha512-HZ3D0RTQMH3oS4gvtYj1P+NBc6PzE2McEra6yEFcQKrUQ9HvtTGU4Dbne083F034p+LRb7kWU0tPRNvSGs1UCQ==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -603,9 +603,9 @@ } }, "node_modules/date-fns": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", - "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz", + "integrity": "sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q==", "dev": true, "engines": { "node": ">=0.11" @@ -1100,16 +1100,16 @@ } }, "node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -1125,9 +1125,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", + "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", "dev": true }, "node_modules/inflight": { @@ -1468,21 +1468,21 @@ } }, "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "dev": true, "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.51.0" }, "engines": { "node": ">= 0.6" @@ -7101,9 +7101,9 @@ } }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -7113,9 +7113,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -7134,9 +7134,9 @@ } }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/serve-index": { @@ -7209,9 +7209,9 @@ } }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, "node_modules/snapdragon": { @@ -7667,9 +7667,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "engines": { "node": ">=0.6" @@ -7691,9 +7691,9 @@ "dev": true }, "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -7949,41 +7949,41 @@ }, "spine-canvas": { "name": "@esotericsoftware/spine-canvas", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.3" + "@esotericsoftware/spine-core": "^4.1.5" } }, "spine-core": { "name": "@esotericsoftware/spine-core", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE" }, "spine-player": { "name": "@esotericsoftware/spine-player", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-webgl": "^4.1.3" + "@esotericsoftware/spine-webgl": "^4.1.5" } }, "spine-threejs": { "name": "@esotericsoftware/spine-threejs", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.3", + "@esotericsoftware/spine-core": "^4.1.5", "@types/three": "^0.133.1", "three": "^0.133.1" } }, "spine-webgl": { "name": "@esotericsoftware/spine-webgl", - "version": "4.1.4", + "version": "4.1.5", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.4" + "@esotericsoftware/spine-core": "^4.1.5" } } }, @@ -7991,7 +7991,7 @@ "@esotericsoftware/spine-canvas": { "version": "file:spine-canvas", "requires": { - "@esotericsoftware/spine-core": "^4.1.3" + "@esotericsoftware/spine-core": "^4.1.5" } }, "@esotericsoftware/spine-core": { @@ -8000,13 +8000,13 @@ "@esotericsoftware/spine-player": { "version": "file:spine-player", "requires": { - "@esotericsoftware/spine-webgl": "^4.1.3" + "@esotericsoftware/spine-webgl": "^4.1.5" } }, "@esotericsoftware/spine-threejs": { "version": "file:spine-threejs", "requires": { - "@esotericsoftware/spine-core": "^4.1.3", + "@esotericsoftware/spine-core": "^4.1.5", "@types/three": "^0.133.1", "three": "^0.133.1" } @@ -8014,7 +8014,7 @@ "@esotericsoftware/spine-webgl": { "version": "file:spine-webgl", "requires": { - "@esotericsoftware/spine-core": "^4.1.4" + "@esotericsoftware/spine-core": "^4.1.5" } }, "@types/offscreencanvas": { @@ -8401,9 +8401,9 @@ "dev": true }, "concurrently": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.3.0.tgz", - "integrity": "sha512-k4k1jQGHHKsfbqzkUszVf29qECBrkvBKkcPJEUDTyVR7tZd1G/JOfnst4g1sYbFvJ4UjHZisj1aWQR8yLKpGPw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.4.0.tgz", + "integrity": "sha512-HZ3D0RTQMH3oS4gvtYj1P+NBc6PzE2McEra6yEFcQKrUQ9HvtTGU4Dbne083F034p+LRb7kWU0tPRNvSGs1UCQ==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -8466,9 +8466,9 @@ } }, "date-fns": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", - "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz", + "integrity": "sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q==", "dev": true }, "debug": { @@ -8861,16 +8861,16 @@ } }, "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "dependencies": { "depd": { @@ -8882,9 +8882,9 @@ } }, "http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", + "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", "dev": true }, "inflight": { @@ -9152,18 +9152,18 @@ "dev": true }, "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", "dev": true }, "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "dev": true, "requires": { - "mime-db": "1.50.0" + "mime-db": "1.51.0" } }, "minimatch": { @@ -13563,9 +13563,9 @@ } }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dev": true, "requires": { "debug": "2.6.9", @@ -13575,9 +13575,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -13590,9 +13590,9 @@ "dev": true }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } @@ -13657,9 +13657,9 @@ } }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, "snapdragon": { @@ -14041,9 +14041,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, "tree-kill": { @@ -14059,9 +14059,9 @@ "dev": true }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "dev": true }, "union-value": { diff --git a/spine-ts/package.json b/spine-ts/package.json index 34f8ca92f..2ccab6037 100644 --- a/spine-ts/package.json +++ b/spine-ts/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "files": [ "README.md" diff --git a/spine-ts/spine-canvas/package.json b/spine-ts/spine-canvas/package.json index 5bb1b9fa6..c06ca6e14 100644 --- a/spine-ts/spine-canvas/package.json +++ b/spine-ts/spine-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-canvas", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.3" + "@esotericsoftware/spine-core": "^4.1.5" } -} +} \ No newline at end of file diff --git a/spine-ts/spine-core/package.json b/spine-ts/spine-core/package.json index 53b2528a8..154959029 100644 --- a/spine-ts/spine-core/package.json +++ b/spine-ts/spine-core/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-core", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/spine-ts/spine-core/src/Animation.ts b/spine-ts/spine-core/src/Animation.ts index 99f0e9b19..88cd0d465 100644 --- a/spine-ts/spine-core/src/Animation.ts +++ b/spine-ts/spine-core/src/Animation.ts @@ -42,8 +42,8 @@ import { SequenceMode, SequenceModeValues } from "./attachments/Sequence"; export class Animation { /** The animation's name, which is unique across all animations in the skeleton. */ name: string; - timelines: Array; - timelineIds: StringSet; + timelines: Array = null; + timelineIds: StringSet = null; /** The duration of the animation in seconds, which is the highest time of all keys in the timeline. */ duration: number; @@ -155,8 +155,8 @@ const Property = { /** The interface for all timelines. */ export abstract class Timeline { - propertyIds: string[]; - frames: NumberArrayLike; + propertyIds: string[] = null; + frames: NumberArrayLike = null; constructor (frameCount: number, propertyIds: string[]) { this.propertyIds = propertyIds; @@ -208,7 +208,7 @@ export interface SlotTimeline { /** The base class for timelines that use interpolation between key frame values. */ export abstract class CurveTimeline extends Timeline { - protected curves: NumberArrayLike; // type, x, y, ... + protected curves: NumberArrayLike = null; // type, x, y, ... constructor (frameCount: number, bezierCount: number, propertyIds: string[]) { super(frameCount, propertyIds); @@ -1430,10 +1430,10 @@ export class DeformTimeline extends CurveTimeline implements SlotTimeline { slotIndex = 0; /** The attachment that will be deformed. */ - attachment: VertexAttachment; + attachment: VertexAttachment = null; /** The vertices for each key frame. */ - vertices: Array; + vertices: Array = null; constructor (frameCount: number, bezierCount: number, slotIndex: number, attachment: VertexAttachment) { super(frameCount, bezierCount, [ @@ -1685,7 +1685,7 @@ export class EventTimeline extends Timeline { static propertyIds = ["" + Property.event]; /** The event for each key frame. */ - events: Array; + events: Array = null; constructor (frameCount: number) { super(frameCount, EventTimeline.propertyIds); @@ -1738,7 +1738,7 @@ export class DrawOrderTimeline extends Timeline { static propertyIds = ["" + Property.drawOrder]; /** The draw order for each key frame. See {@link #setFrame(int, float, int[])}. */ - drawOrders: Array>; + drawOrders: Array> = null; constructor (frameCount: number) { super(frameCount, DrawOrderTimeline.propertyIds); @@ -1784,7 +1784,7 @@ export class DrawOrderTimeline extends Timeline { * {@link IkConstraint#bendDirection}, {@link IkConstraint#stretch}, and {@link IkConstraint#compress}. */ export class IkConstraintTimeline extends CurveTimeline { /** The index of the IK constraint slot in {@link Skeleton#ikConstraints} that will be changed. */ - ikConstraintIndex: number; + ikConstraintIndex: number = 0; constructor (frameCount: number, bezierCount: number, ikConstraintIndex: number) { super(frameCount, bezierCount, [ @@ -1882,7 +1882,7 @@ export class IkConstraintTimeline extends CurveTimeline { * {@link TransformConstraint#scaleMix}, and {@link TransformConstraint#shearMix}. */ export class TransformConstraintTimeline extends CurveTimeline { /** The index of the transform constraint slot in {@link Skeleton#transformConstraints} that will be changed. */ - transformConstraintIndex: number; + transformConstraintIndex: number = 0; constructor (frameCount: number, bezierCount: number, transformConstraintIndex: number) { super(frameCount, bezierCount, [ @@ -1995,7 +1995,7 @@ export class TransformConstraintTimeline extends CurveTimeline { /** Changes a path constraint's {@link PathConstraint#position}. */ export class PathConstraintPositionTimeline extends CurveTimeline1 { /** The index of the path constraint slot in {@link Skeleton#pathConstraints} that will be changed. */ - pathConstraintIndex: number; + pathConstraintIndex: number = 0; constructor (frameCount: number, bezierCount: number, pathConstraintIndex: number) { super(frameCount, bezierCount, Property.pathConstraintPosition + "|" + pathConstraintIndex); @@ -2218,16 +2218,23 @@ export class SequenceTimeline extends Timeline implements SlotTimeline { case SequenceMode.loop: index %= count; break; - case SequenceMode.pingpong: + 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); + break; + case SequenceMode.pingpongReverse: { + let n = (count << 1) - 2; + index = (index + count - 1) % n; + if (index >= count) index = n - index; + } } } slot.sequenceIndex = index; diff --git a/spine-ts/spine-core/src/AnimationState.ts b/spine-ts/spine-core/src/AnimationState.ts index 00716fc76..382b204cf 100644 --- a/spine-ts/spine-core/src/AnimationState.ts +++ b/spine-ts/spine-core/src/AnimationState.ts @@ -46,7 +46,7 @@ export class AnimationState { } /** The AnimationStateData to look up mix durations. */ - data: AnimationStateData; + data: AnimationStateData = null; /** The list of tracks that currently have animations, which may contain null entries. */ tracks = new Array(); @@ -645,6 +645,7 @@ export class AnimationState { /** @param last May be null. */ trackEntry (trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry) { let entry = this.trackEntryPool.obtain(); + entry.reset(); entry.trackIndex = trackIndex; entry.animation = animation; entry.loop = loop; @@ -777,35 +778,35 @@ export class AnimationState { * References to a track entry must not be kept after the {@link AnimationStateListener#dispose()} event occurs. */ export class TrackEntry { /** The animation to apply for this track entry. */ - animation: Animation; + animation: Animation = null; - previous: TrackEntry; + previous: TrackEntry = null; /** The animation queued to start after this animation, or null. `next` makes up a linked list. */ - next: TrackEntry; + next: TrackEntry = null; /** The track entry for the previous animation when mixing from the previous animation to this animation, or null if no * mixing is currently occuring. When mixing from multiple animations, `mixingFrom` makes up a linked list. */ - mixingFrom: TrackEntry; + mixingFrom: TrackEntry = null; /** The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is * currently occuring. When mixing to multiple animations, `mixingTo` makes up a linked list. */ - mixingTo: TrackEntry; + mixingTo: TrackEntry = null; /** The listener for events generated by this track entry, or null. * * A track entry returned from {@link AnimationState#setAnimation()} is already the current animation * for the track, so the track entry listener {@link AnimationStateListener#start()} will not be called. */ - listener: AnimationStateListener; + listener: AnimationStateListener = null; /** The index of the track where this track entry is either current or queued. * * See {@link AnimationState#getCurrent()}. */ - trackIndex: number; + trackIndex: number = 0; /** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its * duration. */ - loop: boolean; + loop: boolean = false; /** If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead * of being mixed out. @@ -818,43 +819,43 @@ export class TrackEntry { * * Snapping will occur if `holdPrevious` is true and this animation does not key all the same properties as the * previous animation. */ - holdPrevious: boolean; + holdPrevious: boolean = false; - reverse: boolean; + reverse: boolean = false; /** When the mix percentage ({@link #mixTime} / {@link #mixDuration}) is less than the * `eventThreshold`, event timelines are applied while this animation is being mixed out. Defaults to 0, so event * timelines are not applied while this animation is being mixed out. */ - eventThreshold: number; + eventThreshold: number = 0; /** When the mix percentage ({@link #mixtime} / {@link #mixDuration}) is less than the * `attachmentThreshold`, attachment timelines are applied while this animation is being mixed out. Defaults to * 0, so attachment timelines are not applied while this animation is being mixed out. */ - attachmentThreshold: number; + attachmentThreshold: number = 0; /** When the mix percentage ({@link #mixTime} / {@link #mixDuration}) is less than the * `drawOrderThreshold`, draw order timelines are applied while this animation is being mixed out. Defaults to 0, * so draw order timelines are not applied while this animation is being mixed out. */ - drawOrderThreshold: number; + drawOrderThreshold: number = 0; /** Seconds when this animation starts, both initially and after looping. Defaults to 0. * * When changing the `animationStart` time, it often makes sense to set {@link #animationLast} to the same * value to prevent timeline keys before the start time from triggering. */ - animationStart: number; + animationStart: number = 0; /** Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will * loop back to {@link #animationStart} at this time. Defaults to the animation {@link Animation#duration}. */ - animationEnd: number; + animationEnd: number = 0; /** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this * animation is applied, event timelines will fire all events between the `animationLast` time (exclusive) and * `animationTime` (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation * is applied. */ - animationLast: number; + animationLast: number = 0; - nextAnimationLast: number; + nextAnimationLast: number = 0; /** Seconds to postpone playing the animation. When this track entry is the current track entry, `delay` * postpones incrementing the {@link #trackTime}. When this track entry is queued, `delay` is the time from @@ -862,14 +863,14 @@ export class TrackEntry { * track entry {@link TrackEntry#trackTime} >= this track entry's `delay`). * * {@link #timeScale} affects the delay. */ - delay: number; + delay: number = 0; /** Current time in seconds this track entry has been the current track entry. The track time determines * {@link #animationTime}. The track time can be set to start the animation at a time other than 0, without affecting * looping. */ - trackTime: number; + trackTime: number = 0; - trackLast: number; nextTrackLast: number; + trackLast: number = 0; nextTrackLast: number = 0; /** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float * value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time @@ -878,7 +879,7 @@ export class TrackEntry { * * It may be desired to use {@link AnimationState#addEmptyAnimation()} rather than have the animation * abruptly cease being applied. */ - trackEnd: number; + trackEnd: number = 0; /** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or * faster. Defaults to 1. @@ -891,18 +892,18 @@ export class TrackEntry { * the time scale is not 1, the delay may need to be adjusted. * * See AnimationState {@link AnimationState#timeScale} for affecting all animations. */ - timeScale: number; + timeScale: number = 0; /** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults * to 1, which overwrites the skeleton's current pose with this animation. * * Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to * use alpha on track 0 if the skeleton pose is from the last frame render. */ - alpha: number; + alpha: number = 0; /** Seconds from 0 to the {@link #getMixDuration()} when mixing from the previous animation to this animation. May be * slightly more than `mixDuration` when the mix is complete. */ - mixTime: number; + mixTime: number = 0; /** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by AnimationStateData * {@link AnimationStateData#getMix()} based on the animation before this animation (if any). @@ -917,7 +918,7 @@ export class TrackEntry { * When using {@link AnimationState#addAnimation()} with a `delay` <= 0, note the * {@link #delay} is set using the mix duration from the {@link AnimationStateData}, not a mix duration set * afterward. */ - mixDuration: number; interruptAlpha: number; totalAlpha: number; + mixDuration: number = 0; interruptAlpha: number = 0; totalAlpha: number = 0; /** Controls how properties keyed in the animation are mixed with lower tracks. Defaults to {@link MixBlend#replace}, which * replaces the values from the lower tracks with the animation values. {@link MixBlend#add} adds the animation values to @@ -990,7 +991,7 @@ export class TrackEntry { export class EventQueue { objects: Array = []; drainDisabled = false; - animState: AnimationState; + animState: AnimationState = null; constructor (animState: AnimationState) { this.animState = animState; diff --git a/spine-ts/spine-core/src/AnimationStateData.ts b/spine-ts/spine-core/src/AnimationStateData.ts index 41a60b747..f6d63deea 100644 --- a/spine-ts/spine-core/src/AnimationStateData.ts +++ b/spine-ts/spine-core/src/AnimationStateData.ts @@ -35,7 +35,7 @@ import { StringMap } from "./Utils"; /** Stores mix (crossfade) durations to be applied when {@link AnimationState} animations are changed. */ export class AnimationStateData { /** The SkeletonData to look up animations when they are specified by name. */ - skeletonData: SkeletonData; + skeletonData: SkeletonData = null; animationToMixTime: StringMap = {}; diff --git a/spine-ts/spine-core/src/AssetManagerBase.ts b/spine-ts/spine-core/src/AssetManagerBase.ts index f52ba8e26..b18778ab8 100644 --- a/spine-ts/spine-core/src/AssetManagerBase.ts +++ b/spine-ts/spine-core/src/AssetManagerBase.ts @@ -32,7 +32,7 @@ import { TextureAtlas } from "./TextureAtlas"; import { Disposable, StringMap } from "./Utils"; export class AssetManagerBase implements Disposable { - private pathPrefix: string; + private pathPrefix: string = null; private textureLoader: (image: HTMLImageElement | ImageBitmap) => Texture; private downloader: Downloader; private assets: StringMap = {}; diff --git a/spine-ts/spine-core/src/AtlasAttachmentLoader.ts b/spine-ts/spine-core/src/AtlasAttachmentLoader.ts index 30973056a..bb5b1a995 100644 --- a/spine-ts/spine-core/src/AtlasAttachmentLoader.ts +++ b/spine-ts/spine-core/src/AtlasAttachmentLoader.ts @@ -43,7 +43,7 @@ import { Sequence } from "./attachments/Sequence" * See [Loading skeleton data](http://esotericsoftware.com/spine-loading-skeleton-data#JSON-and-binary-data) in the * Spine Runtimes Guide. */ export class AtlasAttachmentLoader implements AttachmentLoader { - atlas: TextureAtlas; + atlas: TextureAtlas = null; constructor (atlas: TextureAtlas) { this.atlas = atlas; diff --git a/spine-ts/spine-core/src/Bone.ts b/spine-ts/spine-core/src/Bone.ts index 0b96d29be..4d288a07f 100644 --- a/spine-ts/spine-core/src/Bone.ts +++ b/spine-ts/spine-core/src/Bone.ts @@ -39,13 +39,13 @@ import { MathUtils, Vector2 } from "./Utils"; * constraint or application code modifies the world transform after it was computed from the local transform. */ export class Bone implements Updatable { /** The bone's setup pose data. */ - data: BoneData; + data: BoneData = null; /** The skeleton this bone belongs to. */ - skeleton: Skeleton; + skeleton: Skeleton = null; /** The parent bone, or null if this is the root bone. */ - parent: Bone; + parent: Bone = null; /** The immediate children of this bone. */ children = new Array(); diff --git a/spine-ts/spine-core/src/BoneData.ts b/spine-ts/spine-core/src/BoneData.ts index a3d0388b3..c28caacb8 100644 --- a/spine-ts/spine-core/src/BoneData.ts +++ b/spine-ts/spine-core/src/BoneData.ts @@ -32,16 +32,16 @@ import { Color } from "./Utils"; /** Stores the setup pose for a {@link Bone}. */ export class BoneData { /** The index of the bone in {@link Skeleton#getBones()}. */ - index: number; + index: number = 0; /** The name of the bone, which is unique across all bones in the skeleton. */ - name: string; + name: string = null; /** @returns May be null. */ - parent: BoneData; + parent: BoneData = null; /** The bone's length. */ - length: number; + length: number = 0; /** The local x translation. */ x = 0; diff --git a/spine-ts/spine-core/src/Event.ts b/spine-ts/spine-core/src/Event.ts index 3a1540616..2967d96d3 100644 --- a/spine-ts/spine-core/src/Event.ts +++ b/spine-ts/spine-core/src/Event.ts @@ -35,13 +35,13 @@ import { EventData } from "./EventData"; * AnimationStateListener {@link AnimationStateListener#event()}, and * [Events](http://esotericsoftware.com/spine-events) in the Spine User Guide. */ export class Event { - data: EventData; - intValue: number; - floatValue: number; - stringValue: string; - time: number; - volume: number; - balance: number; + data: EventData = null; + intValue: number = 0; + floatValue: number = 0; + stringValue: string = null; + time: number = 0; + volume: number = 0; + balance: number = 0; constructor (time: number, data: EventData) { if (!data) throw new Error("data cannot be null."); diff --git a/spine-ts/spine-core/src/EventData.ts b/spine-ts/spine-core/src/EventData.ts index 633d4640d..8a4d6898c 100644 --- a/spine-ts/spine-core/src/EventData.ts +++ b/spine-ts/spine-core/src/EventData.ts @@ -31,13 +31,13 @@ * * See [Events](http://esotericsoftware.com/spine-events) in the Spine User Guide. */ export class EventData { - name: string; - intValue: number; - floatValue: number; - stringValue: string; - audioPath: string; - volume: number; - balance: number; + name: string = null; + intValue: number = 0; + floatValue: number = 0; + stringValue: string = null; + audioPath: string = null; + volume: number = 0; + balance: number = 0; constructor (name: string) { this.name = name; diff --git a/spine-ts/spine-core/src/IkConstraint.ts b/spine-ts/spine-core/src/IkConstraint.ts index a3b9930e2..55b32d771 100644 --- a/spine-ts/spine-core/src/IkConstraint.ts +++ b/spine-ts/spine-core/src/IkConstraint.ts @@ -40,13 +40,13 @@ import { MathUtils } from "./Utils"; * See [IK constraints](http://esotericsoftware.com/spine-ik-constraints) in the Spine User Guide. */ export class IkConstraint implements Updatable { /** The IK constraint's setup pose data. */ - data: IkConstraintData; + data: IkConstraintData = null; /** The bones that will be modified by this IK constraint. */ - bones: Array; + bones: Array = null; /** The bone that is the IK target. */ - target: Bone; + target: Bone = null; /** Controls the bend direction of the IK bones, either 1 or -1. */ bendDirection = 0; diff --git a/spine-ts/spine-core/src/IkConstraintData.ts b/spine-ts/spine-core/src/IkConstraintData.ts index 758130b40..35c4a5685 100644 --- a/spine-ts/spine-core/src/IkConstraintData.ts +++ b/spine-ts/spine-core/src/IkConstraintData.ts @@ -39,7 +39,7 @@ export class IkConstraintData extends ConstraintData { bones = new Array(); /** The bone that is the IK target. */ - target: BoneData; + target: BoneData = null; /** Controls the bend direction of the IK bones, either 1 or -1. */ bendDirection = 1; diff --git a/spine-ts/spine-core/src/PathConstraint.ts b/spine-ts/spine-core/src/PathConstraint.ts index f021b1fa6..063b3bbce 100644 --- a/spine-ts/spine-core/src/PathConstraint.ts +++ b/spine-ts/spine-core/src/PathConstraint.ts @@ -45,13 +45,13 @@ export class PathConstraint implements Updatable { static epsilon = 0.00001; /** The path constraint's setup pose data. */ - data: PathConstraintData; + data: PathConstraintData = null; /** The bones that will be modified by this path constraint. */ - bones: Array; + bones: Array = null; /** The slot whose path attachment will be used to constrained the bones. */ - target: Slot; + target: Slot = null; /** The position along the path. */ position = 0; diff --git a/spine-ts/spine-core/src/PathConstraintData.ts b/spine-ts/spine-core/src/PathConstraintData.ts index 5c2ddf1fb..b0049e366 100644 --- a/spine-ts/spine-core/src/PathConstraintData.ts +++ b/spine-ts/spine-core/src/PathConstraintData.ts @@ -41,25 +41,25 @@ export class PathConstraintData extends ConstraintData { bones = new Array(); /** The slot whose path attachment will be used to constrained the bones. */ - target: SlotData; + target: SlotData = null; /** The mode for positioning the first bone on the path. */ - positionMode: PositionMode; + positionMode: PositionMode = null; /** The mode for positioning the bones after the first bone on the path. */ - spacingMode: SpacingMode; + spacingMode: SpacingMode = null; /** The mode for adjusting the rotation of the bones. */ - rotateMode: RotateMode; + rotateMode: RotateMode = null; /** An offset added to the constrained bone rotation. */ - offsetRotation: number; + offsetRotation: number = 0; /** The position along the path. */ - position: number; + position: number = 0; /** The spacing between bones. */ - spacing: number; + spacing: number = 0; mixRotate = 0; mixX = 0; diff --git a/spine-ts/spine-core/src/Skeleton.ts b/spine-ts/spine-core/src/Skeleton.ts index 35ff4589c..9a37d8cb5 100644 --- a/spine-ts/spine-core/src/Skeleton.ts +++ b/spine-ts/spine-core/src/Skeleton.ts @@ -46,34 +46,34 @@ import { Color, Utils, MathUtils, Vector2, NumberArrayLike } from "./Utils"; * See [Instance objects](http://esotericsoftware.com/spine-runtime-architecture#Instance-objects) in the Spine Runtimes Guide. */ export class Skeleton { /** The skeleton's setup pose data. */ - data: SkeletonData; + data: SkeletonData = null; /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ - bones: Array; + bones: Array = null; /** The skeleton's slots. */ - slots: Array; + slots: Array = null; /** The skeleton's slots in the order they should be drawn. The returned array may be modified to change the draw order. */ - drawOrder: Array; + drawOrder: Array = null; /** The skeleton's IK constraints. */ - ikConstraints: Array; + ikConstraints: Array = null; /** The skeleton's transform constraints. */ - transformConstraints: Array; + transformConstraints: Array = null; /** The skeleton's path constraints. */ - pathConstraints: Array; + pathConstraints: Array = null; /** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link #updateCache()}. */ _updateCache = new Array(); /** The skeleton's current skin. May be null. */ - skin: Skin; + skin: Skin = null; /** The color to tint all the skeleton's attachments. */ - color: Color; + color: Color = null; /** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale * inheritance. */ diff --git a/spine-ts/spine-core/src/SkeletonBinary.ts b/spine-ts/spine-core/src/SkeletonBinary.ts index 804dfe702..a628d3a6c 100644 --- a/spine-ts/spine-core/src/SkeletonBinary.ts +++ b/spine-ts/spine-core/src/SkeletonBinary.ts @@ -56,7 +56,7 @@ export class SkeletonBinary { * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ scale = 1; - attachmentLoader: AttachmentLoader; + attachmentLoader: AttachmentLoader = null; private linkedMeshes = new Array(); constructor (attachmentLoader: AttachmentLoader) { diff --git a/spine-ts/spine-core/src/SkeletonData.ts b/spine-ts/spine-core/src/SkeletonData.ts index d8ef9ba22..c543cf3b5 100644 --- a/spine-ts/spine-core/src/SkeletonData.ts +++ b/spine-ts/spine-core/src/SkeletonData.ts @@ -43,7 +43,7 @@ import { TransformConstraintData } from "./TransformConstraintData"; export class SkeletonData { /** The skeleton's name, which by default is the name of the skeleton data file, if possible. May be null. */ - name: string; + name: string = null; /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ bones = new Array(); // Ordered parents first. @@ -56,7 +56,7 @@ export class SkeletonData { * * See {@link Skeleton#getAttachmentByName()}. * May be null. */ - defaultSkin: Skin; + defaultSkin: Skin = null; /** The skeleton's events. */ events = new Array(); @@ -74,32 +74,32 @@ export class SkeletonData { pathConstraints = new Array(); /** The X coordinate of the skeleton's axis aligned bounding box in the setup pose. */ - x: number; + x: number = 0; /** The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. */ - y: number; + y: number = 0; /** The width of the skeleton's axis aligned bounding box in the setup pose. */ - width: number; + width: number = 0; /** The height of the skeleton's axis aligned bounding box in the setup pose. */ - height: number; + height: number = 0; /** The Spine version used to export the skeleton data, or null. */ - version: string; + version: string = null; /** The skeleton data hash. This value will change if any of the skeleton data has changed. May be null. */ - hash: string; + hash: string = null; // Nonessential /** The dopesheet FPS in Spine. Available only when nonessential data was exported. */ fps = 0; /** The path to the images directory as defined in Spine. Available only when nonessential data was exported. May be null. */ - imagesPath: string; + imagesPath: string = null; /** The path to the audio directory as defined in Spine. Available only when nonessential data was exported. May be null. */ - audioPath: string; + audioPath: string = null; /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it * multiple times. diff --git a/spine-ts/spine-core/src/SkeletonJson.ts b/spine-ts/spine-core/src/SkeletonJson.ts index 6ed1a423b..000599404 100644 --- a/spine-ts/spine-core/src/SkeletonJson.ts +++ b/spine-ts/spine-core/src/SkeletonJson.ts @@ -51,7 +51,7 @@ import { HasTextureRegion } from "./attachments/HasTextureRegion"; * [JSON and binary data](http://esotericsoftware.com/spine-loading-skeleton-data#JSON-and-binary-data) in the Spine * Runtimes Guide. */ export class SkeletonJson { - attachmentLoader: AttachmentLoader; + attachmentLoader: AttachmentLoader = null; /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at * runtime than were used in Spine. diff --git a/spine-ts/spine-core/src/Skin.ts b/spine-ts/spine-core/src/Skin.ts index 5369c0593..fcbcef7ef 100644 --- a/spine-ts/spine-core/src/Skin.ts +++ b/spine-ts/spine-core/src/Skin.ts @@ -36,7 +36,7 @@ import { StringMap } from "./Utils"; /** Stores an entry in the skin consisting of the slot index, name, and attachment **/ export class SkinEntry { - constructor (public slotIndex: number, public name: string, public attachment: Attachment) { } + constructor (public slotIndex: number = 0, public name: string = null, public attachment: Attachment = null) { } } /** Stores attachments by slot index and attachment name. @@ -45,7 +45,7 @@ export class SkinEntry { * [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide. */ export class Skin { /** The skin's name, which is unique across all skins in the skeleton. */ - name: string; + name: string = null; attachments = new Array>(); bones = Array(); diff --git a/spine-ts/spine-core/src/Slot.ts b/spine-ts/spine-core/src/Slot.ts index f36e95d39..755fbd87a 100644 --- a/spine-ts/spine-core/src/Slot.ts +++ b/spine-ts/spine-core/src/Slot.ts @@ -38,22 +38,22 @@ import { Color } from "./Utils"; * across multiple skeletons. */ export class Slot { /** The slot's setup pose data. */ - data: SlotData; + data: SlotData = null; /** The bone this slot belongs to. */ - bone: Bone; + bone: Bone = null; /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two * color tinting. */ - color: Color; + color: Color = null; /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark * color's alpha is not used. */ - darkColor: Color; + darkColor: Color = null; - attachment: Attachment; + attachment: Attachment = null; - attachmentState: number; + attachmentState: number = 0; /** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the * {@link Sequence#getSetupIndex()}. */ diff --git a/spine-ts/spine-core/src/SlotData.ts b/spine-ts/spine-core/src/SlotData.ts index 3f97656e0..44cfc5e86 100644 --- a/spine-ts/spine-core/src/SlotData.ts +++ b/spine-ts/spine-core/src/SlotData.ts @@ -33,13 +33,13 @@ import { Color } from "./Utils"; /** Stores the setup pose for a {@link Slot}. */ export class SlotData { /** The index of the slot in {@link Skeleton#getSlots()}. */ - index: number; + index: number = 0; /** The name of the slot, which is unique across all slots in the skeleton. */ - name: string; + name: string = null; /** The bone this slot belongs to. */ - boneData: BoneData; + boneData: BoneData = null; /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two * color tinting. */ @@ -47,13 +47,13 @@ export class SlotData { /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark * color's alpha is not used. */ - darkColor: Color; + darkColor: Color = null; /** The name of the attachment that is visible for this slot in the setup pose, or null if no attachment is visible. */ - attachmentName: string; + attachmentName: string = null; /** The blend mode for drawing the slot's attachment. */ - blendMode: BlendMode; + blendMode: BlendMode = null; constructor (index: number, name: string, boneData: BoneData) { if (index < 0) throw new Error("index must be >= 0."); diff --git a/spine-ts/spine-core/src/TextureAtlas.ts b/spine-ts/spine-core/src/TextureAtlas.ts index 9b9a93f2c..56098e49f 100644 --- a/spine-ts/spine-core/src/TextureAtlas.ts +++ b/spine-ts/spine-core/src/TextureAtlas.ts @@ -198,7 +198,7 @@ export class TextureAtlas implements Disposable { } class TextureAtlasReader { - lines: Array; + lines: Array = null; index: number = 0; constructor (text: string) { @@ -233,15 +233,15 @@ class TextureAtlasReader { } export class TextureAtlasPage { - name: string; + name: string = null; minFilter: TextureFilter = TextureFilter.Nearest; magFilter: TextureFilter = TextureFilter.Nearest; uWrap: TextureWrap = TextureWrap.ClampToEdge; vWrap: TextureWrap = TextureWrap.ClampToEdge; - texture: Texture; - width: number; - height: number; - pma: boolean; + texture: Texture = null; + width: number = 0; + height: number = 0; + pma: boolean = false; setTexture (texture: Texture) { this.texture = texture; @@ -251,16 +251,16 @@ export class TextureAtlasPage { } export class TextureAtlasRegion extends TextureRegion { - page: TextureAtlasPage; - name: string; - x: number; - y: number; - offsetX: number; - offsetY: number; - originalWidth: number; - originalHeight: number; - index: number; - degrees: number; - names: string[]; - values: number[][]; + page: TextureAtlasPage = null; + name: string = null; + x: number = 0; + y: number = 0; + offsetX: number = 0; + offsetY: number = 0; + originalWidth: number = 0; + originalHeight: number = 0; + index: number = 0; + degrees: number = 0; + names: string[] = null; + values: number[][] = null; } diff --git a/spine-ts/spine-core/src/TransformConstraint.ts b/spine-ts/spine-core/src/TransformConstraint.ts index 2accdd527..6c15398fe 100644 --- a/spine-ts/spine-core/src/TransformConstraint.ts +++ b/spine-ts/spine-core/src/TransformConstraint.ts @@ -41,13 +41,13 @@ import { Vector2, MathUtils } from "./Utils"; export class TransformConstraint implements Updatable { /** The transform constraint's setup pose data. */ - data: TransformConstraintData; + data: TransformConstraintData = null; /** The bones that will be modified by this transform constraint. */ - bones: Array; + bones: Array = null; /** The target bone whose world transform will be copied to the constrained bones. */ - target: Bone; + target: Bone = null; mixRotate = 0; mixX = 0; mixY = 0; mixScaleX = 0; mixScaleY = 0; mixShearY = 0; diff --git a/spine-ts/spine-core/src/TransformConstraintData.ts b/spine-ts/spine-core/src/TransformConstraintData.ts index 25ef020d4..6646f83ae 100644 --- a/spine-ts/spine-core/src/TransformConstraintData.ts +++ b/spine-ts/spine-core/src/TransformConstraintData.ts @@ -39,7 +39,7 @@ export class TransformConstraintData extends ConstraintData { bones = new Array(); /** The target bone whose world transform will be copied to the constrained bones. */ - target: BoneData; + target: BoneData = null; mixRotate = 0; mixX = 0; diff --git a/spine-ts/spine-core/src/attachments/Attachment.ts b/spine-ts/spine-core/src/attachments/Attachment.ts index eb69c09b5..8ba50495a 100644 --- a/spine-ts/spine-core/src/attachments/Attachment.ts +++ b/spine-ts/spine-core/src/attachments/Attachment.ts @@ -53,12 +53,12 @@ export abstract class VertexAttachment extends Attachment { /** The bones which affect the {@link #getVertices()}. The array entries are, for each vertex, the number of bones affecting * the vertex followed by that many bone indices, which is the index of the bone in {@link Skeleton#bones}. Will be null * if this attachment has no weights. */ - bones: Array; + bones: Array = null; /** The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y` * entries for each vertex. For a weighted attachment, the values are `x,y,weight` entries for each bone affecting * each vertex. */ - vertices: NumberArrayLike; + vertices: NumberArrayLike = null; /** The maximum number of world vertex values that can be output by * {@link #computeWorldVertices()} using the `count` parameter. */ diff --git a/spine-ts/spine-core/src/attachments/ClippingAttachment.ts b/spine-ts/spine-core/src/attachments/ClippingAttachment.ts index cc3b378cd..8e0ecfc70 100644 --- a/spine-ts/spine-core/src/attachments/ClippingAttachment.ts +++ b/spine-ts/spine-core/src/attachments/ClippingAttachment.ts @@ -35,7 +35,7 @@ import { VertexAttachment, Attachment } from "./Attachment"; export class ClippingAttachment extends VertexAttachment { /** Clipping is performed between the clipping polygon's slot and the end slot. Returns null if clipping is done until the end of * the skeleton's rendering. */ - endSlot: SlotData; + endSlot: SlotData = null; // Nonessential. /** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons diff --git a/spine-ts/spine-core/src/attachments/MeshAttachment.ts b/spine-ts/spine-core/src/attachments/MeshAttachment.ts index 11694f899..7567cabc1 100644 --- a/spine-ts/spine-core/src/attachments/MeshAttachment.ts +++ b/spine-ts/spine-core/src/attachments/MeshAttachment.ts @@ -40,41 +40,41 @@ import { Slot } from "../Slot"; * * See [Mesh attachments](http://esotericsoftware.com/spine-meshes) in the Spine User Guide. */ export class MeshAttachment extends VertexAttachment implements HasTextureRegion { - region: TextureRegion; + region: TextureRegion = null; /** The name of the texture region for this attachment. */ - path: string; + path: string = null; /** The UV pair for each vertex, normalized within the texture region. */ - regionUVs: NumberArrayLike; + regionUVs: NumberArrayLike = null; /** The UV pair for each vertex, normalized within the entire texture. * * See {@link #updateUVs}. */ - uvs: NumberArrayLike; + uvs: NumberArrayLike = null; /** Triplets of vertex indices which describe the mesh's triangulation. */ - triangles: Array; + triangles: Array = null; /** The color to tint the mesh. */ color = new Color(1, 1, 1, 1); /** The width of the mesh's image. Available only when nonessential data was exported. */ - width: number; + width: number = 0; /** The height of the mesh's image. Available only when nonessential data was exported. */ - height: number; + height: number = 0; /** The number of entries at the beginning of {@link #vertices} that make up the mesh hull. */ - hullLength: number; + hullLength: number = 0; /** Vertex index pairs describing edges for controling triangulation. Mesh triangles will never cross edges. Only available if * nonessential data was exported. Triangulation is not performed at runtime. */ - edges: Array; + edges: Array = null; - private parentMesh: MeshAttachment; + private parentMesh: MeshAttachment = null; - sequence: Sequence; + sequence: Sequence = null; tempColor = new Color(0, 0, 0, 0); diff --git a/spine-ts/spine-core/src/attachments/PathAttachment.ts b/spine-ts/spine-core/src/attachments/PathAttachment.ts index 19b3bb67c..cd1912d9c 100644 --- a/spine-ts/spine-core/src/attachments/PathAttachment.ts +++ b/spine-ts/spine-core/src/attachments/PathAttachment.ts @@ -36,7 +36,7 @@ import { VertexAttachment, Attachment } from "./Attachment"; export class PathAttachment extends VertexAttachment { /** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */ - lengths: Array; + lengths: Array = null; /** If true, the start and end knots are connected. */ closed = false; diff --git a/spine-ts/spine-core/src/attachments/PointAttachment.ts b/spine-ts/spine-core/src/attachments/PointAttachment.ts index 9d023d3f1..5924582aa 100644 --- a/spine-ts/spine-core/src/attachments/PointAttachment.ts +++ b/spine-ts/spine-core/src/attachments/PointAttachment.ts @@ -37,7 +37,9 @@ import { VertexAttachment, Attachment } from "./Attachment"; * * See [Point Attachments](http://esotericsoftware.com/spine-point-attachments) in the Spine User Guide. */ export class PointAttachment extends VertexAttachment { - x: number; y: number; rotation: number; + x: number = 0; + y: number = 0; + rotation: number = 0; /** The color of the point attachment as it was in Spine. Available only when nonessential data was exported. Point attachments * are not usually rendered at runtime. */ diff --git a/spine-ts/spine-core/src/attachments/RegionAttachment.ts b/spine-ts/spine-core/src/attachments/RegionAttachment.ts index eabec9ef8..90d401c5b 100644 --- a/spine-ts/spine-core/src/attachments/RegionAttachment.ts +++ b/spine-ts/spine-core/src/attachments/RegionAttachment.ts @@ -64,11 +64,11 @@ export class RegionAttachment extends Attachment implements HasTextureRegion { color = new Color(1, 1, 1, 1); /** The name of the texture region for this attachment. */ - path: string; + path: string = null; - private rendererObject: any; - region: TextureRegion; - sequence: Sequence; + private rendererObject: any = null; + region: TextureRegion = null; + sequence: Sequence = null; /** For each of the 4 vertices, a pair of x,y values that is the local position of the vertex. * diff --git a/spine-ts/spine-player/package.json b/spine-ts/spine-player/package.json index 453f858e2..362de90da 100644 --- a/spine-ts/spine-player/package.json +++ b/spine-ts/spine-player/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-player", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-webgl": "^4.1.3" + "@esotericsoftware/spine-webgl": "^4.1.5" } -} +} \ No newline at end of file diff --git a/spine-ts/spine-threejs/package.json b/spine-ts/spine-threejs/package.json index 8b27def86..c59631bc5 100644 --- a/spine-ts/spine-threejs/package.json +++ b/spine-ts/spine-threejs/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-threejs", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -32,6 +32,6 @@ "dependencies": { "@types/three": "^0.133.1", "three": "^0.133.1", - "@esotericsoftware/spine-core": "^4.1.3" + "@esotericsoftware/spine-core": "^4.1.5" } -} +} \ No newline at end of file diff --git a/spine-ts/spine-webgl/package.json b/spine-ts/spine-webgl/package.json index 0ebd8a227..4d14c4619 100644 --- a/spine-ts/spine-webgl/package.json +++ b/spine-ts/spine-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-webgl", - "version": "4.1.4", + "version": "4.1.5", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.4" + "@esotericsoftware/spine-core": "^4.1.5" } } \ No newline at end of file diff --git a/spine-ts/tsconfig.base.json b/spine-ts/tsconfig.base.json index 354041202..f4f702711 100644 --- a/spine-ts/tsconfig.base.json +++ b/spine-ts/tsconfig.base.json @@ -12,6 +12,8 @@ ], "declaration": true, "composite": true, - "moduleResolution": "node", + "moduleResolution": "node" + /*"strictNullChecks": true, + "strictPropertyInitialization": true*/ } } \ No newline at end of file diff --git a/spine-ue4/Content/GettingStarted/Assets/Raptor/Textures/raptor.uasset b/spine-ue4/Content/GettingStarted/Assets/Raptor/Textures/raptor.uasset index 447587273..685480141 100644 Binary files a/spine-ue4/Content/GettingStarted/Assets/Raptor/Textures/raptor.uasset and b/spine-ue4/Content/GettingStarted/Assets/Raptor/Textures/raptor.uasset differ diff --git a/spine-ue4/Content/GettingStarted/Assets/Raptor/raptor.uasset b/spine-ue4/Content/GettingStarted/Assets/Raptor/raptor.uasset index 3e1ab3323..5f173c30a 100644 Binary files a/spine-ue4/Content/GettingStarted/Assets/Raptor/raptor.uasset and b/spine-ue4/Content/GettingStarted/Assets/Raptor/raptor.uasset differ diff --git a/spine-ue4/Content/GettingStarted/Assets/Spineboy/Textures/spineboy.uasset b/spine-ue4/Content/GettingStarted/Assets/Spineboy/Textures/spineboy.uasset index 85af20564..c8d47dd5b 100644 Binary files a/spine-ue4/Content/GettingStarted/Assets/Spineboy/Textures/spineboy.uasset and b/spine-ue4/Content/GettingStarted/Assets/Spineboy/Textures/spineboy.uasset differ diff --git a/spine-ue4/Content/GettingStarted/Assets/Spineboy/spineboy.uasset b/spine-ue4/Content/GettingStarted/Assets/Spineboy/spineboy.uasset index fdb15cf21..456d5465d 100644 Binary files a/spine-ue4/Content/GettingStarted/Assets/Spineboy/spineboy.uasset and b/spine-ue4/Content/GettingStarted/Assets/Spineboy/spineboy.uasset differ diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp index c9ee73367..968b7168f 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp @@ -45,12 +45,17 @@ using namespace spine; +static int brushNameId = 0; + // Workaround for https://github.com/EsotericSoftware/spine-runtimes/issues/1458 // See issue comments for more information. struct SpineSlateMaterialBrush : public FSlateBrush { SpineSlateMaterialBrush(class UMaterialInterface &InMaterial, const FVector2D &InImageSize) : FSlateBrush(ESlateBrushDrawType::Image, FName(TEXT("None")), FMargin(0), ESlateBrushTileType::NoTile, ESlateBrushImageType::FullColor, InImageSize, FLinearColor::White, &InMaterial) { - ResourceName = FName(*InMaterial.GetFullName()); + // Workaround for https://github.com/EsotericSoftware/spine-runtimes/issues/2006 + FString brushName = TEXT("spineslatebrush"); + brushName.AppendInt(brushNameId++); + ResourceName = FName(brushName); } }; @@ -269,7 +274,7 @@ void SSpineWidget::UpdateMesh(int32 LayerId, FSlateWindowElementList &OutDrawEle RegionAttachment *regionAttachment = (RegionAttachment *) attachment; attachmentColor.set(regionAttachment->getColor()); attachmentAtlasRegion = (AtlasRegion *) regionAttachment->getRendererObject(); - regionAttachment->computeWorldVertices(slot->getBone(), *attachmentVertices, 0, 2); + regionAttachment->computeWorldVertices(*slot, *attachmentVertices, 0, 2); attachmentIndices = quadIndices; attachmentUvs = regionAttachment->getUVs().buffer(); numVertices = 4; @@ -278,7 +283,7 @@ void SSpineWidget::UpdateMesh(int32 LayerId, FSlateWindowElementList &OutDrawEle MeshAttachment *mesh = (MeshAttachment *) attachment; attachmentColor.set(mesh->getColor()); attachmentAtlasRegion = (AtlasRegion *) mesh->getRendererObject(); - mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), *attachmentVertices, 0, 2); + mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), attachmentVertices->buffer(), 0, 2); attachmentIndices = mesh->getTriangles().buffer(); attachmentUvs = mesh->getUVs().buffer(); numVertices = mesh->getWorldVerticesLength() >> 1; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp index 7785c9a16..8bc3b1f4f 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp @@ -39,7 +39,7 @@ using namespace spine; #define SPINE_MAJOR_VERSION 4 -#define SPINE_MINOR_VERSION 0 +#define SPINE_MINOR_VERSION 1 FName USpineSkeletonDataAsset::GetSkeletonDataFileName() const { #if WITH_EDITORONLY_DATA @@ -100,11 +100,11 @@ void USpineSkeletonDataAsset::BeginDestroy() { class SP_API NullAttachmentLoader : public AttachmentLoader { public: - virtual RegionAttachment *newRegionAttachment(Skin &skin, const String &name, const String &path) { + virtual RegionAttachment *newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) { return new (__FILE__, __LINE__) RegionAttachment(name); } - virtual MeshAttachment *newMeshAttachment(Skin &skin, const String &name, const String &path) { + virtual MeshAttachment *newMeshAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) { return new (__FILE__, __LINE__) MeshAttachment(name); } diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp index 367cfe01b..56ac79a4b 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp @@ -226,7 +226,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton *Skeleton) { attachmentColor.set(regionAttachment->getColor()); attachmentAtlasRegion = (AtlasRegion *) regionAttachment->getRendererObject(); - regionAttachment->computeWorldVertices(slot->getBone(), *attachmentVertices, 0, 2); + regionAttachment->computeWorldVertices(*slot, *attachmentVertices, 0, 2); attachmentIndices = quadIndices; attachmentUvs = regionAttachment->getUVs().buffer(); numVertices = 4; @@ -242,7 +242,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton *Skeleton) { attachmentColor.set(mesh->getColor()); attachmentAtlasRegion = (AtlasRegion *) mesh->getRendererObject(); - mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), *attachmentVertices, 0, 2); + mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), attachmentVertices->buffer(), 0, 2); attachmentIndices = mesh->getTriangles().buffer(); attachmentUvs = mesh->getUVs().buffer(); numVertices = mesh->getWorldVerticesLength() >> 1; diff --git a/spine-ue4/README.md b/spine-ue4/README.md index 959f6c6c5..31b7b5841 100644 --- a/spine-ue4/README.md +++ b/spine-ue4/README.md @@ -26,6 +26,7 @@ spine-ue4 does not support multiply and screen blending. spine-ue4 does not supp 2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it as a zip via the download button above. 3. Copy the `Plugins` folder from this directory to your new project's root directory. 4. Copy the folder `spine-runtimes/spine-cpp/spine-cpp` to your project's `Plugins/SpinePlugin/Source/SpinePlugin/Public/` folder. +5. Add `SpinePlugin` to `PublicDependencyModuleNames` in your project's `Build.cs` file. 5. Open the Unreal Project in the Unreal Editor See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documentation#runtimesTitle) on how to use the APIs or check out the Spine UE4 example. diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta index d872e8a1f..aa1c7400e 100644 --- a/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta +++ b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta @@ -49,7 +49,7 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta index 7e61d75f1..ad6fe555c 100644 --- a/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta +++ b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta @@ -84,7 +84,7 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta index 4bce8babc..0646af93a 100644 --- a/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta +++ b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta @@ -49,7 +49,7 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta index b6f7a55c3..fb9020746 100644 --- a/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta +++ b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta @@ -76,7 +76,7 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/whirlyblendmodes/whirlyblendmodes.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/whirlyblendmodes/whirlyblendmodes.png.meta index 349b06520..3e5040bd4 100644 --- a/spine-unity/Assets/Spine Examples/Spine Skeletons/whirlyblendmodes/whirlyblendmodes.png.meta +++ b/spine-unity/Assets/Spine Examples/Spine Skeletons/whirlyblendmodes/whirlyblendmodes.png.meta @@ -49,7 +49,7 @@ TextureImporter: alphaUsage: 1 alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerGraphicInspector.cs index 2339597fc..d42067c69 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerGraphicInspector.cs @@ -40,7 +40,7 @@ namespace Spine.Unity.Editor { public class BoneFollowerGraphicInspector : Editor { SerializedProperty boneName, skeletonGraphic, followXYPosition, followZPosition, followBoneRotation, - followLocalScale, followSkeletonFlip, maintainedAxisOrientation; + followLocalScale, followParentWorldScale, followSkeletonFlip, maintainedAxisOrientation; BoneFollowerGraphic targetBoneFollower; bool needsReset; @@ -77,6 +77,7 @@ namespace Spine.Unity.Editor { followXYPosition = serializedObject.FindProperty("followXYPosition"); followZPosition = serializedObject.FindProperty("followZPosition"); followLocalScale = serializedObject.FindProperty("followLocalScale"); + followParentWorldScale = serializedObject.FindProperty("followParentWorldScale"); followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip"); maintainedAxisOrientation = serializedObject.FindProperty("maintainedAxisOrientation"); @@ -172,6 +173,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.PropertyField(followXYPosition); EditorGUILayout.PropertyField(followZPosition); EditorGUILayout.PropertyField(followLocalScale); + EditorGUILayout.PropertyField(followParentWorldScale); EditorGUILayout.PropertyField(followSkeletonFlip); if ((followSkeletonFlip.hasMultipleDifferentValues || followSkeletonFlip.boolValue == false) && (followBoneRotation.hasMultipleDifferentValues || followBoneRotation.boolValue == true)) { diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerInspector.cs index e9051719b..609808400 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/BoneFollowerInspector.cs @@ -38,7 +38,7 @@ namespace Spine.Unity.Editor { [CustomEditor(typeof(BoneFollower)), CanEditMultipleObjects] public class BoneFollowerInspector : Editor { SerializedProperty boneName, skeletonRenderer, followXYPosition, followZPosition, followBoneRotation, - followLocalScale, followSkeletonFlip, maintainedAxisOrientation; + followLocalScale, followParentWorldScale, followSkeletonFlip, maintainedAxisOrientation; BoneFollower targetBoneFollower; bool needsReset; @@ -86,6 +86,7 @@ namespace Spine.Unity.Editor { followXYPosition = serializedObject.FindProperty("followXYPosition"); followZPosition = serializedObject.FindProperty("followZPosition"); followLocalScale = serializedObject.FindProperty("followLocalScale"); + followParentWorldScale = serializedObject.FindProperty("followParentWorldScale"); followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip"); maintainedAxisOrientation = serializedObject.FindProperty("maintainedAxisOrientation"); @@ -178,6 +179,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.PropertyField(followXYPosition); EditorGUILayout.PropertyField(followZPosition); EditorGUILayout.PropertyField(followLocalScale); + EditorGUILayout.PropertyField(followParentWorldScale); EditorGUILayout.PropertyField(followSkeletonFlip); if ((followSkeletonFlip.hasMultipleDifferentValues || followSkeletonFlip.boolValue == false) && (followBoneRotation.hasMultipleDifferentValues || followBoneRotation.boolValue == true)) { diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs index a4ad0b6b1..3d8bef242 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs @@ -45,8 +45,6 @@ #define HAS_ON_POSTPROCESS_PREFAB #endif -using System.Collections.Generic; -using System.Reflection; using UnityEditor; using UnityEngine; @@ -131,7 +129,7 @@ namespace Spine.Unity.Editor { SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials."); UpdateWhenInvisibleLabel = new GUIContent("Update When Invisible", "Update mode used when the MeshRenderer becomes invisible. Update mode is automatically reset to UpdateMode.FullUpdate when the mesh becomes visible again."); FixDrawOrderLabel = new GUIContent("Fix Draw Order", "Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. \"A B A\"). If true, GPU instancing will be disabled at all materials and MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes by e.g. the LWRP renderer, leading to incorrect draw order (e.g. \"A1 B A2\" changed to \"A1A2 B\"). You can disable this parameter when everything is drawn correctly to save the additional performance cost. Note: the GPU instancing setting will remain disabled at affected material assets after exiting play mode, you have to enable it manually if you accidentally enabled this parameter."); - FixPrefabOverrideViaMeshFilterLabel = new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost."); + FixPrefabOverrideViaMeshFilterLabel = new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost. For global settings see Edit - Preferences - Spine."); MaskInteractionLabel = new GUIContent("Mask Interaction", "SkeletonRenderer's interaction with a Sprite Mask."); MaskMaterialsHeadingLabel = new GUIContent("Mask Interaction Materials", "Materials used for different interaction with sprite masks."); MaskMaterialsNoneLabel = new GUIContent("Normal Materials", "Normal materials used when Mask Interaction is set to None."); @@ -397,11 +395,11 @@ namespace Spine.Unity.Editor { bool ignoredParam = true; MaskMaterialsEditingField(ref setMaskNoneMaterialsQueued, ref ignoredParam, maskMaterialsNone, MaskMaterialsNoneLabel, - differentMaskModesSelected, allowDelete : false, isActiveMaterial : activeMaskInteractionValue == (int)SpriteMaskInteraction.None); + differentMaskModesSelected, allowDelete: false, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.None); MaskMaterialsEditingField(ref setInsideMaskMaterialsQueued, ref deleteInsideMaskMaterialsQueued, maskMaterialsInside, MaskMaterialsInsideLabel, differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleInsideMask); MaskMaterialsEditingField(ref setOutsideMaskMaterialsQueued, ref deleteOutsideMaskMaterialsQueued, maskMaterialsOutside, MaskMaterialsOutsideLabel, - differentMaskModesSelected, allowDelete : true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleOutsideMask); + differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleOutsideMask); } #endif @@ -630,14 +628,13 @@ namespace Spine.Unity.Editor { } #if BUILT_IN_SPRITE_MASK_COMPONENT - static void EditorSetMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) - { + static void EditorSetMaskMaterials (SkeletonRenderer component, SpriteMaskInteraction maskType) { if (component == null) return; if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType); } - static void EditorDeleteMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) { + static void EditorDeleteMaskMaterials (SkeletonRenderer component, SpriteMaskInteraction maskType) { if (component == null) return; if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs index b28df6b53..0abd74b05 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs @@ -35,6 +35,10 @@ #define NEW_PREFERENCES_SETTINGS_PROVIDER #endif +#if UNITY_2020_2_OR_NEWER +#define HAS_ON_POSTPROCESS_PREFAB +#endif + using System.Threading; using UnityEditor; using UnityEngine; @@ -78,6 +82,11 @@ namespace Spine.Unity.Editor { internal const string DEFAULT_TEXTURE_SETTINGS_REFERENCE = ""; public string textureSettingsReference = DEFAULT_TEXTURE_SETTINGS_REFERENCE; +#if HAS_ON_POSTPROCESS_PREFAB + internal const bool DEFAULT_FIX_PREFAB_OVERRIDE_VIA_MESH_FILTER = false; + public bool fixPrefabOverrideViaMeshFilter = DEFAULT_FIX_PREFAB_OVERRIDE_VIA_MESH_FILTER; +#endif + public bool UsesPMAWorkflow { get { return IsPMAWorkflow(textureSettingsReference); @@ -177,8 +186,7 @@ namespace Spine.Unity.Editor { settings = AssetDatabase.LoadAssetAtPath(SPINE_SETTINGS_ASSET_PATH); if (settings == null) settings = FindSpinePreferences(); - if (settings == null) - { + if (settings == null) { settings = ScriptableObject.CreateInstance(); SpineEditorUtilities.OldPreferences.CopyOldToNewPreferences(ref settings); // Multiple threads may be calling this method during import, creating the folder @@ -189,6 +197,10 @@ namespace Spine.Unity.Editor { if (Interlocked.Exchange(ref wasPreferencesAssetCreated, 1) == 0) AssetDatabase.CreateAsset(settings, SPINE_SETTINGS_ASSET_PATH); } + +#if HAS_ON_POSTPROCESS_PREFAB + SkeletonRenderer.fixPrefabOverrideViaMeshFilterGlobal = settings.fixPrefabOverrideViaMeshFilter; +#endif return settings; } @@ -280,6 +292,15 @@ namespace Spine.Unity.Editor { } } +#if HAS_ON_POSTPROCESS_PREFAB + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel); + { + EditorGUILayout.PropertyField(settings.FindProperty("fixPrefabOverrideViaMeshFilter"), new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost. This is a global setting that can be overwritten on each SkeletonRenderer")); + SkeletonRenderer.fixPrefabOverrideViaMeshFilterGlobal = settings.FindProperty("fixPrefabOverrideViaMeshFilter").boolValue; + } +#endif + #if SPINE_TK2D_DEFINE bool isTK2DDefineSet = true; #else diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AtlasAssetBase.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AtlasAssetBase.cs index 8509e7127..e7abeec72 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AtlasAssetBase.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AtlasAssetBase.cs @@ -27,7 +27,6 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System.Collections; using System.Collections.Generic; using UnityEngine; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs index cda7f1e51..25692e713 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs @@ -27,7 +27,6 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using Spine; using System; using System.Collections.Generic; using System.IO; @@ -39,6 +38,7 @@ namespace Spine.Unity { public class SpineAtlasAsset : AtlasAssetBase { public TextAsset atlasFile; public Material[] materials; + public TextureLoader customTextureLoader; protected Atlas atlas; public override bool IsLoaded { get { return this.atlas != null; } } @@ -50,11 +50,19 @@ namespace Spine.Unity { #region Runtime Instantiation ///

/// Creates a runtime AtlasAsset - public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, Material[] materials, bool initialize) { + /// When not null, a function instantiating + /// a custom TextureLoader with the newly created SpineAtlasAsset as argument + /// is used instead of instantiating the default MaterialsTextureLoader. + /// A valid parameter is e.g. (a) => new CustomTextureLoader(a) + public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, Material[] materials, bool initialize, + Func newCustomTextureLoader = null) { + SpineAtlasAsset atlasAsset = ScriptableObject.CreateInstance(); atlasAsset.Reset(); atlasAsset.atlasFile = atlasText; atlasAsset.materials = materials; + if (newCustomTextureLoader != null) + atlasAsset.customTextureLoader = newCustomTextureLoader(atlasAsset); if (initialize) atlasAsset.GetAtlas(); @@ -63,8 +71,18 @@ namespace Spine.Unity { } /// - /// Creates a runtime AtlasAsset. Only providing the textures is slower because it has to search for atlas page matches. - public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Material materialPropertySource, bool initialize) { + /// Creates a runtime AtlasAsset. Only providing the textures is slower + /// because it has to search for atlas page matches. + /// + /// An array of all textures referenced in the provided atlasText + /// atlas asset JSON file. When procedurally creating textures, each Texture.name + /// needs to be set to the atlas page texture filename without the .png extension, + /// e.g. 'my_skeleton' if the png filename listed in the atlas asset file is 'my_skeleton.png'. + /// + public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, + Material materialPropertySource, bool initialize, + Func newCustomTextureLoader = null) { + // Get atlas page names. string atlasString = atlasText.text; atlasString = atlasString.Replace("\r", ""); @@ -99,19 +117,26 @@ namespace Spine.Unity { } // Create AtlasAsset normally - return CreateRuntimeInstance(atlasText, materials, initialize); + return CreateRuntimeInstance(atlasText, materials, initialize, newCustomTextureLoader); } /// - /// Creates a runtime AtlasAsset. Only providing the textures is slower because it has to search for atlas page matches. - public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Shader shader, bool initialize) { + /// Creates a runtime AtlasAsset. Only providing the textures is slower because + /// it has to search for atlas page matches. + /// An array of all textures referenced in the provided atlasText + /// atlas asset JSON file. When procedurally creating textures, each Texture.name + /// needs to be set to the atlas page texture filename without the .png extension, + /// e.g. 'my_skeleton' if the png filename listed in the atlas asset file is 'my_skeleton.png'. + /// + public static SpineAtlasAsset CreateRuntimeInstance (TextAsset atlasText, + Texture2D[] textures, Shader shader, bool initialize, + Func newCustomTextureLoader = null) { + if (shader == null) shader = Shader.Find("Spine/Skeleton"); Material materialProperySource = new Material(shader); - var oa = CreateRuntimeInstance(atlasText, textures, materialProperySource, initialize); - - return oa; + return CreateRuntimeInstance(atlasText, textures, materialProperySource, initialize, newCustomTextureLoader); } #endregion @@ -142,7 +167,7 @@ namespace Spine.Unity { try { TextureLoader loader; if (!onlyMetaData) - loader = new MaterialsTextureLoader(this); + loader = customTextureLoader == null ? new MaterialsTextureLoader(this) : customTextureLoader; else loader = new NoOpTextureLoader(); atlas = new Atlas(new StringReader(atlasFile.text), "", loader); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineSpriteAtlasAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineSpriteAtlasAsset.cs index f02fb5e79..5c8c4b486 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineSpriteAtlasAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineSpriteAtlasAsset.cs @@ -31,10 +31,8 @@ #define EXPOSES_SPRITE_ATLAS_UTILITIES #endif -using Spine; using System; using System.Collections.Generic; -using System.IO; using UnityEngine; using UnityEngine.U2D; @@ -300,8 +298,7 @@ namespace Spine.Unity { if (sprites.Length == 0) { Debug.LogWarning(string.Format("SpriteAtlas '{0}' contains no sprites. Please make sure all assigned images are set to import type 'Sprite'.", spriteAtlasFile.name), spriteAtlasFile); return; - } - else if (sprites[0].packingMode == SpritePackingMode.Tight) { + } else if (sprites[0].packingMode == SpritePackingMode.Tight) { Debug.LogError(string.Format("SpriteAtlas '{0}': Tight packing is not supported. Please disable 'Tight Packing' in the SpriteAtlas Inspector.", spriteAtlasFile.name), spriteAtlasFile); return; } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollower.cs index 0ad58e19e..1e089c18b 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollower.cs @@ -67,9 +67,11 @@ namespace Spine.Unity { [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] public bool followSkeletonFlip = true; - [Tooltip("Follows the target bone's local scale. BoneFollower cannot inherit world/skewed scale because of UnityEngine.Transform property limitations.")] + [Tooltip("Follows the target bone's local scale.")] [UnityEngine.Serialization.FormerlySerializedAs("followScale")] public bool followLocalScale = false; + [Tooltip("Includes the parent bone's lossy world scale. BoneFollower cannot inherit rotated/skewed scale because of UnityEngine.Transform property limitations.")] + public bool followParentWorldScale = false; public enum AxisOrientation { XAxis = 1, @@ -206,12 +208,17 @@ namespace Spine.Unity { * skeletonLossyScale.y * parentLossyScale.y); } - Vector3 localScale = followLocalScale ? new Vector3(bone.ScaleX, bone.ScaleY, 1f) : new Vector3(1f, 1f, 1f); - if (followSkeletonFlip) - localScale.y *= Mathf.Sign(bone.Skeleton.ScaleX * bone.Skeleton.ScaleY) * additionalFlipScale; - - thisTransform.localScale = localScale; + Bone parentBone = bone.Parent; + if (followParentWorldScale || followLocalScale || followSkeletonFlip) { + Vector3 localScale = new Vector3(1f, 1f, 1f); + if (followParentWorldScale && parentBone != null) + localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1f); + if (followLocalScale) + localScale.Scale(new Vector3(bone.ScaleX, bone.ScaleY, 1f)); + if (followSkeletonFlip) + localScale.y *= Mathf.Sign(bone.Skeleton.ScaleX * bone.Skeleton.ScaleY) * additionalFlipScale; + thisTransform.localScale = localScale; + } } } - } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollowerGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollowerGraphic.cs index 283a106ff..bd59c651e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollowerGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoneFollowerGraphic.cs @@ -64,8 +64,10 @@ namespace Spine.Unity { public bool followBoneRotation = true; [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] public bool followSkeletonFlip = true; - [Tooltip("Follows the target bone's local scale. BoneFollower cannot inherit world/skewed scale because of UnityEngine.Transform property limitations.")] + [Tooltip("Follows the target bone's local scale.")] public bool followLocalScale = false; + [Tooltip("Includes the parent bone's lossy world scale. BoneFollower cannot inherit rotated/skewed scale because of UnityEngine.Transform property limitations.")] + public bool followParentWorldScale = false; public bool followXYPosition = true; public bool followZPosition = true; [Tooltip("Applies when 'Follow Skeleton Flip' is disabled but 'Follow Bone Rotation' is enabled." @@ -185,11 +187,17 @@ namespace Spine.Unity { * skeletonLossyScale.y * parentLossyScale.y); } - Vector3 localScale = followLocalScale ? new Vector3(bone.ScaleX, bone.ScaleY, 1f) : new Vector3(1f, 1f, 1f); - if (followSkeletonFlip) - localScale.y *= Mathf.Sign(bone.Skeleton.ScaleX * bone.Skeleton.ScaleY) * additionalFlipScale; - thisTransform.localScale = localScale; + Bone parentBone = bone.Parent; + if (followParentWorldScale || followLocalScale || followSkeletonFlip) { + Vector3 localScale = new Vector3(1f, 1f, 1f); + if (followParentWorldScale && parentBone != null) + localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1f); + if (followLocalScale) + localScale.Scale(new Vector3(bone.ScaleX, bone.ScaleY, 1f)); + if (followSkeletonFlip) + localScale.y *= Mathf.Sign(bone.Skeleton.ScaleX * bone.Skeleton.ScaleY) * additionalFlipScale; + thisTransform.localScale = localScale; + } } - } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 7bbcf08bc..7a068d7e1 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -73,17 +73,26 @@ namespace Spine.Unity { set { editorSkipSkinSync = value; } } protected bool editorSkipSkinSync = false; + /// Sets the MeshFilter's hide flags to DontSaveInEditor which fixes the prefab /// always being marked as changed, but at the cost of references to the MeshFilter by other /// components being lost. - public bool fixPrefabOverrideViaMeshFilter = false; + public SettingsTriState fixPrefabOverrideViaMeshFilter = SettingsTriState.UseGlobalSetting; + public static bool fixPrefabOverrideViaMeshFilterGlobal = false; public void EditorUpdateMeshFilterHideFlags () { if (!meshFilter) { meshFilter = GetComponent(); if (meshFilter == null) meshFilter = gameObject.AddComponent(); } - if (fixPrefabOverrideViaMeshFilter) { + + bool dontSaveInEditor = false; + if (fixPrefabOverrideViaMeshFilter == SettingsTriState.Enable || + (fixPrefabOverrideViaMeshFilter == SettingsTriState.UseGlobalSetting && + fixPrefabOverrideViaMeshFilterGlobal)) + dontSaveInEditor = true; + + if (dontSaveInEditor) { #if NEW_PREFAB_SYSTEM if (UnityEditor.PrefabUtility.IsPartOfAnyPrefab(meshFilter)) { var instanceRoot = UnityEditor.PrefabUtility.GetOutermostPrefabInstanceRoot(meshFilter); @@ -99,8 +108,7 @@ namespace Spine.Unity { } #endif meshFilter.hideFlags = HideFlags.DontSaveInEditor; - } - else { + } else { meshFilter.hideFlags = HideFlags.None; } } @@ -321,7 +329,7 @@ namespace Spine.Unity { #endif #if UNITY_EDITOR - void OnEnable() { + void OnEnable () { if (!Application.isPlaying) LateUpdate(); } @@ -619,8 +627,7 @@ namespace Spine.Unity { separatorSlots.Add(slot); } #if UNITY_EDITOR - else if (!string.IsNullOrEmpty(separatorSlotNames[i])) - { + else if (!string.IsNullOrEmpty(separatorSlotNames[i])) { Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonDataAsset.skeletonJSON.name); } #endif @@ -628,8 +635,7 @@ namespace Spine.Unity { } #if BUILT_IN_SPRITE_MASK_COMPONENT - private void AssignSpriteMaskMaterials() - { + private void AssignSpriteMaskMaterials () { #if UNITY_EDITOR if (!Application.isPlaying && !UnityEditor.EditorApplication.isUpdating) { EditorFixStencilCompParameters(); @@ -644,15 +650,13 @@ namespace Spine.Unity { if (maskMaterials.materialsMaskDisabled.Length > 0 && maskMaterials.materialsMaskDisabled[0] != null && maskInteraction == SpriteMaskInteraction.None) { this.meshRenderer.materials = maskMaterials.materialsMaskDisabled; - } - else if (maskInteraction == SpriteMaskInteraction.VisibleInsideMask) { + } else if (maskInteraction == SpriteMaskInteraction.VisibleInsideMask) { if (maskMaterials.materialsInsideMask.Length == 0 || maskMaterials.materialsInsideMask[0] == null) { if (!InitSpriteMaskMaterialsInsideMask()) return; } this.meshRenderer.materials = maskMaterials.materialsInsideMask; - } - else if (maskInteraction == SpriteMaskInteraction.VisibleOutsideMask) { + } else if (maskInteraction == SpriteMaskInteraction.VisibleOutsideMask) { if (maskMaterials.materialsOutsideMask.Length == 0 || maskMaterials.materialsOutsideMask[0] == null) { if (!InitSpriteMaskMaterialsOutsideMask()) return; @@ -661,18 +665,15 @@ namespace Spine.Unity { } } - private bool InitSpriteMaskMaterialsInsideMask() - { + private bool InitSpriteMaskMaterialsInsideMask () { return InitSpriteMaskMaterialsForMaskType(STENCIL_COMP_MASKINTERACTION_VISIBLE_INSIDE, ref maskMaterials.materialsInsideMask); } - private bool InitSpriteMaskMaterialsOutsideMask() - { + private bool InitSpriteMaskMaterialsOutsideMask () { return InitSpriteMaskMaterialsForMaskType(STENCIL_COMP_MASKINTERACTION_VISIBLE_OUTSIDE, ref maskMaterials.materialsOutsideMask); } - private bool InitSpriteMaskMaterialsForMaskType(UnityEngine.Rendering.CompareFunction maskFunction, ref Material[] materialsToFill) - { + private bool InitSpriteMaskMaterialsForMaskType (UnityEngine.Rendering.CompareFunction maskFunction, ref Material[] materialsToFill) { #if UNITY_EDITOR if (!Application.isPlaying) { return false; @@ -690,14 +691,14 @@ namespace Spine.Unity { } #if UNITY_EDITOR - private void EditorFixStencilCompParameters() { + private void EditorFixStencilCompParameters () { if (!haveStencilParametersBeenFixed && HasAnyStencilComp0Material()) { haveStencilParametersBeenFixed = true; FixAllProjectMaterialsStencilCompParameters(); } } - private void FixAllProjectMaterialsStencilCompParameters() { + private void FixAllProjectMaterialsStencilCompParameters () { string[] materialGUIDS = UnityEditor.AssetDatabase.FindAssets("t:material"); foreach (var guid in materialGUIDS) { string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); @@ -712,7 +713,7 @@ namespace Spine.Unity { UnityEditor.AssetDatabase.SaveAssets(); } - private bool HasAnyStencilComp0Material() { + private bool HasAnyStencilComp0Material () { if (meshRenderer == null) return false; @@ -739,7 +740,7 @@ namespace Spine.Unity { /// Otherwise, e.g. when using Lightweight Render Pipeline, deliberately separated draw calls /// "A1 B A2" are reordered to "A1A2 B", regardless of batching-related project settings. /// - private void SetMaterialSettingsToFixDrawOrder() { + private void SetMaterialSettingsToFixDrawOrder () { if (reusedPropertyBlock == null) reusedPropertyBlock = new MaterialPropertyBlock(); bool hasPerRendererBlock = meshRenderer.HasPropertyBlock(); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs new file mode 100644 index 000000000..8f7647252 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs @@ -0,0 +1,42 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, 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. + *****************************************************************************/ + +namespace Spine.Unity { + + /// + /// TriState enum which can be used to replace and extend a bool variable by + /// a third UseGlobalSettings state. Automatically maps serialized + /// bool values to corresponding Disable and Enable states. + /// + public enum SettingsTriState { + Disable, + Enable, + UseGlobalSetting + } +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs.meta new file mode 100644 index 000000000..2f1cb7908 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SettingsTriState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f6692d1b45ac11459207a012cafeb03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs index 500ad531e..f984d1ae1 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs @@ -233,7 +233,7 @@ namespace Spine.Unity { buffer = buffer ?? new Vector2[bufferTargetSize]; if (buffer.Length < bufferTargetSize) throw new System.ArgumentException(string.Format("Vector2 buffer too small. {0} requires an array of size {1}. Use the attachment's .WorldVerticesLength to get the correct size.", va.Name, floatsCount), "buffer"); - if (va.Bones == null && va.TimelineAttachment == null) { + if (va.Bones == null && slot.Deform.Count == 0) { var localVerts = va.Vertices; for (int i = 0; i < bufferTargetSize; i++) { int j = i * 2; @@ -299,7 +299,6 @@ namespace Spine.Unity { namespace Spine { using System; - using System.Collections.Generic; public struct BoneMatrix { public float a, b, c, d, x, y; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs index 5c69f6637..502234ee9 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs @@ -48,39 +48,9 @@ namespace Spine.Unity.Playables { } var scriptPlayable = ScriptPlayable.Create(graph, inputCount); -#if UNITY_EDITOR - WarnIfDuplicateTrackIndex(); -#endif var mixerBehaviour = scriptPlayable.GetBehaviour(); mixerBehaviour.trackIndex = this.trackIndex; return scriptPlayable; } - -#if UNITY_EDITOR - static float lastWarningTime = 0; - - public void WarnIfDuplicateTrackIndex () { - if (Time.frameCount == lastWarningTime) // only warn once. - return; - lastWarningTime = Time.frameCount; - - var rootTracks = timelineAsset.GetRootTracks(); - List trackIndices = new List(); - int trackFromTop = -1; // first invisible track is marker track, skipped. - foreach (var track in rootTracks) { - ++trackFromTop; - if (track.GetType() != typeof(SpineAnimationStateTrack)) - continue; - var animationStateTrack = (SpineAnimationStateTrack)track; - int trackIndex = animationStateTrack.trackIndex; - if (trackIndices.Contains(trackIndex)) { - Debug.LogWarning(string.Format("Please change the 'Track Index' Inspector property " + - "at Track number {0} from the top, both tracks are setting animations at track index '{1}'.", - trackFromTop, trackIndex)); - } else - trackIndices.Add(trackIndex); - } - } -#endif } } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-NormalsPass-URP-2D.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-NormalsPass-URP-2D.hlsl index 0bdd83882..150a75d76 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-NormalsPass-URP-2D.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-NormalsPass-URP-2D.hlsl @@ -51,16 +51,15 @@ half4 NormalsRenderingFragment(Varyings i) : SV_Target half4 mainTex = i.color * tex2D(_MainTex, i.uv); #if defined(_NORMALMAP) - half3 normalWS = calculateNormalFromBumpMap(i.uv.xy, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz); + half3 normalTS = normalize(UnpackScaleNormal(tex2D(_BumpMap, i.uv.xy), _BumpScale)); + return NormalsRenderingShared(mainTex, normalTS, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz); #else + half3 normalTS = half3(0, 0, 1); + half3 tangentWS = half3(0, 0, 0); + half3 bitangentWS = half3(0, 0, 0); half3 normalWS = i.normalWS.xyz; + return NormalsRenderingShared(mainTex, normalTS, tangentWS, bitangentWS, normalWS); #endif - - half3 normalVS = TransformWorldToViewDir(normalWS); - float4 normalColor; - normalColor.rgb = 0.5 * ((normalVS) + 1); - normalColor.a = mainTex.a; - return normalColor; } #endif diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-StandardPass-URP-2D.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-StandardPass-URP-2D.hlsl index c30493218..9556108c5 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-StandardPass-URP-2D.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-Sprite-StandardPass-URP-2D.hlsl @@ -92,7 +92,18 @@ half4 CombinedShapeLightFragment(VertexOutputSpriteURP2D input) : SV_Target half4 main = texureColor * input.vertexColor; half4 mask = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex, input.texcoord.xy); +#if UNITY_VERSION < 202120 half4 pixel = half4(CombinedShapeLightShared(half4(main.rgb, 1), mask, input.lightingUV).rgb, main.a); +#else + SurfaceData2D surfaceData; + InputData2D inputData; + surfaceData.albedo = main.rgb; + surfaceData.alpha = 1; + surfaceData.mask = mask; + inputData.uv = input.texcoord; + inputData.lightingUV = input.lightingUV; + half4 pixel = half4(CombinedShapeLightShared(surfaceData, inputData).rgb, main.a); +#endif #if defined(_RIM_LIGHTING) #if defined(_NORMALMAP) diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader index bb2dd7f28..77d99f1d7 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader @@ -153,7 +153,7 @@ float4 positionCS : SV_POSITION; float4 color : COLOR; float2 uv : TEXCOORD0; - float3 normalVS : TEXCOORD1; + float3 normalWS : TEXCOORD1; }; TEXTURE2D(_MainTex); @@ -166,8 +166,7 @@ o.positionCS = TransformObjectToHClip(attributes.positionOS); o.uv = attributes.uv; o.color = attributes.color; - float3 normalWS = TransformObjectToWorldDir(float3(0, 0, -1)); - o.normalVS = TransformWorldToViewDir(normalWS); + o.normalWS = TransformObjectToWorldDir(float3(0, 0, -1)); return o; } @@ -176,11 +175,10 @@ float4 NormalsRenderingFragment(Varyings i) : SV_Target { float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); - - float4 normalColor; - normalColor.rgb = 0.5 * ((i.normalVS)+1); - normalColor.a = mainTex.a; - return normalColor; + half3 normalTS = half3(0, 0, 1); + half3 tangentWS = half3(0, 0, 0); + half3 bitangentWS = half3(0, 0, 0); + return NormalsRenderingShared(mainTex, normalTS, tangentWS, bitangentWS, i.normalWS); } ENDHLSL } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json index d132441d9..0c591e2e3 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.urp-shaders", "displayName": "Spine Universal RP Shaders", "description": "This plugin provides universal render pipeline (URP) shaders for the spine-unity runtime.\n\nPrerequisites:\nIt requires a working installation of the spine-unity runtime, version 4.1.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)", - "version": "4.1.0", + "version": "4.1.1", "unity": "2019.3", "author": { "name": "Esoteric Software",