From 8c009e2f56e33c6585ca40d423f4d5cf9928f904 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 23 Jul 2020 16:22:03 +0200 Subject: [PATCH 01/13] [unity] Added Timeline support for SkeletonGraphic. Fixed multi-track Timeline preview when scrubbing in the Editor (note: requires ascending track ordering). Closes #1313. Closes #1724. --- .../Documentation/README.md | 67 +++++++++---- .../Documentation/add-menu.png | Bin 6225 -> 21986 bytes .../animationstate-clip-inspector.png | Bin 31785 -> 45137 bytes .../animationstate-track-inspector.png | Bin 0 -> 9906 bytes .../animationstate-track-inspector.png.meta | 94 ++++++++++++++++++ .../Documentation/animationstate-track.png | Bin 0 -> 24841 bytes .../animationstate-track.png.meta | 74 ++++++++++++++ .../skeleton-flip-clip-inspector.png | Bin 5074 -> 17788 bytes .../Documentation/skeleton-flip-track.png | Bin 0 -> 24580 bytes .../skeleton-flip-track.png.meta | 74 ++++++++++++++ .../Documentation/timeline.png | Bin 23439 -> 26066 bytes .../Documentation/timeline.png.meta | 74 ++++++++++++++ .../Editor/SpineAnimationStateDrawer.cs | 6 +- ...pineAnimationStateGraphicTrackInspector.cs | 52 ++++++++++ ...nimationStateGraphicTrackInspector.cs.meta | 12 +++ .../Editor/SpineSkeletonFlipDrawer.cs | 2 +- .../SkeletonAnimationPlayableHandle.cs | 11 +- .../SkeletonGraphicPlayableHandle.cs | 70 +++++++++++++ .../SkeletonGraphicPlayableHandle.cs.meta | 12 +++ .../SpinePlayableHandleBase.cs | 24 ++--- .../SpineAnimationStateGraphicTrack.cs | 48 +++++++++ .../SpineAnimationStateGraphicTrack.cs.meta | 12 +++ .../SpineAnimationStateMixerBehaviour.cs | 57 +++++++---- .../package.json | 2 +- 24 files changed, 634 insertions(+), 57 deletions(-) create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track.png create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track.png.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/skeleton-flip-track.png create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/skeleton-flip-track.png.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/timeline.png.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs.meta create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs create mode 100644 spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs.meta diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md index ab1c21bf1..5fd9eebc4 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md @@ -4,19 +4,36 @@ The latest version of this documentation can also be found at the [spine-unity R ![](timeline.png) -Timeline support is provided as a separate UPM (Unity Package Manager) package. See section [Optional - Installing Extension UPM Packages](http://esotericsoftware.com/spine-unity#Optional---Installing-Extension-UPM-Packages) on how to download and install this package and section [Updating an Extension UPM Package](http://esotericsoftware.com/spine-unity#Updating-an-Extension-UPM-Package) on how to update it. +Timeline support is provided as a separate UPM (Unity Package Manager) package. See section [Optional Extension UPM Packages](http://esotericsoftware.com/spine-unity#Optional-Extension-UPM-Packages) on how to download and install this package and section [Updating an Extension UPM Package](http://esotericsoftware.com/spine-unity#Updating-an-Extension-UPM-Package) on how to update it. ## Spine-Unity Timeline Playables ![](add-menu.png) -Spine Timeline currently provides two types of Timeline Playables: `Spine AnimationState Track` and `Spine Skeleton Flip Track`, described below. +Spine Timeline currently provides three types of Timeline Playables: +- `Spine AnimationState Track` *(for `SkeletonAnimation`)*, +- `Spine AnimationState Graphic Track` *(for `SkeletonGraphic`)*, +- `Spine Skeleton Flip Track` *(for both `SkeletonAnimation` and `SkeletonGraphic`)*. -**Limitations:** currently only [SkeletonAnimation](http://esotericsoftware.com/spine-unity#SkeletonAnimation-Component) is supported. You can find an implementation for [SkeletonGraphic](http://esotericsoftware.com/spine-unity#SkeletonGraphic-Component) kindly provided by a forum user on [this forum thread](http://zh.esotericsoftware.com/forum/Spine-timeline-plugin-for-2019-1-12000). +**Limitations:** currently only [SkeletonAnimation](http://esotericsoftware.com/spine-unity#SkeletonAnimation-Component) and [SkeletonGraphic](http://esotericsoftware.com/spine-unity#SkeletonGraphic-Component) are supported. There is currently no Timeline support for [SkeletonMecanim](http://esotericsoftware.com/spine-unity#SkeletonMecanim-Component). ### Spine AnimationState Track + +![](animationstate-track.png) + +This track type can be used to set animations at the AnimationState of the target `SkeletonAnimation` or `SkeletonGraphic`. Track type `Spine AnimationState Track` is used for `SkeletonAnimation`, `Spine AnimationState Graphic Track` for `SkeletonGraphic`. + +![](animationstate-track-inspector.png) + +**Parameters** +- *Track Index.* The target AnimationState track index to set animations at. Do not forget to set this value accordingly when using multiple timeline tracks. +> **Important Note:** Currently it is required to order the timeline tracks with base track at the top and overlay tracks below, otherwise the Editor Preview will display incorrect results. + +#### Spine Animation State Clip + +You can add a `Spine Animation State Clip` to a `Spine AnimationState Track` (or `Spine AnimationState Graphic Track`) by dragging an `AnimationReferenceAsset` onto a Timeline track. See the [SkeletonData - Preview](http://esotericsoftware.com/spine-unity#Preview) section on how to generate `AnimationReferenceAssets` for a `SkeletonDataAsset`. + ![](animationstate-clip-inspector.png) -This track type can be used to set animations on the target SkeletonAnimation's AnimationState. **Parameters** - *Clip In.* An initial local start time offset applied when playing this animation. Can also be adjusted by dragging the left edge of the clip. @@ -33,34 +50,42 @@ This track type can be used to set animations on the target SkeletonAnimation's - *Ease Out Duration, Blend Curves*. These parameters are ignored and have no effect. **Usage** -1. Add `SkeletonAnimationPlayableHandle` component to your SkeletonAnimation GameObject. +1. Add `SkeletonAnimationPlayableHandle` component to your SkeletonAnimation GameObject, or the `SkeletonGraphicPlayableHandle` in case of `SkeletonGraphic`. 2. With an existing Unity Playable Director, and in the Unity Timeline window, right-click on an empty space on the left and choose `Spine.Unity.Playables` - `Spine Animation State Track`. -3. Drag the SkeletonAnimation GameObject onto the empty reference property of the new Spine AnimationState Track. -4. Right-click on the row in an empty space in the Timeline dopesheet and choose `Add Spine Animation State Clip Clip`. -5. Adjust the start and end times of the new clip, name it appropriately at the top of the Inspector. -6. Click on the clip inspector's SkeletonDataAsset field and choose your target skeleton's SkeletonDataAsset. This will enable the animation name dropdown to appear. -7. Choose the appropriate animation name, loop, and mix settings. -8. For easier readability, rename your clip to the animation name or something descriptive. +3. Drag the SkeletonAnimation or SkeletonGraphic GameObject onto the empty reference property of the new Spine AnimationState Track. +4. To add an animation at a track, drag the respective [`AnimationReferenceAsset`](http://esotericsoftware.com/spine-unity#Preview) into the clips view (the right part of the Timeline panel) as you would with normal animation clips. -> **Note:** To avoid having to do steps 4-6 repeatedly, use the Duplicate function (`CTRL`/`CMD` + `D`) +See spine-unity Runtime Documentation, [section Preview](http://esotericsoftware.com/spine-unity#Preview) on how to create an `AnimationReferenceAsset` for each of your animations. + +> **Note:** You can use the Duplicate function (`CTRL`/`CMD` + `D`) to duplicate selected clips in the clips view. **Track Behavior** -- `AnimationState.SetAnimation` will be called at the beginning of every clip based on the animationName. +- `AnimationState.SetAnimation` will be called at the beginning of every clip based on the `AnimationReferenceAsset`. - Clip durations don't matter. Animations won't be cleared where there is no active clip at certain slices of time. -- Empty animation: If a clip has no name specified, it will call SetEmptyAnimation instead. -- Error handling: If the animation with the provided animationName is not found, it will do nothing (the previous animation will continue playing normally). +- Empty animation: If a clip has no `AnimationReferenceAsset` assigned, it will call `SetEmptyAnimation` instead. +- Error handling: If the animation with the provided `AnimationReferenceAsset` is not found, it will do nothing (the previous animation will continue playing normally). - Animations playing before the timeline starts playing will not be interrupted until the first clip starts playing. -- At the end of the last clip and at the end of the timeline, nothing happens. This means the effect of the last clip's SetAnimation call will persist until you give other commands to that AnimationState. -- Edit mode preview mixing may look different from Play Mode mixing. Please check in actual Play Mode to see the real results. +- At the end of the last clip and at the end of the timeline, nothing happens. This means the effect of the last clip's `SetAnimation` call will persist until you issue other calls at the AnimationState. +- Edit mode preview mixing may look different from Play Mode mixing. Please check in actual Play Mode to see the actual results. Please see the remark in the [Spine AnimationState Track](#Spine-AnimationState-Track) section on correct track ordering when previewing multiple overlaid tracks. ### Spine Skeleton Flip Track + +![](skeleton-flip-track.png) + +This track type can be used to flip the skeleton of the target `SkeletonAnimation` or `SkeletonGraphic`. + +#### Spine Skeleton Flip Clip + ![](skeleton-flip-clip-inspector.png) -This track type can be used to flip the skeleton of the target SkeletonAnimation. + +**Parameters** +- *Flip X.* Flips the skeleton along the X axis during the extents of the clip. +- *Flip Y.* Flips the skeleton along the Y axis during the extents of the clip. **Usage** -1. Add `SkeletonAnimationPlayableHandle` component to your SkeletonAnimation GameObject. +1. Add `SkeletonAnimationPlayableHandle` component to your SkeletonAnimation GameObject, or the `SkeletonGraphicPlayableHandle` in case of `SkeletonGraphic`. 2. With an existing Unity Playable Director, and in the Unity Timeline window, right-click on an empty space on the left and choose `Spine.Unity.Playables` - `Spine Skeleton Flip Track`. -3. Drag the SkeletonAnimation GameObject onto the empty reference property of the new Spine Skeleton Flip Track. +3. Drag the SkeletonAnimation or SkeletonGraphic GameObject onto the empty reference property of the new Spine Skeleton Flip Track. 4. Right-click on the row in an empty space in the Timeline dopesheet and choose `Add Spine Skeleton Flip Clip Clip`. 5. Adjust the start and end times of the new clip, name it appropriately at the top of the Inspector, and choose the desired FlipX and FlipY values. @@ -69,7 +94,7 @@ This track type can be used to flip the skeleton of the target SkeletonAnimation - At the end of the timeline, the track will revert the skeleton flip to the flip values it captures when it starts playing that timeline. ### Known Issues -- The Console potentially logs an incorrect/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/ +- 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/ - These Spine Tracks (like other custom Unity Timeline Playable types) do not have labels on them. Unity currently doesn't have API to specify their labels yet. - Each track clip currently requires you to specify a reference to SkeletonData so its inspector can show you a convenient list of animation names. This is because track clips are agnostic of its track and target component/track binding, and provides no way of automatically finding it while in the editor. The clips will still function correctly without the SkeletonDataAsset references; you just won't get the dropdown of animation names in the editor. - Each track clip cannot be automatically named based on the chosen animationName. The Timeline object editors currently doesn't provide access to the clip names to do this automatically. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/add-menu.png b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/add-menu.png index f2277f2fbde581ceba213a1a85aa313dcbc22735..92ad84b7c1afbfa3aa5bdd35eacfa23728e944ae 100644 GIT binary patch delta 19430 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 delta 3545 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

