Explorar o código

Merge branch '4.0' of https://github.com/esotericsoftware/spine-runtimes into 4.0

badlogic %!s(int64=3) %!d(string=hai) anos
pai
achega
01524d4cdc
Modificáronse 76 ficheiros con 2586 adicións e 513 borrados
  1. 6 0
      CHANGELOG.md
  2. 13 7
      CMakeLists.txt
  3. 1 1
      spine-c/spine-c/src/spine/SkeletonBinary.c
  4. 10 6
      spine-c/spine-c/src/spine/SkeletonJson.c
  5. 5 5
      spine-cpp/spine-cpp/include/spine/Extension.h
  6. 2 4
      spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
  7. 3 3
      spine-csharp/src/SkeletonBinary.cs
  8. 0 3
      spine-csharp/src/package.json
  9. 15 1
      spine-ts/.vscode/launch.json
  10. 3 3
      spine-ts/README.md
  11. 1 0
      spine-ts/index.html
  12. 168 143
      spine-ts/package-lock.json
  13. 1 1
      spine-ts/package.json
  14. 58 150
      spine-ts/spine-canvas/example/index.html
  15. 111 0
      spine-ts/spine-canvas/example/mouse-click.html
  16. 2 2
      spine-ts/spine-canvas/package.json
  17. 1 1
      spine-ts/spine-core/package.json
  18. 15 0
      spine-ts/spine-core/src/AssetManagerBase.ts
  19. 9 0
      spine-ts/spine-core/src/Skeleton.ts
  20. 1 1
      spine-ts/spine-core/src/SkeletonBinary.ts
  21. 2 2
      spine-ts/spine-player/package.json
  22. 1 1
      spine-ts/spine-player/src/Player.ts
  23. 3 2
      spine-ts/spine-threejs/example/index.html
  24. 4 4
      spine-ts/spine-threejs/package.json
  25. 26 11
      spine-ts/spine-threejs/src/SkeletonMesh.ts
  26. 2 0
      spine-ts/spine-webgl/example/drag-and-drop.html
  27. 10 3
      spine-ts/spine-webgl/example/drag-and-drop.js
  28. 2 2
      spine-ts/spine-webgl/package.json
  29. 1047 0
      spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity
  30. 7 0
      spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity.meta
  31. 90 0
      spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs
  32. 2 1
      spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs.meta
  33. 8 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture.meta
  34. 90 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadMaterial.mat
  35. 8 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadMaterial.mat.meta
  36. 104 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadShader.shader
  37. 10 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadShader.shader.meta
  38. 248 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs
  39. 11 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs.meta
  40. 88 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureFadeout.cs
  41. 11 0
      spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureFadeout.cs.meta
  42. 18 12
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/SkeletonDataAssetInspector.cs
  43. 2 2
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs
  44. 2 2
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/BlendModeMaterialsUtility.cs
  45. 25 26
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/DataReloadHandler.cs
  46. 61 40
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineBuildProcessor.cs
  47. 12 3
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs
  48. 7 0
      spine-unity/Assets/Spine/Runtime/spine-csharp/add spine-csharp here.txt.meta
  49. 6 1
      spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AnimationReferenceAsset.cs
  50. 5 0
      spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs
  51. 4 0
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs
  52. 7 5
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs
  53. 6 4
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs
  54. 4 1
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs
  55. 42 0
      spine-unity/Assets/Spine/Runtime/spine-unity/Utility/BuildUtilities.cs
  56. 11 0
      spine-unity/Assets/Spine/Runtime/spine-unity/Utility/BuildUtilities.cs.meta
  57. 1 2
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md
  58. BIN=BIN
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-clip-inspector.png
  59. 5 1
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs
  60. 19 1
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs
  61. 19 0
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs
  62. 2 0
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipTrackInspector.cs
  63. 3 0
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs
  64. 3 1
      spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs
  65. 1 1
      spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json
  66. 1 1
      spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json
  67. 47 0
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl
  68. 10 0
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl.meta
  69. 2 42
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader
  70. 22 1
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-Sprite-URP-2D.shader
  71. 2 2
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/ShaderShared.cginc
  72. 2 2
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/Spine-Common.cginc
  73. 2 2
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/Spine-Outline-Common.cginc
  74. 2 2
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/SpriteLighting.cginc
  75. 31 1
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader
  76. 1 1
      spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json

