This commit is contained in:
badlogic 2022-04-21 14:05:32 +02:00
commit 01524d4cdc
76 changed files with 2588 additions and 515 deletions

View File

@ -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 - <track type>` to `Spine - <track type>`, `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`.

View File

@ -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)

View File

@ -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)) {

View File

@ -34,10 +34,6 @@
#include <spine/extension.h>
#include <stdio.h>
#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. */

View File

@ -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

View File

@ -73,10 +73,6 @@
#include <spine/TranslateTimeline.h>
#include <spine/Vertices.h>
#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;

View File

@ -1200,7 +1200,7 @@ namespace Spine {
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 @@ namespace Spine {
// 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.");
}
}
}

View File

@ -11,9 +11,6 @@
},
"dependencies": {
},
"files": [
"src"
],
"repository": {
"type": "git",
"url": "git@github.com:EsotericSoftware/spine-runtimes.git"

View File

@ -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}"
}
]
}

View File

@ -56,8 +56,8 @@ You can include a module in your project via a `<script>` tag from the [unpkg](h
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.0.*/dist/iife/spine-player.js">
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.0.*/dist/spine-player.css">
// spine-ts WebGL
<script src="https://unpkg.com/@esotericsoftware/spine-threejs@4.0.*/dist/iife/spine-webgl.js">
// spine-ts ThreeJS
<script src="https://unpkg.com/@esotericsoftware/spine-threejs@4.0.*/dist/iife/spine-threejs.js">
```
We also provide `js.map` source maps. They will be automatically fetched from unpkg when debugging code of a spine-module in Chrome, Firefox, or Safari, mapping the JavaScript code back to its original TypeScript sources.

View File

@ -14,6 +14,7 @@
<li>Canvas</li>
<ul>
<li><a href="/spine-canvas/example">Example</a></li>
<li><a href="/spine-canvas/example/mouse-click.html">Mouse click</a></li>
</ul>
<li>Player</li>
<ul>

View File