L6c3Sm{+NKHrA2*7nwK|wOTt3At5443*5 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 KkP{|TR{wtsWn@3`LY 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 G$m74{rjH^3 delta 20895 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 + InitializeReference(); } #endif @@ -56,6 +59,10 @@ namespace Spine.Unity.Playables { public override SkeletonData SkeletonData { get { return skeletonAnimation.Skeleton.Data; } } void Awake () { + InitializeReference(); + } + + void InitializeReference () { if (skeletonAnimation == null) skeletonAnimation = GetComponent(); } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs new file mode 100644 index 000000000..16a62cdf5 --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs @@ -0,0 +1,70 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software + * or otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, + * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +//using UnityEngine.Playables; + +using Spine; +using Spine.Unity; +using Spine.Unity.Playables; + +namespace Spine.Unity.Playables { + + [AddComponentMenu("Spine/Playables/SkeletonGraphic Playable Handle (Playables)")] + public class SkeletonGraphicPlayableHandle : SpinePlayableHandleBase { + #region Inspector + public SkeletonGraphic skeletonGraphic; + + #if UNITY_EDITOR + void Reset () { + InitializeReference(); + } + + void OnValidate () { + InitializeReference(); + } + #endif + + #endregion + + public override Skeleton Skeleton { get { return skeletonGraphic.Skeleton; } } + public override SkeletonData SkeletonData { get { return skeletonGraphic.Skeleton.Data; } } + + void Awake () { + InitializeReference(); + } + + void InitializeReference () { + if (skeletonGraphic == null) + skeletonGraphic = GetComponent(); + } + } +} diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs.meta b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs.meta new file mode 100644 index 000000000..ad8ea1e25 --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonGraphicPlayableHandle.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 51a0223d4dee020468302946c8ccd329 +timeCreated: 1595439279 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SpinePlayableHandleBase.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SpinePlayableHandleBase.cs index f8b8fca31..de4bf450f 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SpinePlayableHandleBase.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SpinePlayableHandleBase.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs new file mode 100644 index 000000000..4610aaf42 --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs @@ -0,0 +1,48 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated May 1, 2019. Replaces all prior versions. + * + * Copyright (c) 2013-2019, 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. + * + * THIS SOFTWARE IS 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 THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; + +namespace Spine.Unity.Playables { + [TrackColor(0.9960785f, 0.2509804f, 0.003921569f)] + [TrackClipType(typeof(SpineAnimationStateClip))] + [TrackBindingType(typeof(SkeletonGraphic))] + public class SpineAnimationStateGraphicTrack : TrackAsset { + public int trackIndex = 0; + + public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) { + var scriptPlayable = ScriptPlayable.Create(graph, inputCount); + var mixerBehaviour = scriptPlayable.GetBehaviour(); + mixerBehaviour.trackIndex = this.trackIndex; + return scriptPlayable; + } + } +} diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs.meta b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs.meta new file mode 100644 index 000000000..396626a5b --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 72a1f4f2e8b6c194bbdabda6998a77e1 +timeCreated: 1595440391 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs index 3d03d275c..49f6cf13f 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs @@ -42,15 +42,20 @@ namespace Spine.Unity.Playables { // NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties. public override void ProcessFrame (Playable playable, FrameData info, object playerData) { - var spineComponent = playerData as SkeletonAnimation; - if (spineComponent == null) return; - var skeleton = spineComponent.Skeleton; - var state = spineComponent.AnimationState; + var skeletonAnimation = playerData as SkeletonAnimation; + var skeletonGraphic = playerData as SkeletonGraphic; + var animationStateComponent = playerData as IAnimationStateComponent; + var skeletonComponent = playerData as ISkeletonComponent; + if (animationStateComponent == null || skeletonComponent == null) return; + + var skeleton = skeletonComponent.Skeleton; + var state = animationStateComponent.AnimationState; if (!Application.isPlaying) { #if SPINE_EDITMODEPOSE - PreviewEditModePose(playable, spineComponent); + PreviewEditModePose(playable, skeletonComponent, animationStateComponent, + skeletonAnimation, skeletonGraphic); #endif return; } @@ -97,8 +102,14 @@ namespace Spine.Unity.Playables { } // Ensure that the first frame ends with an updated mesh. - spineComponent.Update(0); - spineComponent.LateUpdate(); + if (skeletonAnimation) { + skeletonAnimation.Update(0); + skeletonAnimation.LateUpdate(); + } + else if (skeletonGraphic) { + skeletonGraphic.Update(0); + skeletonGraphic.LateUpdate(); + } } } } @@ -107,9 +118,12 @@ namespace Spine.Unity.Playables { AnimationState dummyAnimationState; - public void PreviewEditModePose (Playable playable, SkeletonAnimation spineComponent) { + public void PreviewEditModePose (Playable playable, + ISkeletonComponent skeletonComponent, IAnimationStateComponent animationStateComponent, + SkeletonAnimation skeletonAnimation, SkeletonGraphic skeletonGraphic) { + if (Application.isPlaying) return; - if (spineComponent == null) return; + if (skeletonComponent == null || animationStateComponent == null) return; int inputCount = playable.GetInputCount(); int lastNonZeroWeightTrack = -1; @@ -120,14 +134,17 @@ namespace Spine.Unity.Playables { } if (lastNonZeroWeightTrack != -1) { - ScriptPlayable inputPlayableClip = (ScriptPlayable)playable.GetInput(lastNonZeroWeightTrack); + ScriptPlayable inputPlayableClip = + (ScriptPlayable)playable.GetInput(lastNonZeroWeightTrack); SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour(); - var skeleton = spineComponent.Skeleton; + var skeleton = skeletonComponent.Skeleton; - bool skeletonDataMismatch = clipData.animationReference != null && spineComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true); + bool skeletonDataMismatch = clipData.animationReference != null && + skeletonComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true); if (skeletonDataMismatch) { - Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", spineComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset); + Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", + skeletonComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset); } // Getting the from-animation here because it's required to get the mix information from AnimationStateData. @@ -147,12 +164,15 @@ namespace Spine.Unity.Playables { float mixDuration = clipData.mixDuration; if (!clipData.customDuration && fromAnimation != null && toAnimation != null) { - mixDuration = spineComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation); + mixDuration = animationStateComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation); } + if (trackIndex == 0) + skeleton.SetToSetupPose(); + // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { - dummyAnimationState = dummyAnimationState ?? new AnimationState(spineComponent.skeletonDataAsset.GetAnimationStateData()); + dummyAnimationState = dummyAnimationState ?? new AnimationState(skeletonComponent.SkeletonDataAsset.GetAnimationStateData()); var toTrack = dummyAnimationState.GetCurrent(0); var fromTrack = toTrack != null ? toTrack.MixingFrom : null; @@ -174,15 +194,18 @@ namespace Spine.Unity.Playables { } // Apply Pose - skeleton.SetToSetupPose(); dummyAnimationState.Update(0); dummyAnimationState.Apply(skeleton); } else { - skeleton.SetToSetupPose(); if (toAnimation != null) toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, 1f, MixBlend.Setup, MixDirection.In); } + skeleton.UpdateWorldTransform(); + if (skeletonAnimation) + skeletonAnimation.LateUpdate(); + else if (skeletonGraphic) + skeletonGraphic.LateUpdate(); } // Do nothing outside of the first clip and the last clip. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json index 9089f61d6..d4ebe02cc 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json +++ b/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 runtime, version 3.8 from 2019-10-03 or newer.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)", - "version": "3.8.1", + "version": "3.8.2", "unity": "2018.3", "author": { "name": "Esoteric Software", From 7611f551ebd22aac5ce044ef213cf9756cbbcec7 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 23 Jul 2020 16:29:41 +0200 Subject: [PATCH 02/13] [unity] Updated license headers at Timeline classes. --- .../SpineAnimationStateClipInspector.cs | 28 +++++++++---------- .../Editor/SpineAnimationStateDrawer.cs | 24 ++++++++-------- ...pineAnimationStateGraphicTrackInspector.cs | 24 ++++++++-------- .../SpineAnimationStateTrackInspector.cs | 24 ++++++++-------- .../Editor/SpineSkeletonFlipClipInspector.cs | 24 ++++++++-------- .../Editor/SpineSkeletonFlipDrawer.cs | 24 ++++++++-------- .../SkeletonAnimationPlayableHandle.cs | 24 ++++++++-------- .../SpineAnimationStateBehaviour.cs | 24 ++++++++-------- .../SpineAnimationStateClip.cs | 24 ++++++++-------- .../SpineAnimationStateGraphicTrack.cs | 24 ++++++++-------- .../SpineAnimationStateMixerBehaviour.cs | 24 ++++++++-------- .../SpineAnimationStateTrack.cs | 24 ++++++++-------- .../SpineSkeletonFlipBehaviour.cs | 24 ++++++++-------- .../SpineSkeletonFlipClip.cs | 24 ++++++++-------- .../SpineSkeletonFlipMixerBehaviour.cs | 24 ++++++++-------- .../SpineSkeletonFlipTrack.cs | 24 ++++++++-------- 16 files changed, 194 insertions(+), 194 deletions(-) diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateClipInspector.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateClipInspector.cs index 3146633c7..80c8eda7b 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateClipInspector.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateClipInspector.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; @@ -46,7 +46,7 @@ namespace Spine.Unity.Editor { } protected ClipInfo[] clipInfo = null; - + public void OnEnable () { templateProp = serializedObject.FindProperty("template"); System.Array.Resize(ref clipInfo, targets.Length); @@ -66,7 +66,7 @@ namespace Spine.Unity.Editor { if (targetClip.template.useBlendDuration) AdjustMixDuration(targetClip, clipInfo[i]); } - + serializedObject.ApplyModifiedProperties(); } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs index 8b47601dc..2a78226dd 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateDrawer.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs index 02e2a4d55..af9abd0c6 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateGraphicTrackInspector.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs index 3d5771186..79b915eac 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineAnimationStateTrackInspector.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipClipInspector.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipClipInspector.cs index d309d2af5..1deec447d 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipClipInspector.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipClipInspector.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipDrawer.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipDrawer.cs index d9106dbac..e50891676 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipDrawer.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Editor/SpineSkeletonFlipDrawer.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 UnityEditor; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonAnimationPlayableHandle.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonAnimationPlayableHandle.cs index 94254c971..166c587c3 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonAnimationPlayableHandle.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/PlayableHandle Component/SkeletonAnimationPlayableHandle.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs index 1a1d028de..685a1c2e7 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateBehaviour.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateClip.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateClip.cs index 21a0a9034..efa194f09 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateClip.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateClip.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs index 4610aaf42..a2307591e 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs index 49f6cf13f..619e9c18b 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. *****************************************************************************/ #define SPINE_EDITMODEPOSE diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs index bb9d2e06b..0f8fb99e6 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipBehaviour.cs index e3a3ba05f..7c744e17c 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipBehaviour.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipClip.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipClip.cs index ba7ca0160..c3c3ec80c 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipClip.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipClip.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs index 5f64367e7..a37b76fd1 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipTrack.cs index 6b9e036c7..089a16362 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineSkeletonFlip/SpineSkeletonFlipTrack.cs @@ -1,8 +1,8 @@ /****************************************************************************** * Spine Runtimes License Agreement - * Last updated May 1, 2019. Replaces all prior versions. + * Last updated January 1, 2020. Replaces all prior versions. * - * Copyright (c) 2013-2019, Esoteric Software LLC + * Copyright (c) 2013-2020, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and @@ -15,16 +15,16 @@ * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * - * THIS SOFTWARE IS 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 THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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; From a67b05725d546eb341d5e8060611b86697b43485 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 23 Jul 2020 16:48:31 +0200 Subject: [PATCH 03/13] [unity] Added changelog section for timeline additions in last commit, see commit 8c009e2. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ba29640..d27c5b1c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -233,6 +233,7 @@ * Added `SkeletonGraphicCustomMaterials` component, providing functionality to override materials and textures of a `SkeletonGraphic`, similar to `SkeletonRendererCustomMaterials`. Note: overriding materials or textures per slot is not provided due to structural limitations. * Added **Root Motion support** for `SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic` via new components `SkeletonRootMotion` and `SkeletonMecanimRootMotion`. The `SkeletonAnimation` and `SkeletonGraphic` component Inspector now provides a line `Root Motion` with `Add Component` and `Remove Component` buttons to add/remove the new `SkeletonRootMotion` component to your GameObject. The `SkeletonMecanim` Inspector detects whether root motion is enabled at the `Animator` component and adds a `SkeletonMecanimRootMotion` component automatically. * `SkeletonMecanim` now provides an additional `Custom MixMode` parameter under `Mecanim Translator`. It is enabled by default in version 3.8 to maintain current behaviour, using the set `Mix Mode` for each Mecanim layer. When disabled, `SkeletonMecanim` will use the recommended `MixMode` according to the layer blend mode. Additional information can be found in the [Mecanim Translator section](http://esotericsoftware.com/spine-unity#Parameters-for-animation-blending-control) on the spine-unity documentation pages. + * Added **SkeletonGraphic Timeline support**. Added supprot for multi-track Timeline preview in the Editor outside of play mode (multi-track scrubbing). See the [Timeline-Extension-UPM-Package](http://esotericsoftware.com/spine-unity#Timeline-Extension-UPM-Package) section of the spine-unity documentation for more information. * **Changes of default values** * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`. From 3be202711cffbc82bbf730133a19101bd128822d Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Fri, 24 Jul 2020 14:25:41 +0200 Subject: [PATCH 04/13] [unity] Added a warning box when URP Sprite shader is improperly configured for receiving shadows ('Add Normals' needs to be enabled). Closes #1726. --- .../spine-unity/Utility/MaterialChecks.cs | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs index ce905ea55..0e1174a75 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs @@ -53,15 +53,23 @@ namespace Spine.Unity { "Warning: Z Spacing recommended on selected shader configuration!\n\nPlease\n" + "1) make sure at least minimal 'Z Spacing' is set at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' and\n" + "2) ensure that the skeleton has overlapping parts on different Z depth. You can adjust this in Spine via draw order.\n"; + public static readonly string kAddNormalsRequiredMessage = + "Warning: 'Add Normals' required on URP shader to receive shadows!\n\nPlease\n" + + "a) enable 'Add Normals' at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' or\n" + + "b) disable 'Receive Shadows' at the Material."; public static bool IsMaterialSetupProblematic (SkeletonRenderer renderer, ref string errorMessage) { var materials = renderer.GetComponent().sharedMaterials; bool isProblematic = false; - foreach (var mat in materials) { - if (mat == null) continue; - isProblematic |= IsMaterialSetupProblematic(mat, ref errorMessage); + foreach (var material in materials) { + if (material == null) continue; + isProblematic |= IsMaterialSetupProblematic(material, ref errorMessage); if (renderer.zSpacing == 0) { - isProblematic |= IsZSpacingRequired(mat, ref errorMessage); + isProblematic |= IsZSpacingRequired(material, ref errorMessage); + } + if (IsURPMaterial(material) && !AreShadowsDisabled(material) && renderer.addNormals == false) { + isProblematic = true; + errorMessage += kAddNormalsRequiredMessage; } } return isProblematic; @@ -101,9 +109,10 @@ namespace Spine.Unity { } public static bool IsTextureSetupProblematic (Material material, ColorSpace colorSpace, - bool sRGBTexture, bool mipmapEnabled, bool alphaIsTransparency, - string texturePath, string materialPath, - ref string errorMessage) { + bool sRGBTexture, bool mipmapEnabled, bool alphaIsTransparency, + string texturePath, string materialPath, + ref string errorMessage) { + if (material == null || !UsesSpineShader(material)) { return false; } @@ -113,19 +122,34 @@ namespace Spine.Unity { // 'sRGBTexture = true' generates incorrectly weighted mipmaps at PMA textures, // causing white borders due to undesired custom weighting. if (sRGBTexture && mipmapEnabled && colorSpace == ColorSpace.Gamma) { - errorMessage += string.Format("`{0}` : Problematic Texture Settings found: When enabling `Generate Mip Maps` in Gamma color space, it is recommended to disable `sRGB (Color Texture)` on `Premultiply alpha` textures. Otherwise you will receive white border artifacts on an atlas exported with default `Premultiply alpha` settings.\n(You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath); + errorMessage += string.Format("`{0}` : Problematic Texture Settings found: " + + "When enabling `Generate Mip Maps` in Gamma color space, it is recommended " + + "to disable `sRGB (Color Texture)` on `Premultiply alpha` textures. Otherwise " + + "you will receive white border artifacts on an atlas exported with default " + + "`Premultiply alpha` settings.\n" + + "(You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath); isProblematic = true; } if (alphaIsTransparency) { string materialName = System.IO.Path.GetFileName(materialPath); - errorMessage += string.Format("`{0}` and material `{1}` : Problematic Texture / Material Settings found: It is recommended to disable `Alpha Is Transparency` on `Premultiply alpha` textures.\nAssuming `Premultiply alpha` texture because `Straight Alpha Texture` is disabled at material). (You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath, materialName); + errorMessage += string.Format("`{0}` and material `{1}` : Problematic " + + "Texture / Material Settings found: It is recommended to disable " + + "`Alpha Is Transparency` on `Premultiply alpha` textures.\n" + + "Assuming `Premultiply alpha` texture because `Straight Alpha Texture` " + + "is disabled at material). " + + "(You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath, materialName); isProblematic = true; } } else { // straight alpha texture if (!alphaIsTransparency) { string materialName = System.IO.Path.GetFileName(materialPath); - errorMessage += string.Format("`{0}` and material `{1}` : Incorrect Texture / Material Settings found: It is strongly recommended to enable `Alpha Is Transparency` on `Straight alpha` textures.\nAssuming `Straight alpha` texture because `Straight Alpha Texture` is enabled at material). (You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath, materialName); + errorMessage += string.Format("`{0}` and material `{1}` : Incorrect" + + "Texture / Material Settings found: It is strongly recommended " + + "to enable `Alpha Is Transparency` on `Straight alpha` textures.\n" + + "Assuming `Straight alpha` texture because `Straight Alpha Texture` " + + "is enabled at material). " + + "(You can disable this warning in `Edit - Preferences - Spine`)\n", texturePath, materialName); isProblematic = true; } } @@ -152,6 +176,14 @@ namespace Spine.Unity { return (material.HasProperty(STRAIGHT_ALPHA_PARAM_ID) && material.GetInt(STRAIGHT_ALPHA_PARAM_ID) == 0) || material.IsKeywordEnabled(ALPHAPREMULTIPLY_ON_KEYWORD); } + + static bool IsURPMaterial (Material material) { + return material.shader.name.Contains("Universal Render Pipeline"); + } + + static bool AreShadowsDisabled (Material material) { + return material.IsKeywordEnabled("_RECEIVE_SHADOWS_OFF"); + } } } From 0e2ced50429e15374d09d2cc926e7a42a01d3a49 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Wed, 29 Jul 2020 11:53:32 +0200 Subject: [PATCH 05/13] [unity] PointFollower and BoundingBoxFollower now correctly unsubscribe from events on deletion / disable. Closes #1729. --- .../spine-unity/Components/Following/BoundingBoxFollower.cs | 3 +++ .../spine-unity/Components/Following/PointFollower.cs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs index 570a2cc78..0ef19dd3a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs @@ -177,6 +177,9 @@ namespace Spine.Unity { void OnDisable () { if (clearStateOnDisable) ClearState(); + + if (skeletonRenderer != null) + skeletonRenderer.OnRebuild -= HandleRebuild; } public void ClearState () { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/PointFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/PointFollower.cs index 699e42823..413b9306c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/PointFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/PointFollower.cs @@ -100,6 +100,11 @@ namespace Spine.Unity { } } + void OnDestroy () { + if (skeletonRenderer != null) + skeletonRenderer.OnRebuild -= HandleRebuildRenderer; + } + public void LateUpdate () { #if UNITY_EDITOR if (!Application.isPlaying) skeletonTransformIsParent = Transform.ReferenceEquals(skeletonTransform, transform.parent); From 3c94f52b528dcfe4e1fc22141e052d0167ffb4ec Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 30 Jul 2020 12:13:52 +0200 Subject: [PATCH 06/13] [unity] Added support for double-sided lighting at SkeletonLit shaders (including URP and LWRP packages). Closes #1730. --- .../CGIncludes/Spine-Skeleton-Lit-Common.cginc | 8 +++++++- .../Shaders/Outline/Spine-Skeleton-Lit-Outline.shader | 1 + .../Outline/Spine-Skeleton-Lit-ZWrite-Outline.shader | 1 + .../Shaders/Spine-Skeleton-Lit-ZWrite.shader | 2 ++ .../spine-unity/Shaders/Spine-Skeleton-Lit.shader | 2 ++ .../CGIncludes/Spine-SkeletonLit-ForwardPass-LW.hlsl | 11 ++++++++++- .../Shaders/Spine-SkeletonLit-LW.shader | 6 ++++-- .../Include/Spine-SkeletonLit-ForwardPass-URP.hlsl | 9 +++++++++ .../Shaders/Spine-SkeletonLit-URP.shader | 2 ++ 9 files changed, 38 insertions(+), 4 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Skeleton-Lit-Common.cginc b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Skeleton-Lit-Common.cginc index 9dc1709d4..73a6e1875 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Skeleton-Lit-Common.cginc +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/CGIncludes/Spine-Skeleton-Lit-Common.cginc @@ -83,7 +83,13 @@ VertexOutput vert (appdata v) { float3 eyePos = UnityObjectToViewPos(float4(v.pos, 1)).xyz; //mul(UNITY_MATRIX_MV, float4(v.pos,1)).xyz; half3 fixedNormal = half3(0,0,-1); half3 eyeNormal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, fixedNormal)); - //half3 eyeNormal = half3(0,0,1); + +#ifdef _DOUBLE_SIDED_LIGHTING + // unfortunately we have to compute the sign here in the vertex shader + // instead of using VFACE in fragment shader stage. + half faceSign = sign(eyeNormal.z); + eyeNormal *= faceSign; +#endif // Lights half3 lcolor = half4(0,0,0,1).rgb + color.rgb * glstate_lightmodel_ambient.rgb; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-Outline.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-Outline.shader index 411036fee..75c0a9f5a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-Outline.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-Outline.shader @@ -5,6 +5,7 @@ Shader "Spine/Outline/Skeleton Lit" { _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-ZWrite-Outline.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-ZWrite-Outline.shader index 4cdf0e7c7..044308562 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-ZWrite-Outline.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Outline/Spine-Skeleton-Lit-ZWrite-Outline.shader @@ -6,6 +6,7 @@ Shader "Spine/Outline/Skeleton Lit ZWrite" { _ShadowAlphaCutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit-ZWrite.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit-ZWrite.shader index c8f43fd3d..95f77b77f 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit-ZWrite.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit-ZWrite.shader @@ -8,6 +8,7 @@ Shader "Spine/Skeleton Lit ZWrite" { _ShadowAlphaCutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default @@ -42,6 +43,7 @@ Shader "Spine/Skeleton Lit ZWrite" { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT + #pragma shader_feature _ _DOUBLE_SIDED_LIGHTING #pragma vertex vert #pragma fragment frag #pragma target 2.0 diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit.shader index b2e90b031..f10c478fa 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Spine-Skeleton-Lit.shader @@ -7,6 +7,7 @@ Shader "Spine/Skeleton Lit" { _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default @@ -41,6 +42,7 @@ Shader "Spine/Skeleton Lit" { CGPROGRAM #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT + #pragma shader_feature _ _DOUBLE_SIDED_LIGHTING #pragma vertex vert #pragma fragment frag #pragma target 2.0 diff --git a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-SkeletonLit-ForwardPass-LW.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-SkeletonLit-ForwardPass-LW.hlsl index 53e958fd9..b6b54affb 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-SkeletonLit-ForwardPass-LW.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-SkeletonLit-ForwardPass-LW.hlsl @@ -6,7 +6,7 @@ struct appdata { float3 normal : NORMAL; half4 color : COLOR; float2 uv0 : TEXCOORD0; - + UNITY_VERTEX_INPUT_INSTANCE_ID }; @@ -44,6 +44,15 @@ VertexOutput vert(appdata v) { float3 positionWS = TransformObjectToWorld(v.pos); half3 fixedNormal = half3(0, 0, -1); half3 normalWS = normalize(mul((float3x3)unity_ObjectToWorld, fixedNormal)); + +#ifdef _DOUBLE_SIDED_LIGHTING + // unfortunately we have to compute the sign here in the vertex shader + // instead of using VFACE in fragment shader stage. + half3 viewDirWS = UNITY_MATRIX_V[2].xyz; + half faceSign = sign(dot(viewDirWS, normalWS)); + normalWS *= faceSign; +#endif + color.rgb = LightweightLightVertexSimplified(positionWS, normalWS); // Note: ambient light is also handled via SH. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/Spine-SkeletonLit-LW.shader b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/Spine-SkeletonLit-LW.shader index 14ab34d7b..f03856a19 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/Spine-SkeletonLit-LW.shader +++ b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/Spine-SkeletonLit-LW.shader @@ -7,6 +7,7 @@ Shader "Lightweight Render Pipeline/Spine/Skeleton Lit" { _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } @@ -19,7 +20,7 @@ Shader "Lightweight Render Pipeline/Spine/Skeleton Lit" { Cull Off ZWrite Off Blend One OneMinusSrcAlpha - + Stencil { Ref[_StencilRef] Comp[_StencilComp] @@ -48,7 +49,7 @@ Shader "Lightweight Render Pipeline/Spine/Skeleton Lit" { #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE - + // ------------------------------------- // Unity defined keywords #pragma multi_compile_fog @@ -60,6 +61,7 @@ Shader "Lightweight Render Pipeline/Spine/Skeleton Lit" { //-------------------------------------- // Spine related keywords #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT + #pragma shader_feature _ _DOUBLE_SIDED_LIGHTING #pragma vertex vert #pragma fragment frag #pragma target 2.0 diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-SkeletonLit-ForwardPass-URP.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-SkeletonLit-ForwardPass-URP.hlsl index f0fa20e1b..0fd0c788c 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-SkeletonLit-ForwardPass-URP.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-SkeletonLit-ForwardPass-URP.hlsl @@ -44,6 +44,15 @@ VertexOutput vert(appdata v) { float3 positionWS = TransformObjectToWorld(v.pos); half3 fixedNormal = half3(0, 0, -1); half3 normalWS = normalize(mul((float3x3)unity_ObjectToWorld, fixedNormal)); + +#ifdef _DOUBLE_SIDED_LIGHTING + // unfortunately we have to compute the sign here in the vertex shader + // instead of using VFACE in fragment shader stage. + half3 viewDirWS = UNITY_MATRIX_V[2].xyz; + half faceSign = sign(dot(viewDirWS, normalWS)); + normalWS *= faceSign; +#endif + color.rgb = LightweightLightVertexSimplified(positionWS, normalWS); // Note: ambient light is also handled via SH. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-SkeletonLit-URP.shader b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-SkeletonLit-URP.shader index 166c8d2b5..f8328d65d 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-SkeletonLit-URP.shader +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-SkeletonLit-URP.shader @@ -3,6 +3,7 @@ _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 + [Toggle(_DOUBLE_SIDED_LIGHTING)] _DoubleSidedLighting("Double-Sided Lighting", Int) = 0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default } @@ -55,6 +56,7 @@ //-------------------------------------- // Spine related keywords #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT + #pragma shader_feature _ _DOUBLE_SIDED_LIGHTING #pragma vertex vert #pragma fragment frag From 1c2d4fa2e021e8c1cb0827a0712d6f8f97388bd7 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 30 Jul 2020 12:17:31 +0200 Subject: [PATCH 07/13] [unity] Added changelog entry for previous commit 3c94f52 (double sided lighting at SkeletonLit shaders). --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d27c5b1c6..aee67e828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -234,6 +234,7 @@ * Added **Root Motion support** for `SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic` via new components `SkeletonRootMotion` and `SkeletonMecanimRootMotion`. The `SkeletonAnimation` and `SkeletonGraphic` component Inspector now provides a line `Root Motion` with `Add Component` and `Remove Component` buttons to add/remove the new `SkeletonRootMotion` component to your GameObject. The `SkeletonMecanim` Inspector detects whether root motion is enabled at the `Animator` component and adds a `SkeletonMecanimRootMotion` component automatically. * `SkeletonMecanim` now provides an additional `Custom MixMode` parameter under `Mecanim Translator`. It is enabled by default in version 3.8 to maintain current behaviour, using the set `Mix Mode` for each Mecanim layer. When disabled, `SkeletonMecanim` will use the recommended `MixMode` according to the layer blend mode. Additional information can be found in the [Mecanim Translator section](http://esotericsoftware.com/spine-unity#Parameters-for-animation-blending-control) on the spine-unity documentation pages. * Added **SkeletonGraphic Timeline support**. Added supprot for multi-track Timeline preview in the Editor outside of play mode (multi-track scrubbing). See the [Timeline-Extension-UPM-Package](http://esotericsoftware.com/spine-unity#Timeline-Extension-UPM-Package) section of the spine-unity documentation for more information. + * Added support for double-sided lighting at all `SkeletonLit` shaders (including URP and LWRP packages). * **Changes of default values** * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`. From 5d61effc686f983fab5fe98d9cbbff8a32eb2fca Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 30 Jul 2020 15:59:47 +0200 Subject: [PATCH 08/13] [unity] Fixed automatic asset import in Unity 2020.1 (uses Asset Pipeline V2). Also fixes import when using Asset Pipeline V2 at Unity 2019.X. Closes #1727. --- .../Editor/Utility/AssetUtility.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs index d95dfb0f2..54988fdc1 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs @@ -256,7 +256,6 @@ namespace Spine.Unity.Editor { bool reimport = false) { var atlasPaths = new List(); - var spriteAtlasPaths = new List(); var imagePaths = new List(); var skeletonPaths = new List(); CompatibilityProblemInfo compatibilityProblemInfo = null; @@ -273,9 +272,6 @@ namespace Spine.Unity.Editor { if (str.EndsWith(".atlas.txt", System.StringComparison.Ordinal)) atlasPaths.Add(str); break; - case ".spriteatlas": - spriteAtlasPaths.Add(str); - break; case ".png": case ".jpg": imagePaths.Add(str); @@ -295,13 +291,13 @@ namespace Spine.Unity.Editor { } // Import atlases first. - var atlases = new List(); + var newAtlases = new List(); foreach (string ap in atlasPaths) { if (ap.StartsWith("Packages")) continue; TextAsset atlasText = AssetDatabase.LoadAssetAtPath(ap); AtlasAssetBase atlas = IngestSpineAtlas(atlasText, texturesWithoutMetaFile); - atlases.Add(atlas); + newAtlases.Add(atlas); } AddDependentSkeletonIfAtlasChanged(skeletonPaths, atlasPaths); @@ -328,13 +324,14 @@ namespace Spine.Unity.Editor { #if SPINE_TK2D IngestSpineProject(loadedAsset, null); #else - var localAtlases = FindAtlasesAtPath(dir); + var atlasesForSkeleton = FindAtlasesAtPath(dir); + atlasesForSkeleton.AddRange(newAtlases); var requiredPaths = GetRequiredAtlasRegions(skeletonPath); - var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + var atlasMatch = GetMatchingAtlas(requiredPaths, atlasesForSkeleton); if (atlasMatch != null || requiredPaths.Count == 0) { IngestSpineProject(loadedAsset, atlasMatch); } else { - SkeletonImportDialog(skeletonPath, localAtlases, requiredPaths, ref abortSkeletonImport); + SkeletonImportDialog(skeletonPath, atlasesForSkeleton, requiredPaths, ref abortSkeletonImport); } if (abortSkeletonImport) @@ -580,7 +577,10 @@ namespace Spine.Unity.Editor { } protectFromStackGarbageCollection.Remove(atlasAsset); - return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase)); + // note: at Asset Pipeline V2 this LoadAssetAtPath of the just created + // asset returns null, regardless of refresh calls. + var loadedAtlas = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase)); + return loadedAtlas != null ? loadedAtlas : atlasAsset; } public static bool SpriteAtlasSettingsNeedAdjustment (UnityEngine.U2D.SpriteAtlas spriteAtlas) { From a67094d64265435f32ab57153be927b0d49fe81e Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Mon, 3 Aug 2020 19:17:53 +0200 Subject: [PATCH 09/13] [unity] Ordered attribute drawers SpineSlot alphabetically and SpineBone as hierarchial tree selector. Closes #1731. --- .../Editor/SpineAttributeDrawers.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs index c5b38557b..33a928352 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs @@ -35,6 +35,7 @@ using System; using System.Collections.Generic; using System.Reflection; using Spine; +using System.Linq; namespace Spine.Unity.Editor { public struct SpineDrawerValuePair { @@ -177,8 +178,10 @@ namespace Spine.Unity.Editor { if (TargetAttribute.includeNone) menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); - for (int slotIndex = 0; slotIndex < data.Slots.Count; slotIndex++) { - string name = data.Slots.Items[slotIndex].Name; + IEnumerable orderedSlots = data.Slots.Items.OrderBy(slotData => slotData.Name); + foreach (SlotData slotData in orderedSlots) { + int slotIndex = slotData.Index; + string name = slotData.Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) { if (targetAttribute.containsBoundingBoxes) { @@ -521,9 +524,17 @@ namespace Spine.Unity.Editor { menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < data.Bones.Count; i++) { - string name = data.Bones.Items[i].Name; - if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + var bone = data.Bones.Items[i]; + string name = bone.Name; + if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) { + // jointName = "root/hip/bone" to show a hierarchial tree. + string jointName = name; + var iterator = bone; + while ((iterator = iterator.Parent) != null) + jointName = string.Format("{0}/{1}", iterator.Name, jointName); + + menu.AddItem(new GUIContent(jointName), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } } } From 978b305717d393bd864834c244734091e5fa800a Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Wed, 5 Aug 2020 19:24:49 +0200 Subject: [PATCH 10/13] [unity] Added frustum culling / update mode parameters `Update When Invisible` and `UpdateMode` to all Skeleton components. Closes #1595. --- CHANGELOG.md | 1 + .../Components/SkeletonGraphicInspector.cs | 5 ++- .../Components/SkeletonRendererInspector.cs | 8 +++- .../Components/SkeletonAnimation.cs | 15 ++++++- .../spine-unity/Components/SkeletonGraphic.cs | 42 +++++++++++++++++-- .../spine-unity/Components/SkeletonMecanim.cs | 18 +++++--- .../Components/SkeletonRenderer.cs | 26 ++++++++++-- .../Runtime/spine-unity/ISkeletonAnimation.cs | 7 ++++ 8 files changed, 105 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aee67e828..d003e19a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -235,6 +235,7 @@ * `SkeletonMecanim` now provides an additional `Custom MixMode` parameter under `Mecanim Translator`. It is enabled by default in version 3.8 to maintain current behaviour, using the set `Mix Mode` for each Mecanim layer. When disabled, `SkeletonMecanim` will use the recommended `MixMode` according to the layer blend mode. Additional information can be found in the [Mecanim Translator section](http://esotericsoftware.com/spine-unity#Parameters-for-animation-blending-control) on the spine-unity documentation pages. * Added **SkeletonGraphic Timeline support**. Added supprot for multi-track Timeline preview in the Editor outside of play mode (multi-track scrubbing). See the [Timeline-Extension-UPM-Package](http://esotericsoftware.com/spine-unity#Timeline-Extension-UPM-Package) section of the spine-unity documentation for more information. * Added support for double-sided lighting at all `SkeletonLit` shaders (including URP and LWRP packages). + * Added frustum culling update mode parameters `Update When Invisible` (Inspector parameter) and `UpdateMode` (available via code) to all Skeleton components. This provides a simple way to disable certain updates when the `Renderer` is no longer visible (outside all cameras, culled in frustum culling). The new `UpdateMode` property allows disabling updates at a finer granularity level than disabling the whole component. Available modes are: `Nothing`, `OnlyAnimationStatus`, `EverythingExceptMesh` and `FullUpdate`. * **Changes of default values** * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`. diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs index 5f9c5942a..e1725fd6a 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs @@ -37,7 +37,6 @@ using UnityEditor; namespace Spine.Unity.Editor { using Icons = SpineEditorUtilities.Icons; - [InitializeOnLoad] [CustomEditor(typeof(SkeletonGraphic))] [CanEditMultipleObjects] public class SkeletonGraphicInspector : UnityEditor.Editor { @@ -51,7 +50,7 @@ namespace Spine.Unity.Editor { SerializedProperty material, color; SerializedProperty skeletonDataAsset, initialSkinName; - SerializedProperty startingAnimation, startingLoop, timeScale, freeze, unscaledTime, tintBlack; + SerializedProperty startingAnimation, startingLoop, timeScale, freeze, updateWhenInvisible, unscaledTime, tintBlack; SerializedProperty initialFlipX, initialFlipY; SerializedProperty meshGeneratorSettings; SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation; @@ -111,6 +110,7 @@ namespace Spine.Unity.Editor { timeScale = so.FindProperty("timeScale"); unscaledTime = so.FindProperty("unscaledTime"); freeze = so.FindProperty("freeze"); + updateWhenInvisible = so.FindProperty("updateWhenInvisible"); meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings"); meshGeneratorSettings.isExpanded = SkeletonRendererInspector.advancedFoldout; @@ -233,6 +233,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.PropertyField(unscaledTime, SpineInspectorUtility.TempContent(unscaledTime.displayName, tooltip: "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied.")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(freeze); + EditorGUILayout.PropertyField(updateWhenInvisible); EditorGUILayout.Space(); SkeletonRendererInspector.SkeletonRootMotionParameter(targets); EditorGUILayout.Space(); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs index 62f50ed22..1e8a3e50b 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs @@ -59,7 +59,7 @@ namespace Spine.Unity.Editor { protected SerializedProperty skeletonDataAsset, initialSkinName; protected SerializedProperty initialFlipX, initialFlipY; - protected SerializedProperty singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles, fixDrawOrder; + protected SerializedProperty updateWhenInvisible, singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles, fixDrawOrder; protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings protected SerializedProperty maskInteraction; protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside; @@ -74,7 +74,7 @@ namespace Spine.Unity.Editor { protected bool deleteOutsideMaskMaterialsQueued = false; protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent; - protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, SingleSubmeshLabel, FixDrawOrderLabel; + protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, UpdateWhenInvisibleLabel, SingleSubmeshLabel, FixDrawOrderLabel; protected GUIContent NormalsLabel, TangentsLabel, MaskInteractionLabel; protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel; protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel; @@ -119,6 +119,7 @@ namespace Spine.Unity.Editor { TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents."); TintBlackLabel = new GUIContent("Tint Black (!)", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock."); SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials."); + UpdateWhenInvisibleLabel = new GUIContent("Update When Invisible", "Update mode used when the MeshRenderer becomes invisible. Update mode is automatically reset to UpdateMode.FullUpdate when the mesh becomes visible again."); FixDrawOrderLabel = new GUIContent("Fix Draw Order", "Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. \"A B A\"). If true, GPU instancing will be disabled at all materials and MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes by e.g. the LWRP renderer, leading to incorrect draw order (e.g. \"A1 B A2\" changed to \"A1A2 B\"). You can disable this parameter when everything is drawn correctly to save the additional performance cost. Note: the GPU instancing setting will remain disabled at affected material assets after exiting play mode, you have to enable it manually if you accidentally enabled this parameter."); MaskInteractionLabel = new GUIContent("Mask Interaction", "SkeletonRenderer's interaction with a Sprite Mask."); MaskMaterialsHeadingLabel = new GUIContent("Mask Interaction Materials", "Materials used for different interaction with sprite masks."); @@ -140,6 +141,7 @@ namespace Spine.Unity.Editor { pmaVertexColors = so.FindProperty("pmaVertexColors"); clearStateOnDisable = so.FindProperty("clearStateOnDisable"); tintBlack = so.FindProperty("tintBlack"); + updateWhenInvisible = so.FindProperty("updateWhenInvisible"); singleSubmesh = so.FindProperty("singleSubmesh"); fixDrawOrder = so.FindProperty("fixDrawOrder"); maskInteraction = so.FindProperty("maskInteraction"); @@ -319,6 +321,8 @@ namespace Spine.Unity.Editor { EditorGUILayout.LabelField("Renderer Settings", EditorStyles.boldLabel); using (new SpineInspectorUtility.LabelWidthScope()) { // Optimization options + if (updateWhenInvisible != null) EditorGUILayout.PropertyField(updateWhenInvisible, UpdateWhenInvisibleLabel); + if (singleSubmesh != null) EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel); #if PER_MATERIAL_PROPERTY_BLOCKS if (fixDrawOrder != null) EditorGUILayout.PropertyField(fixDrawOrder, FixDrawOrderLabel); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs index 69679ff9b..112f231d5 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs @@ -185,9 +185,23 @@ namespace Spine.Unity { if (!valid || state == null) return; + wasUpdatedAfterInit = true; + if (updateMode < UpdateMode.OnlyAnimationStatus) + return; + UpdateAnimationStatus(deltaTime); + + if (updateMode == UpdateMode.OnlyAnimationStatus) + return; + ApplyAnimation(); + } + + protected void UpdateAnimationStatus (float deltaTime) { deltaTime *= timeScale; skeleton.Update(deltaTime); state.Update(deltaTime); + } + + protected void ApplyAnimation () { state.Apply(skeleton); if (_UpdateLocal != null) @@ -203,7 +217,6 @@ namespace Spine.Unity { if (_UpdateComplete != null) { _UpdateComplete(this); } - wasUpdatedAfterInit = true; } public override void LateUpdate () { 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 3ea70fbea..fd6a6f7f6 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -58,6 +58,16 @@ namespace Spine.Unity { public bool startingLoop; public float timeScale = 1f; public bool freeze; + + ///

Update mode to optionally limit updates to e.g. only apply animations but not update the mesh. + public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } } + [SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate; + + /// Update mode used when the MeshRenderer becomes invisible + /// (when OnBecameInvisible() is called). Update mode is automatically + /// reset to UpdateMode.FullUpdate when the mesh becomes visible again. + public UpdateMode updateWhenInvisible = UpdateMode.FullUpdate; + public bool unscaledTime; public bool allowMultipleCanvasRenderers = false; public List canvasRenderers = new List(); @@ -232,12 +242,27 @@ namespace Spine.Unity { public virtual void Update (float deltaTime) { if (!this.IsValid) return; + wasUpdatedAfterInit = true; + if (updateMode < UpdateMode.OnlyAnimationStatus) + return; + UpdateAnimationStatus(deltaTime); + + if (updateMode == UpdateMode.OnlyAnimationStatus) + return; + ApplyAnimation(); + } + + protected void UpdateAnimationStatus (float deltaTime) { deltaTime *= timeScale; skeleton.Update(deltaTime); state.Update(deltaTime); + } + + protected void ApplyAnimation () { state.Apply(skeleton); - if (UpdateLocal != null) UpdateLocal(this); + if (UpdateLocal != null) + UpdateLocal(this); skeleton.UpdateWorldTransform(); @@ -246,18 +271,27 @@ namespace Spine.Unity { skeleton.UpdateWorldTransform(); } - if (UpdateComplete != null) UpdateComplete(this); - wasUpdatedAfterInit = true; + if (UpdateComplete != null) + UpdateComplete(this); } public void LateUpdate () { // instantiation can happen from Update() after this component, leading to a missing Update() call. if (!wasUpdatedAfterInit) Update(0); if (freeze) return; - //this.SetVerticesDirty(); // Which is better? + if (updateMode <= UpdateMode.EverythingExceptMesh) return; + UpdateMesh(); } + public void OnBecameVisible () { + updateMode = UpdateMode.FullUpdate; + } + + public void OnBecameInvisible () { + updateMode = updateWhenInvisible; + } + public void ReapplySeparatorSlotNames () { if (!IsValid) return; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs index d85390b18..2a28fd46b 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs @@ -78,14 +78,23 @@ namespace Spine.Unity { public void Update () { if (!valid) return; - #if UNITY_EDITOR + wasUpdatedAfterInit = true; + // animation status is kept by Mecanim Animator component + if (updateMode <= UpdateMode.OnlyAnimationStatus) + return; + ApplyAnimation(); + } + + protected void ApplyAnimation () { + #if UNITY_EDITOR var translatorAnimator = translator.Animator; if (translatorAnimator != null && !translatorAnimator.isInitialized) translatorAnimator.Rebind(); 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 @@ -93,9 +102,9 @@ namespace Spine.Unity { translator.Apply(skeleton); } } - #else + #else translator.Apply(skeleton); - #endif + #endif // UpdateWorldTransform and Bone Callbacks { @@ -112,7 +121,6 @@ namespace Spine.Unity { if (_UpdateComplete != null) _UpdateComplete(this); } - wasUpdatedAfterInit = true; } public override void LateUpdate () { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index e75c00682..2e7e9b88a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -55,11 +55,11 @@ namespace Spine.Unity { [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] [HelpURL("http://esotericsoftware.com/spine-unity-rendering")] public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, IHasSkeletonDataAsset { - [SerializeField] public SkeletonDataAsset skeletonDataAsset; + public SkeletonDataAsset skeletonDataAsset; #region Initialization settings /// Skin name to use when the Skeleton is initialized. - [SerializeField] [SpineSkin(defaultAsEmptyString:true)] public string initialSkinName; + [SpineSkin(defaultAsEmptyString:true)] public string initialSkinName; /// Enable this parameter when overwriting the Skeleton's skin from an editor script. /// Otherwise any changes will be overwritten by the next inspector update. @@ -71,10 +71,20 @@ namespace Spine.Unity { protected bool editorSkipSkinSync = false; #endif /// Flip X and Y to use when the Skeleton is initialized. - [SerializeField] public bool initialFlipX, initialFlipY; + public bool initialFlipX, initialFlipY; #endregion #region Advanced Render Settings + + /// Update mode to optionally limit updates to e.g. only apply animations but not update the mesh. + public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } } + [SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate; + + /// Update mode used when the MeshRenderer becomes invisible + /// (when OnBecameInvisible() is called). Update mode is automatically + /// reset to UpdateMode.FullUpdate when the mesh becomes visible again. + public UpdateMode updateWhenInvisible = UpdateMode.FullUpdate; + // Submesh Separation /// Slot names used to populate separatorSlots list when the Skeleton is initialized. Changing this after initialization does nothing. [UnityEngine.Serialization.FormerlySerializedAs("submeshSeparators")][SerializeField][SpineSlot] protected string[] separatorSlotNames = new string[0]; @@ -361,6 +371,8 @@ namespace Spine.Unity { } #endif + if (updateMode <= UpdateMode.EverythingExceptMesh) return; + #if SPINE_OPTIONAL_RENDEROVERRIDE bool doMeshOverride = generateMeshOverride != null; if ((!meshRenderer.enabled) && !doMeshOverride) return; @@ -477,6 +489,14 @@ namespace Spine.Unity { OnMeshAndMaterialsUpdated(this); } + public void OnBecameVisible () { + updateMode = UpdateMode.FullUpdate; + } + + public void OnBecameInvisible () { + updateMode = updateWhenInvisible; + } + public void FindAndApplySeparatorSlots (string startsWith, bool clearExistingSeparators = true, bool updateStringArray = false) { if (string.IsNullOrEmpty(startsWith)) return; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs index 496957574..36e300ec9 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs @@ -28,6 +28,13 @@ *****************************************************************************/ namespace Spine.Unity { + public enum UpdateMode { + Nothing = 0, + OnlyAnimationStatus, + EverythingExceptMesh, + FullUpdate + }; + public delegate void UpdateBonesDelegate (ISkeletonAnimation animated); /// A Spine-Unity Component that animates a Skeleton but not necessarily with a Spine.AnimationState. From bb34e33aeee35c33fe205ae9f49c32eb0976d357 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 6 Aug 2020 18:41:43 +0200 Subject: [PATCH 11/13] [unity] Moved SkeletonGraphic Inspector property "Update when Invisible" to the Advanced section for consistency. --- .../spine-unity/Editor/Components/SkeletonGraphicInspector.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs index e1725fd6a..6af4c6901 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs @@ -172,6 +172,7 @@ namespace Spine.Unity.Editor { meshGeneratorSettings.isExpanded = true; using (new SpineInspectorUtility.BoxScope()) { + EditorGUILayout.PropertyField(meshGeneratorSettings, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: true); SkeletonRendererInspector.advancedFoldout = meshGeneratorSettings.isExpanded; @@ -190,6 +191,8 @@ namespace Spine.Unity.Editor { } EditorGUILayout.EndHorizontal(); + EditorGUILayout.PropertyField(updateWhenInvisible); + // warning box if (isSeparationEnabledButNotMultipleRenderers) { using (new SpineInspectorUtility.BoxScope()) { @@ -233,7 +236,6 @@ namespace Spine.Unity.Editor { EditorGUILayout.PropertyField(unscaledTime, SpineInspectorUtility.TempContent(unscaledTime.displayName, tooltip: "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied.")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(freeze); - EditorGUILayout.PropertyField(updateWhenInvisible); EditorGUILayout.Space(); SkeletonRendererInspector.SkeletonRootMotionParameter(targets); EditorGUILayout.Space(); From 11006baa65988d7e1bbe921681aab1e8d7d57e47 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Fri, 7 Aug 2020 15:40:35 +0200 Subject: [PATCH 12/13] [unity] Fixed URP Sprite shader treating skeleton alpha incorrectly. Closes #1735. --- .../CGIncludes/Spine-Sprite-ForwardPass-LW.hlsl | 12 ++++++------ .../Include/Spine-Sprite-ForwardPass-URP.hlsl | 13 +++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-Sprite-ForwardPass-LW.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-Sprite-ForwardPass-LW.hlsl index 4c1e890a5..0736f78b2 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-Sprite-ForwardPass-LW.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.lwrp-shaders/Shaders/CGIncludes/Spine-Sprite-ForwardPass-LW.hlsl @@ -75,7 +75,7 @@ half4 LightweightFragmentPBRSimplified(InputData inputData, half4 texAlbedoAlpha half4 albedo = texAlbedoAlpha * vertexColor; BRDFData brdfData; - half ignoredAlpha = 1; // ignore alpha, otherwise + half ignoredAlpha = 1; // ignore alpha, otherwise InitializeBRDFData(albedo.rgb, metallic, specular, smoothness, ignoredAlpha, brdfData); brdfData.specular *= albedo.a; @@ -105,7 +105,7 @@ half4 LightweightFragmentPBRSimplified(InputData inputData, half4 texAlbedoAlpha finalColor += inputData.vertexLighting * brdfData.diffuse; #endif finalColor += emission; - return prepareLitPixelForOutput(half4(finalColor, texAlbedoAlpha.a), vertexColor); + return prepareLitPixelForOutput(half4(finalColor, albedo.a), vertexColor); } #else // !SPECULAR @@ -148,7 +148,7 @@ half4 LightweightFragmentBlinnPhongSimplified(InputData inputData, half4 texDiff diffuseLighting += emission; //half3 finalColor = diffuseLighting * diffuse + emission; half3 finalColor = diffuseLighting * diffuse.rgb; - return prepareLitPixelForOutput(half4(finalColor, texDiffuseAlpha.a), vertexColor); + return prepareLitPixelForOutput(half4(finalColor, diffuse.a), vertexColor); } #endif // SPECULAR @@ -168,7 +168,7 @@ VertexOutputLWRP ForwardPassVertexSprite(VertexInput input) float backFaceSign = 1; #if defined(FIXED_NORMALS_BACKFACE_RENDERING) backFaceSign = calculateBackfacingSign(positionWS.xyz); -#endif +#endif output.viewDirectionWS = GetCameraPositionWS() - positionWS; #if defined(PER_PIXEL_LIGHTING) @@ -219,7 +219,7 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) inputData.shadowCoord = input.shadowCoord; #endif - + inputData.viewDirectionWS = input.viewDirectionWS; inputData.vertexLighting = input.fogFactorAndVertexLight.yzw; @@ -239,7 +239,7 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target #if defined(_RIM_LIGHTING) || defined(_ADDITIONAL_LIGHTS) inputData.positionWS = input.positionWS.rgb; #endif - + #if defined(SPECULAR) half2 metallicGloss = getMetallicGloss(input.texcoord.xy); half metallic = metallicGloss.x; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl index 1be33a8d1..d4f7ccd7a 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl +++ b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl @@ -75,7 +75,7 @@ half4 LightweightFragmentPBRSimplified(InputData inputData, half4 texAlbedoAlpha half4 albedo = texAlbedoAlpha * vertexColor; BRDFData brdfData; - half ignoredAlpha = 1; // ignore alpha, otherwise + half ignoredAlpha = 1; // ignore alpha, otherwise InitializeBRDFData(albedo.rgb, metallic, specular, smoothness, ignoredAlpha, brdfData); brdfData.specular *= albedo.a; @@ -105,7 +105,7 @@ half4 LightweightFragmentPBRSimplified(InputData inputData, half4 texAlbedoAlpha finalColor += inputData.vertexLighting * brdfData.diffuse; #endif finalColor += emission; - return prepareLitPixelForOutput(half4(finalColor, texAlbedoAlpha.a), vertexColor); + return prepareLitPixelForOutput(half4(finalColor, albedo.a), vertexColor); } #else // !SPECULAR @@ -148,7 +148,7 @@ half4 LightweightFragmentBlinnPhongSimplified(InputData inputData, half4 texDiff diffuseLighting += emission; //half3 finalColor = diffuseLighting * diffuse + emission; half3 finalColor = diffuseLighting * diffuse.rgb; - return prepareLitPixelForOutput(half4(finalColor, texDiffuseAlpha.a), vertexColor); + return prepareLitPixelForOutput(half4(finalColor, diffuse.a), vertexColor); } #endif // SPECULAR @@ -168,7 +168,7 @@ VertexOutputLWRP ForwardPassVertexSprite(VertexInput input) float backFaceSign = 1; #if defined(FIXED_NORMALS_BACKFACE_RENDERING) backFaceSign = calculateBackfacingSign(positionWS.xyz); -#endif +#endif output.viewDirectionWS = GetCameraPositionWS() - positionWS; #if defined(PER_PIXEL_LIGHTING) @@ -219,7 +219,7 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) inputData.shadowCoord = input.shadowCoord; #endif - + inputData.viewDirectionWS = input.viewDirectionWS; inputData.vertexLighting = input.fogFactorAndVertexLight.yzw; @@ -239,7 +239,7 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target #if defined(_RIM_LIGHTING) || defined(_ADDITIONAL_LIGHTS) inputData.positionWS = input.positionWS.rgb; #endif - + #if defined(SPECULAR) half2 metallicGloss = getMetallicGloss(input.texcoord.xy); half metallic = metallicGloss.x; @@ -261,6 +261,7 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target COLORISE(pixel) APPLY_FOG_LWRP(pixel, input.fogFactorAndVertexLight.x) + return pixel; } From 13b3b2e01193796a6b57eff6cd4132ad7b25a3e4 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Mon, 10 Aug 2020 23:47:50 +0200 Subject: [PATCH 13/13] Formatting. --- spine-cocos2dx/src/spine/SkeletonRenderer.cpp | 1804 ++++++++--------- 1 file changed, 898 insertions(+), 906 deletions(-) diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index d7331158f..07471159f 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -34,1049 +34,1041 @@ USING_NS_CC; - namespace spine { - namespace { - Cocos2dTextureLoader textureLoader; +namespace { + Cocos2dTextureLoader textureLoader; - int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex); - cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount); - void interleaveCoordinates(float* dst, const float* src, int vertexCount, int dstStride); - BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha); - void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex); - bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect); - Color4B ColorToColor4B(const Color& color); - bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex); - bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex); - } + int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex); + cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount); + void interleaveCoordinates(float* dst, const float* src, int vertexCount, int dstStride); + BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha); + void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex); + bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect); + Color4B ColorToColor4B(const Color& color); + bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex); + bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex); +} // C Variable length array #ifdef _MSC_VER - // VLA not supported, use _malloca - #define VLA(type, arr, count) \ - type* arr = static_cast( _malloca(sizeof(type) * count) ) - #define VLA_FREE(arr) do { _freea(arr); } while(false) +// VLA not supported, use _malloca +#define VLA(type, arr, count) \ + type* arr = static_cast( _malloca(sizeof(type) * count) ) +#define VLA_FREE(arr) do { _freea(arr); } while(false) #else - #define VLA(type, arr, count) \ - type arr[count] - #define VLA_FREE(arr) +#define VLA(type, arr, count) \ + type arr[count] +#define VLA_FREE(arr) #endif +SkeletonRenderer* SkeletonRenderer::createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData) { + SkeletonRenderer* node = new SkeletonRenderer(skeleton, ownsSkeleton, ownsSkeletonData); + node->autorelease(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData) { - SkeletonRenderer* node = new SkeletonRenderer(skeleton, ownsSkeleton, ownsSkeletonData); - node->autorelease(); - return node; - } +SkeletonRenderer* SkeletonRenderer::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); + node->autorelease(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); - node->autorelease(); - return node; - } +SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale); + node->autorelease(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale); - node->autorelease(); - return node; - } +SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale); + node->autorelease(); + return node; +} - SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale); - node->autorelease(); - return node; - } +void SkeletonRenderer::initialize () { + _clipper = new (__FILE__, __LINE__) SkeletonClipping(); - void SkeletonRenderer::initialize () { - _clipper = new (__FILE__, __LINE__) SkeletonClipping(); + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; + setOpacityModifyRGB(true); - _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; - setOpacityModifyRGB(true); + setTwoColorTint(false); - setTwoColorTint(false); + _skeleton->setToSetupPose(); + _skeleton->updateWorldTransform(); +} - _skeleton->setToSetupPose(); - _skeleton->updateWorldTransform(); - } - - void SkeletonRenderer::setupGLProgramState (bool twoColorTintEnabled) { - if (twoColorTintEnabled) { +void SkeletonRenderer::setupGLProgramState (bool twoColorTintEnabled) { + if (twoColorTintEnabled) { #if COCOS2D_VERSION < 0x00040000 - setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState()); + setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState()); #endif - return; + return; + } + + Texture2D *texture = nullptr; + for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { + Slot* slot = _skeleton->getDrawOrder()[i]; + Attachment* const attachment = slot->getAttachment(); + if (!attachment) continue; + if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { + RegionAttachment* regionAttachment = static_cast(attachment); + texture = static_cast(regionAttachment->getRendererObject())->_texture; + } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { + MeshAttachment* meshAttachment = static_cast(attachment); + texture = static_cast(meshAttachment->getRendererObject())->_texture; + } else { + continue; } - Texture2D *texture = nullptr; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { - Slot* slot = _skeleton->getDrawOrder()[i]; - Attachment* const attachment = slot->getAttachment(); - if (!attachment) continue; - if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { - RegionAttachment* regionAttachment = static_cast(attachment); - texture = static_cast(regionAttachment->getRendererObject())->_texture; - } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { - MeshAttachment* meshAttachment = static_cast(attachment); - texture = static_cast(meshAttachment->getRendererObject())->_texture; - } - else { - continue; - } - - if (texture != nullptr) { - break; - } + if (texture != nullptr) { + break; } + } #if COCOS2D_VERSION < 0x00040000 - setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture)); + setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture)); #endif +} + +void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) { + _skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData); + _ownsSkeletonData = ownsSkeletonData; +} + +SkeletonRenderer::SkeletonRenderer () + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { +} + +SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { + initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas); +} + +SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { + initWithData(skeletonData, ownsSkeletonData); +} + +SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { + initWithJsonFile(skeletonDataFile, atlas, scale); +} + +SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) + : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { + initWithJsonFile(skeletonDataFile, atlasFile, scale); +} + +SkeletonRenderer::~SkeletonRenderer () { + if (_ownsSkeletonData) delete _skeleton->getData(); + if (_ownsSkeleton) delete _skeleton; + if (_ownsAtlas && _atlas) delete _atlas; + if (_attachmentLoader) delete _attachmentLoader; + delete _clipper; +} + +void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) { + _skeleton = skeleton; + _ownsSkeleton = ownsSkeleton; + _ownsSkeletonData = ownsSkeletonData; + _ownsAtlas = ownsAtlas; + initialize(); +} + +void SkeletonRenderer::initWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { + _ownsSkeleton = true; + setSkeletonData(skeletonData, ownsSkeletonData); + initialize(); +} + +void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { + _atlas = atlas; + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + SkeletonJson json(_attachmentLoader); + json.setScale(scale); + SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str()); + CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data."); + + _ownsSkeleton = true; + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + SkeletonJson json(_attachmentLoader); + json.setScale(scale); + SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str()); + CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data."); + + _ownsSkeleton = true; + _ownsAtlas = true; + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { + _atlas = atlas; + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + SkeletonBinary binary(_attachmentLoader); + binary.setScale(scale); + SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str()); + CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data."); + _ownsSkeleton = true; + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); + + SkeletonBinary binary(_attachmentLoader); + binary.setScale(scale); + SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str()); + CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data."); + _ownsSkeleton = true; + _ownsAtlas = true; + setSkeletonData(skeletonData, true); + + initialize(); +} + + +void SkeletonRenderer::update (float deltaTime) { + Node::update(deltaTime); + if (_ownsSkeleton) _skeleton->update(deltaTime * _timeScale); +} + +void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { + // Early exit if the skeleton is invisible. + if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) { + return; } - void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) { - _skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData); - _ownsSkeletonData = ownsSkeletonData; + const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); + if (coordCount == 0) { + return; + } + assert(coordCount % 2 == 0); + + VLA(float, worldCoords, coordCount); + transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); + +#if CC_USE_CULLING + const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); + + if (cullRectangle(renderer, transform, bb)) { + VLA_FREE(worldCoords); + return; + } +#endif + + const float* worldCoordPtr = worldCoords; + SkeletonBatch* batch = SkeletonBatch::getInstance(); + SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance(); + const bool hasSingleTint = (isTwoColorTint() == false); + + if (_effect) { + _effect->begin(*_skeleton); } - SkeletonRenderer::SkeletonRenderer () - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - } + const Color3B displayedColor = getDisplayedColor(); + Color nodeColor; + nodeColor.r = displayedColor.r / 255.f; + nodeColor.g = displayedColor.g / 255.f; + nodeColor.b = displayedColor.b / 255.f; + nodeColor.a = getDisplayedOpacity() / 255.f; - SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas); - } + Color color; + Color darkColor; + const float darkPremultipliedAlpha = _premultipliedAlpha ? 1.f : 0; + AttachmentVertices* attachmentVertices = nullptr; + TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr; + for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { + Slot* slot = _skeleton->getDrawOrder()[i];; - SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - initWithData(skeletonData, ownsSkeletonData); - } - - SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - initWithJsonFile(skeletonDataFile, atlas, scale); - } - - SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits::max()) { - initWithJsonFile(skeletonDataFile, atlasFile, scale); - } - - SkeletonRenderer::~SkeletonRenderer () { - if (_ownsSkeletonData) delete _skeleton->getData(); - if (_ownsSkeleton) delete _skeleton; - if (_ownsAtlas && _atlas) delete _atlas; - if (_attachmentLoader) delete _attachmentLoader; - delete _clipper; - } - - void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) { - _skeleton = skeleton; - _ownsSkeleton = ownsSkeleton; - _ownsSkeletonData = ownsSkeletonData; - _ownsAtlas = ownsAtlas; - initialize(); - } - - void SkeletonRenderer::initWithData (SkeletonData* skeletonData, bool ownsSkeletonData) { - _ownsSkeleton = true; - setSkeletonData(skeletonData, ownsSkeletonData); - initialize(); - } - - void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { - _atlas = atlas; - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - SkeletonJson json(_attachmentLoader); - json.setScale(scale); - SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str()); - CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data."); - - _ownsSkeleton = true; - setSkeletonData(skeletonData, true); - - initialize(); - } - - void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - SkeletonJson json(_attachmentLoader); - json.setScale(scale); - SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str()); - CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data."); - - _ownsSkeleton = true; - _ownsAtlas = true; - setSkeletonData(skeletonData, true); - - initialize(); - } - - void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) { - _atlas = atlas; - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - SkeletonBinary binary(_attachmentLoader); - binary.setScale(scale); - SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str()); - CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data."); - _ownsSkeleton = true; - setSkeletonData(skeletonData, true); - - initialize(); - } - - void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas); - - SkeletonBinary binary(_attachmentLoader); - binary.setScale(scale); - SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str()); - CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data."); - _ownsSkeleton = true; - _ownsAtlas = true; - setSkeletonData(skeletonData, true); - - initialize(); - } - - - void SkeletonRenderer::update (float deltaTime) { - Node::update(deltaTime); - if (_ownsSkeleton) _skeleton->update(deltaTime * _timeScale); - } - - void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { - // Early exit if the skeleton is invisible - if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) { - return; - } - - const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); - if (coordCount == 0) { - return; - } - assert(coordCount % 2 == 0); - - VLA(float, worldCoords, coordCount); - transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); - - #if CC_USE_CULLING - const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); - - if (cullRectangle(renderer, transform, bb)) { - VLA_FREE(worldCoords); - return; - } - #endif - - const float* worldCoordPtr = worldCoords; - SkeletonBatch* batch = SkeletonBatch::getInstance(); - SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance(); - const bool hasSingleTint = (isTwoColorTint() == false); - - if (_effect) { - _effect->begin(*_skeleton); - } - - const Color3B displayedColor = getDisplayedColor(); - Color nodeColor; - nodeColor.r = displayedColor.r / 255.f; - nodeColor.g = displayedColor.g / 255.f; - nodeColor.b = displayedColor.b / 255.f; - nodeColor.a = getDisplayedOpacity() / 255.f; - - Color color; - Color darkColor; - const float darkPremultipliedAlpha = _premultipliedAlpha ? 1.f : 0; - AttachmentVertices* attachmentVertices = nullptr; - TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { - Slot* slot = _skeleton->getDrawOrder()[i];; - - if (nothingToDraw(*slot, _startSlotIndex, _endSlotIndex)) { - _clipper->clipEnd(*slot); - continue; - } - - cocos2d::TrianglesCommand::Triangles triangles; - TwoColorTriangles trianglesTwoColor; - - if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) { - RegionAttachment* attachment = static_cast(slot->getAttachment()); - attachmentVertices = static_cast(attachment->getRendererObject()); - - float* dstTriangleVertices = nullptr; - int dstStride = 0; // in floats - if (hasSingleTint) { - triangles.indices = attachmentVertices->_triangles->indices; - triangles.indexCount = attachmentVertices->_triangles->indexCount; - triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount); - triangles.vertCount = attachmentVertices->_triangles->vertCount; - assert(triangles.vertCount == 4); - memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount); - dstStride = sizeof(V3F_C4B_T2F) / sizeof(float); - dstTriangleVertices = reinterpret_cast(triangles.verts); - } else { - trianglesTwoColor.indices = attachmentVertices->_triangles->indices; - trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount; - trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount); - trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount; - assert(trianglesTwoColor.vertCount == 4); - for (int v = 0; v < trianglesTwoColor.vertCount; v++) { - trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; - } - dstTriangleVertices = reinterpret_cast(trianglesTwoColor.verts); - dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); - } - // Copy world vertices to triangle vertices - interleaveCoordinates(dstTriangleVertices, worldCoordPtr, 4, dstStride); - worldCoordPtr += 8; - - color = attachment->getColor(); - } - else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) { - MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment(); - attachmentVertices = (AttachmentVertices*)attachment->getRendererObject(); - - float* dstTriangleVertices = nullptr; - int dstStride = 0; // in floats - int dstVertexCount = 0; - if (hasSingleTint) { - triangles.indices = attachmentVertices->_triangles->indices; - triangles.indexCount = attachmentVertices->_triangles->indexCount; - triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount); - triangles.vertCount = attachmentVertices->_triangles->vertCount; - memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount); - dstTriangleVertices = (float*)triangles.verts; - dstStride = sizeof(V3F_C4B_T2F) / sizeof(float); - dstVertexCount = triangles.vertCount; - } else { - trianglesTwoColor.indices = attachmentVertices->_triangles->indices; - trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount; - trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount); - trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount; - for (int v = 0; v < trianglesTwoColor.vertCount; v++) { - trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; - } - dstTriangleVertices = (float*)trianglesTwoColor.verts; - dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); - dstVertexCount = trianglesTwoColor.vertCount; - } - - // Copy world vertices to triangle vertices - //assert(dstVertexCount * 2 == attachment->super.worldVerticesLength); - interleaveCoordinates(dstTriangleVertices, worldCoordPtr, dstVertexCount, dstStride); - worldCoordPtr += dstVertexCount * 2; - - color = attachment->getColor(); - } - else if (slot->getAttachment()->getRTTI().isExactly(ClippingAttachment::rtti)) { - ClippingAttachment* clip = (ClippingAttachment*)slot->getAttachment(); - _clipper->clipStart(*slot, clip); - continue; - } else { - _clipper->clipEnd(*slot); - continue; - } - - if (slot->hasDarkColor()) { - darkColor = slot->getDarkColor(); - } else { - darkColor.r = 0; - darkColor.g = 0; - darkColor.b = 0; - } - darkColor.a = darkPremultipliedAlpha; - - color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a; - // skip rendering if the color of this attachment is 0 - if (color.a == 0){ + if (nothingToDraw(*slot, _startSlotIndex, _endSlotIndex)) { _clipper->clipEnd(*slot); - continue; - } - color.r *= nodeColor.r * _skeleton->getColor().r * slot->getColor().r; - color.g *= nodeColor.g * _skeleton->getColor().g * slot->getColor().g; - color.b *= nodeColor.b * _skeleton->getColor().b * slot->getColor().b; - if (_premultipliedAlpha) - { - color.r *= color.a; - color.g *= color.a; - color.b *= color.a; - } + continue; + } - const cocos2d::Color4B color4B = ColorToColor4B(color); - const cocos2d::Color4B darkColor4B = ColorToColor4B(darkColor); - const BlendFunc blendFunc = makeBlendFunc(slot->getData().getBlendMode(), attachmentVertices->_texture->hasPremultipliedAlpha()); - _blendFunc = blendFunc; + cocos2d::TrianglesCommand::Triangles triangles; + TwoColorTriangles trianglesTwoColor; + if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) { + RegionAttachment* attachment = static_cast(slot->getAttachment()); + attachmentVertices = static_cast(attachment->getRendererObject()); + + float* dstTriangleVertices = nullptr; + int dstStride = 0; // in floats if (hasSingleTint) { - if (_clipper->isClipping()) { - _clipper->clipTriangles((float*)&triangles.verts[0].vertices, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, sizeof(cocos2d::V3F_C4B_T2F) / 4); - batch->deallocateVertices(triangles.vertCount); + triangles.indices = attachmentVertices->_triangles->indices; + triangles.indexCount = attachmentVertices->_triangles->indexCount; + triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount); + triangles.vertCount = attachmentVertices->_triangles->vertCount; + assert(triangles.vertCount == 4); + memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount); + dstStride = sizeof(V3F_C4B_T2F) / sizeof(float); + dstTriangleVertices = reinterpret_cast(triangles.verts); + } else { + trianglesTwoColor.indices = attachmentVertices->_triangles->indices; + trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount; + trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount); + trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount; + assert(trianglesTwoColor.vertCount == 4); + for (int v = 0; v < trianglesTwoColor.vertCount; v++) { + trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; + } + dstTriangleVertices = reinterpret_cast(trianglesTwoColor.verts); + dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); + } + // Copy world vertices to triangle vertices. + interleaveCoordinates(dstTriangleVertices, worldCoordPtr, 4, dstStride); + worldCoordPtr += 8; - if (_clipper->getClippedTriangles().size() == 0){ - _clipper->clipEnd(*slot); - continue; - } + color = attachment->getColor(); + } + else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) { + MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment(); + attachmentVertices = (AttachmentVertices*)attachment->getRendererObject(); - triangles.vertCount = _clipper->getClippedVertices().size() / 2; - triangles.verts = batch->allocateVertices(triangles.vertCount); - triangles.indexCount = _clipper->getClippedTriangles().size(); - triangles.indices = - batch->allocateIndices(triangles.indexCount); - memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); + float* dstTriangleVertices = nullptr; + int dstStride = 0; // in floats + int dstVertexCount = 0; + if (hasSingleTint) { + triangles.indices = attachmentVertices->_triangles->indices; + triangles.indexCount = attachmentVertices->_triangles->indexCount; + triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount); + triangles.vertCount = attachmentVertices->_triangles->vertCount; + memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount); + dstTriangleVertices = (float*)triangles.verts; + dstStride = sizeof(V3F_C4B_T2F) / sizeof(float); + dstVertexCount = triangles.vertCount; + } else { + trianglesTwoColor.indices = attachmentVertices->_triangles->indices; + trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount; + trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount); + trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount; + for (int v = 0; v < trianglesTwoColor.vertCount; v++) { + trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords; + } + dstTriangleVertices = (float*)trianglesTwoColor.verts; + dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float); + dstVertexCount = trianglesTwoColor.vertCount; + } + + // Copy world vertices to triangle vertices. + //assert(dstVertexCount * 2 == attachment->super.worldVerticesLength); + interleaveCoordinates(dstTriangleVertices, worldCoordPtr, dstVertexCount, dstStride); + worldCoordPtr += dstVertexCount * 2; + + color = attachment->getColor(); + } + else if (slot->getAttachment()->getRTTI().isExactly(ClippingAttachment::rtti)) { + ClippingAttachment* clip = (ClippingAttachment*)slot->getAttachment(); + _clipper->clipStart(*slot, clip); + continue; + } else { + _clipper->clipEnd(*slot); + continue; + } + + if (slot->hasDarkColor()) { + darkColor = slot->getDarkColor(); + } else { + darkColor.r = 0; + darkColor.g = 0; + darkColor.b = 0; + } + darkColor.a = darkPremultipliedAlpha; + + color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a; + if (color.a == 0) { + _clipper->clipEnd(*slot); + continue; + } + color.r *= nodeColor.r * _skeleton->getColor().r * slot->getColor().r; + color.g *= nodeColor.g * _skeleton->getColor().g * slot->getColor().g; + color.b *= nodeColor.b * _skeleton->getColor().b * slot->getColor().b; + if (_premultipliedAlpha) { + color.r *= color.a; + color.g *= color.a; + color.b *= color.a; + } + + const cocos2d::Color4B color4B = ColorToColor4B(color); + const cocos2d::Color4B darkColor4B = ColorToColor4B(darkColor); + const BlendFunc blendFunc = makeBlendFunc(slot->getData().getBlendMode(), attachmentVertices->_texture->hasPremultipliedAlpha()); + _blendFunc = blendFunc; + + if (hasSingleTint) { + if (_clipper->isClipping()) { + _clipper->clipTriangles((float*)&triangles.verts[0].vertices, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, sizeof(cocos2d::V3F_C4B_T2F) / 4); + batch->deallocateVertices(triangles.vertCount); + + if (_clipper->getClippedTriangles().size() == 0) { + _clipper->clipEnd(*slot); + continue; + } + + triangles.vertCount = _clipper->getClippedVertices().size() / 2; + triangles.verts = batch->allocateVertices(triangles.vertCount); + triangles.indexCount = _clipper->getClippedTriangles().size(); + triangles.indices = + batch->allocateIndices(triangles.indexCount); + memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); #if COCOS2D_VERSION < 0x00040000 - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); #else - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); #endif - const float* verts = _clipper->getClippedVertices().buffer(); - const float* uvs = _clipper->getClippedUVs().buffer(); - if (_effect) { - V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - Color darkTmp; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) { - Color lightCopy = color; - vertex->vertices.x = verts[vv]; - vertex->vertices.y = verts[vv + 1]; - vertex->texCoords.u = uvs[vv]; - vertex->texCoords.v = uvs[vv + 1]; - _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp); - vertex->colors = ColorToColor4B(lightCopy); - } - } else { - V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) { - vertex->vertices.x = verts[vv]; - vertex->vertices.y = verts[vv + 1]; - vertex->texCoords.u = uvs[vv]; - vertex->texCoords.v = uvs[vv + 1]; - vertex->colors = color4B; - } + const float* verts = _clipper->getClippedVertices().buffer(); + const float* uvs = _clipper->getClippedUVs().buffer(); + if (_effect) { + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + Color darkTmp; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) { + Color lightCopy = color; + vertex->vertices.x = verts[vv]; + vertex->vertices.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp); + vertex->colors = ColorToColor4B(lightCopy); } } else { - // Not clipping -#if COCOS2D_VERSION < 0x00040000 - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); -#else - cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); -#endif - - if (_effect) { - V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - Color darkTmp; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { - Color lightCopy = color; - _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp); - vertex->colors = ColorToColor4B(lightCopy); - } - } else { - V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { - vertex->colors = color4B; - } + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) { + vertex->vertices.x = verts[vv]; + vertex->vertices.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + vertex->colors = color4B; } } } else { - // Two tints - - if (_clipper->isClipping()) { - _clipper->clipTriangles((float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, sizeof(V3F_C4B_C4B_T2F) / 4); - twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount); - - if (_clipper->getClippedTriangles().size() == 0){ - _clipper->clipEnd(*slot); - continue; - } - - trianglesTwoColor.vertCount = _clipper->getClippedVertices().size() / 2; - trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount); - trianglesTwoColor.indexCount = _clipper->getClippedTriangles().size(); - trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount); - memcpy(trianglesTwoColor.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); - + // Not clipping. #if COCOS2D_VERSION < 0x00040000 - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); #else - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); + cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); #endif - const float* verts = _clipper->getClippedVertices().buffer(); - const float* uvs = _clipper->getClippedUVs().buffer(); - - if (_effect) { - V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) { - Color lightCopy = color; - Color darkCopy = darkColor; - vertex->position.x = verts[vv]; - vertex->position.y = verts[vv + 1]; - vertex->texCoords.u = uvs[vv]; - vertex->texCoords.v = uvs[vv + 1]; - _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy); - vertex->color = ColorToColor4B(lightCopy); - vertex->color2 = ColorToColor4B(darkCopy); - } - } else { - V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) { - vertex->position.x = verts[vv]; - vertex->position.y = verts[vv + 1]; - vertex->texCoords.u = uvs[vv]; - vertex->texCoords.v = uvs[vv + 1]; - vertex->color = color4B; - vertex->color2 = darkColor4B; - } + if (_effect) { + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + Color darkTmp; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { + Color lightCopy = color; + _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp); + vertex->colors = ColorToColor4B(lightCopy); } } else { - -#if COCOS2D_VERSION < 0x00040000 - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); -#else - TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); -#endif - - if (_effect) { - V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { - Color lightCopy = color; - Color darkCopy = darkColor; - _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy); - vertex->color = ColorToColor4B(lightCopy); - vertex->color2 = ColorToColor4B(darkCopy); - } - } else { - V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; - for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { - vertex->color = color4B; - vertex->color2 = darkColor4B; - } + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { + vertex->colors = color4B; + } + } + } + } else { + // Two color tinting. + + if (_clipper->isClipping()) { + _clipper->clipTriangles((float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, sizeof(V3F_C4B_C4B_T2F) / 4); + twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount); + + if (_clipper->getClippedTriangles().size() == 0) { + _clipper->clipEnd(*slot); + continue; + } + + trianglesTwoColor.vertCount = _clipper->getClippedVertices().size() / 2; + trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount); + trianglesTwoColor.indexCount = _clipper->getClippedTriangles().size(); + trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount); + memcpy(trianglesTwoColor.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size()); + +#if COCOS2D_VERSION < 0x00040000 + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); +#else + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); +#endif + + const float* verts = _clipper->getClippedVertices().buffer(); + const float* uvs = _clipper->getClippedUVs().buffer(); + + if (_effect) { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) { + Color lightCopy = color; + Color darkCopy = darkColor; + vertex->position.x = verts[vv]; + vertex->position.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy); + vertex->color = ColorToColor4B(lightCopy); + vertex->color2 = ColorToColor4B(darkCopy); + } + } else { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) { + vertex->position.x = verts[vv]; + vertex->position.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + vertex->color = color4B; + vertex->color2 = darkColor4B; + } + } + } else { + +#if COCOS2D_VERSION < 0x00040000 + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags); +#else + TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); +#endif + + if (_effect) { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { + Color lightCopy = color; + Color darkCopy = darkColor; + _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy); + vertex->color = ColorToColor4B(lightCopy); + vertex->color2 = ColorToColor4B(darkCopy); + } + } else { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) { + vertex->color = color4B; + vertex->color2 = darkColor4B; } } } - _clipper->clipEnd(*slot); } - _clipper->clipEnd(); + _clipper->clipEnd(*slot); + } + _clipper->clipEnd(); - if (lastTwoColorTrianglesCommand) { - Node* parent = this->getParent(); + if (lastTwoColorTrianglesCommand) { + Node* parent = this->getParent(); - // We need to decide if we can postpone flushing the current - // batch. We can postpone if the next sibling node is a - // two color tinted skeleton with the same global-z. - // The parent->getChildrenCount() > 100 check is a hack - // as checking for a sibling is an O(n) operation, and if - // all children of this nodes parent are skeletons, we - // are in O(n2) territory. - if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) { + // We need to decide if we can postpone flushing the current batch. We can postpone if the next sibling node is a two color + // tinted skeleton with the same global-z. + // The parent->getChildrenCount() > 100 check is a hack as checking for a sibling is an O(n) operation, and if all children + // of this nodes parent are skeletons, we are in O(n2) territory. + if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) { + lastTwoColorTrianglesCommand->setForceFlush(true); + } else { + const cocos2d::Vector& children = parent->getChildren(); + Node* sibling = nullptr; + for (ssize_t i = 0; i < children.size(); i++) { + if (children.at(i) == this) { + if (i < children.size() - 1) { + sibling = children.at(i+1); + break; + } + } + } + if (!sibling) { lastTwoColorTrianglesCommand->setForceFlush(true); } else { - const cocos2d::Vector& children = parent->getChildren(); - Node* sibling = nullptr; - for (ssize_t i = 0; i < children.size(); i++) { - if (children.at(i) == this) { - if (i < children.size() - 1) { - sibling = children.at(i+1); - break; - } - } - } - if (!sibling) { + SkeletonRenderer* siblingSkeleton = dynamic_cast(sibling); + if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer + !siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted + !siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible + (siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs lastTwoColorTrianglesCommand->setForceFlush(true); - } else { - SkeletonRenderer* siblingSkeleton = dynamic_cast(sibling); - if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer - !siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted - !siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible - (siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs - lastTwoColorTrianglesCommand->setForceFlush(true); - } } } } - - if (_effect) _effect->end(); - - if (_debugBoundingRect || _debugSlots || _debugBones || _debugMeshes) { - drawDebug(renderer, transform, transformFlags); - } - - VLA_FREE(worldCoords); } + if (_effect) _effect->end(); - void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) { + if (_debugBoundingRect || _debugSlots || _debugBones || _debugMeshes) { + drawDebug(renderer, transform, transformFlags); + } + + VLA_FREE(worldCoords); +} + + +void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) { #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY) - Director* director = Director::getInstance(); - director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); + Director* director = Director::getInstance(); + director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); + director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); #endif - DrawNode* drawNode = DrawNode::create(); - drawNode->setGlobalZOrder(getGlobalZOrder()); + DrawNode* drawNode = DrawNode::create(); + drawNode->setGlobalZOrder(getGlobalZOrder()); - // Draw bounding rectangle - if (_debugBoundingRect) { + // Draw bounding rectangle + if (_debugBoundingRect) { #if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); + glLineWidth(2); #else - drawNode->setLineWidth(2.0f); + drawNode->setLineWidth(2.0f); #endif - const cocos2d::Rect brect = getBoundingBox(); + const cocos2d::Rect brect = getBoundingBox(); + const Vec2 points[4] = + { + brect.origin, + { brect.origin.x + brect.size.width, brect.origin.y }, + { brect.origin.x + brect.size.width, brect.origin.y + brect.size.height }, + { brect.origin.x, brect.origin.y + brect.size.height } + }; + drawNode->drawPoly(points, 4, true, Color4F::GREEN); + } + + if (_debugSlots) { + // Slots. + // DrawPrimitives::setDrawColor4B(0, 0, 255, 255); +#if COCOS2D_VERSION < 0x00040000 + glLineWidth(2); +#else + drawNode->setLineWidth(2.0f); +#endif + V3F_C4B_T2F_Quad quad; + for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { + Slot* slot = _skeleton->getDrawOrder()[i]; + + if (!slot->getBone().isActive()) continue; + if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) continue; + + if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) { + continue; + } + + RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment(); + float worldVertices[8]; + attachment->computeWorldVertices(slot->getBone(), worldVertices, 0, 2); const Vec2 points[4] = { - brect.origin, - { brect.origin.x + brect.size.width, brect.origin.y }, - { brect.origin.x + brect.size.width, brect.origin.y + brect.size.height }, - { brect.origin.x, brect.origin.y + brect.size.height } + { worldVertices[0], worldVertices[1] }, + { worldVertices[2], worldVertices[3] }, + { worldVertices[4], worldVertices[5] }, + { worldVertices[6], worldVertices[7] } }; - drawNode->drawPoly(points, 4, true, Color4F::GREEN); + drawNode->drawPoly(points, 4, true, Color4F::BLUE); } + } - if (_debugSlots) { - // Slots. - // DrawPrimitives::setDrawColor4B(0, 0, 255, 255); + if (_debugBones) { + // Bone lengths. #if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); + glLineWidth(2); #else - drawNode->setLineWidth(2.0f); + drawNode->setLineWidth(2.0f); #endif - V3F_C4B_T2F_Quad quad; - for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) { - Slot* slot = _skeleton->getDrawOrder()[i]; + for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { + Bone *bone = _skeleton->getBones()[i]; + if (!bone->isActive()) continue; + float x = bone->getData().getLength() * bone->getA() + bone->getWorldX(); + float y = bone->getData().getLength() * bone->getC() + bone->getWorldY(); + drawNode->drawLine(Vec2(bone->getWorldX(), bone->getWorldY()), Vec2(x, y), Color4F::RED); + } + // Bone origins. + auto color = Color4F::BLUE; // Root bone is blue. + for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { + Bone *bone = _skeleton->getBones()[i]; + if (!bone->isActive()) continue; + drawNode->drawPoint(Vec2(bone->getWorldX(), bone->getWorldY()), 4, color); + if (i == 0) color = Color4F::GREEN; + } + } - if (!slot->getBone().isActive()) continue; - if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) continue; - - if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) { - continue; - } - - RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment(); - float worldVertices[8]; - attachment->computeWorldVertices(slot->getBone(), worldVertices, 0, 2); - const Vec2 points[4] = + if (_debugMeshes) { + // Meshes. +#if COCOS2D_VERSION < 0x00040000 + glLineWidth(2); +#else + drawNode->setLineWidth(2.0f); +#endif + for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { + Slot* slot = _skeleton->getDrawOrder()[i]; + if (!slot->getBone().isActive()) continue; + if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) continue; + MeshAttachment* const mesh = static_cast(slot->getAttachment()); + VLA(float, worldCoord, mesh->getWorldVerticesLength()); + mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), worldCoord, 0, 2); + for (size_t t = 0; t < mesh->getTriangles().size(); t += 3) { + // Fetch triangle indices + const int idx0 = mesh->getTriangles()[t + 0]; + const int idx1 = mesh->getTriangles()[t + 1]; + const int idx2 = mesh->getTriangles()[t + 2]; + const Vec2 v[3] = { - { worldVertices[0], worldVertices[1] }, - { worldVertices[2], worldVertices[3] }, - { worldVertices[4], worldVertices[5] }, - { worldVertices[6], worldVertices[7] } + worldCoord + (idx0 * 2), + worldCoord + (idx1 * 2), + worldCoord + (idx2 * 2) }; - drawNode->drawPoly(points, 4, true, Color4F::BLUE); + drawNode->drawPoly(v, 3, true, Color4F::YELLOW); } + VLA_FREE(worldCoord); } + } - if (_debugBones) { - // Bone lengths. -#if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); -#else - drawNode->setLineWidth(2.0f); -#endif - for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { - Bone *bone = _skeleton->getBones()[i]; - if (!bone->isActive()) continue; - float x = bone->getData().getLength() * bone->getA() + bone->getWorldX(); - float y = bone->getData().getLength() * bone->getC() + bone->getWorldY(); - drawNode->drawLine(Vec2(bone->getWorldX(), bone->getWorldY()), Vec2(x, y), Color4F::RED); - } - // Bone origins. - auto color = Color4F::BLUE; // Root bone is blue. - for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) { - Bone *bone = _skeleton->getBones()[i]; - if (!bone->isActive()) continue; - drawNode->drawPoint(Vec2(bone->getWorldX(), bone->getWorldY()), 4, color); - if (i == 0) color = Color4F::GREEN; - } - } - - if (_debugMeshes) { - // Meshes. -#if COCOS2D_VERSION < 0x00040000 - glLineWidth(2); -#else - drawNode->setLineWidth(2.0f); -#endif - for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) { - Slot* slot = _skeleton->getDrawOrder()[i]; - if (!slot->getBone().isActive()) continue; - if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) continue; - MeshAttachment* const mesh = static_cast(slot->getAttachment()); - VLA(float, worldCoord, mesh->getWorldVerticesLength()); - mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), worldCoord, 0, 2); - for (size_t t = 0; t < mesh->getTriangles().size(); t += 3) { - // Fetch triangle indices - const int idx0 = mesh->getTriangles()[t + 0]; - const int idx1 = mesh->getTriangles()[t + 1]; - const int idx2 = mesh->getTriangles()[t + 2]; - const Vec2 v[3] = - { - worldCoord + (idx0 * 2), - worldCoord + (idx1 * 2), - worldCoord + (idx2 * 2) - }; - drawNode->drawPoly(v, 3, true, Color4F::YELLOW); - } - VLA_FREE(worldCoord); - } - } - - drawNode->draw(renderer, transform, transformFlags); + drawNode->draw(renderer, transform, transformFlags); #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY) - director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); + director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); #endif - } +} - cocos2d::Rect SkeletonRenderer::getBoundingBox () const { - const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); - if (coordCount == 0) return { 0, 0, 0, 0 }; - VLA(float, worldCoords, coordCount); - transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); - const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); - VLA_FREE(worldCoords); - return bb; - } +cocos2d::Rect SkeletonRenderer::getBoundingBox () const { + const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); + if (coordCount == 0) return { 0, 0, 0, 0 }; + VLA(float, worldCoords, coordCount); + transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex); + const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2); + VLA_FREE(worldCoords); + return bb; +} - // --- Convenience methods for Skeleton_* functions. +// --- Convenience methods for Skeleton_* functions. - void SkeletonRenderer::updateWorldTransform() { - _skeleton->updateWorldTransform(); - } +void SkeletonRenderer::updateWorldTransform() { + _skeleton->updateWorldTransform(); +} - void SkeletonRenderer::setToSetupPose () { - _skeleton->setToSetupPose(); - } - void SkeletonRenderer::setBonesToSetupPose () { - _skeleton->setBonesToSetupPose(); - } - void SkeletonRenderer::setSlotsToSetupPose () { - _skeleton->setSlotsToSetupPose(); - } +void SkeletonRenderer::setToSetupPose () { + _skeleton->setToSetupPose(); +} +void SkeletonRenderer::setBonesToSetupPose () { + _skeleton->setBonesToSetupPose(); +} +void SkeletonRenderer::setSlotsToSetupPose () { + _skeleton->setSlotsToSetupPose(); +} - Bone* SkeletonRenderer::findBone (const std::string& boneName) const { - return _skeleton->findBone(boneName.c_str()); - } +Bone* SkeletonRenderer::findBone (const std::string& boneName) const { + return _skeleton->findBone(boneName.c_str()); +} - Slot* SkeletonRenderer::findSlot (const std::string& slotName) const { - return _skeleton->findSlot( slotName.c_str()); - } +Slot* SkeletonRenderer::findSlot (const std::string& slotName) const { + return _skeleton->findSlot( slotName.c_str()); +} - void SkeletonRenderer::setSkin (const std::string& skinName) { - _skeleton->setSkin(skinName.empty() ? 0 : skinName.c_str()); - } - void SkeletonRenderer::setSkin (const char* skinName) { - _skeleton->setSkin(skinName); - } +void SkeletonRenderer::setSkin (const std::string& skinName) { + _skeleton->setSkin(skinName.empty() ? 0 : skinName.c_str()); +} +void SkeletonRenderer::setSkin (const char* skinName) { + _skeleton->setSkin(skinName); +} - Attachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const { - return _skeleton->getAttachment(slotName.c_str(), attachmentName.c_str()); - } - bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { - bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; - _skeleton->setAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()); - return result; - } - bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { - bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName) ? true : false; - _skeleton->setAttachment(slotName.c_str(), attachmentName); - return result; - } +Attachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const { + return _skeleton->getAttachment(slotName.c_str(), attachmentName.c_str()); +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { + bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; + _skeleton->setAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()); + return result; +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { + bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName) ? true : false; + _skeleton->setAttachment(slotName.c_str(), attachmentName); + return result; +} - void SkeletonRenderer::setTwoColorTint(bool enabled) { +void SkeletonRenderer::setTwoColorTint(bool enabled) { #if COCOS2D_VERSION >= 0x00040000 - _twoColorTint = enabled; + _twoColorTint = enabled; #endif - setupGLProgramState(enabled); - } + setupGLProgramState(enabled); +} - bool SkeletonRenderer::isTwoColorTint() { +bool SkeletonRenderer::isTwoColorTint() { #if COCOS2D_VERSION < 0x00040000 - return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState(); + return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState(); #else - return _twoColorTint; + return _twoColorTint; #endif - } +} - void SkeletonRenderer::setVertexEffect(VertexEffect *effect) { - this->_effect = effect; - } +void SkeletonRenderer::setVertexEffect(VertexEffect *effect) { + this->_effect = effect; +} - void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) { - _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex; - _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits::max() : endSlotIndex; - } +void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) { + _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex; + _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits::max() : endSlotIndex; +} - Skeleton* SkeletonRenderer::getSkeleton () const { - return _skeleton; - } +Skeleton* SkeletonRenderer::getSkeleton () const { + return _skeleton; +} - void SkeletonRenderer::setTimeScale (float scale) { - _timeScale = scale; - } - float SkeletonRenderer::getTimeScale () const { - return _timeScale; - } +void SkeletonRenderer::setTimeScale (float scale) { + _timeScale = scale; +} +float SkeletonRenderer::getTimeScale () const { + return _timeScale; +} - void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) { - _debugSlots = enabled; - } - bool SkeletonRenderer::getDebugSlotsEnabled () const { - return _debugSlots; - } +void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) { + _debugSlots = enabled; +} +bool SkeletonRenderer::getDebugSlotsEnabled () const { + return _debugSlots; +} - void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { - _debugBones = enabled; - } - bool SkeletonRenderer::getDebugBonesEnabled () const { - return _debugBones; - } +void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { + _debugBones = enabled; +} +bool SkeletonRenderer::getDebugBonesEnabled () const { + return _debugBones; +} - void SkeletonRenderer::setDebugMeshesEnabled (bool enabled) { - _debugMeshes = enabled; - } - bool SkeletonRenderer::getDebugMeshesEnabled () const { - return _debugMeshes; - } +void SkeletonRenderer::setDebugMeshesEnabled (bool enabled) { + _debugMeshes = enabled; +} +bool SkeletonRenderer::getDebugMeshesEnabled () const { + return _debugMeshes; +} - void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) { - _debugBoundingRect = enabled; - } +void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) { + _debugBoundingRect = enabled; +} - bool SkeletonRenderer::getDebugBoundingRectEnabled() const { - return _debugBoundingRect; - } +bool SkeletonRenderer::getDebugBoundingRectEnabled() const { + return _debugBoundingRect; +} - void SkeletonRenderer::onEnter () { +void SkeletonRenderer::onEnter () { #if CC_ENABLE_SCRIPT_BINDING - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; #endif - Node::onEnter(); - scheduleUpdate(); - } + Node::onEnter(); + scheduleUpdate(); +} - void SkeletonRenderer::onExit () { +void SkeletonRenderer::onExit () { #if CC_ENABLE_SCRIPT_BINDING - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; #endif - Node::onExit(); - unscheduleUpdate(); - } + Node::onExit(); + unscheduleUpdate(); +} - // --- CCBlendProtocol +// --- CCBlendProtocol - const BlendFunc& SkeletonRenderer::getBlendFunc () const { - return _blendFunc; - } +const BlendFunc& SkeletonRenderer::getBlendFunc () const { + return _blendFunc; +} - void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { - _blendFunc = blendFunc; - } +void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { + _blendFunc = blendFunc; +} - void SkeletonRenderer::setOpacityModifyRGB (bool value) { - _premultipliedAlpha = value; - } +void SkeletonRenderer::setOpacityModifyRGB (bool value) { + _premultipliedAlpha = value; +} - bool SkeletonRenderer::isOpacityModifyRGB () const { - return _premultipliedAlpha; - } +bool SkeletonRenderer::isOpacityModifyRGB () const { + return _premultipliedAlpha; +} - namespace { - cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) { - assert(coords); - assert(vertexCount > 0); +namespace { + cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) { + assert(coords); + assert(vertexCount > 0); - const float* v = coords; - float minX = v[0]; - float minY = v[1]; - float maxX = minX; - float maxY = minY; - for (int i = 1; i < vertexCount; ++i) { - v += 2; - float x = v[0]; - float y = v[1]; - minX = std::min(minX, x); - minY = std::min(minY, y); - maxX = std::max(maxX, x); - maxY = std::max(maxY, y); - } - return { minX, minY, maxX - minX, maxY - minY }; + const float* v = coords; + float minX = v[0]; + float minY = v[1]; + float maxX = minX; + float maxY = minY; + for (int i = 1; i < vertexCount; ++i) { + v += 2; + float x = v[0]; + float y = v[1]; + minX = std::min(minX, x); + minY = std::min(minY, y); + maxX = std::max(maxX, x); + maxY = std::max(maxY, y); } + return { minX, minY, maxX - minX, maxY - minY }; + } - bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) { - const int index = slot.getData().getIndex(); - return startSlotIndex > index || endSlotIndex < index; - } + bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) { + const int index = slot.getData().getIndex(); + return startSlotIndex > index || endSlotIndex < index; + } - bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex) { - Attachment *attachment = slot.getAttachment(); - if (!attachment || - slotIsOutRange(slot, startSlotIndex, endSlotIndex) || - !slot.getBone().isActive() || - slot.getColor().a == 0) + bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex) { + Attachment *attachment = slot.getAttachment(); + if (!attachment || + slotIsOutRange(slot, startSlotIndex, endSlotIndex) || + !slot.getBone().isActive() || + slot.getColor().a == 0) + return true; + if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { + if (static_cast(attachment)->getColor().a == 0) return true; + } + else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { + if (static_cast(attachment)->getColor().a == 0) + return true; + } + return false; + } + + int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) { + int coordCount = 0; + for (size_t i = 0; i < skeleton.getSlots().size(); ++i) { + Slot& slot = *skeleton.getSlots()[i]; + if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { + continue; + } + Attachment* const attachment = slot.getAttachment(); if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { - if (static_cast(attachment)->getColor().a == 0) - return true; + coordCount += 8; } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { - if (static_cast(attachment)->getColor().a == 0) - return true; + MeshAttachment* const mesh = static_cast(attachment); + coordCount += mesh->getWorldVerticesLength(); } - return false; - } - - int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) { - int coordCount = 0; - for (size_t i = 0; i < skeleton.getSlots().size(); ++i) { - Slot& slot = *skeleton.getSlots()[i]; - if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { - continue; - } - Attachment* const attachment = slot.getAttachment(); - if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { - coordCount += 8; - } - else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { - MeshAttachment* const mesh = static_cast(attachment); - coordCount += mesh->getWorldVerticesLength(); - } - } - return coordCount; - } - - - void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex) { - float* dstPtr = dstCoord; -#ifndef NDEBUG - float* const dstEnd = dstCoord + coordCount; -#endif - for (size_t i = 0; i < skeleton.getSlots().size(); ++i) { - /*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw - if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { - continue; - } - Attachment* const attachment = slot.getAttachment(); - if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { - RegionAttachment* const regionAttachment = static_cast(attachment); - assert(dstPtr + 8 <= dstEnd); - regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2); - dstPtr += 8; - } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { - MeshAttachment* const mesh = static_cast(attachment); - assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd); - mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2); - dstPtr += mesh->getWorldVerticesLength(); - } - } - assert(dstPtr == dstEnd); - } - - void interleaveCoordinates(float* dst, const float* src, int count, int dstStride) { - if (dstStride == 2) { - memcpy(dst, src, sizeof(float) * count * 2); - } else { - for (int i = 0; i < count; ++i) { - dst[0] = src[0]; - dst[1] = src[1]; - dst += dstStride; - src += 2; - } - } - - } - - BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha) { - BlendFunc blendFunc; - -#if COCOS2D_VERSION < 0x00040000 - switch (blendMode) { - case BlendMode_Additive: - blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - blendFunc.dst = GL_ONE; - break; - case BlendMode_Multiply: - blendFunc.src = GL_DST_COLOR; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - break; - case BlendMode_Screen: - blendFunc.src = GL_ONE; - blendFunc.dst = GL_ONE_MINUS_SRC_COLOR; - break; - default: - blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - break; - } -#else - switch (blendMode) { - case BlendMode_Additive: - blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; - blendFunc.dst = backend::BlendFactor::ONE; - break; - case BlendMode_Multiply: - blendFunc.src = backend::BlendFactor::DST_COLOR; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - break; - case BlendMode_Screen: - blendFunc.src = backend::BlendFactor::ONE; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_COLOR; - break; - default: - blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; - blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - } -#endif - return blendFunc; - } - - - bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) { - if (Camera::getVisitingCamera() == nullptr) - return false; - - auto director = Director::getInstance(); - auto scene = director->getRunningScene(); - - if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera())) - return false; - - Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize()); - - // transform center point to screen space - float hSizeX = rect.size.width/2; - float hSizeY = rect.size.height/2; - Vec3 v3p(rect.origin.x + hSizeX, rect.origin.y + hSizeY, 0); - transform.transformPoint(&v3p); - Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p); - - // convert content size to world coordinates - float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4])); - float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5])); - - // enlarge visible rect half size in screen coord - visibleRect.origin.x -= wshw; - visibleRect.origin.y -= wshh; - visibleRect.size.width += wshw * 2; - visibleRect.size.height += wshh * 2; - return !visibleRect.containsPoint(v2p); - } - - - Color4B ColorToColor4B(const Color& color) { - return { (uint8_t)(color.r * 255.f), (uint8_t)(color.g * 255.f), (uint8_t)(color.b * 255.f), (uint8_t)(color.a * 255.f) }; } + return coordCount; } + + void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex) { + float* dstPtr = dstCoord; +#ifndef NDEBUG + float* const dstEnd = dstCoord + coordCount; +#endif + for (size_t i = 0; i < skeleton.getSlots().size(); ++i) { + /*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw + if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) { + continue; + } + Attachment* const attachment = slot.getAttachment(); + if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { + RegionAttachment* const regionAttachment = static_cast(attachment); + assert(dstPtr + 8 <= dstEnd); + regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2); + dstPtr += 8; + } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { + MeshAttachment* const mesh = static_cast(attachment); + assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd); + mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2); + dstPtr += mesh->getWorldVerticesLength(); + } + } + assert(dstPtr == dstEnd); + } + + void interleaveCoordinates(float* dst, const float* src, int count, int dstStride) { + if (dstStride == 2) { + memcpy(dst, src, sizeof(float) * count * 2); + } else { + for (int i = 0; i < count; ++i) { + dst[0] = src[0]; + dst[1] = src[1]; + dst += dstStride; + src += 2; + } + } + + } + + BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha) { + BlendFunc blendFunc; + +#if COCOS2D_VERSION < 0x00040000 + switch (blendMode) { + case BlendMode_Additive: + blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + blendFunc.dst = GL_ONE; + break; + case BlendMode_Multiply: + blendFunc.src = GL_DST_COLOR; + blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case BlendMode_Screen: + blendFunc.src = GL_ONE; + blendFunc.dst = GL_ONE_MINUS_SRC_COLOR; + break; + default: + blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + } +#else + switch (blendMode) { + case BlendMode_Additive: + blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; + blendFunc.dst = backend::BlendFactor::ONE; + break; + case BlendMode_Multiply: + blendFunc.src = backend::BlendFactor::DST_COLOR; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + break; + case BlendMode_Screen: + blendFunc.src = backend::BlendFactor::ONE; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_COLOR; + break; + default: + blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA; + blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + } +#endif + return blendFunc; + } + + + bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) { + if (Camera::getVisitingCamera() == nullptr) + return false; + + auto director = Director::getInstance(); + auto scene = director->getRunningScene(); + + if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera())) + return false; + + Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize()); + + // transform center point to screen space + float hSizeX = rect.size.width/2; + float hSizeY = rect.size.height/2; + Vec3 v3p(rect.origin.x + hSizeX, rect.origin.y + hSizeY, 0); + transform.transformPoint(&v3p); + Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p); + + // convert content size to world coordinates + float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4])); + float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5])); + + // enlarge visible rect half size in screen coord + visibleRect.origin.x -= wshw; + visibleRect.origin.y -= wshh; + visibleRect.size.width += wshw * 2; + visibleRect.size.height += wshh * 2; + return !visibleRect.containsPoint(v2p); + } + + + Color4B ColorToColor4B(const Color& color) { + return { (uint8_t)(color.r * 255.f), (uint8_t)(color.g * 255.f), (uint8_t)(color.b * 255.f), (uint8_t)(color.a * 255.f) }; + } +} + }

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 diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png new file mode 100644 index 0000000000000000000000000000000000000000..42b411b6d2ad052557b6c8fd3323f20400bbb92a GIT binary patch literal 9906 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 literal 0 HcmV?d00001 diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png.meta b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png.meta new file mode 100644 index 000000000..3fa5d3077 --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png.meta @@ -0,0 +1,94 @@ +fileFormatVersion: 2 +guid: 04051f71b9b3db740a8d236ff80672e7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track.png b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track.png new file mode 100644 index 0000000000000000000000000000000000000000..14d0e0194a06d7ae30cda9eb8136b396c1b7eac5 GIT binary patch literal 24841 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≺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 R31e1Kr;nQ$78p2&{|`Oei~#@u literal 0 HcmV?d00001 diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/skeleton-flip-track.png.meta b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/skeleton-flip-track.png.meta new file mode 100644 index 000000000..5bbe58d1c --- /dev/null +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/skeleton-flip-track.png.meta @@ -0,0 +1,74 @@ +fileFormatVersion: 2 +guid: e56f159fca97b5d4ab93f104e1cce135 +timeCreated: 1595514078 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/timeline.png b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/timeline.png index 341a9b2142580779d6ac5b1cd2c9accbf45f0213..246d8d7d66ff1ab1c0ed8d43f184db5741cd851a 100644 GIT binary patch delta 23543 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