+ 6 - 0
CHANGELOG.md

@@ -163,6 +163,9 @@
   * Improved `Advanced - Fix Prefab Override MeshFilter` property for `SkeletonRenderer` (and subclasses`SkeletonAnimation` and `SkeletonMecanim`), now providing an additional option to use a global value which can be set in `Edit - Preferences - Spine`.
   * Timeline naming improvements: `Spine AnimationState Clip` Inspector parameter `Custom Duration` changed and inverted to `Default Mix Duration` for more clarity. Shortened all Timeline add track menu entries from: `Spine.Unity.Playables - <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`.

+ 13 - 7
CMakeLists.txt

@@ -1,6 +1,13 @@
 cmake_minimum_required(VERSION 3.17)
 project(spine)
 
+set(CMAKE_INSTALL_PREFIX "./")
+set(CMAKE_VERBOSE_MAKEFILE ON)
+set(SPINE_SFML FALSE CACHE BOOL FALSE)
+set(SPINE_COCOS2D_OBJC FALSE CACHE BOOL FALSE)
+set(SPINE_COCOS2D_X FALSE CACHE BOOL FALSE)
+set(SPINE_SANITIZE FALSE CACHE BOOL FALSE)
+
 if(MSVC)
 	message("MSCV detected")
 	set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
@@ -8,13 +15,12 @@ if(MSVC)
 else()
 	set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wunused-value -Wno-c++11-long-long -Wno-variadic-macros -Werror -Wextra -pedantic -Wnonportable-include-path -Wshadow -std=c89")
 	set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunused-value -Wno-c++11-long-long -Wno-variadic-macros -Werror -Wextra -Wnon-virtual-dtor -pedantic -Wnonportable-include-path -Wshadow -std=c++11 -fno-exceptions -fno-rtti")
-endif()
 
-set(CMAKE_INSTALL_PREFIX "./")
-set(CMAKE_VERBOSE_MAKEFILE ON)
-set(SPINE_SFML FALSE CACHE BOOL FALSE)
-set(SPINE_COCOS2D_OBJC FALSE CACHE BOOL FALSE)
-set(SPINE_COCOS2D_X FALSE CACHE BOOL FALSE)
+	if (${SPINE_SANITIZE})
+		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize=undefined")
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined")
+	endif()
+endif()
 
 if((${SPINE_SFML}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sfml"))
 	add_subdirectory(spine-c)
@@ -34,4 +40,4 @@ if((${SPINE_COCOS2D_X}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-cocos2dx"
 endif()
 
 # add_subdirectory(spine-c/spine-c-unit-tests)
-add_subdirectory(spine-cpp/spine-cpp-unit-tests)
+add_subdirectory(spine-cpp/spine-cpp-unit-tests)

+ 1 - 1
spine-c/spine-c/src/spine/SkeletonBinary.c

@@ -1189,7 +1189,7 @@ spSkeletonData *spSkeletonBinary_readSkeletonData(spSkeletonBinary *self, const
 	highHash = readInt(input);
 	sprintf(buffer, "%x%x", highHash, lowHash);
 	buffer[31] = 0;
-	skeletonData->hash = strdup(buffer);
+	MALLOC_STR(skeletonData->hash, buffer);
 
 	skeletonData->version = readString(input);
 	if (!strlen(skeletonData->version)) {

+ 10 - 6
spine-c/spine-c/src/spine/SkeletonJson.c

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

+ 5 - 5
spine-cpp/spine-cpp/include/spine/Extension.h

@@ -104,15 +104,15 @@ namespace spine {
 		virtual ~DefaultSpineExtension();
 
 	protected:
-		virtual void *_alloc(size_t size, const char *file, int line);
+		virtual void *_alloc(size_t size, const char *file, int line) override;
 
-		virtual void *_calloc(size_t size, const char *file, int line);
+		virtual void *_calloc(size_t size, const char *file, int line) override;
 
-		virtual void *_realloc(void *ptr, size_t size, const char *file, int line);
+		virtual void *_realloc(void *ptr, size_t size, const char *file, int line) override;
 
-		virtual void _free(void *mem, const char *file, int line);
+		virtual void _free(void *mem, const char *file, int line) override;
 
-		virtual char *_readFile(const String &path, int *length);
+		virtual char *_readFile(const String &path, int *length) override;
 	};
 
 // This function is to be implemented by engine specific runtimes to provide

+ 2 - 4
spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp

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

+ 3 - 3
spine-csharp/src/SkeletonBinary.cs

@@ -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.");
 			}
 		}
 	}

+ 0 - 3
spine-csharp/src/package.json

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

+ 15 - 1
spine-ts/.vscode/launch.json

@@ -17,6 +17,20 @@
 			"name": "drag-and-drop",
 			"url": "http://localhost:8080/spine-webgl/example/drag-and-drop.html",
 			"webRoot": "${workspaceFolder}"
+		},
+		{
+			"type": "pwa-chrome",
+			"request": "launch",
+			"name": "barebones-dragon",
+			"url": "http://localhost:8080/spine-webgl/example/barebones-dragon.html",
+			"webRoot": "${workspaceFolder}"
+		},
+		{
+			"type": "pwa-chrome",
+			"request": "launch",
+			"name": "threejs-example",
+			"url": "http://localhost:8080/spine-threejs/example/index.html",
+			"webRoot": "${workspaceFolder}"
 		}
 	]
-}
+}