@ -1,12 +1,12 @@
{
"name": "@esotericsoftware/spine-ts",
"version": "4.0.20",
"version": "4.0.27",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@esotericsoftware/spine-ts",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE",
"workspaces": [
"spine-core",
@ -53,18 +53,18 @@
"dev": true
},
"node_modules/@types/three": {
"version": "0.133.1",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.133.1.tgz",
"integrity": "sha512-XqBrP/+kbs+o0CYRhCVVE95v7FaL2bO5Z7+3VQJE0nEyjo+9LoLfeNgZITOnndKHxM+7ltEciAIR7uE0SZlsOg=="
"version": "0.138.0",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.138.0.tgz",
"integrity": "sha512-D8AoV7h2kbCfrv/DcebHOFh1WDwyus3HdooBkAwcBikXArdqnsQ38PQ85JCunnvun160oA9jz53GszF3zch3tg=="
},
"node_modules/accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
"dependencies": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
@ -656,10 +656,14 @@
}
},
"node_modules/destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
"dev": true
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"dev": true,
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/duplexer": {
"version": "0.1.2",
@ -1031,9 +1035,9 @@
}
},
"node_modules/graceful-fs": {
"version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"node_modules/has-flag": {
@ -1100,34 +1104,34 @@
}
},
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dev": true,
"dependencies": {
"depd": "~1.1.2",
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.6"
"node": ">= 0.8"
}
},
"node_modules/http-errors/node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"node_modules/http-errors/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true,
"engines": {
"node": ">= 0.6"
"node": ">= 0.8"
}
},
"node_modules/http-parser-js": {
"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==",
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz",
"integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==",
"dev": true
},
"node_modules/inflight": {
@ -1468,30 +1472,30 @@
}
},
"node_modules/mime-db": {
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"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==",
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
"mime-db": "1.51.0"
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@ -1623,9 +1627,9 @@
}
},
"node_modules/negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true,
"engines": {
"node": ">= 0.6"
@ -7101,44 +7105,56 @@
}
},
"node_modules/send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dev": true,
"dependencies": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "1.8.1",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "~2.3.0",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/send/node_modules/ms": {
"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/send/node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dev": true,
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true,
"engines": {
"node": ">= 0.8"
}
},
"node_modules/serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@ -7553,9 +7569,9 @@
}
},
"node_modules/three": {
"version": "0.133.1",
"resolved": "https://registry.npmjs.org/three/-/three-0.133.1.tgz",
"integrity": "sha512-WydohO8ll949B0FTD6MGz59Yv2Lwj8hvObg/0Heh2r42S6+tQC1WByfCNRdmG4D7+odfGod+n8JPV1I2xrboWw=="
"version": "0.138.3",
"resolved": "https://registry.npmjs.org/three/-/three-0.138.3.tgz",
"integrity": "sha512-4t1cKC8gimNyJChJbaklg8W/qj3PpsLJUIFm5LIuAy/hVxxNm1ru2FGTSfbTSsuHmC/7ipsyuGKqrSAKLNtkzg=="
},
"node_modules/through": {
"version": "2.3.8",
@ -7693,9 +7709,9 @@
"dev": true
},
"node_modules/typescript": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@ -7951,41 +7967,41 @@
},
"spine-canvas": {
"name": "@esotericsoftware/spine-canvas",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE",
"dependencies": {
"@esotericsoftware/spine-core": "^4.0.20"
"@esotericsoftware/spine-core": "^4.0.27"
}
},
"spine-core": {
"name": "@esotericsoftware/spine-core",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE"
},
"spine-player": {
"name": "@esotericsoftware/spine-player",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE",
"dependencies": {
"@esotericsoftware/spine-webgl": "^4.0.20"
"@esotericsoftware/spine-webgl": "^4.0.27"
}
},
"spine-threejs": {
"name": "@esotericsoftware/spine-threejs",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE",
"dependencies": {
"@esotericsoftware/spine-core": "^4.0.20",
"@types/three": "^0.133.1",
"three": "^0.133.1"
"@esotericsoftware/spine-core": "^4.0.27",
"@types/three": "^0.138.0",
"three": "^0.138.3"
}
},
"spine-webgl": {
"name": "@esotericsoftware/spine-webgl",
"version": "4.0.20",
"version": "4.0.27",
"license": "LicenseRef-LICENSE",
"dependencies": {
"@esotericsoftware/spine-core": "^4.0.20"
"@esotericsoftware/spine-core": "^4.0.27"
}
}
},
@ -7993,7 +8009,7 @@
"@esotericsoftware/spine-canvas": {
"version": "file:spine-canvas",
"requires": {
"@esotericsoftware/spine-core": "^4.0.20"
"@esotericsoftware/spine-core": "^4.0.27"
}
},
"@esotericsoftware/spine-core": {
@ -8002,21 +8018,21 @@
"@esotericsoftware/spine-player": {
"version": "file:spine-player",
"requires": {
"@esotericsoftware/spine-webgl": "^4.0.20"
"@esotericsoftware/spine-webgl": "^4.0.27"
}
},
"@esotericsoftware/spine-threejs": {
"version": "file:spine-threejs",
"requires": {
"@esotericsoftware/spine-core": "^4.0.20",
"@types/three": "^0.133.1",
"three": "^0.133.1"
"@esotericsoftware/spine-core": "^4.0.27",
"@types/three": "^0.138.0",
"three": "^0.138.3"
}
},
"@esotericsoftware/spine-webgl": {
"version": "file:spine-webgl",
"requires": {
"@esotericsoftware/spine-core": "^4.0.20"
"@esotericsoftware/spine-core": "^4.0.27"
}
},
"@types/offscreencanvas": {
@ -8026,18 +8042,18 @@
"dev": true
},
"@types/three": {
"version": "0.133.1",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.133.1.tgz",
"integrity": "sha512-XqBrP/+kbs+o0CYRhCVVE95v7FaL2bO5Z7+3VQJE0nEyjo+9LoLfeNgZITOnndKHxM+7ltEciAIR7uE0SZlsOg=="
"version": "0.138.0",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.138.0.tgz",
"integrity": "sha512-D8AoV7h2kbCfrv/DcebHOFh1WDwyus3HdooBkAwcBikXArdqnsQ38PQ85JCunnvun160oA9jz53GszF3zch3tg=="
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
}
},
"ansi-regex": {
@ -8505,9 +8521,9 @@
"dev": true
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"dev": true
},
"duplexer": {
@ -8807,9 +8823,9 @@
}
},
"graceful-fs": {
"version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"has-flag": {
@ -8863,30 +8879,30 @@
}
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dev": true,
"requires": {
"depd": "~1.1.2",
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"dependencies": {
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true
}
}
},
"http-parser-js": {
"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==",
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz",
"integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==",
"dev": true
},
"inflight": {
@ -9154,24 +9170,24 @@
"dev": true
},
"mime-db": {
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true
},
"mime-types": {
"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==",
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"requires": {
"mime-db": "1.51.0"
"mime-db": "1.52.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
@ -9277,9 +9293,9 @@
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true
},
"noms": {
@ -13565,37 +13581,46 @@
}
},
"send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dev": true,
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "1.8.1",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "~2.3.0",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
"statuses": "2.0.1"
},
"dependencies": {
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"dev": true
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dev": true,
"requires": {
"ee-first": "1.1.1"
}
},
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"dev": true
}
}
},
@ -13938,9 +13963,9 @@
}
},
"three": {
"version": "0.133.1",
"resolved": "https://registry.npmjs.org/three/-/three-0.133.1.tgz",
"integrity": "sha512-WydohO8ll949B0FTD6MGz59Yv2Lwj8hvObg/0Heh2r42S6+tQC1WByfCNRdmG4D7+odfGod+n8JPV1I2xrboWw=="
"version": "0.138.3",
"resolved": "https://registry.npmjs.org/three/-/three-0.138.3.tgz",
"integrity": "sha512-4t1cKC8gimNyJChJbaklg8W/qj3PpsLJUIFm5LIuAy/hVxxNm1ru2FGTSfbTSsuHmC/7ipsyuGKqrSAKLNtkzg=="
},
"through": {
"version": "2.3.8",
@ -14061,9 +14086,9 @@
"dev": true
},
"typescript": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
"dev": true
},
"union-value": {

View File

@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-ts",
"version": "4.0.20",
"version": "4.0.27",
"description": "The official Spine Runtimes for the web.",
"files": [
"README.md"

View File

@ -1,181 +1,89 @@
<!DOCTYPE html>
<html>
<script src="../dist/iife/spine-canvas.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
body,
html {
height: 100%
}
<head>
<!--<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.0.*/dist/iife/spine-canvas.js"></script>-->
<script src="../dist/iife/spine-canvas.js"></script>
</head>
canvas {
position: absolute;
width: 100%;
height: 100%;
}
</style>
<body>
<canvas id="canvas"></canvas>
<body style="margin: 0; padding: 0; background: #333">
<canvas id="canvas" style="width: 100%; height: 100vh;"></canvas>
</body>
<script>
let lastFrameTime = Date.now() / 1000;
let canvas, context;
let assetManager;
let skeleton, animationState, bounds;
let skeletonRenderer;
var lastFrameTime = Date.now() / 1000;
var canvas, context;
var assetManager;
var skeleton, state, bounds;
var skeletonRenderer;
var skelName = "spineboy-ess";
var animName = "walk";
function init() {
async function load() {
canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context = canvas.getContext("2d");
skeletonRenderer = new spine.SkeletonRenderer(context);
// enable debug rendering
skeletonRenderer.debugRendering = true;
// enable the triangle renderer, supports meshes, but may produce artifacts in some browsers
skeletonRenderer.triangleRendering = false;
assetManager = new spine.AssetManager("assets/");
// Load the assets.
assetManager = new spine.AssetManager("https://esotericsoftware.com/files/examples/4.0/spineboy/export/");
assetManager.loadText("spineboy-ess.json");
assetManager.loadTextureAtlas("spineboy.atlas");
await assetManager.loadAll();
assetManager.loadText(skelName + ".json");
assetManager.loadText(skelName.replace("-pro", "").replace("-ess", "") + ".atlas");
assetManager.loadTexture(skelName.replace("-pro", "").replace("-ess", "") + ".png");
// Create the texture atlas and skeleton data.
let atlas = assetManager.require("spineboy.atlas");
let atlasLoader = new spine.AtlasAttachmentLoader(atlas);
let skeletonJson = new spine.SkeletonJson(atlasLoader);
let skeletonData = skeletonJson.readSkeletonData(assetManager.require("spineboy-ess.json"));
requestAnimationFrame(load);
}
function load() {
if (assetManager.isLoadingComplete()) {
var data = loadSkeleton(skelName, animName, "default");
skeleton = data.skeleton;
state = data.state;
bounds = data.bounds;
requestAnimationFrame(render);
} else {
requestAnimationFrame(load);
}
}
function loadSkeleton(name, initialAnimation, skin) {
if (skin === undefined) skin = "default";
// Load the texture atlas using name.atlas and name.png from the AssetManager.
// The function passed to TextureAtlas is used to resolve relative paths.
atlas = new spine.TextureAtlas(assetManager.require(name.replace("-pro", "").replace("-ess", "") + ".atlas"));
atlas.setTextures(assetManager);
// Create a AtlasAttachmentLoader, which is specific to the WebGL backend.
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
// Create a SkeletonJson instance for parsing the .json file.
var skeletonJson = new spine.SkeletonJson(atlasLoader);
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
var skeletonData = skeletonJson.readSkeletonData(assetManager.require(name + ".json"));
var skeleton = new spine.Skeleton(skeletonData);
skeleton.scaleY = -1;
var bounds = calculateBounds(skeleton);
skeleton.setSkinByName(skin);
// Create an AnimationState, and set the initial animation in looping mode.
var animationState = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
animationState.setAnimation(0, initialAnimation, true);
animationState.addListener({
event: function (trackIndex, event) {
// console.log("Event on track " + trackIndex + ": " + JSON.stringify(event));
},
complete: function (trackIndex, loopCount) {
// console.log("Animation on track " + trackIndex + " completed, loop count: " + loopCount);
},
start: function (trackIndex) {
// console.log("Animation on track " + trackIndex + " started");
},
end: function (trackIndex) {
// console.log("Animation on track " + trackIndex + " ended");
}
})
// Pack everything up and return to caller.
return { skeleton: skeleton, state: animationState, bounds: bounds };
}
function calculateBounds(skeleton) {
var data = skeleton.data;
// Instantiate a new skeleton based on the atlas and skeleton data.
skeleton = new spine.Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
var offset = new spine.Vector2();
var size = new spine.Vector2();
skeleton.getBounds(offset, size, []);
return { offset: offset, size: size };
bounds = skeleton.getBoundsRect();
// Setup an animation state with a default mix of 0.2 seconds.
var animationStateData = new spine.AnimationStateData(skeleton.data);
animationStateData.defaultMix = 0.2;
animationState = new spine.AnimationState(animationStateData);
// Set the run animation, looping.
animationState.setAnimation(0, "run", true);
// Start rendering.
requestAnimationFrame(render);
}
function render() {
// Calculate the delta time between this and the last frame in seconds.
var now = Date.now() / 1000;
var delta = now - lastFrameTime;
lastFrameTime = now;
resize();
// Resize the canvas drawing buffer if the canvas CSS width and height changed
// and clear the canvas.
if (canvas.width != canvas.clientWidth || canvas.height != canvas.clientHeight) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.fillStyle = "#cccccc";
context.fillRect(0, 0, canvas.width, canvas.height);
context.restore();
// Center the skeleton and resize it so it fits inside the canvas.
skeleton.x = canvas.width / 2;
skeleton.y = canvas.height - canvas.height * 0.1;
let scale = canvas.height / bounds.height * 0.8;
skeleton.scaleX = scale;
skeleton.scaleY = -scale;
state.update(delta);
state.apply(skeleton);
// Update and apply the animation state, update the skeleton's
// world transforms and render the skeleton.
animationState.update(delta);
animationState.apply(skeleton);
skeleton.updateWorldTransform();
skeletonRenderer.draw(skeleton);
context.strokeStyle = "green";
context.beginPath();
context.moveTo(-1000, 0);
context.lineTo(1000, 0);
context.moveTo(0, -1000);
context.lineTo(0, 1000);
context.stroke();
requestAnimationFrame(render);
}
function resize() {
var w = canvas.clientWidth;
var h = canvas.clientHeight;
if (canvas.width != w || canvas.height != h) {
canvas.width = w;
canvas.height = h;
}
// magic
var centerX = bounds.offset.x + bounds.size.x / 2;
var centerY = bounds.offset.y + bounds.size.y / 2;
var scaleX = bounds.size.x / canvas.width;
var scaleY = bounds.size.y / canvas.height;
var scale = Math.max(scaleX, scaleY) * 1.2;
if (scale < 1) scale = 1;
var width = canvas.width * scale;
var height = canvas.height * scale;
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(1 / scale, 1 / scale);
context.translate(-centerX, -centerY);
context.translate(width / 2, height / 2);
}
(function () {
init();
}());
load();
</script>
</html>

View File

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html>
<head>
<!--<script src="https://unpkg.com/@esotericsoftware/spine-canvas@4.0.*/dist/iife/spine-canvas.js"></script>-->
<script src="../dist/iife/spine-canvas.js"></script>
</head>
<body style="margin: 0; padding: 0; background: #333">
<canvas id="canvas" style="width: 100%; height: 100vh;"></canvas>
</body>
<script>
let lastFrameTime = Date.now() / 1000;
let canvas, context;
let assetManager;
let skeleton, animationState, bounds;
let skeletonRenderer;
async function load() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
skeletonRenderer = new spine.SkeletonRenderer(context);
// Load the assets.
assetManager = new spine.AssetManager("https://esotericsoftware.com/files/examples/4.0/spineboy/export/");
assetManager.loadText("spineboy-ess.json");
assetManager.loadTextureAtlas("spineboy.atlas");
await assetManager.loadAll();
// Create the texture atlas and skeleton data.
let atlas = assetManager.require("spineboy.atlas");
let atlasLoader = new spine.AtlasAttachmentLoader(atlas);
let skeletonJson = new spine.SkeletonJson(atlasLoader);
let skeletonData = skeletonJson.readSkeletonData(assetManager.require("spineboy-ess.json"));
// Instantiate a new skeleton based on the atlas and skeleton data.
skeleton = new spine.Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
bounds = skeleton.getBoundsRect();
// Setup an animation state with a default mix of 0.2 seconds.
var animationStateData = new spine.AnimationStateData(skeleton.data);
animationStateData.defaultMix = 0.2;
animationState = new spine.AnimationState(animationStateData);
// Add a click listener to the canvas which checks if Spineboy's head
// was clicked.
canvas.addEventListener('click', event => {
// Make the mouse click coordinates relative to the canvas.
let canvasRect = canvas.getBoundingClientRect();
var mouseX = event.x - canvasRect.x;
var mouseY = event.y - canvasRect.y;
// Find the "head" bone.
var headBone = skeleton.findBone("head");
// If the mouse pointer is within 100 pixels of the head bone, fire the jump animation event.
// Afterwards, loop the run animation.
if (pointInCircle(mouseX, mouseY, headBone.worldX, headBone.worldY, 100)) {
var jumpEntry = animationState.setAnimation(0, "jump", false);
var walkEntry = animationState.addAnimation(0, "run", true);
}
});
requestAnimationFrame(render);
}
function render() {
// Calculate the delta time between this and the last frame in seconds.
var now = Date.now() / 1000;
var delta = now - lastFrameTime;
lastFrameTime = now;
// Resize the canvas drawing buffer if the canvas CSS width and height changed
// and clear the canvas.
if (canvas.width != canvas.clientWidth || canvas.height != canvas.clientHeight) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
context.clearRect(0, 0, canvas.width, canvas.height);
// Center the skeleton and resize it so it fits inside the canvas.
skeleton.x = canvas.width / 2;
skeleton.y = canvas.height - canvas.height * 0.1;
let scale = canvas.height / bounds.height * 0.8;
skeleton.scaleX = scale;
skeleton.scaleY = -scale;
// Update and apply the animation state, update the skeleton's
// world transforms and render the skeleton.
animationState.update(delta);
animationState.apply(skeleton);
skeleton.updateWorldTransform();
skeletonRenderer.draw(skeleton);
requestAnimationFrame(render);
}
// Checks if the point given by x/y are within the circle.
function pointInCircle(x, y, circleX, circleY, circleRadius) {
var distX = x - circleX;
var distY = y - circleY;
return distX * distX + distY * distY <= circleRadius * circleRadius;
}
load();
</script>
</html>

View File

@ -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"
}
}

