diff --git a/CHANGELOG.md b/CHANGELOG.md index a80ba455cd..23d62ade51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -163,6 +163,9 @@ * 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`. * Timeline naming improvements: `Spine AnimationState Clip` Inspector parameter `Custom Duration` changed and inverted to `Default Mix Duration` for more clarity. Shortened all Timeline add track menu entries from: `Spine.Unity.Playables - ` to `Spine - `, `Spine Animation State Track` to `SkeletonAnimation Track`, `Spine AnimationState Graphic Track` to `SkeletonGraphic Track`, and `Spine Skeleton Flip Track` to `Skeleton Flip Track`. * Timeline track appearance and Inspector: Tracks now show icons and track colors to make them easier to distinguish. When a Track is selected, the Inspector now shows an editable track name which was previously only editable at the Timeline asset. + * Added example component `SkeletonRenderTexture` to render a `SkeletonRenderer` to a `RenderTexture`, mainly for proper transparency. Added an example scene named `RenderTexture FadeOut Transparency` that demonstrates usage for a fadeout transparency effect. + * Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect. + * Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0. * **Changes of default values** @@ -237,6 +240,7 @@ * `SkeletonMesh` now takes an optional `SkeletonMeshMaterialParametersCustomizer` function that allows you to modify the `ShaderMaterialParameters` before the material is finalized. Use it to modify things like THREEJS' `Material.depthTest` etc. See #1590. * **Breaking change:** the global object `spine.canvas` no longer exists. All classes and functions are now exposed on the global `spine` object directly. Simply replace any reference to `spine.threejs.` in your source code with `spine.`. * **Breaking change:** the default fragment shader of `SkeletonMeshMaterial` now explicitely discards fragments with alpha < 0.5. See https://github.com/EsotericSoftware/spine-runtimes/issues/1985 +* **Breaking change:** reversal of the previous breaking change: the default fragment shader of `SkeletonMeshMaterial` does no longer discard fragments with alpha < 0.5. Pass a `SkeletonMeshMaterialParametersCustomizer` to the `SkeletonMesh` constructor, and modify `parameters.alphaTest` to be > 0. ### Player * Added `SpinePlayerConfig.rawDataURIs`. Allows to embed data URIs for skeletons, atlases and atlas page images directly in the HTML/JS without needing to load it from a separate file. See the example for a demonstration. @@ -631,6 +635,8 @@ * Added `MeshAttachment#newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh. * Added IK softness. * Added `AssetManager.setRawDataURI(path, data)`. Allows to embed data URIs for skeletons, atlases and atlas page images directly in the HTML/JS without needing to load it from a separate file. + * Added `AssetManager.loadAll()` to allow Promise/async/await based waiting for completion of asset load. See the `spine-canvas` examples. + * Added `Skeleton.getBoundRect()` helper method to calculate the bouding rectangle of the current pose, returning the result as `{ x, y, width, height }`. Note that this method will create temporary objects which can add to garbage collection pressure. ### WebGL backend * `Input` can now take a partially defined implementation of `InputListener`. diff --git a/CMakeLists.txt b/CMakeLists.txt index e038894b06..6ed6cc4908 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,13 @@ cmake_minimum_required(VERSION 3.17) project(spine) +set(CMAKE_INSTALL_PREFIX "./") +set(CMAKE_VERBOSE_MAKEFILE ON) +set(SPINE_SFML FALSE CACHE BOOL FALSE) +set(SPINE_COCOS2D_OBJC FALSE CACHE BOOL FALSE) +set(SPINE_COCOS2D_X FALSE CACHE BOOL FALSE) +set(SPINE_SANITIZE FALSE CACHE BOOL FALSE) + if(MSVC) message("MSCV detected") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") @@ -8,13 +15,12 @@ if(MSVC) else() set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wunused-value -Wno-c++11-long-long -Wno-variadic-macros -Werror -Wextra -pedantic -Wnonportable-include-path -Wshadow -std=c89") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunused-value -Wno-c++11-long-long -Wno-variadic-macros -Werror -Wextra -Wnon-virtual-dtor -pedantic -Wnonportable-include-path -Wshadow -std=c++11 -fno-exceptions -fno-rtti") -endif() -set(CMAKE_INSTALL_PREFIX "./") -set(CMAKE_VERBOSE_MAKEFILE ON) -set(SPINE_SFML FALSE CACHE BOOL FALSE) -set(SPINE_COCOS2D_OBJC FALSE CACHE BOOL FALSE) -set(SPINE_COCOS2D_X FALSE CACHE BOOL FALSE) + if (${SPINE_SANITIZE}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize=undefined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined") + endif() +endif() if((${SPINE_SFML}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sfml")) add_subdirectory(spine-c) @@ -34,4 +40,4 @@ if((${SPINE_COCOS2D_X}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-cocos2dx" endif() # add_subdirectory(spine-c/spine-c-unit-tests) -add_subdirectory(spine-cpp/spine-cpp-unit-tests) \ No newline at end of file +add_subdirectory(spine-cpp/spine-cpp-unit-tests) diff --git a/spine-c/spine-c/src/spine/SkeletonBinary.c b/spine-c/spine-c/src/spine/SkeletonBinary.c index db9431c1c4..b997f9143b 100644 --- a/spine-c/spine-c/src/spine/SkeletonBinary.c +++ b/spine-c/spine-c/src/spine/SkeletonBinary.c @@ -1189,7 +1189,7 @@ spSkeletonData *spSkeletonBinary_readSkeletonData(spSkeletonBinary *self, const highHash = readInt(input); sprintf(buffer, "%x%x", highHash, lowHash); buffer[31] = 0; - skeletonData->hash = strdup(buffer); + MALLOC_STR(skeletonData->hash, buffer); skeletonData->version = readString(input); if (!strlen(skeletonData->version)) { diff --git a/spine-c/spine-c/src/spine/SkeletonJson.c b/spine-c/spine-c/src/spine/SkeletonJson.c index e6bbf63020..349c83743d 100644 --- a/spine-c/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/spine-c/src/spine/SkeletonJson.c @@ -34,10 +34,6 @@ #include #include -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) -#define strdup _strdup -#endif - typedef struct { const char *parent; const char *skin; @@ -938,9 +934,17 @@ spSkeletonData *spSkeletonJson_readSkeletonData(spSkeletonJson *self, const char skeletonData->height = Json_getFloat(skeleton, "height", 0); skeletonData->fps = Json_getFloat(skeleton, "fps", 30); skeletonData->imagesPath = Json_getString(skeleton, "images", 0); - if (skeletonData->imagesPath) skeletonData->imagesPath = strdup(skeletonData->imagesPath); + if (skeletonData->imagesPath) { + char *tmp = NULL; + MALLOC_STR(tmp, skeletonData->imagesPath); + skeletonData->imagesPath = tmp; + } skeletonData->audioPath = Json_getString(skeleton, "audio", 0); - if (skeletonData->audioPath) skeletonData->audioPath = strdup(skeletonData->audioPath); + if (skeletonData->audioPath) { + char *tmp = NULL; + MALLOC_STR(tmp, skeletonData->audioPath); + skeletonData->audioPath = tmp; + } } /* Bones. */ diff --git a/spine-cpp/spine-cpp/include/spine/Extension.h b/spine-cpp/spine-cpp/include/spine/Extension.h index 02133506dd..31d91daf78 100644 --- a/spine-cpp/spine-cpp/include/spine/Extension.h +++ b/spine-cpp/spine-cpp/include/spine/Extension.h @@ -104,15 +104,15 @@ namespace spine { virtual ~DefaultSpineExtension(); protected: - virtual void *_alloc(size_t size, const char *file, int line); + virtual void *_alloc(size_t size, const char *file, int line) override; - virtual void *_calloc(size_t size, const char *file, int line); + virtual void *_calloc(size_t size, const char *file, int line) override; - virtual void *_realloc(void *ptr, size_t size, const char *file, int line); + virtual void *_realloc(void *ptr, size_t size, const char *file, int line) override; - virtual void _free(void *mem, const char *file, int line); + virtual void _free(void *mem, const char *file, int line) override; - virtual char *_readFile(const String &path, int *length); + virtual char *_readFile(const String &path, int *length) override; }; // This function is to be implemented by engine specific runtimes to provide diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index 6238307522..88e45fca3c 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -73,10 +73,6 @@ #include #include -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) -#define strdup _strdup -#endif - using namespace spine; static float toColor(const char *value, size_t index) { @@ -418,6 +414,8 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) { data->_spacingMode = SpacingMode_Fixed; else if (strcmp(item, "percent") == 0) data->_spacingMode = SpacingMode_Percent; + else + data->_spacingMode = SpacingMode_Proportional; item = Json::getString(constraintMap, "rotateMode", "tangent"); if (strcmp(item, "tangent") == 0) data->_rotateMode = RotateMode_Tangent; diff --git a/spine-csharp/src/SkeletonBinary.cs b/spine-csharp/src/SkeletonBinary.cs index b24068643e..a4e32116cf 100644 --- a/spine-csharp/src/SkeletonBinary.cs +++ b/spine-csharp/src/SkeletonBinary.cs @@ -1200,7 +1200,7 @@ internal class SkeletonInput { input.Position = initialPosition; return GetVersionStringOld3X(); } catch (Exception e) { - throw new ArgumentException("Stream does not contain a valid binary Skeleton Data.\n" + e, "input"); + throw new ArgumentException("Stream does not contain valid binary Skeleton Data.\n" + e, "input"); } } @@ -1212,13 +1212,13 @@ internal class SkeletonInput { // Version. byteCount = ReadInt(true); - if (byteCount > 1) { + if (byteCount > 1 && byteCount <= 13) { byteCount--; var buffer = new byte[byteCount]; ReadFully(buffer, 0, byteCount); return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount); } - return null; + throw new ArgumentException("Stream does not contain valid binary Skeleton Data."); } } } diff --git a/spine-csharp/src/package.json b/spine-csharp/src/package.json index 106d9ffe81..5ca1e0caf0 100644 --- a/spine-csharp/src/package.json +++ b/spine-csharp/src/package.json @@ -11,9 +11,6 @@ }, "dependencies": { }, - "files": [ - "src" - ], "repository": { "type": "git", "url": "git@github.com:EsotericSoftware/spine-runtimes.git" diff --git a/spine-ts/.vscode/launch.json b/spine-ts/.vscode/launch.json index 109a37100a..08d870cc9e 100644 --- a/spine-ts/.vscode/launch.json +++ b/spine-ts/.vscode/launch.json @@ -17,6 +17,20 @@ "name": "drag-and-drop", "url": "http://localhost:8080/spine-webgl/example/drag-and-drop.html", "webRoot": "${workspaceFolder}" + }, + { + "type": "pwa-chrome", + "request": "launch", + "name": "barebones-dragon", + "url": "http://localhost:8080/spine-webgl/example/barebones-dragon.html", + "webRoot": "${workspaceFolder}" + }, + { + "type": "pwa-chrome", + "request": "launch", + "name": "threejs-example", + "url": "http://localhost:8080/spine-threejs/example/index.html", + "webRoot": "${workspaceFolder}" } ] -} \ No newline at end of file +} diff --git a/spine-ts/README.md b/spine-ts/README.md index c9e2bb5aae..13b72e6c7d 100644 --- a/spine-ts/README.md +++ b/spine-ts/README.md @@ -56,8 +56,8 @@ You can include a module in your project via a ` - - + + + + - - + + - \ No newline at end of file diff --git a/spine-ts/spine-canvas/example/mouse-click.html b/spine-ts/spine-canvas/example/mouse-click.html new file mode 100644 index 0000000000..56920f649a --- /dev/null +++ b/spine-ts/spine-canvas/example/mouse-click.html @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spine-ts/spine-canvas/package.json b/spine-ts/spine-canvas/package.json index daa137dd8b..5c1841937d 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.0.20", + "version": "4.0.27", "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.0.20" + "@esotericsoftware/spine-core": "^4.0.27" } } \ No newline at end of file diff --git a/spine-ts/spine-core/package.json b/spine-ts/spine-core/package.json index b61797c6e0..b251e379dd 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.0.20", + "version": "4.0.27", "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/AssetManagerBase.ts b/spine-ts/spine-core/src/AssetManagerBase.ts index deb8d6fb52..607ac9a36c 100644 --- a/spine-ts/spine-core/src/AssetManagerBase.ts +++ b/spine-ts/spine-core/src/AssetManagerBase.ts @@ -65,6 +65,21 @@ export class AssetManagerBase implements Disposable { if (callback) callback(path, message); } + loadAll () { + let promise = new Promise((resolve: (assetManager: AssetManagerBase) => void, reject: (errors: StringMap) => void) => { + let check = () => { + if (this.isLoadingComplete()) { + if (this.hasErrors()) reject(this.errors); + else resolve(this); + return; + } + requestAnimationFrame(check); + } + requestAnimationFrame(check); + }); + return promise; + } + setRawDataURI (path: string, data: string) { this.downloader.rawDataUris[this.pathPrefix + path] = data; } diff --git a/spine-ts/spine-core/src/Skeleton.ts b/spine-ts/spine-core/src/Skeleton.ts index 3be52c8f25..eca98def0e 100644 --- a/spine-ts/spine-core/src/Skeleton.ts +++ b/spine-ts/spine-core/src/Skeleton.ts @@ -585,6 +585,15 @@ export class Skeleton { return null; } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose as `{ x: number, y: number, width: number, height: number }`. + * Note that this method will create temporary objects which can add to garbage collection pressure. Use `getBounds()` if garbage collection is a concern. */ + getBoundsRect () { + let offset = new Vector2(); + let size = new Vector2(); + this.getBounds(offset, size); + return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. * @param size An output value, the width and height of the AABB. diff --git a/spine-ts/spine-core/src/SkeletonBinary.ts b/spine-ts/spine-core/src/SkeletonBinary.ts index f61e807886..4b1b1daba6 100644 --- a/spine-ts/spine-core/src/SkeletonBinary.ts +++ b/spine-ts/spine-core/src/SkeletonBinary.ts @@ -1022,7 +1022,7 @@ export class BinaryInput { let chars = ""; let charCount = 0; for (let i = 0; i < byteCount;) { - let b = this.readByte(); + let b = this.readUnsignedByte(); switch (b >> 4) { case 12: case 13: diff --git a/spine-ts/spine-player/package.json b/spine-ts/spine-player/package.json index 85345e6cb8..72f447ab7f 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.0.20", + "version": "4.0.27", "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.0.20" + "@esotericsoftware/spine-webgl": "^4.0.27" } } \ No newline at end of file diff --git a/spine-ts/spine-player/src/Player.ts b/spine-ts/spine-player/src/Player.ts index bb31df0ab1..14e6c8da1c 100644 --- a/spine-ts/spine-player/src/Player.ts +++ b/spine-ts/spine-player/src/Player.ts @@ -258,7 +258,7 @@ export class SpinePlayer implements Disposable { dispose (): void { this.sceneRenderer.dispose(); - this.loadingScreen.dispose(); + if (this.loadingScreen) this.loadingScreen.dispose(); this.assetManager.dispose(); for (var i = 0; i < this.eventListeners.length; i++) { var eventListener = this.eventListeners[i]; diff --git a/spine-ts/spine-threejs/example/index.html b/spine-ts/spine-threejs/example/index.html index ca632b15d4..f63dd8ac33 100644 --- a/spine-ts/spine-threejs/example/index.html +++ b/spine-ts/spine-threejs/example/index.html @@ -3,7 +3,7 @@ spine-threejs - +