+ 3 - 3
spine-ts/README.md

@@ -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/[email protected].*/dist/iife/spine-player.js">
 <link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/[email protected].*/dist/spine-player.css">
 
-// spine-ts WebGL
-<script src="https://unpkg.com/@esotericsoftware/[email protected].*/dist/iife/spine-webgl.js">
+// spine-ts ThreeJS
+<script src="https://unpkg.com/@esotericsoftware/[email protected].*/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.
@@ -113,4 +113,4 @@ The final command `npm run dev` will start a local web server at http://127.0.0.
 
 You can then open Visual Studio Code to inspect, edit, and debug the source code. We also supply launch configurations to start examples and demos in debug mode, so you can debug them right inside Visual Studio code.
 
-To build the artifacts as they are published to NPM, run `npm run build`.
+To build the artifacts as they are published to NPM, run `npm run build`.

+ 1 - 0
spine-ts/index.html

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

+ 168 - 143
spine-ts/package-lock.json

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

+ 1 - 1
spine-ts/package.json

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

+ 58 - 150
spine-ts/spine-canvas/example/index.html

@@ -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%
-	}
 
-	canvas {
-		position: absolute;
-		width: 100%;
-		height: 100%;
-	}
-</style>
+<head>
+	<!--<script src="https://unpkg.com/@esotericsoftware/[email protected].*/dist/iife/spine-canvas.js"></script>-->
+	<script src="../dist/iife/spine-canvas.js"></script>
+</head>
 
-<body>
-	<canvas id="canvas"></canvas>
+<body style="margin: 0; padding: 0; background: #333">
+	<canvas id="canvas" style="width: 100%; height: 100vh;"></canvas>
 </body>
-<script>
-
-	var lastFrameTime = Date.now() / 1000;
-	var canvas, context;
-	var assetManager;
-	var skeleton, state, bounds;
-	var skeletonRenderer;
 
-	var skelName = "spineboy-ess";
-	var animName = "walk";
+<script>
+	let lastFrameTime = Date.now() / 1000;
+	let canvas, context;
+	let assetManager;
+	let skeleton, animationState, bounds;
+	let skeletonRenderer;
 