View File

@ -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",

View File

@ -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<string>) => 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;
}

View File

@ -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.

View File

@ -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:

View File

@ -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"
}
}

View File

@ -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];

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<title>spine-threejs</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.js"></script>
<script src="https://unpkg.com/three@0.138.3/build/three.js"></script>
<script src="../dist/iife/spine-threejs.js"></script>
</head>
<style>
@ -81,8 +81,9 @@
var skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
// Create a SkeletonMesh from the data and attach it to the scene
skeletonMesh = new spine.SkeletonMesh(skeletonData, function (parameters) {
skeletonMesh = new spine.SkeletonMesh(skeletonData, (parameters) => {
parameters.depthTest = false;
parameters.alphaTest = 0.5;
});
skeletonMesh.state.setAnimation(0, animation, true);
mesh.add(skeletonMesh);

View File

@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-threejs",
"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,8 +30,8 @@
},
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
"dependencies": {
"@types/three": "^0.133.1",
"three": "^0.133.1",
"@esotericsoftware/spine-core": "^4.0.20"
"@types/three": "^0.138.0",
"three": "^0.138.3",
"@esotericsoftware/spine-core": "^4.0.27"
}
}

View File

@ -32,9 +32,7 @@ import { MeshBatcher } from "./MeshBatcher";
import * as THREE from "three";
import { ThreeJsTexture } from "./ThreeJsTexture";
export interface SkeletonMeshMaterialParametersCustomizer {
(materialParameters: THREE.ShaderMaterialParameters): void;
}
export type SkeletonMeshMaterialParametersCustomizer = (materialParameters: THREE.ShaderMaterialParameters) => void;
export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
constructor (customizer: SkeletonMeshMaterialParametersCustomizer) {
@ -50,26 +48,35 @@ export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
`;
let fragmentShader = `
uniform sampler2D map;
#ifdef USE_SPINE_ALPHATEST
uniform float alphaTest;
#endif
varying vec2 vUv;
varying vec4 vColor;
void main(void) {
gl_FragColor = texture2D(map, vUv)*vColor;
if (gl_FragColor.a < 0.5) discard;
#ifdef USE_SPINE_ALPHATEST
if (gl_FragColor.a < alphaTest) discard;
#endif
}
`;
let parameters: THREE.ShaderMaterialParameters = {
uniforms: {
map: { type: "t", value: null } as any
map: { value: null },
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide,
transparent: true,
depthWrite: false,
alphaTest: 0.5
alphaTest: 0.0
};
customizer(parameters);
if (parameters.alphaTest > 0) {
parameters.defines = { "USE_SPINE_ALPHATEST": 1 };
parameters.uniforms["alphaTest"] = { value: parameters.alphaTest };
}
super(parameters);
};
}
@ -94,7 +101,7 @@ export class SkeletonMesh extends THREE.Object3D {
private vertices = Utils.newFloatArray(1024);
private tempColor = new Color();
constructor (skeletonData: SkeletonData) {
constructor (skeletonData: SkeletonData, private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (material) => { }) {
super();
this.skeleton = new Skeleton(skeletonData);
@ -129,7 +136,7 @@ export class SkeletonMesh extends THREE.Object3D {
private nextBatch () {
if (this.batches.length == this.nextBatchIndex) {
let batch = new MeshBatcher();
let batch = new MeshBatcher(10920, this.materialCustomerizer);
this.add(batch);
this.batches.push(batch);
}
@ -164,7 +171,10 @@ export class SkeletonMesh extends THREE.Object3D {
for (let i = 0, n = drawOrder.length; i < n; i++) {
let vertexSize = clipper.isClipping() ? 2 : SkeletonMesh.VERTEX_SIZE;
let slot = drawOrder[i];
if (!slot.bone.active) continue;
if (!slot.bone.active) {
clipper.clipEndWithSlot(slot);
continue;
}
let attachment = slot.getAttachment();
let attachmentColor: Color = null;
let texture: ThreeJsTexture = null;
@ -194,7 +204,10 @@ export class SkeletonMesh extends THREE.Object3D {
let clip = <ClippingAttachment>(attachment);
clipper.clipStart(slot, clip);
continue;
} else continue;
} else {
clipper.clipEndWithSlot(slot);
continue;
}
if (texture != null) {
let skeleton = slot.bone.skeleton;
@ -278,8 +291,10 @@ export class SkeletonMesh extends THREE.Object3D {
finalIndicesLength = triangles.length;
}
if (finalVerticesLength == 0 || finalIndicesLength == 0)
if (finalVerticesLength == 0 || finalIndicesLength == 0) {
clipper.clipEndWithSlot(slot);
continue;
}
// Start new batch if this one can't hold vertices/indices
if (!batch.canBatch(finalVerticesLength, finalIndicesLength)) {

View File

@ -12,6 +12,8 @@
<div style="position: absolute; top: 1em; left: 1em; z-index: 1; color: #ccc;">
<label style="margin-right: 0.5em;">Animations</label>
<select id="animations"></select>
<label>PMA</label>
<input type="checkbox" id="pma" checked>
</div>
<script src="drag-and-drop.js"></script>
</body>

View File

@ -3,6 +3,7 @@ class App {
this.skeleton = null;
this.animationState = null;
this.canvas = null;
this.pma = true;
}
loadAssets(canvas) {
@ -23,6 +24,12 @@ class App {
this.animationState.setAnimation(0, animationSelectBox.value, true);
}
// Setup listener for the PMA checkbox
let pmaCheckbox = document.body.querySelector("#pma");
pmaCheckbox.onchange = () => {
this.pma = pmaCheckbox.checked;
}
// Setup the drag and drop listener
new FileDragAndDrop(canvas.htmlCanvas, (files) => this.onDrop(files))
@ -116,8 +123,7 @@ class App {
option.selected = animation.name == animationName;
animationSelectBox.appendChild(option);
}
if (animationName) this.animationState.setAnimation(0, animationName, true);
this.animationState.setAnimation(0, animationName, true);
// Center the skeleton in the viewport
this.centerSkeleton();
@ -153,10 +159,11 @@ class App {
renderer.resize(spine.ResizeMode.Expand);
canvas.clear(0.2, 0.2, 0.2, 1);
renderer.begin();
renderer.line(-10000, 0, 10000, 0, spine.Color.RED);
renderer.line(0, -10000, 0, 10000, spine.Color.GREEN);
renderer.drawSkeleton(this.skeleton, true);
renderer.drawSkeleton(this.skeleton, this.pma);
renderer.end();
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-webgl",
"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"
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 28687d6c4c7e84e48a6907ea466198f9
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,90 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2022, 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.
*****************************************************************************/
#if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR_INT
#endif
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
namespace Spine.Unity.Examples {
public class RenderTextureFadeoutExample : MonoBehaviour {
public SkeletonRenderTextureFadeout renderTextureFadeout;
public SkeletonRenderer normalSkeletonRenderer;
float fadeoutSeconds = 2.0f;
float fadeoutSecondsRemaining;
IEnumerator Start () {
while (true) {
StartFadeoutBad();
StartFadeoutGood();
yield return new WaitForSeconds(5.0f);
}
}
void Update () {
UpdateBadFadeOutAlpha();
}
void UpdateBadFadeOutAlpha () {
if (fadeoutSecondsRemaining == 0)
return;
fadeoutSecondsRemaining -= Time.deltaTime;
if (fadeoutSecondsRemaining <= 0) {
fadeoutSecondsRemaining = 0;
return;
}
float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds;
// changing transparency at a MeshRenderer does not yield the desired effect
// due to overlapping attachment meshes.
normalSkeletonRenderer.Skeleton.SetColor(new Color(1, 1, 1, fadeoutAlpha));
}
void StartFadeoutBad () {
fadeoutSecondsRemaining = fadeoutSeconds;
}
void StartFadeoutGood () {
renderTextureFadeout.gameObject.SetActive(true);
// enabling the SkeletonRenderTextureFadeout component starts the fadeout.
renderTextureFadeout.enabled = true;
renderTextureFadeout.OnFadeoutComplete -= DisableGameObject;
renderTextureFadeout.OnFadeoutComplete += DisableGameObject;
}
void DisableGameObject (SkeletonRenderTextureFadeout target) {
target.gameObject.SetActive(false);
}
}
}

View File

@ -1,6 +1,7 @@
fileFormatVersion: 2
guid: 6e55c8477eccddc4cb5c3551a3945ca7
guid: a4cc2b5fcffcac846aacb02b6dad0440
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1b5dc12395d030642b857afc9dff2ae2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,90 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: RenderQuadMaterial
m_Shader: {fileID: 4800000, guid: 1e0cc951f440af74dacaf86ac4ae2602, type: 3}
m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _USE8NEIGHBOURHOOD_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DarkColorAlphaAdditive: 0
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 3
- _OcclusionStrength: 1
- _OutlineMipLevel: 0
- _OutlineReferenceTexWidth: 1024
- _OutlineSmoothness: 1
- _OutlineWidth: 3
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _StencilComp: 8
- _StencilRef: 1
- _StraightAlphaInput: 0
- _ThresholdEnd: 0.25
- _UVSec: 0
- _Use8Neighbourhood: 1
- _ZWrite: 0
m_Colors:
- _Black: {r: 0, g: 0, b: 0, a: 0}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _OutlineColor: {r: 1, g: 1, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4c507f887c6274a44a603d96e0eabf2a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,104 @@
// Simple shader for e.g. a Quad that renders a RenderTexture.
// Texture color is multiplied by a color property, mostly for alpha fadeout.
Shader "Spine/RenderQuad" {
Properties{
_Color("Color", Color) = (1,1,1,1)
[NoScaleOffset] _MainTex("MainTex", 2D) = "white" {}
_Cutoff("Shadow alpha cutoff", Range(0,1)) = 0.1
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
}
SubShader{
Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" }
Blend One OneMinusSrcAlpha
Cull Off
ZWrite Off
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}
Pass {
Name "Normal"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _Color;
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
VertexOutput vert(VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv = v.uv;
o.vertexColor = v.vertexColor;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
float4 frag(VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex,i.uv);
_Color.rgb *= _Color.a;
return texColor * _Color;
}
ENDCG
}
Pass {
Name "Caster"
Tags { "LightMode" = "ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual
Fog { Mode Off }
Cull Off
Lighting Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Cutoff;
struct VertexOutput {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};
VertexOutput vert(appdata_base v, float4 vertexColor : COLOR) {
VertexOutput o;
o.uvAndAlpha = v.texcoord;
o.uvAndAlpha.a = vertexColor.a;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag(VertexOutput i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a* i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
FallBack "Diffuse"
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1e0cc951f440af74dacaf86ac4ae2602
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,248 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2022, 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.
*****************************************************************************/
#if UNITY_2019_3_OR_NEWER
#define HAS_FORCE_RENDER_OFF
#endif
#if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR_INT
#endif
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace Spine.Unity.Examples {
/// <summary>
/// When enabled, this component renders a skeleton to a RenderTexture and
/// then draws this RenderTexture at a quad of the same size.
/// This allows changing transparency at a single quad, which produces a more
/// natural fadeout effect.
/// Note: It is recommended to keep this component disabled as much as possible
/// because of the additional rendering overhead. Only enable it when alpha blending is required.
/// </summary>
[RequireComponent(typeof(SkeletonRenderer))]
public class SkeletonRenderTexture : MonoBehaviour {
#if HAS_VECTOR_INT
public Color color = Color.white;
public Material quadMaterial;
public Camera targetCamera;
public int maxRenderTextureSize = 1024;
protected SkeletonRenderer skeletonRenderer;
protected MeshRenderer meshRenderer;
protected MeshFilter meshFilter;
public GameObject quad;
protected MeshRenderer quadMeshRenderer;
protected MeshFilter quadMeshFilter;
protected Mesh quadMesh;
public RenderTexture renderTexture;
private CommandBuffer commandBuffer;
private MaterialPropertyBlock propertyBlock;
private readonly List<Material> materials = new List<Material>();
protected Vector2Int requiredRenderTextureSize;
protected Vector2Int allocatedRenderTextureSize;
void Awake () {
meshRenderer = this.GetComponent<MeshRenderer>();
meshFilter = this.GetComponent<MeshFilter>();
skeletonRenderer = this.GetComponent<SkeletonRenderer>();
if (targetCamera == null)
targetCamera = Camera.main;
commandBuffer = new CommandBuffer();
propertyBlock = new MaterialPropertyBlock();
CreateQuadChild();
}
void OnDestroy () {
if (renderTexture)
RenderTexture.ReleaseTemporary(renderTexture);
}
void CreateQuadChild () {
quad = new GameObject(this.name + " RenderTexture", typeof(MeshRenderer), typeof(MeshFilter));
quad.transform.SetParent(this.transform.parent, false);
quadMeshRenderer = quad.GetComponent<MeshRenderer>();
quadMeshFilter = quad.GetComponent<MeshFilter>();
quadMesh = new Mesh();
quadMesh.MarkDynamic();
quadMesh.name = "RenderTexture Quad";
quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor;
if (quadMaterial != null)
quadMeshRenderer.material = new Material(quadMaterial);
else
quadMeshRenderer.material = new Material(Shader.Find("Spine/RenderQuad"));
}
void OnEnable () {
skeletonRenderer.OnMeshAndMaterialsUpdated += RenderOntoQuad;
#if HAS_FORCE_RENDER_OFF
meshRenderer.forceRenderingOff = true;
#else
Debug.LogError("This component requires Unity 2019.3 or newer for meshRenderer.forceRenderingOff. " +
"Otherwise you will see the mesh rendered twice.");
#endif
if (quadMeshRenderer)
quadMeshRenderer.gameObject.SetActive(true);
}
void OnDisable () {
skeletonRenderer.OnMeshAndMaterialsUpdated -= RenderOntoQuad;
#if HAS_FORCE_RENDER_OFF
meshRenderer.forceRenderingOff = false;
#endif
if (quadMeshRenderer)
quadMeshRenderer.gameObject.SetActive(false);
if (renderTexture)
RenderTexture.ReleaseTemporary(renderTexture);
allocatedRenderTextureSize = Vector2Int.zero;
}
void RenderOntoQuad (SkeletonRenderer skeletonRenderer) {
PrepareForMesh();
RenderToRenderTexture();
AssignAtQuad();
}
protected void PrepareForMesh () {
Bounds boundsLocalSpace = meshFilter.sharedMesh.bounds;
Vector3 meshMinWorldSpace = transform.TransformPoint(boundsLocalSpace.min);
Vector3 meshMaxWorldSpace = transform.TransformPoint(boundsLocalSpace.max);
Vector3 meshMinXMaxYWorldSpace = new Vector3(meshMinWorldSpace.x, meshMaxWorldSpace.y);
Vector3 meshMaxXMinYWorldSpace = new Vector3(meshMaxWorldSpace.x, meshMinWorldSpace.y);
// We need to get the min/max of all four corners, close position and rotation of the skeleton
// in combination with perspective projection otherwise might lead to incorrect screen space min/max.
Vector3 meshMinProjected = targetCamera.WorldToScreenPoint(meshMinWorldSpace);
Vector3 meshMaxProjected = targetCamera.WorldToScreenPoint(meshMaxWorldSpace);
Vector3 meshMinXMaxYProjected = targetCamera.WorldToScreenPoint(meshMinXMaxYWorldSpace);
Vector3 meshMaxXMinYProjected = targetCamera.WorldToScreenPoint(meshMaxXMinYWorldSpace);
// To handle 180 degree rotation and thus min/max inversion, we get min/max of all four corners
Vector3 meshMinScreenSpace =
Vector3.Min(meshMinProjected, Vector3.Min(meshMaxProjected,
Vector3.Min(meshMinXMaxYProjected, meshMaxXMinYProjected)));
Vector3 meshMaxScreenSpace =
Vector3.Max(meshMinProjected, Vector3.Max(meshMaxProjected,
Vector3.Max(meshMinXMaxYProjected, meshMaxXMinYProjected)));
requiredRenderTextureSize = new Vector2Int(
Mathf.Min(maxRenderTextureSize, Mathf.CeilToInt(Mathf.Abs(meshMaxScreenSpace.x - meshMinScreenSpace.x))),
Mathf.Min(maxRenderTextureSize, Mathf.CeilToInt(Mathf.Abs(meshMaxScreenSpace.y - meshMinScreenSpace.y))));
PrepareRenderTexture();
PrepareCommandBuffer(meshMinWorldSpace, meshMaxWorldSpace);
}
protected void PrepareCommandBuffer (Vector3 meshMinWorldSpace, Vector3 meshMaxWorldSpace) {
commandBuffer.Clear();
commandBuffer.SetRenderTarget(renderTexture);
commandBuffer.ClearRenderTarget(true, true, Color.clear);
Matrix4x4 projectionMatrix = Matrix4x4.Ortho(
meshMinWorldSpace.x, meshMaxWorldSpace.x,
meshMinWorldSpace.y, meshMaxWorldSpace.y,
float.MinValue, float.MaxValue);
commandBuffer.SetProjectionMatrix(projectionMatrix);
commandBuffer.SetViewport(new Rect(Vector2.zero, requiredRenderTextureSize));
}
protected void RenderToRenderTexture () {
meshRenderer.GetPropertyBlock(propertyBlock);
meshRenderer.GetSharedMaterials(materials);
for (int i = 0; i < materials.Count; i++)
commandBuffer.DrawMesh(meshFilter.sharedMesh, transform.localToWorldMatrix,
materials[i], meshRenderer.subMeshStartIndex + i, -1, propertyBlock);
Graphics.ExecuteCommandBuffer(commandBuffer);
}
protected void AssignAtQuad () {
Vector2 min = meshFilter.sharedMesh.bounds.min;
Vector2 max = meshFilter.sharedMesh.bounds.max;
Vector3[] vertices = new Vector3[4] {
new Vector3(min.x, min.y, 0),
new Vector3(max.x, min.y, 0),
new Vector3(min.x, max.y, 0),
new Vector3(max.x, max.y, 0)
};
quadMesh.vertices = vertices;
int[] indices = new int[6] { 0, 2, 1, 2, 3, 1 };
quadMesh.triangles = indices;
Vector3[] normals = new Vector3[4] {
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
quadMesh.normals = normals;
float maxU = (float)(requiredRenderTextureSize.x) / allocatedRenderTextureSize.x;
float maxV = (float)(requiredRenderTextureSize.y) / allocatedRenderTextureSize.y;
Vector2[] uv = new Vector2[4] {
new Vector2(0, 0),
new Vector2(maxU, 0),
new Vector2(0, maxV),
new Vector2(maxU, maxV)
};
quadMesh.uv = uv;
quadMeshFilter.mesh = quadMesh;
quadMeshRenderer.sharedMaterial.mainTexture = this.renderTexture;
quadMeshRenderer.sharedMaterial.color = color;
quadMeshRenderer.transform.position = this.transform.position;
quadMeshRenderer.transform.rotation = this.transform.rotation;
quadMeshRenderer.transform.localScale = this.transform.localScale;
}
protected void PrepareRenderTexture () {
Vector2Int textureSize = new Vector2Int(
Mathf.NextPowerOfTwo(requiredRenderTextureSize.x),
Mathf.NextPowerOfTwo(requiredRenderTextureSize.y));
if (textureSize != allocatedRenderTextureSize) {
if (renderTexture)
RenderTexture.ReleaseTemporary(renderTexture);
renderTexture = RenderTexture.GetTemporary(textureSize.x, textureSize.y);
allocatedRenderTextureSize = textureSize;
}
}
#endif
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 25e6ceb271c9af848ae53f2af1073d0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,88 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2022, 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.
*****************************************************************************/
#if UNITY_2019_3_OR_NEWER
#define HAS_FORCE_RENDER_OFF
#endif
#if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR_INT
#endif
using UnityEngine;
namespace Spine.Unity.Examples {
/// <summary>
/// A simple fadeout component that uses a <see cref="SkeletonRenderTexture"/> for transparency fadeout.
/// Attach a <see cref="SkeletonRenderTexture"/> and this component to a skeleton GameObject and disable both
/// components initially and keep them disabled during normal gameplay. When you need to start fadeout,
/// enable this component.
/// At the end of the fadeout, the event delegate <c>OnFadeoutComplete</c> is called, to which you can bind e.g.
/// a method that disables or destroys the entire GameObject.
/// </summary>
[RequireComponent(typeof(SkeletonRenderTexture))]
public class SkeletonRenderTextureFadeout : MonoBehaviour {
SkeletonRenderTexture skeletonRenderTexture;
public float fadeoutSeconds = 2.0f;
protected float fadeoutSecondsRemaining;
public delegate void FadeoutCallback (SkeletonRenderTextureFadeout skeleton);
public event FadeoutCallback OnFadeoutComplete;
protected void Awake () {
skeletonRenderTexture = this.GetComponent<SkeletonRenderTexture>();
}
protected void OnEnable () {
fadeoutSecondsRemaining = fadeoutSeconds;
skeletonRenderTexture.enabled = true;
}
protected void Update () {
if (fadeoutSecondsRemaining == 0)
return;
fadeoutSecondsRemaining -= Time.deltaTime;
if (fadeoutSecondsRemaining <= 0) {
fadeoutSecondsRemaining = 0;
if (OnFadeoutComplete != null)
OnFadeoutComplete(this);
return;
}
float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds;
#if HAS_VECTOR_INT
skeletonRenderTexture.color.a = fadeoutAlpha;
#else
Debug.LogError("The SkeletonRenderTexture component requires Unity 2017.2 or newer.");
#endif
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fc94f89310427643babb41e000a8462
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -71,6 +71,7 @@ namespace Spine.Unity.Editor {
readonly List<string> warnings = new List<string>();
CompatibilityProblemInfo compatibilityProblemInfo = null;
readonly SkeletonInspectorPreview preview = new SkeletonInspectorPreview();
bool requiresReload = false;
GUIStyle activePlayButtonStyle, idlePlayButtonStyle;
readonly GUIContent DefaultMixLabel = new GUIContent("Default Mix Duration", "Sets 'SkeletonDataAsset.defaultMix' in the asset and 'AnimationState.data.defaultMix' at runtime load time.");
@ -153,7 +154,7 @@ namespace Spine.Unity.Editor {
void Clear () {
preview.Clear();
targetSkeletonDataAsset.Clear();
SpineEditorUtilities.ClearSkeletonDataAsset(targetSkeletonDataAsset);
targetSkeletonData = null;
}
@ -192,13 +193,12 @@ namespace Spine.Unity.Editor {
}
if (changeCheck.changed) {
if (serializedObject.ApplyModifiedProperties()) {
if (requiresReload || serializedObject.ApplyModifiedProperties()) {
this.Clear();
this.InitializeEditor();
if (SpineEditorUtilities.Preferences.autoReloadSceneSkeletons)
if (SpineEditorUtilities.Preferences.autoReloadSceneSkeletons && NoProblems())
SpineEditorUtilities.DataReloadHandler.ReloadSceneSkeletonComponents(targetSkeletonDataAsset);
return;
}
}
@ -361,18 +361,24 @@ namespace Spine.Unity.Editor {
void DrawAtlasAssetsFields () {
EditorGUILayout.LabelField("Atlas", EditorStyles.boldLabel);
#if !SPINE_TK2D
EditorGUILayout.PropertyField(atlasAssets, true);
#else
using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) {
EditorGUILayout.PropertyField(atlasAssets, true);
}
EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(spriteCollection, true);
#endif
if (atlasAssets.arraySize == 0)
EditorGUILayout.HelpBox("AtlasAssets array is empty. Skeleton's attachments will load without being mapped to images.", MessageType.Info);
using (var changeCheck = new EditorGUI.ChangeCheckScope()) {
#if !SPINE_TK2D
EditorGUILayout.PropertyField(atlasAssets, true);
#else
using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) {
EditorGUILayout.PropertyField(atlasAssets, true);
}
EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(spriteCollection, true);
#endif
if (atlasAssets.arraySize == 0)
EditorGUILayout.HelpBox("AtlasAssets array is empty. Skeleton's attachments will load without being mapped to images.", MessageType.Info);
if (changeCheck.changed) {
requiresReload = true;
}
}
}
void HandleAtlasAssetsNulls () {

View File

@ -462,7 +462,7 @@ namespace Spine.Unity.Editor {
}
Debug.LogFormat("Changes to '{0}' or atlas detected. Clearing SkeletonDataAsset: {1}", skeletonJSONPath, localPath);
skeletonDataAsset.Clear();
SpineEditorUtilities.ClearSkeletonDataAsset(skeletonDataAsset);
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset));
string lastHash = EditorPrefs.GetString(guid + "_hash");
@ -947,7 +947,7 @@ namespace Spine.Unity.Editor {
AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
} else {
skeletonDataAsset.atlasAssets = atlasAssets;
skeletonDataAsset.Clear();
SpineEditorUtilities.ClearSkeletonDataAsset(skeletonDataAsset);
}
var skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (skeletonData != null)

View File

@ -96,7 +96,7 @@ namespace Spine.Unity.Editor {
}
}
skeletonDataAsset.Clear();
SpineEditorUtilities.ClearSkeletonDataAsset(skeletonDataAsset);
skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (anyMaterialsChanged)
ReloadSceneSkeletons(skeletonDataAsset);
@ -164,7 +164,7 @@ namespace Spine.Unity.Editor {
var skinEntries = new List<Skin.SkinEntry>();
skeletonDataAsset.Clear();
SpineEditorUtilities.ClearSkeletonDataAsset(skeletonDataAsset);
skeletonDataAsset.isUpgradingBlendModeMaterials = true;
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);

View File

@ -80,36 +80,24 @@ namespace Spine.Unity.Editor {
// Here we save the skeletonGraphic.skeletonDataAsset asset path in order
// to restore it later.
var activeSkeletonGraphics = GameObject.FindObjectsOfType<SkeletonGraphic>();
foreach (var sg in activeSkeletonGraphics) {
var skeletonDataAsset = sg.skeletonDataAsset;
foreach (var skeletonGraphic in activeSkeletonGraphics) {
var skeletonDataAsset = skeletonGraphic.skeletonDataAsset;
if (skeletonDataAsset != null) {
var assetPath = AssetDatabase.GetAssetPath(skeletonDataAsset);
var sgID = sg.GetInstanceID();
var sgID = skeletonGraphic.GetInstanceID();
savedSkeletonDataAssetAtSKeletonGraphicID[sgID] = assetPath;
skeletonDataAssetsToReload.Add(skeletonDataAsset);
}
}
foreach (var sda in skeletonDataAssetsToReload) {
sda.Clear();
sda.GetSkeletonData(true);
foreach (var skeletonDataAsset in skeletonDataAssetsToReload) {
ReloadSkeletonDataAsset(skeletonDataAsset, false);
}
foreach (var sr in activeSkeletonRenderers) {
var meshRenderer = sr.GetComponent<MeshRenderer>();
var sharedMaterials = meshRenderer.sharedMaterials;
foreach (var m in sharedMaterials) {
if (m == null) {
sr.Initialize(true);
break;
}
}
}
foreach (var sg in activeSkeletonGraphics) {
if (sg.mainTexture == null)
sg.Initialize(true);
}
foreach (var skeletonRenderer in activeSkeletonRenderers)
skeletonRenderer.Initialize(true);
foreach (var skeletonGraphic in activeSkeletonGraphics)
skeletonGraphic.Initialize(true);
}
public static void ReloadSceneSkeletonComponents (SkeletonDataAsset skeletonDataAsset) {
@ -119,24 +107,35 @@ namespace Spine.Unity.Editor {
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
var activeSkeletonRenderers = GameObject.FindObjectsOfType<SkeletonRenderer>();
foreach (var sr in activeSkeletonRenderers) {
if (sr.isActiveAndEnabled && sr.skeletonDataAsset == skeletonDataAsset) sr.Initialize(true);
foreach (var renderer in activeSkeletonRenderers) {
if (renderer.isActiveAndEnabled && renderer.skeletonDataAsset == skeletonDataAsset) renderer.Initialize(true);
}
var activeSkeletonGraphics = GameObject.FindObjectsOfType<SkeletonGraphic>();
foreach (var sg in activeSkeletonGraphics) {
if (sg.isActiveAndEnabled && sg.skeletonDataAsset == skeletonDataAsset) sg.Initialize(true);
foreach (var graphic in activeSkeletonGraphics) {
if (graphic.isActiveAndEnabled && graphic.skeletonDataAsset == skeletonDataAsset)
graphic.Initialize(true);
}
}
public static void ClearAnimationReferenceAssets (SkeletonDataAsset skeletonDataAsset) {
ForEachAnimationReferenceAsset(skeletonDataAsset, (referenceAsset) => referenceAsset.Clear());
}
public static void ReloadAnimationReferenceAssets (SkeletonDataAsset skeletonDataAsset) {
ForEachAnimationReferenceAsset(skeletonDataAsset, (referenceAsset) => referenceAsset.Initialize());
}
private static void ForEachAnimationReferenceAsset (SkeletonDataAsset skeletonDataAsset,
System.Action<AnimationReferenceAsset> func) {
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:AnimationReferenceAsset");
foreach (string guid in guids) {
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
if (!string.IsNullOrEmpty(path)) {
var referenceAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<AnimationReferenceAsset>(path);
if (referenceAsset.SkeletonDataAsset == skeletonDataAsset)
referenceAsset.Initialize();
func(referenceAsset);
}
}
}

View File

@ -71,62 +71,83 @@ namespace Spine.Unity.Editor {
#if HAS_ON_POSTPROCESS_PREFAB
internal static void PreprocessSpinePrefabMeshes () {
AssetDatabase.StartAssetEditing();
prefabsToRestore.Clear();
var prefabAssets = AssetDatabase.FindAssets("t:Prefab");
foreach (var asset in prefabAssets) {
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
GameObject prefabGameObject = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
if (SpineEditorUtilities.CleanupSpinePrefabMesh(prefabGameObject)) {
prefabsToRestore.Add(assetPath);
BuildUtilities.IsInSkeletonAssetBuildPreProcessing = true;
try {
AssetDatabase.StartAssetEditing();
prefabsToRestore.Clear();
var prefabAssets = AssetDatabase.FindAssets("t:Prefab");
foreach (var asset in prefabAssets) {
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
GameObject prefabGameObject = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
if (SpineEditorUtilities.CleanupSpinePrefabMesh(prefabGameObject)) {
prefabsToRestore.Add(assetPath);
}
EditorUtility.UnloadUnusedAssetsImmediate();
}
EditorUtility.UnloadUnusedAssetsImmediate();
AssetDatabase.StopAssetEditing();
if (prefabAssets.Length > 0)
AssetDatabase.SaveAssets();
} finally {
BuildUtilities.IsInSkeletonAssetBuildPreProcessing = false;
}
AssetDatabase.StopAssetEditing();
if (prefabAssets.Length > 0)
AssetDatabase.SaveAssets();
}
internal static void PostprocessSpinePrefabMeshes () {
foreach (string assetPath in prefabsToRestore) {
GameObject g = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
SpineEditorUtilities.SetupSpinePrefabMesh(g, null);
BuildUtilities.IsInSkeletonAssetBuildPostProcessing = true;
try {
foreach (string assetPath in prefabsToRestore) {
GameObject g = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
SpineEditorUtilities.SetupSpinePrefabMesh(g, null);
}
if (prefabsToRestore.Count > 0)
AssetDatabase.SaveAssets();
prefabsToRestore.Clear();
} finally {
BuildUtilities.IsInSkeletonAssetBuildPostProcessing = false;
}
if (prefabsToRestore.Count > 0)
AssetDatabase.SaveAssets();
prefabsToRestore.Clear();
}
#endif
internal static void PreprocessSpriteAtlases () {
AssetDatabase.StartAssetEditing();
spriteAtlasTexturesToRestore.Clear();
var spriteAtlasAssets = AssetDatabase.FindAssets("t:SpineSpriteAtlasAsset");
foreach (var asset in spriteAtlasAssets) {
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
SpineSpriteAtlasAsset atlasAsset = AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(assetPath);
if (atlasAsset && atlasAsset.materials.Length > 0) {
spriteAtlasTexturesToRestore[assetPath] = AssetDatabase.GetAssetPath(atlasAsset.materials[0].mainTexture);
atlasAsset.materials[0].mainTexture = null;
BuildUtilities.IsInSpriteAtlasBuildPreProcessing = true;
try {
AssetDatabase.StartAssetEditing();
spriteAtlasTexturesToRestore.Clear();
var spriteAtlasAssets = AssetDatabase.FindAssets("t:SpineSpriteAtlasAsset");
foreach (var asset in spriteAtlasAssets) {
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
SpineSpriteAtlasAsset atlasAsset = AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(assetPath);
if (atlasAsset && atlasAsset.materials.Length > 0) {
spriteAtlasTexturesToRestore[assetPath] = AssetDatabase.GetAssetPath(atlasAsset.materials[0].mainTexture);
atlasAsset.materials[0].mainTexture = null;
}
EditorUtility.UnloadUnusedAssetsImmediate();
}
EditorUtility.UnloadUnusedAssetsImmediate();
AssetDatabase.StopAssetEditing();
if (spriteAtlasAssets.Length > 0)
AssetDatabase.SaveAssets();
} finally {
BuildUtilities.IsInSpriteAtlasBuildPreProcessing = false;
}
AssetDatabase.StopAssetEditing();
if (spriteAtlasAssets.Length > 0)
AssetDatabase.SaveAssets();
}
internal static void PostprocessSpriteAtlases () {
foreach (var pair in spriteAtlasTexturesToRestore) {
string assetPath = pair.Key;
SpineSpriteAtlasAsset atlasAsset = AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(assetPath);
if (atlasAsset && atlasAsset.materials.Length > 0) {
Texture atlasTexture = AssetDatabase.LoadAssetAtPath<Texture>(pair.Value);
atlasAsset.materials[0].mainTexture = atlasTexture;
BuildUtilities.IsInSpriteAtlasBuildPostProcessing = true;
try {
foreach (var pair in spriteAtlasTexturesToRestore) {
string assetPath = pair.Key;
SpineSpriteAtlasAsset atlasAsset = AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(assetPath);
if (atlasAsset && atlasAsset.materials.Length > 0) {
Texture atlasTexture = AssetDatabase.LoadAssetAtPath<Texture>(pair.Value);
atlasAsset.materials[0].mainTexture = atlasTexture;
}
}
if (spriteAtlasTexturesToRestore.Count > 0)
AssetDatabase.SaveAssets();
spriteAtlasTexturesToRestore.Clear();
} finally {
BuildUtilities.IsInSpriteAtlasBuildPostProcessing = false;
}
if (spriteAtlasTexturesToRestore.Count > 0)
AssetDatabase.SaveAssets();
spriteAtlasTexturesToRestore.Clear();
}
}

View File

@ -266,14 +266,23 @@ namespace Spine.Unity.Editor {
ReinitializeComponent(component);
}
public static void ReloadSkeletonDataAsset (SkeletonDataAsset skeletonDataAsset) {
if (skeletonDataAsset != null) {
public static void ClearSkeletonDataAsset (SkeletonDataAsset skeletonDataAsset) {
skeletonDataAsset.Clear();
DataReloadHandler.ClearAnimationReferenceAssets(skeletonDataAsset);
}
public static void ReloadSkeletonDataAsset (SkeletonDataAsset skeletonDataAsset, bool clearAtlasAssets = true) {
if (skeletonDataAsset == null)
return;
if (clearAtlasAssets) {
foreach (AtlasAssetBase aa in skeletonDataAsset.atlasAssets) {
if (aa != null) aa.Clear();
}
skeletonDataAsset.Clear();
}
ClearSkeletonDataAsset(skeletonDataAsset);
skeletonDataAsset.GetSkeletonData(true);
DataReloadHandler.ReloadAnimationReferenceAssets(skeletonDataAsset);
}
public static void ReinitializeComponent (SkeletonRenderer component) {

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2b53e3e7c2824094b9259a24cd9a7e03
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -48,11 +48,16 @@ namespace Spine.Unity {
if (animation == null)
Initialize();
#endif
return animation;
}
}
/// <summary>Clears the cached animation corresponding to a loaded SkeletonData object.
/// Use this to force a reload for the next time Animation is called.</summary>
public void Clear () {
animation = null;
}
public void Initialize () {
if (skeletonDataAsset == null) return;
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(AnimationReferenceAsset.QuietSkeletonData);

View File

@ -238,6 +238,11 @@ namespace Spine.Unity {
}
public void Load (AtlasPage page, string path) {
#if UNITY_EDITOR
if (BuildUtilities.IsInSkeletonAssetBuildPreProcessing ||
BuildUtilities.IsInSkeletonAssetBuildPostProcessing)
return;
#endif
String name = Path.GetFileNameWithoutExtension(path);
Material material = null;
foreach (Material other in atlasAsset.materials) {

View File

@ -166,6 +166,10 @@ namespace Spine.Unity {
public override void Initialize (bool overwrite, bool quiet = false) {
if (valid && !overwrite)
return;
#if UNITY_EDITOR
if (BuildUtilities.IsInSkeletonAssetBuildPreProcessing)
return;
#endif
base.Initialize(overwrite, quiet);
if (!valid)

View File

@ -102,7 +102,7 @@ namespace Spine.Unity {
#if UNITY_EDITOR
protected override void OnValidate () {
// This handles Scene View preview.
base.OnValidate ();
base.OnValidate();
if (this.IsValid) {
if (skeletonDataAsset == null) {
Clear();
@ -360,8 +360,7 @@ namespace Spine.Unity {
separatorSlots.Add(slot);
}
#if UNITY_EDITOR
else
{
else {
Debug.LogWarning(slotName + " is not a slot in " + skeletonDataAsset.skeletonJSON.name);
}
#endif
@ -521,7 +520,10 @@ namespace Spine.Unity {
public void Initialize (bool overwrite) {
if (this.IsValid && !overwrite) return;
#if UNITY_EDITOR
if (BuildUtilities.IsInSkeletonAssetBuildPreProcessing)
return;
#endif
if (this.skeletonDataAsset == null) return;
var skeletonData = this.skeletonDataAsset.GetSkeletonData(false);
if (skeletonData == null) return;
@ -839,7 +841,7 @@ namespace Spine.Unity {
#if UNITY_EDITOR
if (Application.isEditor && !Application.isPlaying) {
for (int i = separatorParts.Count-1; i >= 0; --i) {
for (int i = separatorParts.Count - 1; i >= 0; --i) {
if (separatorParts[i] == null) {
separatorParts.RemoveAt(i);
}

View File

@ -72,7 +72,10 @@ namespace Spine.Unity {
public override void Initialize (bool overwrite, bool quiet = false) {
if (valid && !overwrite)
return;
#if UNITY_EDITOR
if (BuildUtilities.IsInSkeletonAssetBuildPreProcessing)
return;
#endif
base.Initialize(overwrite, quiet);
if (!valid)
@ -104,8 +107,7 @@ namespace Spine.Unity {
if (Application.isPlaying) {
translator.Apply(skeleton);
}
else {
} else {
if (translatorAnimator != null && translatorAnimator.isInitialized &&
translatorAnimator.isActiveAndEnabled && translatorAnimator.runtimeAnimatorController != null) {
// Note: Rebind is required to prevent warning "Animator is not playing an AnimatorController" with prefabs
@ -535,7 +537,7 @@ namespace Spine.Unity {
}
#if UNITY_EDITOR
void GetLayerBlendModes() {
void GetLayerBlendModes () {
if (layerBlendModes.Length < animator.layerCount) {
System.Array.Resize<MixBlend>(ref layerBlendModes, animator.layerCount);
}

View File

@ -367,7 +367,10 @@ namespace Spine.Unity {
public virtual void Initialize (bool overwrite, bool quiet = false) {
if (valid && !overwrite)
return;
#if UNITY_EDITOR
if (BuildUtilities.IsInSkeletonAssetBuildPreProcessing)
return;
#endif
// Clear
{
// Note: do not reset meshFilter.sharedMesh or meshRenderer.sharedMaterial to null,

View File

@ -0,0 +1,42 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2022, 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.
*****************************************************************************/
#if UNITY_EDITOR
namespace Spine.Unity {
public static class BuildUtilities {
public static bool IsInSkeletonAssetBuildPreProcessing = false;
public static bool IsInSkeletonAssetBuildPostProcessing = false;
public static bool IsInSpriteAtlasBuildPreProcessing = false;
public static bool IsInSpriteAtlasBuildPostProcessing = false;
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2f1169aaf0063f4da1c2b6033bbc13f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -58,6 +58,7 @@ You can add a `Spine Animation State Clip` to a `SkeletonAnimation Track` (or `S
- *Event Threshold.* See [TrackEntry.EventThreshold](http://esotericsoftware.com/spine-api-reference#TrackEntry-eventThreshold).
- *Attachment Threshold.* See [TrackEntry.AttachmentThreshold](http://esotericsoftware.com/spine-api-reference#TrackEntry-attachmentThreshold).
- *Draw Order Threshold.* See [TrackEntry.DrawOrderThreshold](http://esotericsoftware.com/spine-api-reference#TrackEntry-drawOrderThreshold).
- *Alpha.* See [TrackEntry.Alpha](http://esotericsoftware.com/spine-api-reference#TrackEntry-alpha).
*Ignored Parameters*
- *Ease Out Duration, Blend Curves*. These parameters are ignored and have no effect.
@ -111,5 +112,3 @@ This track type can be used to flip the skeleton of the target `SkeletonAnimatio
#### Known Issues
- The Console potentially logs an incorrect and harmless error `DrivenPropertyManager has failed to register property "m_Script" of object "Spine GameObject (spineboy-pro)" with driver "" because the property doesn't exist.`. This is a known issue on Unity's end. See more here: https://forum.unity.com/threads/default-playables-text-switcher-track-error.502903/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -36,7 +36,7 @@ using UnityEngine;
public class SpineAnimationStateDrawer : PropertyDrawer {
public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
const int fieldCount = 15;
const int fieldCount = 16;
return fieldCount * EditorGUIUtility.singleLineHeight;
}
@ -48,6 +48,7 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
SerializedProperty useBlendDurationProp = property.FindPropertyRelative("useBlendDuration");
SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration");
SerializedProperty holdPreviousProp = property.FindPropertyRelative("holdPrevious");
SerializedProperty alphaProp = property.FindPropertyRelative("alpha");
SerializedProperty dontPauseWithDirectorProp = property.FindPropertyRelative("dontPauseWithDirector");
SerializedProperty dontEndWithClip = property.FindPropertyRelative("dontEndWithClip");
SerializedProperty endMixOutDuration = property.FindPropertyRelative("endMixOutDuration");
@ -129,5 +130,8 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, drawOrderProp);
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, alphaProp);
}
}

View File

@ -34,7 +34,7 @@ using UnityEngine;
using UnityEngine.Timeline;
namespace Spine.Unity.Editor {
#if UNITY_2019_1_OR_NEWER
[CustomTimelineEditor(typeof(SpineAnimationStateGraphicTrack))]
[CanEditMultipleObjects]
public class SpineAnimationStateGraphicTrackInspector : TrackEditor {
@ -46,4 +46,22 @@ namespace Spine.Unity.Editor {
return options;
}
}
#else
[CustomEditor(typeof(SpineAnimationStateGraphicTrack))]
[CanEditMultipleObjects]
public class SpineAnimationStateGraphicTrackInspector : UnityEditor.Editor {
protected SerializedProperty trackIndexProperty = null;
public void OnEnable () {
trackIndexProperty = serializedObject.FindProperty("trackIndex");
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUILayout.PropertyField(trackIndexProperty);
serializedObject.ApplyModifiedProperties();
}
}
#endif
}

View File

@ -34,6 +34,7 @@ using UnityEngine;
using UnityEngine.Timeline;
namespace Spine.Unity.Editor {
#if UNITY_2019_1_OR_NEWER
[CustomTimelineEditor(typeof(SpineAnimationStateTrack))]
[CanEditMultipleObjects]
public class SpineAnimationStateTrackInspector : TrackEditor {
@ -45,4 +46,22 @@ namespace Spine.Unity.Editor {
return options;
}
}
#else
[CustomEditor(typeof(SpineAnimationStateTrack))]
[CanEditMultipleObjects]
public class SpineAnimationStateTrackInspector : UnityEditor.Editor {
protected SerializedProperty trackIndexProperty = null;
public void OnEnable () {
trackIndexProperty = serializedObject.FindProperty("trackIndex");
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUILayout.PropertyField(trackIndexProperty);
serializedObject.ApplyModifiedProperties();
}
}
#endif
}

View File

@ -34,6 +34,7 @@ using UnityEngine;
using UnityEngine.Timeline;
namespace Spine.Unity.Editor {
#if UNITY_2019_1_OR_NEWER
[CustomTimelineEditor(typeof(SpineSkeletonFlipTrack))]
[CanEditMultipleObjects]
public class SpineSkeletonFlipTrackInspector : TrackEditor {
@ -45,4 +46,5 @@ namespace Spine.Unity.Editor {
return options;
}
}
#endif
}

View File

@ -69,6 +69,9 @@ namespace Spine.Unity.Playables {
[Range(0, 1f)]
public float drawOrderThreshold = 0.5f;
[Range(0, 1f)]
public float alpha = 1.0f;
}
}

