From 6ef7df4be600729a5da3d687ee3bf0423adfdc35 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 2 Aug 2022 16:04:54 +0200 Subject: [PATCH 1/9] [unity] Added example component `SkeletonGraphicRenderTexture`. Closes #2130. Added additional render callback delegates at SkeletonGraphic. --- CHANGELOG.md | 2 + .../RenderTexture FadeOut Transparency.unity | 291 +++++++++++++++++- .../Scripts/RenderTextureFadeoutExample.cs | 16 +- .../SkeletonGraphicRenderTexture.cs | 253 +++++++++++++++ .../SkeletonGraphicRenderTexture.cs.meta | 11 + .../SkeletonRenderTexture.cs | 78 +---- .../SkeletonRenderTextureBase.cs | 88 +++++- .../SkeletonRenderTextureBase.cs.meta | 11 + .../spine-unity/Components/SkeletonGraphic.cs | 204 +++++++++--- .../spine-unity/Utility/MathUtilities.cs | 71 +++++ .../spine-unity/Utility/MathUtilities.cs.meta | 11 + 11 files changed, 882 insertions(+), 154 deletions(-) create mode 100644 spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs create mode 100644 spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta create mode 100644 spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta create mode 100644 spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs create mode 100644 spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 72e4e19d2..223e4d9bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -316,6 +316,8 @@ * 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. + * `SkeletonGraphic` now provides additional render callback delegates `OnInstructionsPrepared`, `AssignMeshOverrideSingleRenderer` and `AssignMeshOverrideMultipleRenderers`. `OnInstructionsPrepared` is raised at the end of LateUpdate after render instructions are done, target renderers are prepared, and the mesh is ready to be generated. The two `AssignMeshOverride` delegates allow separate code to take over mesh and material assignment of a `SkeletonGraphic` component. + * Added example component `SkeletonGraphicRenderTexture` to render a `SkeletonGraphic` to a `RenderTexture` (similar as `SkeletonRenderTexture`), mainly for proper transparency. Extended example scene `RenderTexture FadeOut Transparency` accordingly. * **Changes of default values** diff --git a/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity b/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity index c5ae69f86..93acf07d8 100644 --- a/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity +++ b/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity @@ -153,7 +153,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 592567554} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -256,6 +256,8 @@ MonoBehaviour: materialsInsideMask: [] materialsOutsideMask: [] disableRenderingOnOverride: 1 + updateTiming: 1 + unscaledTime: 0 _animationName: run loop: 1 timeScale: 1 @@ -316,11 +318,11 @@ Transform: 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_LocalPosition: {x: -7.83, y: 0, z: 5.66} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &541830406 GameObject: @@ -352,7 +354,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 592567554} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -433,9 +435,11 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0} m_Children: + - {fileID: 1911967440} - {fileID: 71621967} - {fileID: 541830407} - {fileID: 1682675646} + - {fileID: 1735507358} m_Father: {fileID: 1799507978} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -488,6 +492,41 @@ Canvas: m_SortingLayerID: 0 m_SortingOrder: 0 m_TargetDisplay: 0 +--- !u!1 &1089682726 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1089682727} + m_Layer: 0 + m_Name: CustomRenderRect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1089682727 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1089682726} + 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: 1911967440} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 126.27, y: 7.130005} + m_SizeDelta: {x: 1893.1, y: 1654.617} + m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &1368805070 GameObject: m_ObjectHideFlags: 0 @@ -532,6 +571,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: renderTextureFadeout: {fileID: 1786065619} + renderTextureFadeoutCanvas: {fileID: 1911967443} normalSkeletonRenderer: {fileID: 334034153} --- !u!1 &1369381599 GameObject: @@ -805,12 +845,12 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 592567554} - m_RootOrder: 2 + m_RootOrder: 3 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_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0.6932292, y: 0.18750001} + m_AnchoredPosition: {x: 18.079224, y: 1.5001221} + m_SizeDelta: {x: -44.942017, y: 10} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1682675647 MonoBehaviour: @@ -847,12 +887,13 @@ MonoBehaviour: 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). + (center and 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.' + The two Spineboys on the right use SkeletonRenderTexture + and SkeletonGraphicRenderTexture components 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 @@ -861,6 +902,87 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1682675645} m_CullTransparentMesh: 1 +--- !u!1 &1735507357 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1735507358} + - component: {fileID: 1735507360} + - component: {fileID: 1735507359} + m_Layer: 5 + m_Name: SkeletonGraphic Notes + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1735507358 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1735507357} + 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: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.6932292, y: 0} + m_AnchorMax: {x: 1, y: 0.18750001} + m_AnchoredPosition: {x: 6.5009766, y: -2.5753784} + m_SizeDelta: {x: -49.462, y: 1.8482} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1735507359 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1735507357} + 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: 2 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: SkeletonGraphicRenderTexture supports setting a RectTransform as 'Custom + Render Rect' to define render texture bounds different from the SkeletonGraphic + rect. +--- !u!222 &1735507360 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1735507357} + m_CullTransparentMesh: 1 --- !u!1 &1786065613 GameObject: m_ObjectHideFlags: 0 @@ -895,11 +1017,11 @@ MonoBehaviour: 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} + targetCamera: {fileID: 0} + quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2} --- !u!114 &1786065615 MonoBehaviour: m_ObjectHideFlags: 0 @@ -935,6 +1057,8 @@ MonoBehaviour: materialsInsideMask: [] materialsOutsideMask: [] disableRenderingOnOverride: 1 + updateTiming: 1 + unscaledTime: 0 _animationName: run loop: 1 timeScale: 1 @@ -995,11 +1119,11 @@ Transform: 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_LocalPosition: {x: 2.38, y: 0, z: 5.66} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 3 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1786065619 MonoBehaviour: @@ -1045,3 +1169,136 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1911967439 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1911967440} + - component: {fileID: 1911967442} + - component: {fileID: 1911967441} + - component: {fileID: 1911967444} + - component: {fileID: 1911967443} + m_Layer: 0 + m_Name: SkeletonGraphic (spineboy-pro) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1911967440 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911967439} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} + m_Children: + - {fileID: 1089682727} + m_Father: {fileID: 592567554} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 84, y: -317.51} + m_SizeDelta: {x: 1185.6, y: 1302.059} + m_Pivot: {x: 0.63858336, y: 0.010301443} +--- !u!114 &1911967441 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911967439} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d85b887af7e6c3f45a2e2d2920d641bc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2} + 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: [] + skeletonDataAsset: {fileID: 11400000, guid: af38a3de26ed9b84abc2fe7c7f3b209d, type: 2} + additiveMaterial: {fileID: 2100000, guid: 2e8245019faeb8c43b75f9ca3ac8ee34, type: 2} + multiplyMaterial: {fileID: 2100000, guid: e74a1f8978a7da348a721508d0d58834, type: 2} + screenMaterial: {fileID: 2100000, guid: bab24c479f34eec45be6ea8595891569, type: 2} + initialSkinName: default + initialFlipX: 0 + initialFlipY: 0 + startingAnimation: run + startingLoop: 1 + timeScale: 1 + freeze: 0 + updateWhenInvisible: 3 + allowMultipleCanvasRenderers: 0 + canvasRenderers: [] + separatorSlotNames: [] + enableSeparatorSlots: 0 + separatorParts: [] + updateSeparatorPartLocation: 1 + disableMeshAssignmentOnOverride: 1 + meshGenerator: + settings: + useClipping: 1 + zSpacing: 0 + pmaVertexColors: 1 + tintBlack: 0 + canvasGroupTintBlack: 0 + calculateTangents: 0 + addNormals: 0 + immutableTriangles: 0 + updateTiming: 1 + unscaledTime: 0 +--- !u!222 &1911967442 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911967439} + m_CullTransparentMesh: 0 +--- !u!114 &1911967443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911967439} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fc94f89310427643babb41e000a8462, type: 3} + m_Name: + m_EditorClassIdentifier: + fadeoutSeconds: 2 +--- !u!114 &1911967444 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911967439} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6cbe1f11426513d49ad8e21e9d6643f7, type: 3} + m_Name: + m_EditorClassIdentifier: + color: {r: 1, g: 1, b: 1, a: 1} + maxRenderTextureSize: 1024 + quad: {fileID: 0} + renderTexture: {fileID: 0} + targetCamera: {fileID: 0} + customRenderRect: {fileID: 1089682727} + meshRendererMaterialForTexture: + - texture: {fileID: 2800000, guid: 4ea2c33e839afb34c98f66e892b3b2d2, type: 3} + material: {fileID: 2100000, guid: f89bbf05902e77242a3ad20f3c927353, type: 2} diff --git a/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs b/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs index 19b67376d..4e5babaf2 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs @@ -39,6 +39,7 @@ namespace Spine.Unity.Examples { public class RenderTextureFadeoutExample : MonoBehaviour { public SkeletonRenderTextureFadeout renderTextureFadeout; + public SkeletonRenderTextureFadeout renderTextureFadeoutCanvas; public SkeletonRenderer normalSkeletonRenderer; float fadeoutSeconds = 2.0f; @@ -47,8 +48,9 @@ namespace Spine.Unity.Examples { IEnumerator Start () { while (true) { StartFadeoutBad(); - StartFadeoutGood(); - yield return new WaitForSeconds(5.0f); + StartFadeoutGood(renderTextureFadeout); + StartFadeoutGood(renderTextureFadeoutCanvas); + yield return new WaitForSeconds(fadeoutSeconds + 1.0f); } } void Update () { @@ -75,12 +77,12 @@ namespace Spine.Unity.Examples { fadeoutSecondsRemaining = fadeoutSeconds; } - void StartFadeoutGood () { - renderTextureFadeout.gameObject.SetActive(true); + void StartFadeoutGood (SkeletonRenderTextureFadeout fadeoutComponent) { + fadeoutComponent.gameObject.SetActive(true); // enabling the SkeletonRenderTextureFadeout component starts the fadeout. - renderTextureFadeout.enabled = true; - renderTextureFadeout.OnFadeoutComplete -= DisableGameObject; - renderTextureFadeout.OnFadeoutComplete += DisableGameObject; + fadeoutComponent.enabled = true; + fadeoutComponent.OnFadeoutComplete -= DisableGameObject; + fadeoutComponent.OnFadeoutComplete += DisableGameObject; } void DisableGameObject (SkeletonRenderTextureFadeout target) { diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs new file mode 100644 index 000000000..af30ad8e7 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs @@ -0,0 +1,253 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UI; + +namespace Spine.Unity.Examples { + + /// + /// When enabled, this component renders a skeleton to a RenderTexture and + /// then draws this RenderTexture at a UI RawImage 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. + /// + [RequireComponent(typeof(SkeletonGraphic))] + public class SkeletonGraphicRenderTexture : SkeletonRenderTextureBase { + [System.Serializable] + public struct TextureMaterialPair { + public Texture texture; + public Material material; + + public TextureMaterialPair (Texture texture, Material material) { + this.texture = texture; + this.material = material; + } + } + + public RectTransform customRenderRect; + protected SkeletonGraphic skeletonGraphic; + public List meshRendererMaterialForTexture = new List(); + protected CanvasRenderer quadCanvasRenderer; + protected RawImage quadRawImage; + protected readonly Vector3[] worldCorners = new Vector3[4]; + + protected override void Awake () { + base.Awake(); + skeletonGraphic = this.GetComponent(); + if (targetCamera == null) { + targetCamera = skeletonGraphic.canvas.worldCamera; + if (targetCamera == null) + targetCamera = Camera.main; + } + CreateQuadChild(); + } + + void CreateQuadChild () { + quad = new GameObject(this.name + " RenderTexture", typeof(CanvasRenderer), typeof(RawImage)); + quad.transform.SetParent(this.transform.parent, false); + quadCanvasRenderer = quad.GetComponent(); + quadRawImage = quad.GetComponent(); + + quadMesh = new Mesh(); + quadMesh.MarkDynamic(); + quadMesh.name = "RenderTexture Quad"; + quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + } + + void Reset () { + skeletonGraphic = this.GetComponent(); + AtlasAssetBase[] atlasAssets = skeletonGraphic.SkeletonDataAsset.atlasAssets; + for (int i = 0; i < atlasAssets.Length; ++i) { + foreach (var material in atlasAssets[i].Materials) { + if (material.mainTexture != null) { + meshRendererMaterialForTexture.Add( + new TextureMaterialPair(material.mainTexture, material)); + } + } + } + } + + void OnEnable () { + skeletonGraphic.OnInstructionsPrepared += PrepareQuad; + skeletonGraphic.AssignMeshOverrideSingleRenderer += RenderSingleMeshToRenderTexture; + skeletonGraphic.AssignMeshOverrideMultipleRenderers += RenderMultipleMeshesToRenderTexture; + skeletonGraphic.disableMeshAssignmentOnOverride = true; + skeletonGraphic.OnMeshAndMaterialsUpdated += RenderOntoQuad; + var canvasRenderers = skeletonGraphic.canvasRenderers; + for (int i = 0; i < canvasRenderers.Count; ++i) + canvasRenderers[i].cull = true; + + if (quadCanvasRenderer) + quadCanvasRenderer.gameObject.SetActive(true); + } + + void OnDisable () { + skeletonGraphic.OnInstructionsPrepared -= PrepareQuad; + skeletonGraphic.AssignMeshOverrideSingleRenderer -= RenderSingleMeshToRenderTexture; + skeletonGraphic.AssignMeshOverrideMultipleRenderers -= RenderMultipleMeshesToRenderTexture; + skeletonGraphic.disableMeshAssignmentOnOverride = false; + skeletonGraphic.OnMeshAndMaterialsUpdated -= RenderOntoQuad; + var canvasRenderers = skeletonGraphic.canvasRenderers; + for (int i = 0; i < canvasRenderers.Count; ++i) + canvasRenderers[i].cull = false; + + if (quadCanvasRenderer) + quadCanvasRenderer.gameObject.SetActive(false); + if (renderTexture) + RenderTexture.ReleaseTemporary(renderTexture); + allocatedRenderTextureSize = Vector2Int.zero; + } + + void PrepareQuad (SkeletonRendererInstruction instruction) { + PrepareForMesh(); + SetupQuad(); + } + + void RenderOntoQuad (SkeletonGraphic skeletonRenderer) { + AssignAtQuad(); + } + + protected void PrepareForMesh () { + // We need to get the min/max of all four corners, rotation of the skeleton + // in combination with perspective projection otherwise might lead to incorrect + // screen space min/max. + RectTransform rectTransform = customRenderRect ? customRenderRect : skeletonGraphic.rectTransform; + rectTransform.GetWorldCorners(worldCorners); + + RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode; + Vector3 screenCorner0, screenCorner1, screenCorner2, screenCorner3; + // note: world corners are ordered bottom left, top left, top right, bottom right. + // This corresponds to 0, 3, 1, 2 in our desired order. + if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) { + screenCorner0 = worldCorners[0]; + screenCorner1 = worldCorners[3]; + screenCorner2 = worldCorners[1]; + screenCorner3 = worldCorners[2]; + } else { + screenCorner0 = targetCamera.WorldToScreenPoint(worldCorners[0]); + screenCorner1 = targetCamera.WorldToScreenPoint(worldCorners[3]); + screenCorner2 = targetCamera.WorldToScreenPoint(worldCorners[1]); + screenCorner3 = targetCamera.WorldToScreenPoint(worldCorners[2]); + } + + // To avoid perspective distortion when rotated, we project all vertices + // onto a plane parallel to the view frustum near plane. + // Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders. + float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f; + screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth; + + if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) { + worldCornerNoDistortion0 = screenCorner0; + worldCornerNoDistortion1 = screenCorner1; + worldCornerNoDistortion2 = screenCorner2; + worldCornerNoDistortion3 = screenCorner3; + } else { + worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0); + worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1); + worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2); + worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3); + } + Vector3 screenSpaceMin, screenSpaceMax; + PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax, + screenCorner0, screenCorner1, screenCorner2, screenCorner3); + PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax); + } + + protected Material MeshRendererMaterialForTexture (Texture texture) { + return meshRendererMaterialForTexture.Find(x => x.texture == texture).material; + } + + protected void RenderSingleMeshToRenderTexture (Mesh mesh, Material graphicMaterial, Texture texture) { + Material meshRendererMaterial = MeshRendererMaterialForTexture(texture); + commandBuffer.DrawMesh(mesh, transform.localToWorldMatrix, meshRendererMaterial, 0, -1); + Graphics.ExecuteCommandBuffer(commandBuffer); + } + + protected void RenderMultipleMeshesToRenderTexture (int meshCount, + Mesh[] meshes, Material[] graphicMaterials, Texture[] textures) { + + for (int i = 0; i < meshCount; ++i) { + Material meshRendererMaterial = MeshRendererMaterialForTexture(textures[i]); + commandBuffer.DrawMesh(meshes[i], transform.localToWorldMatrix, meshRendererMaterial, 0, -1); + } + Graphics.ExecuteCommandBuffer(commandBuffer); + } + + protected void SetupQuad () { + quadRawImage.texture = this.renderTexture; + quadRawImage.color = color; + quadCanvasRenderer.SetColor(color); + + var srcRectTransform = skeletonGraphic.rectTransform; + var dstRectTransform = quadRawImage.rectTransform; + + dstRectTransform.anchorMin = srcRectTransform.anchorMin; + dstRectTransform.anchorMax = srcRectTransform.anchorMax; + dstRectTransform.anchoredPosition = srcRectTransform.anchoredPosition; + dstRectTransform.pivot = srcRectTransform.pivot; + dstRectTransform.localScale = srcRectTransform.localScale; + dstRectTransform.sizeDelta = srcRectTransform.sizeDelta; + dstRectTransform.rotation = srcRectTransform.rotation; + } + + protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) { + commandBuffer.Clear(); + commandBuffer.SetRenderTarget(renderTexture); + commandBuffer.ClearRenderTarget(true, true, Color.clear); + + Rect canvasRect = skeletonGraphic.canvas.pixelRect; + + Matrix4x4 projectionMatrix = Matrix4x4.Ortho( + canvasRect.x, canvasRect.x + canvasRect.width, + canvasRect.y, canvasRect.y + canvasRect.height, + float.MinValue, float.MaxValue); + + RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode; + if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) { + commandBuffer.SetViewMatrix(Matrix4x4.identity); + commandBuffer.SetProjectionMatrix(projectionMatrix); + } else { + commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix); + commandBuffer.SetProjectionMatrix(targetCamera.projectionMatrix); + } + + Vector2 targetCameraViewportSize = targetCamera.pixelRect.size; + commandBuffer.SetViewport(new Rect(-screenSpaceMin, targetCameraViewportSize)); + } + + protected override void AssignMeshAtRenderer () { + quadCanvasRenderer.SetMesh(quadMesh); + } + } +} diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta new file mode 100644 index 000000000..7d3e6d8ed --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6cbe1f11426513d49ad8e21e9d6643f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs index 19c814c04..4ded9af01 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs @@ -35,7 +35,6 @@ #define HAS_GET_SHARED_MATERIALS #endif -using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; @@ -54,20 +53,11 @@ namespace Spine.Unity.Examples { public class SkeletonRenderTexture : SkeletonRenderTextureBase { #if HAS_GET_SHARED_MATERIALS public Material quadMaterial; - public Camera targetCamera; protected SkeletonRenderer skeletonRenderer; protected MeshRenderer meshRenderer; protected MeshFilter meshFilter; protected MeshRenderer quadMeshRenderer; protected MeshFilter quadMeshFilter; - protected Vector3 worldCornerNoDistortion0; - protected Vector3 worldCornerNoDistortion1; - protected Vector3 worldCornerNoDistortion2; - protected Vector3 worldCornerNoDistortion3; - protected Vector2 uvCorner0; - protected Vector2 uvCorner1; - protected Vector2 uvCorner2; - protected Vector2 uvCorner3; private MaterialPropertyBlock propertyBlock; private readonly List materials = new List(); @@ -160,40 +150,13 @@ namespace Spine.Unity.Examples { worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2); worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3); - Vector3 screenSpaceMin = - Vector3.Min(screenCorner0, Vector3.Min(screenCorner1, - Vector3.Min(screenCorner2, screenCorner3))); - Vector3 screenSpaceMax = - Vector3.Max(screenCorner0, Vector3.Max(screenCorner1, - Vector3.Max(screenCorner2, screenCorner3))); - // ensure we are on whole pixel borders - screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x); - screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y); - screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x); - screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y); - - // inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates - uvCorner0 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0); - uvCorner1 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1); - uvCorner2 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2); - uvCorner3 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3); - - requiredRenderTextureSize = new Vector2Int( - Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x)), - Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y))); - - PrepareRenderTexture(); + Vector3 screenSpaceMin, screenSpaceMax; + PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax, + screenCorner0, screenCorner1, screenCorner2, screenCorner3); PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax); } - protected Vector2 InverseLerp (Vector2 a, Vector2 b, Vector2 value) { - return new Vector2( - (value.x - a.x) / (b.x - a.x), - (value.y - a.y) / (b.y - a.y)); - } - protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) { - commandBuffer.Clear(); commandBuffer.SetRenderTarget(renderTexture); commandBuffer.ClearRenderTarget(true, true, Color.clear); @@ -214,40 +177,7 @@ namespace Spine.Unity.Examples { Graphics.ExecuteCommandBuffer(commandBuffer); } - protected void AssignAtQuad () { - Transform quadTransform = quadMeshRenderer.transform; - quadTransform.position = this.transform.position; - quadTransform.rotation = this.transform.rotation; - quadTransform.localScale = this.transform.localScale; - - Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0); - Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1); - Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2); - Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3); - Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 }; - - 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 / (float)allocatedRenderTextureSize.x; - float maxV = (float)requiredRenderTextureSize.y / (float)allocatedRenderTextureSize.y; - Vector2[] uv = new Vector2[4] { - new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV), - new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV), - new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV), - new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV), - }; - quadMesh.uv = uv; + protected override void AssignMeshAtRenderer () { quadMeshFilter.mesh = quadMesh; quadMeshRenderer.sharedMaterial.mainTexture = this.renderTexture; quadMeshRenderer.sharedMaterial.color = color; diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs index 9a6e13959..8842385ff 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs @@ -27,31 +27,33 @@ * 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_2018_2_OR_NEWER -#define HAS_GET_SHARED_MATERIALS -#endif - +using System; using UnityEngine; using UnityEngine.Rendering; namespace Spine.Unity.Examples { public abstract class SkeletonRenderTextureBase : MonoBehaviour { -#if HAS_GET_SHARED_MATERIALS public Color color = Color.white; public int maxRenderTextureSize = 1024; public GameObject quad; protected Mesh quadMesh; public RenderTexture renderTexture; + public Camera targetCamera; protected CommandBuffer commandBuffer; protected Vector2Int requiredRenderTextureSize; protected Vector2Int allocatedRenderTextureSize; + protected Vector3 worldCornerNoDistortion0; + protected Vector3 worldCornerNoDistortion1; + protected Vector3 worldCornerNoDistortion2; + protected Vector3 worldCornerNoDistortion3; + protected Vector2 uvCorner0; + protected Vector2 uvCorner1; + protected Vector2 uvCorner2; + protected Vector2 uvCorner3; + protected virtual void Awake () { commandBuffer = new CommandBuffer(); } @@ -61,6 +63,34 @@ namespace Spine.Unity.Examples { RenderTexture.ReleaseTemporary(renderTexture); } + protected void PrepareTextureMapping (out Vector3 screenSpaceMin, out Vector3 screenSpaceMax, + Vector3 screenCorner0, Vector3 screenCorner1, Vector3 screenCorner2, Vector3 screenCorner3) { + + screenSpaceMin = + Vector3.Min(screenCorner0, Vector3.Min(screenCorner1, + Vector3.Min(screenCorner2, screenCorner3))); + screenSpaceMax = + Vector3.Max(screenCorner0, Vector3.Max(screenCorner1, + Vector3.Max(screenCorner2, screenCorner3))); + // ensure we are on whole pixel borders + screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x); + screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y); + screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x); + screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y); + + // inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates + uvCorner0 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0); + uvCorner1 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1); + uvCorner2 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2); + uvCorner3 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3); + + requiredRenderTextureSize = new Vector2Int( + Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x)), + Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y))); + + PrepareRenderTexture(); + } + protected void PrepareRenderTexture () { Vector2Int textureSize = new Vector2Int( Mathf.NextPowerOfTwo(requiredRenderTextureSize.x), @@ -74,6 +104,44 @@ namespace Spine.Unity.Examples { allocatedRenderTextureSize = textureSize; } } -#endif + + protected void AssignAtQuad () { + Transform quadTransform = quad.transform; + quadTransform.position = this.transform.position; + quadTransform.rotation = this.transform.rotation; + quadTransform.localScale = this.transform.localScale; + + Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0); + Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1); + Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2); + Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3); + Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 }; + + quadMesh.vertices = vertices; + + int[] indices = new int[6] { 0, 1, 2, 2, 1, 3 }; + quadMesh.triangles = indices; + + Vector3[] normals = new Vector3[4] { + -Vector3.forward, + -Vector3.forward, + -Vector3.forward, + -Vector3.forward + }; + quadMesh.normals = normals; + + float maxU = (float)requiredRenderTextureSize.x / (float)allocatedRenderTextureSize.x; + float maxV = (float)requiredRenderTextureSize.y / (float)allocatedRenderTextureSize.y; + Vector2[] uv = new Vector2[4] { + new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV), + new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV), + new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV), + new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV), + }; + quadMesh.uv = uv; + AssignMeshAtRenderer(); + } + + protected abstract void AssignMeshAtRenderer (); } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta new file mode 100644 index 000000000..e63c652b4 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ccf9b5e5034b0ea45962f9cf32168dd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index fdadf6a72..01f9aa995 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -183,6 +183,59 @@ namespace Spine.Unity { #endregion #region Overrides + // API for taking over rendering. + /// When true, no meshes and materials are assigned at CanvasRenderers if the used override + /// AssignMeshOverrideSingleRenderer or AssignMeshOverrideMultipleRenderers is non-null. + public bool disableMeshAssignmentOnOverride = true; + /// Delegate type for overriding mesh and material assignment, + /// used when allowMultipleCanvasRenderers is false. + /// Mesh normally assigned at the main CanvasRenderer. + /// Material normally assigned at the main CanvasRenderer. + /// Texture normally assigned at the main CanvasRenderer. + public delegate void MeshAssignmentDelegateSingle (Mesh mesh, Material graphicMaterial, Texture texture); + /// Number of meshes. Don't use meshes.Length as this might be higher + /// due to pre-allocated entries. + /// Mesh array where each element is normally assigned to one of the canvasRenderers. + /// Material array where each element is normally assigned to one of the canvasRenderers. + /// Texture array where each element is normally assigned to one of the canvasRenderers. + public delegate void MeshAssignmentDelegateMultiple (int meshCount, Mesh[] meshes, Material[] graphicMaterials, Texture[] textures); + event MeshAssignmentDelegateSingle assignMeshOverrideSingle; + event MeshAssignmentDelegateMultiple assignMeshOverrideMultiple; + + /// Allows separate code to take over mesh and material assignment for this SkeletonGraphic component. + /// Used when allowMultipleCanvasRenderers is false. + public event MeshAssignmentDelegateSingle AssignMeshOverrideSingleRenderer { + add { + assignMeshOverrideSingle += value; + if (disableMeshAssignmentOnOverride && assignMeshOverrideSingle != null) { + Initialize(false); + } + } + remove { + assignMeshOverrideSingle -= value; + if (disableMeshAssignmentOnOverride && assignMeshOverrideSingle == null) { + Initialize(false); + } + } + } + /// Allows separate code to take over mesh and material assignment for this SkeletonGraphic component. + /// Used when allowMultipleCanvasRenderers is true. + public event MeshAssignmentDelegateMultiple AssignMeshOverrideMultipleRenderers { + add { + assignMeshOverrideMultiple += value; + if (disableMeshAssignmentOnOverride && assignMeshOverrideMultiple != null) { + Initialize(false); + } + } + remove { + assignMeshOverrideMultiple -= value; + if (disableMeshAssignmentOnOverride && assignMeshOverrideMultiple == null) { + Initialize(false); + } + } + } + + [System.NonSerialized] readonly Dictionary customTextureOverride = new Dictionary(); /// Use this Dictionary to override a Texture with a different Texture. public Dictionary CustomTextureOverride { get { return customTextureOverride; } } @@ -334,6 +387,8 @@ namespace Spine.Unity { if (updateMode != UpdateMode.FullUpdate) return; PrepareInstructionsAndRenderers(); + if (OnInstructionsPrepared != null) + OnInstructionsPrepared(this.currentInstructions); SetVerticesDirty(); // triggers Rebuild and avoids potential double-update in a single frame } @@ -390,13 +445,21 @@ namespace Spine.Unity { public bool IsValid { get { return skeleton != null; } } public delegate void SkeletonRendererDelegate (SkeletonGraphic skeletonGraphic); + public delegate void InstructionDelegate (SkeletonRendererInstruction instruction); /// OnRebuild is raised after the Skeleton is successfully initialized. public event SkeletonRendererDelegate OnRebuild; - /// OnMeshAndMaterialsUpdated is at the end of LateUpdate after the Mesh and - /// all materials have been updated. + /// OnInstructionsPrepared is raised at the end of LateUpdate after render instructions + /// are done, target renderers are prepared, and the mesh is ready to be generated. + public event InstructionDelegate OnInstructionsPrepared; + + /// OnMeshAndMaterialsUpdated is raised at the end of Rebuild after the Mesh and + /// all materials have been updated. Note that some Unity API calls are not permitted to be issued from + /// Rebuild, so you may want to subscribe to instead + /// from where you can issue such preparation calls. public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated; + //FIXXME: perform some final checks on documentation and changes, then finalize these changes and commit. then integrate in 4.0_cleanup project as well. protected Spine.AnimationState state; public Spine.AnimationState AnimationState { @@ -411,6 +474,12 @@ namespace Spine.Unity { DoubleBuffered meshBuffers; SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction(); readonly ExposedList meshes = new ExposedList(); + readonly ExposedList usedMaterials = new ExposedList(); + readonly ExposedList usedTextures = new ExposedList(); + + public ExposedList MeshesMultipleCanvasRenderers { get { return meshes; } } + public ExposedList MaterialsMultipleCanvasRenderers { get { return usedMaterials; } } + public ExposedList TexturesMultipleCanvasRenderers { get { return usedTextures; } } public Mesh GetLastMesh () { return meshBuffers.GetCurrent().mesh; @@ -513,6 +582,8 @@ namespace Spine.Unity { for (int i = 0; i < canvasRenderers.Count; ++i) canvasRenderers[i].Clear(); DestroyMeshes(); + usedMaterials.Clear(); + usedTextures.Clear(); DisposeMeshBuffers(); } @@ -601,6 +672,7 @@ namespace Spine.Unity { int submeshCount = currentInstructions.submeshInstructions.Count; EnsureCanvasRendererCount(submeshCount); EnsureMeshesCount(submeshCount); + EnsureUsedTexturesAndMaterialsCount(submeshCount); EnsureSeparatorPartCount(); PrepareRendererGameObjects(currentInstructions); } @@ -618,6 +690,7 @@ namespace Spine.Unity { if (!this.allowMultipleCanvasRenderers) { UpdateMeshSingleCanvasRenderer(currentInstructions); } else { + UpdateMaterialsMultipleCanvasRenderers(currentInstructions); UpdateMeshMultipleCanvasRenderers(currentInstructions); } @@ -675,19 +748,67 @@ namespace Spine.Unity { if (updateTriangles) meshGenerator.FillTriangles(mesh); meshGenerator.FillLateVertexData(mesh); - canvasRenderer.SetMesh(mesh); smartMesh.instructionUsed.Set(currentInstructions); + if (assignMeshOverrideSingle != null) + assignMeshOverrideSingle(mesh, this.canvasRenderer.GetMaterial(), this.mainTexture); + + bool assignAtCanvasRenderer = (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride); + if (assignAtCanvasRenderer) + canvasRenderer.SetMesh(mesh); + else + canvasRenderer.SetMesh(null); if (currentInstructions.submeshInstructions.Count > 0) { var material = currentInstructions.submeshInstructions.Items[0].material; if (material != null && baseTexture != material.mainTexture) { baseTexture = material.mainTexture; - if (overrideTexture == null) + if (overrideTexture == null && assignAtCanvasRenderer) canvasRenderer.SetTexture(this.mainTexture); } } + } - //this.UpdateMaterial(); // note: This would allocate memory. + protected void UpdateMaterialsMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) { + int submeshCount = currentInstructions.submeshInstructions.Count; + bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0); + + BlendModeMaterials blendModeMaterials = skeletonDataAsset.blendModeMaterials; + bool hasBlendModeMaterials = blendModeMaterials.RequiresBlendModeMaterials; + + bool pmaVertexColors = meshGenerator.settings.pmaVertexColors; + Material[] usedMaterialItems = usedMaterials.Items; + Texture[] usedTextureItems = usedTextures.Items; + for (int i = 0; i < submeshCount; i++) { + var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i]; + var submeshMaterial = submeshInstructionItem.material; + if (useOriginalTextureAndMaterial) { + usedTextureItems[i] = submeshMaterial.mainTexture; + if (!hasBlendModeMaterials) { + usedMaterialItems[i] = this.materialForRendering; + } else { + BlendMode blendMode = blendModeMaterials.BlendModeForMaterial(submeshMaterial); + Material usedMaterial = this.materialForRendering; + if (blendMode == BlendMode.Additive && !pmaVertexColors && additiveMaterial) { + usedMaterial = additiveMaterial; + } else if (blendMode == BlendMode.Multiply && multiplyMaterial) + usedMaterial = multiplyMaterial; + else if (blendMode == BlendMode.Screen && screenMaterial) + usedMaterial = screenMaterial; + usedMaterialItems[i] = submeshGraphics[i].GetModifiedMaterial(usedMaterial); + } + } else { + var originalTexture = submeshMaterial.mainTexture; + Material usedMaterial; + Texture usedTexture; + if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial)) + usedMaterial = material; + if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture)) + usedTexture = originalTexture; + + usedMaterialItems[i] = submeshGraphics[i].GetModifiedMaterial(usedMaterial); + usedTextureItems[i] = usedTexture; + } + } } protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) { @@ -705,6 +826,9 @@ namespace Spine.Unity { bool mainCullTransparentMesh = this.canvasRenderer.cullTransparentMesh; #endif bool pmaVertexColors = meshGenerator.settings.pmaVertexColors; + Material[] usedMaterialItems = usedMaterials.Items; + Texture[] usedTextureItems = usedTextures.Items; + bool assignAtCanvasRenderer = (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride); for (int i = 0; i < submeshCount; i++) { var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i]; meshGenerator.Begin(); @@ -717,53 +841,31 @@ namespace Spine.Unity { meshGenerator.FillTriangles(targetMesh); meshGenerator.FillLateVertexData(targetMesh); - var submeshMaterial = submeshInstructionItem.material; var canvasRenderer = canvasRenderers[i]; - canvasRenderer.SetMesh(targetMesh); - canvasRenderer.materialCount = 1; + if (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride) + canvasRenderer.SetMesh(targetMesh); + else + canvasRenderer.SetMesh(null); SkeletonSubmeshGraphic submeshGraphic = submeshGraphics[i]; - if (useOriginalTextureAndMaterial) { - Texture usedTexture = submeshMaterial.mainTexture; - if (!hasBlendModeMaterials) - canvasRenderer.SetMaterial(this.materialForRendering, usedTexture); - else { - bool allowCullTransparentMesh = true; - BlendMode blendMode = blendModeMaterials.BlendModeForMaterial(submeshMaterial); - Material usedMaterial = this.materialForRendering; - if (blendMode == BlendMode.Normal) { - if (submeshInstructionItem.hasPMAAdditiveSlot) - allowCullTransparentMesh = false; - } else if (blendMode == BlendMode.Additive) { - if (pmaVertexColors) - allowCullTransparentMesh = false; - else if (additiveMaterial) - usedMaterial = additiveMaterial; - } else if (blendMode == BlendMode.Multiply && multiplyMaterial) - usedMaterial = multiplyMaterial; - else if (blendMode == BlendMode.Screen && screenMaterial) - usedMaterial = screenMaterial; - - usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial); - canvasRenderer.SetMaterial(usedMaterial, usedTexture); -#if HAS_CULL_TRANSPARENT_MESH - canvasRenderer.cullTransparentMesh = allowCullTransparentMesh ? - mainCullTransparentMesh : false; -#endif + if (useOriginalTextureAndMaterial && hasBlendModeMaterials) { + bool allowCullTransparentMesh = true; + BlendMode materialBlendMode = blendModeMaterials.BlendModeForMaterial(usedMaterialItems[i]); + if ((materialBlendMode == BlendMode.Normal && submeshInstructionItem.hasPMAAdditiveSlot) || + (materialBlendMode == BlendMode.Additive && pmaVertexColors)) { + allowCullTransparentMesh = false; } - } else { - var originalTexture = submeshMaterial.mainTexture; - Material usedMaterial; - Texture usedTexture; - if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial)) - usedMaterial = material; - if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture)) - usedTexture = originalTexture; - - usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial); - canvasRenderer.SetMaterial(usedMaterial, usedTexture); +#if HAS_CULL_TRANSPARENT_MESH + canvasRenderer.cullTransparentMesh = allowCullTransparentMesh ? + mainCullTransparentMesh : false; +#endif } + canvasRenderer.materialCount = 1; + if (assignAtCanvasRenderer) + canvasRenderer.SetMaterial(usedMaterialItems[i], usedTextureItems[i]); } + if (assignMeshOverrideMultiple != null) + assignMeshOverrideMultiple(submeshCount, meshesItems, usedMaterialItems, usedTextureItems); } protected void EnsureCanvasRendererCount (int targetCount) { @@ -856,6 +958,16 @@ namespace Spine.Unity { meshes.Add(SpineMesh.NewSkeletonMesh()); } + protected void EnsureUsedTexturesAndMaterialsCount (int targetCount) { + int oldCount = usedMaterials.Count; + usedMaterials.EnsureCapacity(targetCount); + usedTextures.EnsureCapacity(targetCount); + for (int i = oldCount; i < targetCount; i++) { + usedMaterials.Add(null); + usedTextures.Add(null); + } + } + protected void DestroyMeshes () { foreach (var mesh in meshes) { #if UNITY_EDITOR diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs new file mode 100644 index 000000000..1879e2d4b --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs @@ -0,0 +1,71 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +using UnityEngine; + +namespace Spine.Unity { + public static class MathUtilities { + public static float InverseLerp (float a, float b, float value) { + return (value - a) / (b - a); + } + + /// + /// Returns the linear interpolation ratio of a to b that value lies on. + /// This is the t value that fulfills value = lerp(a, b, t). + /// + public static Vector2 InverseLerp (Vector2 a, Vector2 b, Vector2 value) { + return new Vector2( + (value.x - a.x) / (b.x - a.x), + (value.y - a.y) / (b.y - a.y)); + } + + /// + /// Returns the linear interpolation ratio of a to b that value lies on. + /// This is the t value that fulfills value = lerp(a, b, t). + /// + public static Vector3 InverseLerp (Vector3 a, Vector3 b, Vector3 value) { + return new Vector3( + (value.x - a.x) / (b.x - a.x), + (value.y - a.y) / (b.y - a.y), + (value.z - a.z) / (b.z - a.z)); + } + + /// + /// Returns the linear interpolation ratio of a to b that value lies on. + /// This is the t value that fulfills value = lerp(a, b, t). + /// + public static Vector4 InverseLerp (Vector4 a, Vector4 b, Vector4 value) { + return new Vector4( + (value.x - a.x) / (b.x - a.x), + (value.y - a.y) / (b.y - a.y), + (value.z - a.z) / (b.z - a.z), + (value.w - a.w) / (b.w - a.w)); + } + } +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta new file mode 100644 index 000000000..9e0d973d7 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef2b5da9383ed474d895b702a9baf79e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 005e714534004213c7095334aad81cf66168977c Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 2 Aug 2022 16:19:34 +0200 Subject: [PATCH 2/9] [unity] Fixed compile error of previous commit regarding Vector2Int on Unity 2017.1. --- .../SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs | 6 ++++++ .../SkeletonRenderTexture/SkeletonRenderTextureBase.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs index af30ad8e7..5587bced2 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs @@ -27,6 +27,10 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#if UNITY_2017_2_OR_NEWER +#define HAS_VECTOR2INT +#endif + using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; @@ -44,6 +48,7 @@ namespace Spine.Unity.Examples { /// [RequireComponent(typeof(SkeletonGraphic))] public class SkeletonGraphicRenderTexture : SkeletonRenderTextureBase { +#if HAS_VECTOR2INT [System.Serializable] public struct TextureMaterialPair { public Texture texture; @@ -249,5 +254,6 @@ namespace Spine.Unity.Examples { protected override void AssignMeshAtRenderer () { quadCanvasRenderer.SetMesh(quadMesh); } +#endif // HAS_VECTOR2INT } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs index 8842385ff..bdd84d153 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs @@ -31,9 +31,14 @@ using System; using UnityEngine; using UnityEngine.Rendering; +#if UNITY_2017_2_OR_NEWER +#define HAS_VECTOR2INT +#endif + namespace Spine.Unity.Examples { public abstract class SkeletonRenderTextureBase : MonoBehaviour { +#if HAS_VECTOR2INT public Color color = Color.white; public int maxRenderTextureSize = 1024; public GameObject quad; @@ -143,5 +148,6 @@ namespace Spine.Unity.Examples { } protected abstract void AssignMeshAtRenderer (); +#endif // HAS_VECTOR2INT } } From 10d71afe57b0df245700ee0bb8db8bc8019e7499 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 2 Aug 2022 16:24:24 +0200 Subject: [PATCH 3/9] [unity] Minor fix of last commit. --- .../SkeletonRenderTexture/SkeletonRenderTextureBase.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs index bdd84d153..0413d8b4a 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs @@ -27,14 +27,14 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using UnityEngine; -using UnityEngine.Rendering; - #if UNITY_2017_2_OR_NEWER #define HAS_VECTOR2INT #endif +using System; +using UnityEngine; +using UnityEngine.Rendering; + namespace Spine.Unity.Examples { public abstract class SkeletonRenderTextureBase : MonoBehaviour { From 4386cb8c8eca5f1583845266b1ff21a54e811c40 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 3 Aug 2022 07:14:08 +0200 Subject: [PATCH 4/9] Update README.md --- spine-godot/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spine-godot/README.md b/spine-godot/README.md index bb4609b03..4a987cbf5 100644 --- a/spine-godot/README.md +++ b/spine-godot/README.md @@ -2,7 +2,7 @@ The spine-godot runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Godot](https://godotengine.org/). spine-godot is based on [spine-cpp](../spine-cpp). -# See the [spine-godot documentation](http://esotericsoftware.com/spine-godot]) for in-depth information. +# See the [spine-godot documentation](http://esotericsoftware.com/spine-godot) for in-depth information. ## Licensing From b0a609f027ce612bd44003bc9d59c0463163361c Mon Sep 17 00:00:00 2001 From: Pol <36154612+PolRecasensSarra@users.noreply.github.com> Date: Wed, 3 Aug 2022 18:31:40 +0200 Subject: [PATCH 5/9] Corrected Tint black (#2122) Tint black wasn't working correctly because the red channelwas discarded by error, replacing it by the green channel. --- spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index 8184ff13b..80a88c8d0 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -967,7 +967,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) { toColor(color2, Json::getString(keyMap, "dark", 0), false); for (frame = 0, bezier = 0;; ++frame) { - timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.g, color2.g, color2.b); + timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b); nextMap = keyMap->_next; if (!nextMap) { // timeline.shrink(); // BOZO From 1485bb47087caccc8a5171f990806c1b5b907858 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Wed, 3 Aug 2022 19:16:07 +0200 Subject: [PATCH 6/9] [unity] Minor cleanup: removed a leftover resolved fixxme line. --- .../Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index 01f9aa995..64dd609f8 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -459,7 +459,6 @@ namespace Spine.Unity { /// Rebuild, so you may want to subscribe to instead /// from where you can issue such preparation calls. public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated; - //FIXXME: perform some final checks on documentation and changes, then finalize these changes and commit. then integrate in 4.0_cleanup project as well. protected Spine.AnimationState state; public Spine.AnimationState AnimationState { From d9696997acaca7ebee0e9879b6fa2d2b385c44c8 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 5 Aug 2022 08:50:04 +0200 Subject: [PATCH 7/9] [threejs] Fixes #2108, create CanvasTexture for ImageBitmap. --- spine-ts/spine-threejs/src/ThreeJsTexture.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spine-ts/spine-threejs/src/ThreeJsTexture.ts b/spine-ts/spine-threejs/src/ThreeJsTexture.ts index aef066548..be48c3013 100644 --- a/spine-ts/spine-threejs/src/ThreeJsTexture.ts +++ b/spine-ts/spine-threejs/src/ThreeJsTexture.ts @@ -35,8 +35,10 @@ export class ThreeJsTexture extends Texture { constructor (image: HTMLImageElement | ImageBitmap) { super(image); - if (image instanceof ImageBitmap) throw new Error("ImageBitmap not supported."); - this.texture = new THREE.Texture(image); + if (image instanceof ImageBitmap) + this.texture = new THREE.CanvasTexture(image); + else + this.texture = new THREE.Texture(image); this.texture.flipY = false; this.texture.needsUpdate = true; } From 3e0349e94ff61a8178cf67ac271a9f6dee7d5e74 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 5 Aug 2022 08:51:03 +0200 Subject: [PATCH 8/9] [c] Formatting. --- spine-sdl/example/main.c | 4 ++-- spine-sdl/example/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spine-sdl/example/main.c b/spine-sdl/example/main.c index 8992a0ef1..fa010d513 100644 --- a/spine-sdl/example/main.c +++ b/spine-sdl/example/main.c @@ -51,14 +51,14 @@ int main() { json->scale = 0.5f; spSkeletonData *skeletonData = spSkeletonJson_readSkeletonDataFile(json, "data/spineboy-pro.json"); spAnimationStateData *animationStateData = spAnimationStateData_create(skeletonData); - animationStateData->defaultMix = 0.2f; + animationStateData->defaultMix = 0.2f; spSkeletonDrawable *drawable = spSkeletonDrawable_create(skeletonData, animationStateData); drawable->skeleton->x = 400; drawable->skeleton->y = 500; spSkeleton_setToSetupPose(drawable->skeleton); spSkeletonDrawable_update(drawable, 0); spAnimationState_setAnimationByName(drawable->animationState, 0, "portal", 0); - spAnimationState_addAnimationByName(drawable->animationState, 0, "run", -1, 0); + spAnimationState_addAnimationByName(drawable->animationState, 0, "run", -1, 0); int quit = 0; uint64_t lastFrameTime = SDL_GetPerformanceCounter(); diff --git a/spine-sdl/example/main.cpp b/spine-sdl/example/main.cpp index 50083a6b8..89a69a556 100644 --- a/spine-sdl/example/main.cpp +++ b/spine-sdl/example/main.cpp @@ -53,11 +53,11 @@ int main() { json.setScale(0.5f); spine::SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json"); spine::SkeletonDrawable drawable(skeletonData); - drawable.animationState->getData()->setDefaultMix(0.2f); + drawable.animationState->getData()->setDefaultMix(0.2f); drawable.skeleton->setPosition(400, 500); drawable.skeleton->setToSetupPose(); drawable.update(0); - drawable.animationState->setAnimation(0, "portal", true); + drawable.animationState->setAnimation(0, "portal", true); drawable.animationState->addAnimation(0, "run", true, 0); bool quit = false; From 3387a470b3ba64e7fdeacb5d2ef0d0f10ecf4cdf Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 5 Aug 2022 08:53:39 +0200 Subject: [PATCH 9/9] [ts] Release 4.1.20. --- spine-ts/package-lock.json | 54 ++++++++++++++--------------- spine-ts/package.json | 2 +- spine-ts/spine-canvas/package.json | 4 +-- spine-ts/spine-core/package.json | 2 +- spine-ts/spine-player/package.json | 4 +-- spine-ts/spine-threejs/package.json | 4 +-- spine-ts/spine-webgl/package.json | 4 +-- 7 files changed, 37 insertions(+), 37 deletions(-) diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json index 1699c752f..93b24fe59 100644 --- a/spine-ts/package-lock.json +++ b/spine-ts/package-lock.json @@ -1,12 +1,12 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.1.19", + "version": "4.1.20", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@esotericsoftware/spine-ts", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE", "workspaces": [ "spine-core", @@ -603,9 +603,9 @@ } }, "node_modules/date-fns": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", - "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz", + "integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==", "dev": true, "engines": { "node": ">=0.11" @@ -1129,9 +1129,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/inflight": { @@ -7967,41 +7967,41 @@ }, "spine-canvas": { "name": "@esotericsoftware/spine-canvas", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } }, "spine-core": { "name": "@esotericsoftware/spine-core", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE" }, "spine-player": { "name": "@esotericsoftware/spine-player", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-webgl": "^4.1.19" + "@esotericsoftware/spine-webgl": "^4.1.20" } }, "spine-threejs": { "name": "@esotericsoftware/spine-threejs", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.19", + "@esotericsoftware/spine-core": "^4.1.20", "@types/three": "^0.140.0", "three": "^0.140.0" } }, "spine-webgl": { "name": "@esotericsoftware/spine-webgl", - "version": "4.1.19", + "version": "4.1.20", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } } }, @@ -8009,7 +8009,7 @@ "@esotericsoftware/spine-canvas": { "version": "file:spine-canvas", "requires": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } }, "@esotericsoftware/spine-core": { @@ -8018,13 +8018,13 @@ "@esotericsoftware/spine-player": { "version": "file:spine-player", "requires": { - "@esotericsoftware/spine-webgl": "^4.1.19" + "@esotericsoftware/spine-webgl": "^4.1.20" } }, "@esotericsoftware/spine-threejs": { "version": "file:spine-threejs", "requires": { - "@esotericsoftware/spine-core": "^4.1.19", + "@esotericsoftware/spine-core": "^4.1.20", "@types/three": "^0.140.0", "three": "^0.140.0" } @@ -8032,7 +8032,7 @@ "@esotericsoftware/spine-webgl": { "version": "file:spine-webgl", "requires": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } }, "@types/offscreencanvas": { @@ -8484,9 +8484,9 @@ } }, "date-fns": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", - "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz", + "integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==", "dev": true }, "debug": { @@ -8900,9 +8900,9 @@ } }, "http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "inflight": { diff --git a/spine-ts/package.json b/spine-ts/package.json index dcd0b7f75..df1b7aeef 100644 --- a/spine-ts/package.json +++ b/spine-ts/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "files": [ "README.md" diff --git a/spine-ts/spine-canvas/package.json b/spine-ts/spine-canvas/package.json index 5f0cf533d..4e70671e0 100644 --- a/spine-ts/spine-canvas/package.json +++ b/spine-ts/spine-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-canvas", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } } \ No newline at end of file diff --git a/spine-ts/spine-core/package.json b/spine-ts/spine-core/package.json index d924a7fe2..6cfcd02c3 100644 --- a/spine-ts/spine-core/package.json +++ b/spine-ts/spine-core/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-core", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/spine-ts/spine-player/package.json b/spine-ts/spine-player/package.json index b64718b6a..5ba5ada69 100644 --- a/spine-ts/spine-player/package.json +++ b/spine-ts/spine-player/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-player", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-webgl": "^4.1.19" + "@esotericsoftware/spine-webgl": "^4.1.20" } } \ No newline at end of file diff --git a/spine-ts/spine-threejs/package.json b/spine-ts/spine-threejs/package.json index 7d6265c91..a50b9746e 100644 --- a/spine-ts/spine-threejs/package.json +++ b/spine-ts/spine-threejs/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-threejs", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -32,6 +32,6 @@ "dependencies": { "@types/three": "^0.140.0", "three": "^0.140.0", - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } } \ No newline at end of file diff --git a/spine-ts/spine-webgl/package.json b/spine-ts/spine-webgl/package.json index 7a9f57201..f4ad4e80b 100644 --- a/spine-ts/spine-webgl/package.json +++ b/spine-ts/spine-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-webgl", - "version": "4.1.19", + "version": "4.1.20", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,6 +30,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "^4.1.19" + "@esotericsoftware/spine-core": "^4.1.20" } } \ No newline at end of file