-	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);
-	}
+		// Instantiate a new skeleton based on the atlas and skeleton data.
+		skeleton = new spine.Skeleton(skeletonData);
+		skeleton.setToSetupPose();
+		skeleton.updateWorldTransform();
+		bounds = skeleton.getBoundsRect();
 
-	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);
-		}
-	}
+		// 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);
 
-	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 };
-	}
+		// Set the run animation, looping.
+		animationState.setAnimation(0, "run", true);
 
-	function calculateBounds(skeleton) {
-		var data = skeleton.data;
-		skeleton.setToSetupPose();
-		skeleton.updateWorldTransform();
-		var offset = new spine.Vector2();
-		var size = new spine.Vector2();
-		skeleton.getBounds(offset, size, []);
-		return { offset: offset, size: size };
+		// 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();
-
-		context.save();
-		context.setTransform(1, 0, 0, 1, 0, 0);
-		context.fillStyle = "#cccccc";
-		context.fillRect(0, 0, canvas.width, canvas.height);
-		context.restore();
-
-		state.update(delta);
-		state.apply(skeleton);
+		// 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);
 
-		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>

+ 111 - 0
spine-ts/spine-canvas/example/mouse-click.html

@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+	<!--<script src="https://unpkg.com/@esotericsoftware/[email protected].*/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>

+ 2 - 2
spine-ts/spine-canvas/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@esotericsoftware/spine-canvas",
-  "version": "4.0.20",
+  "version": "4.0.27",
   "description": "The official Spine Runtimes for the web.",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
@@ -30,6 +30,6 @@
   },
   "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
   "dependencies": {
-    "@esotericsoftware/spine-core": "^4.0.20"
+    "@esotericsoftware/spine-core": "^4.0.27"
   }
 }

+ 1 - 1
spine-ts/spine-core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@esotericsoftware/spine-core",
-  "version": "4.0.20",
+  "version": "4.0.27",
   "description": "The official Spine Runtimes for the web.",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",

+ 15 - 0
spine-ts/spine-core/src/AssetManagerBase.ts

@@ -65,6 +65,21 @@ export class AssetManagerBase implements Disposable {
 		if (callback) callback(path, message);
 	}
 