View File

@ -191,6 +191,7 @@ namespace Spine.Unity.Playables {
trackEntry.TimeScale = (float)clipPlayable.GetSpeed();
trackEntry.AttachmentThreshold = clipData.attachmentThreshold;
trackEntry.HoldPrevious = clipData.holdPrevious;
trackEntry.Alpha = clipData.alpha;
if (clipData.customDuration)
trackEntry.MixDuration = customMixDuration;
@ -286,6 +287,7 @@ namespace Spine.Unity.Playables {
if (toAnimation != null) {
toEntry = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop);
toEntry.HoldPrevious = clipData.holdPrevious;
toEntry.Alpha = clipData.alpha;
}
}
@ -301,7 +303,7 @@ namespace Spine.Unity.Playables {
dummyAnimationState.Apply(skeleton);
} else {
if (toAnimation != null)
toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, 1f, MixBlend.Setup, MixDirection.In);
toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, clipData.alpha, MixBlend.Setup, MixDirection.In);
}
if (skeletonAnimation) {

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.timeline",
"displayName": "Spine Timeline Extensions",
"description": "This plugin provides integration of spine-unity for the Unity Timeline.\n\nPrerequisites:\nIt requires a working installation of the spine-unity runtime (via the spine-unity unitypackage), version 4.0.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)",
"version": "4.0.9",
"version": "4.0.10",
"unity": "2018.3",
"author": {
"name": "Esoteric Software",

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.timeline",
"displayName": "Spine Timeline Extensions",
"description": "This plugin provides integration of spine-unity for the Unity Timeline.\n\nPrerequisites:\nIt requires a working installation of the spine-unity and spine-csharp runtimes as UPM packages (not as spine-unity unitypackage), version 4.0.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)",
"version": "4.0.9",
"version": "4.0.10",
"unity": "2018.3",
"author": {
"name": "Esoteric Software",

View File

@ -0,0 +1,47 @@
#ifndef SKELETONLIT_UNLIT_PASS_INCLUDED
#define SKELETONLIT_UNLIT_PASS_INCLUDED
struct Attributes
{
float3 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_ST;
Varyings UnlitVertex(Attributes attributes)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(attributes.positionOS);
o.uv = TRANSFORM_TEX(attributes.uv, _MainTex);
o.uv = attributes.uv;
o.color = attributes.color;
return o;
}
float4 UnlitFragment(Varyings i) : SV_Target
{
half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
half4 main;
#if defined(_STRAIGHT_ALPHA_INPUT)
main.rgb = tex.rgb * i.color.rgb * tex.a;
#else
main.rgb = tex.rgb * i.color.rgb;
#endif
main.a = tex.a * i.color.a;
return main;
}
#endif

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 580dd7e812fc63c4a9330abe519946de
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -193,52 +193,12 @@
Blend One OneMinusSrcAlpha
HLSLPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma prefer_hlslcc gles
#pragma vertex UnlitVertex
#pragma fragment UnlitFragment
struct Attributes
{
float3 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_ST;
Varyings UnlitVertex(Attributes attributes)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(attributes.positionOS);
o.uv = TRANSFORM_TEX(attributes.uv, _MainTex);
o.uv = attributes.uv;
o.color = attributes.color;
return o;
}
float4 UnlitFragment(Varyings i) : SV_Target
{
half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
half4 main;
#if defined(_STRAIGHT_ALPHA_INPUT)
main.rgb = tex.rgb * i.color.rgb * tex.a;
#else
main.rgb = tex.rgb * i.color.rgb;
#endif
main.a = tex.a * i.color.a;
return main;
}
#include "Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl"
ENDHLSL
}
}

View File

@ -147,7 +147,28 @@ Shader "Universal Render Pipeline/2D/Spine/Sprite"
ENDHLSL
}
UsePass "Universal Render Pipeline/2D/Spine/Skeleton Lit/UNLIT"
Pass
{
Name "Unlit"
Tags { "LightMode" = "UniversalForward" "Queue" = "Transparent" "RenderType" = "Transparent"}
ZWrite Off
Cull Off
Blend One OneMinusSrcAlpha
HLSLPROGRAM
#pragma shader_feature _ _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON _ALPHAPREMULTIPLY_VERTEX_ONLY _ADDITIVEBLEND _ADDITIVEBLEND_SOFT _MULTIPLYBLEND _MULTIPLYBLEND_X2
#if defined(_ALPHAPREMULTIPLY_VERTEX_ONLY) || defined(_ALPHABLEND_ON)
#define _STRAIGHT_ALPHA_INPUT
#endif
#pragma prefer_hlslcc gles
#pragma vertex UnlitVertex
#pragma fragment UnlitFragment
#include "Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl"
ENDHLSL
}
}
FallBack "Universal Render Pipeline/2D/Spine/Skeleton Lit"