+	loadAll () {
+		let promise = new Promise((resolve: (assetManager: AssetManagerBase) => void, reject: (errors: StringMap<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;
 	}

+ 9 - 0
spine-ts/spine-core/src/Skeleton.ts

@@ -585,6 +585,15 @@ export class Skeleton {
 		return null;
 	}
 
+	/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose as `{ x: number, y: number, width: number, height: number }`.
+	 * Note that this method will create temporary objects which can add to garbage collection pressure. Use `getBounds()` if garbage collection is a concern. */
+	getBoundsRect () {
+		let offset = new Vector2();
+		let size = new Vector2();
+		this.getBounds(offset, size);
+		return { x: offset.x, y: offset.y, width: size.x, height: size.y };
+	}
+
 	/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.
 	 * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
 	 * @param size An output value, the width and height of the AABB.

+ 1 - 1
spine-ts/spine-core/src/SkeletonBinary.ts

@@ -1022,7 +1022,7 @@ export class BinaryInput {
 		let chars = "";
 		let charCount = 0;
 		for (let i = 0; i < byteCount;) {
-			let b = this.readByte();
+			let b = this.readUnsignedByte();
 			switch (b >> 4) {
 				case 12:
 				case 13:

+ 2 - 2
spine-ts/spine-player/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@esotericsoftware/spine-player",
-  "version": "4.0.20",
+  "version": "4.0.27",
   "description": "The official Spine Runtimes for the web.",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
@@ -30,6 +30,6 @@
   },
   "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
   "dependencies": {
-    "@esotericsoftware/spine-webgl": "^4.0.20"
+    "@esotericsoftware/spine-webgl": "^4.0.27"
   }
 }

+ 1 - 1
spine-ts/spine-player/src/Player.ts

@@ -258,7 +258,7 @@ export class SpinePlayer implements Disposable {
 
 	dispose (): void {
 		this.sceneRenderer.dispose();
-		this.loadingScreen.dispose();
+		if (this.loadingScreen) this.loadingScreen.dispose();
 		this.assetManager.dispose();
 		for (var i = 0; i < this.eventListeners.length; i++) {
 			var eventListener = this.eventListeners[i];

+ 3 - 2
spine-ts/spine-threejs/example/index.html

@@ -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/[email protected]/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);

+ 4 - 4
spine-ts/spine-threejs/package.json

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

+ 26 - 11
spine-ts/spine-threejs/src/SkeletonMesh.ts

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

+ 2 - 0
spine-ts/spine-webgl/example/drag-and-drop.html

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

+ 10 - 3
spine-ts/spine-webgl/example/drag-and-drop.js

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

+ 2 - 2
spine-ts/spine-webgl/package.json

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

+ 1047 - 0
spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity

@@ -0,0 +1,1047 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 512
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 256
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 1
+    m_PVRDenoiserTypeDirect: 1
+    m_PVRDenoiserTypeIndirect: 1
+    m_PVRDenoiserTypeAO: 1
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 0}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &71621966
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 71621967}
+  - component: {fileID: 71621969}
+  - component: {fileID: 71621968}
+  m_Layer: 5
+  m_Name: Title
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &71621967
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 71621966}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 592567554}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 1, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: -60, y: -60}
+  m_SizeDelta: {x: 600, y: 60}
+  m_Pivot: {x: 0.9999999, y: 1.0000007}
+--- !u!114 &71621968
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 71621966}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 55
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 10
+    m_MaxSize: 55
+    m_Alignment: 5
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: RenderTexture Fade-Out Transparency
+--- !u!222 &71621969
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 71621966}
+  m_CullTransparentMesh: 1
+--- !u!1 &334034152
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 334034156}
+  - component: {fileID: 334034155}
+  - component: {fileID: 334034154}
+  - component: {fileID: 334034153}
+  m_Layer: 0
+  m_Name: Spineboy Normal
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &334034153
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 334034152}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: d247ba06193faa74d9335f5481b2b56c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  skeletonDataAsset: {fileID: 11400000, guid: af38a3de26ed9b84abc2fe7c7f3b209d, type: 2}
+  initialSkinName: 
+  fixPrefabOverrideViaMeshFilter: 2
+  initialFlipX: 0
+  initialFlipY: 0
+  updateWhenInvisible: 3
+  separatorSlotNames: []
+  zSpacing: 0
+  useClipping: 1
+  immutableTriangles: 0
+  pmaVertexColors: 1
+  clearStateOnDisable: 0
+  tintBlack: 0
+  singleSubmesh: 0
+  fixDrawOrder: 0
+  addNormals: 0
+  calculateTangents: 0
+  maskInteraction: 0
+  maskMaterials:
+    materialsMaskDisabled: []
+    materialsInsideMask: []
+    materialsOutsideMask: []
+  disableRenderingOnOverride: 1
+  _animationName: run
+  loop: 1
+  timeScale: 1
+--- !u!23 &334034154
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 334034152}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: f89bbf05902e77242a3ad20f3c927353, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!33 &334034155
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 334034152}
+  m_Mesh: {fileID: 0}
+--- !u!4 &334034156
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 334034152}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: -5.93, y: 0, z: 5.66}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &541830406
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 541830407}
+  - component: {fileID: 541830409}
+  - component: {fileID: 541830408}
+  m_Layer: 5
+  m_Name: Instructions
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &541830407
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 541830406}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 592567554}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 1, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: -391, y: -190}
+  m_SizeDelta: {x: 662, y: 101.6}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &541830408
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 541830406}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 28
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 10
+    m_MaxSize: 40
+    m_Alignment: 2
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: 'Enter play mode to see the problem of conventional alpha transparency
+
+    fadeout
+    and how this can be fixed by using a RenderTexture.'
+--- !u!222 &541830409
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 541830406}
+  m_CullTransparentMesh: 1
+--- !u!1 &592567553
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 592567554}
+  - component: {fileID: 592567556}
+  - component: {fileID: 592567555}
+  m_Layer: 5
+  m_Name: Canvas
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &592567554
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 592567553}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0, y: 0, z: 0}
+  m_Children:
+  - {fileID: 71621967}
+  - {fileID: 541830407}
+  - {fileID: 1682675646}
+  m_Father: {fileID: 1799507978}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0}
+--- !u!114 &592567555
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 592567553}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 1
+  m_ReferencePixelsPerUnit: 200
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 1920, y: 1080}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 0
+--- !u!223 &592567556
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 592567553}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 1
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!1 &1368805070
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1368805071}
+  - component: {fileID: 1368805072}
+  m_Layer: 0
+  m_Name: Transparency FadeOut Example
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1368805071
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1368805070}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: -3.7153435, y: -0.0017910004, z: 5.9292965}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1368805072
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1368805070}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a4cc2b5fcffcac846aacb02b6dad0440, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  renderTextureFadeout: {fileID: 1786065619}
+  normalSkeletonRenderer: {fileID: 334034153}
+--- !u!1 &1369381599
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1369381601}
+  - component: {fileID: 1369381600}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &1369381600
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1369381599}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &1369381601
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1369381599}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &1407691187
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1407691190}
+  - component: {fileID: 1407691189}
+  - component: {fileID: 1407691188}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &1407691188
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1407691187}
+  m_Enabled: 1
+--- !u!20 &1407691189
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1407691187}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 2
+  m_BackGroundColor: {r: 0.43316126, g: 0.5290042, b: 0.5849056, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &1407691190
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1407691187}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 4.8, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1606174180
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1606174183}
+  - component: {fileID: 1606174182}
+  - component: {fileID: 1606174181}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1606174181
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1606174180}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1606174182
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1606174180}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1606174183
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1606174180}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1682675645
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1682675646}
+  - component: {fileID: 1682675648}
+  - component: {fileID: 1682675647}
+  m_Layer: 5
+  m_Name: Example Notes
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1682675646
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1682675645}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 592567554}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: -331.4, y: -186}
+  m_SizeDelta: {x: 1176.1, y: -365}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1682675647
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1682675645}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 26
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 0
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: 'This scene demonstrates the problems of using conventional alpha transparency
+    for a fadeout effect (left), and how this problem can be fixed by using a RenderTexture
+    (right).
+
+
+    Spineboy on the right uses a SkeletonRenderTexture component to
+    render the overlapping mesh to a RenderTexture first and then draw this texture
+    to the scene at once using a single quad.'
+--- !u!222 &1682675648
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1682675645}
+  m_CullTransparentMesh: 1
+--- !u!1 &1786065613
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1786065618}
+  - component: {fileID: 1786065617}
+  - component: {fileID: 1786065616}
+  - component: {fileID: 1786065615}
+  - component: {fileID: 1786065614}
+  - component: {fileID: 1786065619}
+  m_Layer: 0
+  m_Name: Spineboy CorrectFadeout
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1786065614
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_Enabled: 0
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 25e6ceb271c9af848ae53f2af1073d0d, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  color: {r: 1, g: 1, b: 1, a: 1}
+  quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2}
+  targetCamera: {fileID: 0}
+  maxRenderTextureSize: 1024
+  quad: {fileID: 0}
+  renderTexture: {fileID: 0}
+--- !u!114 &1786065615
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: d247ba06193faa74d9335f5481b2b56c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  skeletonDataAsset: {fileID: 11400000, guid: af38a3de26ed9b84abc2fe7c7f3b209d, type: 2}
+  initialSkinName: 
+  fixPrefabOverrideViaMeshFilter: 2
+  initialFlipX: 0
+  initialFlipY: 0
+  updateWhenInvisible: 3
+  separatorSlotNames: []
+  zSpacing: 0
+  useClipping: 1
+  immutableTriangles: 0
+  pmaVertexColors: 1
+  clearStateOnDisable: 0
+  tintBlack: 0
+  singleSubmesh: 0
+  fixDrawOrder: 0
+  addNormals: 0
+  calculateTangents: 0
+  maskInteraction: 0
+  maskMaterials:
+    materialsMaskDisabled: []
+    materialsInsideMask: []
+    materialsOutsideMask: []
+  disableRenderingOnOverride: 1
+  _animationName: run
+  loop: 1
+  timeScale: 1
+--- !u!23 &1786065616
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: f89bbf05902e77242a3ad20f3c927353, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!33 &1786065617
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_Mesh: {fileID: 0}
+--- !u!4 &1786065618
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 3.32, y: 0, z: 5.66}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1786065619
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1786065613}
+  m_Enabled: 0
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5fc94f89310427643babb41e000a8462, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  fadeoutSeconds: 2
+--- !u!1 &1799507977
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1799507978}
+  m_Layer: 0
+  m_Name: UI
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1799507978
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1799507977}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: -4.7074776, y: 0.042612553, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 592567554}
+  m_Father: {fileID: 0}
+  m_RootOrder: 6
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 7 - 0
spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity.meta

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

+ 90 - 0
spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs

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

+ 2 - 1
spine-unity/Assets/Spine Examples/Scripts/Sample Components/Legacy/CustomSkin.cs.meta → spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs.meta

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

+ 8 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture.meta

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

+ 90 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadMaterial.mat

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

+ 8 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadMaterial.mat.meta

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

+ 104 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadShader.shader

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

+ 10 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/RenderQuadShader.shader.meta

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

+ 248 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs

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

+ 11 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs.meta

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

+ 88 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureFadeout.cs

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

+ 11 - 0
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureFadeout.cs.meta

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

+ 18 - 12
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/SkeletonDataAssetInspector.cs

@@ -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);
+
+			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);
+#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 (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 () {

+ 2 - 2
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs

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

+ 2 - 2
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/BlendModeMaterialsUtility.cs

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

+ 25 - 26
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/DataReloadHandler.cs

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

+ 61 - 40
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineBuildProcessor.cs

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

+ 12 - 3
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs

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

+ 7 - 0
spine-unity/Assets/Spine/Runtime/spine-csharp/add spine-csharp here.txt.meta

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

+ 6 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/AnimationReferenceAsset.cs

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

+ 5 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs

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

+ 4 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs

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

+ 7 - 5
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs

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

+ 6 - 4
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs

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