View File

@ -1,3 +1,3 @@
// Adapt this path accordingly if you have unpacked the Spine directory to another location.
#include "Assets/Spine/Runtime/spine-unity/Shaders/Sprite/CGIncludes/ShaderShared.cginc"
//#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/Sprite/CGIncludes/ShaderShared.cginc"
//#include "Assets/Spine/Runtime/spine-unity/Shaders/Sprite/CGIncludes/ShaderShared.cginc"
#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/Sprite/CGIncludes/ShaderShared.cginc"

View File

@ -1,3 +1,3 @@
// Adapt this path accordingly if you have unpacked the Spine directory to another location.
#include "Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Common.cginc"
//#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/CGIncludes/Spine-Common.cginc"
//#include "Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Common.cginc"
#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/CGIncludes/Spine-Common.cginc"

View File

@ -1,3 +1,3 @@
// Adapt this path accordingly if you have unpacked the Spine directory to another location.
#include "Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Outline-Common.cginc"
//#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/CGIncludes/Spine-Outline-Common.cginc"
//#include "Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Outline-Common.cginc"
#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/CGIncludes/Spine-Outline-Common.cginc"

View File

@ -1,3 +1,3 @@
// Adapt this path accordingly if you have unpacked the Spine directory to another location.
#include "Assets/Spine/Runtime/spine-unity/Shaders/Sprite/CGIncludes/SpriteLighting.cginc"
//#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/Sprite/CGIncludes/SpriteLighting.cginc"
//#include "Assets/Spine/Runtime/spine-unity/Shaders/Sprite/CGIncludes/SpriteLighting.cginc"
#include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/Sprite/CGIncludes/SpriteLighting.cginc"

View File

@ -113,7 +113,7 @@ Shader "Universal Render Pipeline/Spine/Sprite"
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
//--------------------------------------
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
@ -202,6 +202,36 @@ Shader "Universal Render Pipeline/Spine/Sprite"
#include "Include/Spine-Sprite-DepthOnlyPass-URP.hlsl"
ENDHLSL
}
Pass
{
Name "Unlit"
Tags { "LightMode" = "UniversalForward" "Queue" = "Transparent" "RenderType" = "Transparent"}
ZWrite Off
Cull Off
Blend One OneMinusSrcAlpha
HLSLPROGRAM
#pragma shader_feature _ _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON _ALPHAPREMULTIPLY_VERTEX_ONLY _ADDITIVEBLEND _ADDITIVEBLEND_SOFT _MULTIPLYBLEND _MULTIPLYBLEND_X2
#if defined(_ALPHAPREMULTIPLY_VERTEX_ONLY) || defined(_ALPHABLEND_ON)
#define _STRAIGHT_ALPHA_INPUT
#endif
#pragma prefer_hlslcc gles
#pragma vertex vert
#pragma fragment frag
#undef LIGHTMAP_ON
#define USE_URP
#define fixed4 half4
#define fixed3 half3
#define fixed half
#include "Include/Spine-Input-URP.hlsl"
#include "Include/Spine-Skeleton-ForwardPass-URP.hlsl"
ENDHLSL
}
}
FallBack "Hidden/InternalErrorShader"

View File

@ -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.0.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)",
"version": "4.0.6",
"version": "4.0.7",
"unity": "2019.3",
"author": {
"name": "Esoteric Software",