+ 4 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs

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

+ 42 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/BuildUtilities.cs

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

+ 11 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/BuildUtilities.cs.meta

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

+ 1 - 2
spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md

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

BIN=BIN
spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-clip-inspector.png


+ 5 - 1
spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs

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

+ 19 - 1
spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs

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

+ 19 - 0
spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs

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

+ 2 - 0
spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipTrackInspector.cs

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

+ 3 - 0
spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs

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

+ 3 - 1
spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs

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

+ 1 - 1
spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json

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

+ 1 - 1
spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json

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

+ 47 - 0
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl

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

+ 10 - 0
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Include/Spine-SkeletonLit-UnlitPass-URP-2D.hlsl.meta

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

+ 2 - 42
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-SkeletonLit-URP-2D.shader

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

+ 22 - 1
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/2D/Spine-Sprite-URP-2D.shader

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

+ 2 - 2
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/ShaderShared.cginc

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

+ 2 - 2
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/Spine-Common.cginc

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

+ 2 - 2
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/Spine-Outline-Common.cginc

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

+ 2 - 2
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/SpineCoreShaders/SpriteLighting.cginc

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

+ 31 - 1
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader

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

+ 1 - 1
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/package.json

@@ -2,7 +2,7 @@
   "name": "com.esotericsoftware.spine.urp-shaders",
   "displayName": "Spine Universal RP Shaders",
   "description": "This plugin provides universal render pipeline (URP) shaders for the spine-unity runtime.\n\nPrerequisites:\nIt requires a working installation of the spine-unity runtime, version 4.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",