Merge branch '3.8' into 3.9-beta

This commit is contained in:
badlogic 2020-06-03 13:17:58 +02:00
commit 3bdd39a409
21 changed files with 1695 additions and 67 deletions

View File

@ -357,6 +357,9 @@
4) Assign this *_Outline* material at the `RenderExistingMesh` component under *Replacement Materials*.
* Added `Outline Shaders URP` example scene to URP extension module to demonstrate the above additions.
* Added support for Unity's [`SpriteAtlas`](https://docs.unity3d.com/Manual/class-SpriteAtlas.html) as atlas provider (as an alternative to `.atlas.txt` and `.png` files) alongside a skeleton data file. There is now an additional `Spine SpriteAtlas Import` tool window accessible via `Window - Spine - SpriteAtlas Import`. Additional information can be found in a new section on the [spine-unity documentation page](http://esotericsoftware.com/spine-unity#Advanced---Using-Unity-SpriteAtlas-as-Atlas-Provider).
* Added support for **multiple atlas textures at `SkeletonGraphic`**. You can enable this feature by enabling the parameter `Multiple CanvasRenders` in the `Advanced` section of the `SkeletonGraphic` Inspector. This automatically creates the required number of child `CanvasRenderer` GameObjects for each required draw call (submesh).
* Added support for **Render Separator Slots** at `SkeletonGraphic`. Render separation can be enabled directly in the `Advanced` section of the `SkeletonGraphic` Inspector, it does not require any additional components (like `SkeletonRenderSeparator` or `SkeletonPartsRenderer` for `SkeletonRenderer` components). When enabled, additional separator GameObjects will be created automatically for each separation part, and `CanvasRenderer` GameObjects re-parented to them accordingly. The separator GameObjects can be moved around and re-parented in the hierarchy according to your requirements to achieve the desired draw order within your `Canvas`. A usage example can be found in the updated `Spine Examples/Other Examples/SkeletonRenderSeparator` scene.
* 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.
* **Changes of default values**
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.

View File

@ -143,6 +143,8 @@ package spine {
var prx : Number = 0;
if (s > 0.0001) {
s = Math.abs(pa * pd - pb * pc) / s;
pa /= this.skeleton.scaleX;
pc /= this.skeleton.scaleY;
pb = pc * s;
pd = pa * s;
prx = Math.atan2(pc, pa) * MathUtils.radDeg;
@ -161,7 +163,7 @@ package spine {
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
return;
break;
}
case TransformMode.noScale:
case TransformMode.noScaleOrReflection: {

View File

@ -385,6 +385,7 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
timelines = current->animation->timelines;
if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) {
for (ii = 0; ii < timelineCount; ii++) {
timeline = timelines[ii];
if (timeline->type == SP_TIMELINE_ATTACHMENT) {
_spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, blend, -1);
} else {

View File

@ -144,6 +144,8 @@ function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX,
local prx = 0
if s > 0.0001 then
s = math_abs(pa * pd - pb * pc) / s
pa = pa / self.skeleton.scaleX
pc = pc / self.skeleton.scaleY
pb = pc * s
pd = pa * s
prx = math_deg(math_atan2(pc, pa));

View File

@ -108,6 +108,42 @@ NavMeshSettings:
tileSize: 256
accuratePlacement: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &33325432
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 33325433}
m_Layer: 5
m_Name: SkeletonGraphic with Separator
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &33325433
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 33325432}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 835737018}
- {fileID: 1738423300}
- {fileID: 1185404038}
m_Father: {fileID: 624843597}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 314.43, y: -527.6}
m_SizeDelta: {x: 176.7, y: 265.7}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &51877969
GameObject:
m_ObjectHideFlags: 0
@ -202,6 +238,74 @@ RectTransform:
m_AnchoredPosition: {x: 6.56, y: -2.09}
m_SizeDelta: {x: 452.17, y: 108.32}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &84997716
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 84997717}
- component: {fileID: 84997719}
- component: {fileID: 84997718}
m_Layer: 5
m_Name: GreenBar1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &84997717
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 84997716}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1738423300}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -0.0000038146973, y: -0.00012207031}
m_SizeDelta: {x: 36.8, y: 183.94}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &84997718
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 84997716}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.3529412, g: 0.56078434, b: 0.10980393, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!222 &84997719
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 84997716}
--- !u!1 &93048074
GameObject:
m_ObjectHideFlags: 0
@ -328,6 +432,90 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &105238416
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 105238417}
- component: {fileID: 105238419}
- component: {fileID: 105238418}
m_Layer: 5
m_Name: Text SkeletonGraphic
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &105238417
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 105238416}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 0.99999994}
m_Children: []
m_Father: {fileID: 624843597}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -101, y: -527.6}
m_SizeDelta: {x: 256.3, y: 63}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &105238418
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 105238416}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 18
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 77
m_Alignment: 0
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 1
m_LineSpacing: 1
m_Text: 'Spineboy to the right is an example of SkeletonGraphics render separation
functionality.
The separator slots are setup via the SkeletonGraphics Advanced Inspector section.
The separator can be enabled via ''SkeletonGraphic.enableSeparatorSlots''.
Please note that ''Multiple Canvas Renderers'' must be enabled.
'
--- !u!222 &105238419
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 105238416}
--- !u!1 &122287539
GameObject:
m_ObjectHideFlags: 0
@ -409,6 +597,40 @@ Transform:
m_Father: {fileID: 1918225119}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &415442239
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 415442240}
m_Layer: 0
m_Name: Part[1]
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &415442240
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 415442239}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 1211557619}
m_Father: {fileID: 1185404038}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 35.678116, y: -357.22165}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &565117361
GameObject:
m_ObjectHideFlags: 0
@ -3791,7 +4013,7 @@ GameObject:
- component: {fileID: 624843595}
- component: {fileID: 624843594}
m_Layer: 5
m_Name: World Canvas
m_Name: World Canvas With Spineboy
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -3865,6 +4087,9 @@ RectTransform:
m_LocalScale: {x: 0.02, y: 0.02, z: 0.1}
m_Children:
- {fileID: 1618699050}
- {fileID: 105238417}
- {fileID: 1055098057}
- {fileID: 33325433}
m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -3938,12 +4163,124 @@ Transform:
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 774732875}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 5.5483284, y: 48.482475, z: 1}
m_LocalPosition: {x: 0, y: 2.175, z: 0}
m_LocalScale: {x: 5.5483284, y: 34.887302, z: 1}
m_Children: []
m_Father: {fileID: 1675659861}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &835737017
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 835737018}
m_Layer: 0
m_Name: Part[0]
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &835737018
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 835737017}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.25, y: 0.25, z: 0.25}
m_Children:
- {fileID: 1882323273}
m_Father: {fileID: 33325433}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -32.299957, y: -63.99994}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1055098056
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1055098057}
- component: {fileID: 1055098059}
- component: {fileID: 1055098058}
m_Layer: 5
m_Name: Text SkeletonGraphic Location
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1055098057
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1055098056}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 0.99999994}
m_Children: []
m_Father: {fileID: 624843597}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 577, y: -513.5}
m_SizeDelta: {x: -54.3, y: 63}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1055098058
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1055098056}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 18
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 77
m_Alignment: 0
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 1
m_LineSpacing: 1
m_Text: 'The Part[0] GameObject was re-parented above the GreenBar object to render
in the desired order
The SkeletonGraphic''s ''Update Part Location'' parameter lets the re-parented
parts follow the main SkeletonGraphic location.'
--- !u!222 &1055098059
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1055098056}
--- !u!1 &1149289853
GameObject:
m_ObjectHideFlags: 0
@ -3967,8 +4304,8 @@ Transform:
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1149289853}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.06, y: 0, z: 0}
m_LocalScale: {x: 4.661441, y: 48.482475, z: 1}
m_LocalPosition: {x: 0.06, y: 2.175, z: 0}
m_LocalScale: {x: 4.661441, y: 34.887302, z: 1}
m_Children: []
m_Father: {fileID: 1675659861}
m_RootOrder: 1
@ -4015,6 +4352,153 @@ SpriteRenderer:
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
--- !u!1 &1185404037
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1185404038}
- component: {fileID: 1185404040}
- component: {fileID: 1185404039}
- component: {fileID: 1185404041}
m_Layer: 0
m_Name: SkeletonGraphic (spineboy-unity)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1185404038
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1185404037}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.25, y: 0.25, z: 0.25}
m_Children:
- {fileID: 415442240}
m_Father: {fileID: 33325433}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -32.3, y: -64}
m_SizeDelta: {x: 371.0865, y: 731.54474}
m_Pivot: {x: 0.59614486, y: 0.011688247}
--- !u!114 &1185404039
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1185404037}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d85b887af7e6c3f45a2e2d2920d641bc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
skeletonDataAsset: {fileID: 11400000, guid: a467507a4ffb1d542a558739b2fede77, type: 2}
initialSkinName: base
initialFlipX: 0
initialFlipY: 0
startingAnimation:
startingLoop: 1
timeScale: 1
freeze: 0
unscaledTime: 0
allowMultipleCanvasRenderers: 1
canvasRenderers:
- {fileID: 1882323272}
- {fileID: 1211557620}
separatorSlotNames:
- --A
enableSeparatorSlots: 1
separatorParts:
- {fileID: 835737018}
- {fileID: 415442240}
updateSeparatorPartLocation: 1
meshGenerator:
settings:
useClipping: 1
zSpacing: 0
pmaVertexColors: 1
tintBlack: 0
calculateTangents: 0
addNormals: 0
immutableTriangles: 0
--- !u!222 &1185404040
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1185404037}
--- !u!114 &1185404041
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1185404037}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d6bb29eb283767441a398ce2a7be27c3, type: 3}
m_Name:
m_EditorClassIdentifier:
skeletonGraphic: {fileID: 1185404039}
run: {fileID: 11400000, guid: 2d841d20c203ff24a859b8c73f9c3817, type: 2}
pole: {fileID: 11400000, guid: dff7c26e6e007e748b47240522cff0c8, type: 2}
startX: -600
endX: 0
--- !u!1 &1211557618
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1211557619}
- component: {fileID: 1211557620}
m_Layer: 0
m_Name: Renderer1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1211557619
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1211557618}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 415442240}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1211557620
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1211557618}
--- !u!1 &1406277772
GameObject:
m_ObjectHideFlags: 0
@ -4038,8 +4522,8 @@ Transform:
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1406277772}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.44, y: 0, z: 0}
m_LocalScale: {x: 0.44441086, y: 48.482475, z: 1}
m_LocalPosition: {x: 0.44, y: 2.175, z: 0}
m_LocalScale: {x: 0.44441086, y: 34.887302, z: 1}
m_Children: []
m_Father: {fileID: 1675659861}
m_RootOrder: 2
@ -4439,6 +4923,42 @@ Transform:
m_Father: {fileID: 1918225119}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1738423299
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1738423300}
m_Layer: 5
m_Name: GreenBar
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1738423300
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1738423299}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 84997717}
- {fileID: 1983276686}
- {fileID: 2132214121}
m_Father: {fileID: 33325433}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 6.700018, y: 24.610062}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1769987559
GameObject:
m_ObjectHideFlags: 0
@ -4520,6 +5040,46 @@ Transform:
m_Father: {fileID: 93048079}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1882323271
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1882323273}
- component: {fileID: 1882323272}
m_Layer: 0
m_Name: Renderer0
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!222 &1882323272
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1882323271}
--- !u!224 &1882323273
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1882323271}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 835737018}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1918225114
GameObject:
m_ObjectHideFlags: 0
@ -4663,6 +5223,142 @@ MonoBehaviour:
pole: {fileID: 11400000, guid: dff7c26e6e007e748b47240522cff0c8, type: 2}
startX: -11.5
endX: 2.8
--- !u!1 &1983276685
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1983276686}
- component: {fileID: 1983276688}
- component: {fileID: 1983276687}
m_Layer: 5
m_Name: GreenBar2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1983276686
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1983276685}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1738423300}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -14.800003, y: -0.000061035156}
m_SizeDelta: {x: 7.2, y: 183.98}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1983276687
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1983276685}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.3647059, g: 0.4901961, b: 0.17254902, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!222 &1983276688
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1983276685}
--- !u!1 &2132214120
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 2132214121}
- component: {fileID: 2132214123}
- component: {fileID: 2132214122}
m_Layer: 5
m_Name: GreenBar3
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2132214121
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2132214120}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1738423300}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 6.7999954, y: -0.000061035156}
m_SizeDelta: {x: 7.2, y: 183.98}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2132214122
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2132214120}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.4784314, g: 0.9686275, b: 0.007843138, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!222 &2132214123
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2132214120}
--- !u!1 &2142418130
GameObject:
m_ObjectHideFlags: 0

View File

@ -0,0 +1,80 @@
/******************************************************************************
* 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 UnityEngine;
using System.Collections;
using Spine.Unity;
using Spine.Unity.Examples;
namespace Spine.Unity.Examples {
public class SpineboyPoleGraphic : MonoBehaviour {
public SkeletonGraphic skeletonGraphic;
[Space(18)]
public AnimationReferenceAsset run;
public AnimationReferenceAsset pole;
public float startX;
public float endX;
const float Speed = 18f;
const float RunTimeScale = 1.5f;
IEnumerator Start () {
var state = skeletonGraphic.AnimationState;
while (true) {
// Run phase
SetXPosition(startX);
skeletonGraphic.enableSeparatorSlots = false; // Disable Separator during run.
state.SetAnimation(0, run, true);
state.TimeScale = RunTimeScale;
while (transform.localPosition.x < endX) {
transform.Translate(Vector3.right * Speed * Time.deltaTime);
yield return null;
}
// Hit phase
SetXPosition(endX);
skeletonGraphic.enableSeparatorSlots = true; // Enable Separator when hit
var poleTrack = state.SetAnimation(0, pole, false);
yield return new WaitForSpineAnimationComplete(poleTrack);
yield return new WaitForSeconds(1f);
}
}
void SetXPosition (float x) {
var tp = transform.localPosition;
tp.x = x;
transform.localPosition = tp;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d6bb29eb283767441a398ce2a7be27c3
timeCreated: 1458684804
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,159 @@
/******************************************************************************
* 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;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Spine.Unity.Examples;
namespace Spine.Unity.Editor {
// This script is not intended for use with code. See spine-unity documentation page for additional information.
[CustomEditor(typeof(SkeletonGraphicCustomMaterials))]
public class SkeletonGraphicCustomMaterialsInspector : UnityEditor.Editor {
List<SkeletonGraphicCustomMaterials.AtlasMaterialOverride> componentCustomMaterialOverrides, _customMaterialOverridesPrev;
List<SkeletonGraphicCustomMaterials.AtlasTextureOverride> componentCustomTextureOverrides, _customTextureOverridesPrev;
SkeletonGraphicCustomMaterials component;
const BindingFlags PrivateInstance = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo RemoveCustomMaterialOverrides, RemoveCustomTextureOverrides, SetCustomMaterialOverrides, SetCustomTextureOverrides;
#region SkeletonGraphic context menu
[MenuItem("CONTEXT/SkeletonGraphic/Add Basic Serialized Custom Materials")]
static void AddSkeletonGraphicCustomMaterials (MenuCommand menuCommand) {
var skeletonGraphic = (SkeletonGraphic)menuCommand.context;
var newComponent = skeletonGraphic.gameObject.AddComponent<SkeletonGraphicCustomMaterials>();
Undo.RegisterCreatedObjectUndo(newComponent, "Add Basic Serialized Custom Materials");
}
[MenuItem("CONTEXT/SkeletonGraphic/Add Basic Serialized Custom Materials", true)]
static bool AddSkeletonGraphicCustomMaterials_Validate (MenuCommand menuCommand) {
var skeletonGraphic = (SkeletonGraphic)menuCommand.context;
return (skeletonGraphic.GetComponent<SkeletonGraphicCustomMaterials>() == null);
}
#endregion
void OnEnable () {
Type cm = typeof(SkeletonGraphicCustomMaterials);
RemoveCustomMaterialOverrides = cm.GetMethod("RemoveCustomMaterialOverrides", PrivateInstance);
RemoveCustomTextureOverrides = cm.GetMethod("RemoveCustomTextureOverrides", PrivateInstance);
SetCustomMaterialOverrides = cm.GetMethod("SetCustomMaterialOverrides", PrivateInstance);
SetCustomTextureOverrides = cm.GetMethod("SetCustomTextureOverrides", PrivateInstance);
}
public override void OnInspectorGUI () {
component = (SkeletonGraphicCustomMaterials)target;
var skeletonGraphic = component.skeletonGraphic;
// Draw the default inspector
DrawDefaultInspector();
if (serializedObject.isEditingMultipleObjects)
return;
if (componentCustomMaterialOverrides == null) {
Type cm = typeof(SkeletonGraphicCustomMaterials);
componentCustomMaterialOverrides = cm.GetField("customMaterialOverrides", PrivateInstance).GetValue(component) as List<SkeletonGraphicCustomMaterials.AtlasMaterialOverride>;
componentCustomTextureOverrides = cm.GetField("customTextureOverrides", PrivateInstance).GetValue(component) as List<SkeletonGraphicCustomMaterials.AtlasTextureOverride>;
if (componentCustomMaterialOverrides == null) {
Debug.Log("Reflection failed.");
return;
}
}
// Fill with current values at start
if (_customMaterialOverridesPrev == null || _customTextureOverridesPrev == null) {
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customTextureOverridesPrev = CopyList(componentCustomTextureOverrides);
}
// Compare new values with saved. If change is detected:
// store new values, restore old values, remove overrides, restore new values, restore overrides.
// 1. Store new values
var customMaterialOverridesNew = CopyList(componentCustomMaterialOverrides);
var customTextureOverridesNew = CopyList(componentCustomTextureOverrides);
// Detect changes
if (!_customMaterialOverridesPrev.SequenceEqual(customMaterialOverridesNew) ||
!_customTextureOverridesPrev.SequenceEqual(customTextureOverridesNew)) {
// 2. Restore old values
componentCustomMaterialOverrides.Clear();
componentCustomTextureOverrides.Clear();
componentCustomMaterialOverrides.AddRange(_customMaterialOverridesPrev);
componentCustomTextureOverrides.AddRange(_customTextureOverridesPrev);
// 3. Remove overrides
RemoveCustomMaterials();
// 4. Restore new values
componentCustomMaterialOverrides.Clear();
componentCustomTextureOverrides.Clear();
componentCustomMaterialOverrides.AddRange(customMaterialOverridesNew);
componentCustomTextureOverrides.AddRange(customTextureOverridesNew);
// 5. Restore overrides
SetCustomMaterials();
if (skeletonGraphic != null)
skeletonGraphic.LateUpdate();
}
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customTextureOverridesPrev = CopyList(componentCustomTextureOverrides);
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Clear and Reapply Changes", tooltip: "Removes all non-serialized overrides in the SkeletonGraphic and reapplies the overrides on this component."))) {
if (skeletonGraphic != null) {
skeletonGraphic.CustomMaterialOverride.Clear();
skeletonGraphic.CustomTextureOverride.Clear();
RemoveCustomMaterials();
SetCustomMaterials();
skeletonGraphic.LateUpdate();
}
}
}
void RemoveCustomMaterials () {
RemoveCustomMaterialOverrides.Invoke(component, null);
RemoveCustomTextureOverrides.Invoke(component, null);
}
void SetCustomMaterials () {
SetCustomMaterialOverrides.Invoke(component, null);
SetCustomTextureOverrides.Invoke(component, null);
}
static List<T> CopyList<T> (List<T> list) {
return list.GetRange(0, list.Count);
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 349bf125947e3aa4bb78690fec69ea17
timeCreated: 1588789940
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -42,15 +42,20 @@ namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonGraphic))]
[CanEditMultipleObjects]
public class SkeletonGraphicInspector : UnityEditor.Editor {
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
SerializedProperty material, color;
SerializedProperty skeletonDataAsset, initialSkinName;
SerializedProperty startingAnimation, startingLoop, timeScale, freeze, unscaledTime, tintBlack;
SerializedProperty initialFlipX, initialFlipY;
SerializedProperty meshGeneratorSettings;
SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation;
SerializedProperty raycastTarget;
SkeletonGraphic thisSkeletonGraphic;
protected bool isInspectingPrefab;
protected bool slotsReapplyRequired = false;
protected bool TargetIsValid {
get {
@ -100,9 +105,17 @@ namespace Spine.Unity.Editor {
meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings");
meshGeneratorSettings.isExpanded = SkeletonRendererInspector.advancedFoldout;
allowMultipleCanvasRenderers = so.FindProperty("allowMultipleCanvasRenderers");
updateSeparatorPartLocation = so.FindProperty("updateSeparatorPartLocation");
enableSeparatorSlots = so.FindProperty("enableSeparatorSlots");
separatorSlotNames = so.FindProperty("separatorSlotNames");
separatorSlotNames.isExpanded = true;
}
public override void OnInspectorGUI () {
bool wasChanged = false;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(skeletonDataAsset);
@ -115,9 +128,56 @@ namespace Spine.Unity.Editor {
serializedObject.Update();
return;
}
bool isSingleRendererOnly = (!allowMultipleCanvasRenderers.hasMultipleDifferentValues && allowMultipleCanvasRenderers.boolValue == false);
bool isSeparationEnabledButNotMultipleRenderers =
isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true);
bool meshRendersIncorrectlyWithSingleRenderer =
isSingleRendererOnly && SkeletonHasMultipleSubmeshes();
if (isSeparationEnabledButNotMultipleRenderers || meshRendersIncorrectlyWithSingleRenderer)
meshGeneratorSettings.isExpanded = true;
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.PropertyField(meshGeneratorSettings, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: true);
SkeletonRendererInspector.advancedFoldout = meshGeneratorSettings.isExpanded;
if (meshGeneratorSettings.isExpanded) {
EditorGUILayout.Space();
using (new SpineInspectorUtility.IndentScope()) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(allowMultipleCanvasRenderers, SpineInspectorUtility.TempContent("Multiple CanvasRenderers"));
if (GUILayout.Button(new GUIContent("Trim Renderers", "Remove currently unused CanvasRenderer GameObjects. These will be regenerated whenever needed."),
EditorStyles.miniButton, GUILayout.Width(100f))) {
foreach (var skeletonGraphic in targets) {
((SkeletonGraphic)skeletonGraphic).TrimRenderers();
}
}
EditorGUILayout.EndHorizontal();
// warning box
if (isSeparationEnabledButNotMultipleRenderers) {
using (new SpineInspectorUtility.BoxScope()) {
meshGeneratorSettings.isExpanded = true;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("'Multiple Canvas Renderers' must be enabled\nwhen 'Enable Separation' is enabled.", Icons.warning), GUILayout.Height(42), GUILayout.Width(340));
}
}
else if (meshRendersIncorrectlyWithSingleRenderer) {
using (new SpineInspectorUtility.BoxScope()) {
meshGeneratorSettings.isExpanded = true;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("This mesh uses multiple atlas pages. You\n" +
"need to enable 'Multiple Canvas Renderers'\n" +
"for correct rendering. Consider packing\n" +
"attachments to a single atlas page if possible.", Icons.warning), GUILayout.Height(60), GUILayout.Width(340));
}
}
}
EditorGUILayout.Space();
SeparatorsField(separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation);
}
}
EditorGUILayout.Space();
@ -164,10 +224,82 @@ namespace Spine.Unity.Editor {
}
}
bool wasChanged = EditorGUI.EndChangeCheck();
wasChanged |= EditorGUI.EndChangeCheck();
if (wasChanged)
if (wasChanged) {
serializedObject.ApplyModifiedProperties();
slotsReapplyRequired = true;
}
if (slotsReapplyRequired && UnityEngine.Event.current.type == EventType.Repaint) {
foreach (var target in targets) {
var skeletonGraphic = (SkeletonGraphic)target;
skeletonGraphic.ReapplySeparatorSlotNames();
skeletonGraphic.LateUpdate();
SceneView.RepaintAll();
}
slotsReapplyRequired = false;
}
}
protected bool SkeletonHasMultipleSubmeshes () {
foreach (var target in targets) {
var skeletonGraphic = (SkeletonGraphic)target;
if (skeletonGraphic.HasMultipleSubmeshInstructions())
return true;
}
return false;
}
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
field.SetValue(skeletonRenderer, newSlotNames);
}
public static string[] GetSeparatorSlotNames (SkeletonRenderer skeletonRenderer) {
var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
return field.GetValue(skeletonRenderer) as string[];
}
public static void SeparatorsField (SerializedProperty separatorSlotNames, SerializedProperty enableSeparatorSlots,
SerializedProperty updateSeparatorPartLocation) {
bool multi = separatorSlotNames.serializedObject.isEditingMultipleObjects;
bool hasTerminalSlot = false;
if (!multi) {
var sr = separatorSlotNames.serializedObject.targetObject as ISkeletonComponent;
var skeleton = sr.Skeleton;
int lastSlot = skeleton.Slots.Count - 1;
if (skeleton != null) {
for (int i = 0, n = separatorSlotNames.arraySize; i < n; i++) {
int index = skeleton.FindSlotIndex(separatorSlotNames.GetArrayElementAtIndex(i).stringValue);
if (index == 0 || index == lastSlot) {
hasTerminalSlot = true;
break;
}
}
}
}
string terminalSlotWarning = hasTerminalSlot ? " (!)" : "";
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
const string SeparatorsDescription = "Stored names of slots where the Skeleton's render will be split into different batches. This is used by separate components that split the render into different MeshRenderers or GameObjects.";
if (separatorSlotNames.isExpanded) {
EditorGUILayout.PropertyField(separatorSlotNames, SpineInspectorUtility.TempContent(separatorSlotNames.displayName + terminalSlotWarning, Icons.slotRoot, SeparatorsDescription), true);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("+", GUILayout.MaxWidth(28f), GUILayout.MaxHeight(15f))) {
separatorSlotNames.arraySize++;
}
GUILayout.EndHorizontal();
}
else
EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + string.Format("{0} [{1}]", terminalSlotWarning, separatorSlotNames.arraySize), SeparatorsDescription), true);
EditorGUILayout.PropertyField(enableSeparatorSlots, SpineInspectorUtility.TempContent("Enable Separation", tooltip: "Whether to enable separation at the above separator slots."));
EditorGUILayout.PropertyField(updateSeparatorPartLocation, SpineInspectorUtility.TempContent("Update Part Location", tooltip:"Update separator part GameObject location to match the position of the SkeletonGraphic. This can be helpful when re-parenting parts to a different GameObject."));
}
}
#region Menus

View File

@ -31,6 +31,7 @@
#define NEW_PREFAB_SYSTEM
#endif
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@ -58,6 +59,20 @@ namespace Spine.Unity {
public float timeScale = 1f;
public bool freeze;
public bool unscaledTime;
public bool allowMultipleCanvasRenderers = false;
public List<CanvasRenderer> canvasRenderers = new List<CanvasRenderer>();
// Submesh Separation
public const string SeparatorPartGameObjectName = "Part";
/// <summary>Slot names used to populate separatorSlots list when the Skeleton is initialized. Changing this after initialization does nothing.</summary>
[SerializeField] [SpineSlot] protected string[] separatorSlotNames = new string[0];
/// <summary>Slots that determine where the render is split. This is used by components such as SkeletonRenderSeparator so that the skeleton can be rendered by two separate renderers on different GameObjects.</summary>
[System.NonSerialized] public readonly List<Slot> separatorSlots = new List<Slot>();
public bool enableSeparatorSlots = false;
[SerializeField] protected List<Transform> separatorParts = new List<Transform>();
public List<Transform> SeparatorParts { get { return separatorParts; } }
public bool updateSeparatorPartLocation = true;
private bool wasUpdatedAfterInit = true;
private Texture baseTexture = null;
@ -74,8 +89,8 @@ namespace Spine.Unity {
} else if (skeletonDataAsset.GetSkeletonData(true) != skeleton.data) {
Clear();
Initialize(true);
if (skeletonDataAsset.atlasAssets.Length > 1 || skeletonDataAsset.atlasAssets[0].MaterialCount > 1)
Debug.LogError("Unity UI does not support multiple textures per Renderer. Your skeleton will not be rendered correctly. Recommend using SkeletonAnimation instead. This requires the use of a Screen space camera canvas.");
if (!allowMultipleCanvasRenderers && (skeletonDataAsset.atlasAssets.Length > 1 || skeletonDataAsset.atlasAssets[0].MaterialCount > 1))
Debug.LogError("Unity UI does not support multiple textures per Renderer. Please enable 'Advanced - Multiple CanvasRenderers' to generate the required CanvasRenderer GameObjects. Otherwise your skeleton will not be rendered correctly.", this);
} else {
if (freeze) return;
@ -143,7 +158,15 @@ namespace Spine.Unity {
}
#endregion
#region Internals
#region Overrides
[System.NonSerialized] readonly Dictionary<Texture, Texture> customTextureOverride = new Dictionary<Texture, Texture>();
/// <summary>Use this Dictionary to override a Texture with a different Texture.</summary>
public Dictionary<Texture, Texture> CustomTextureOverride { get { return customTextureOverride; } }
[System.NonSerialized] readonly Dictionary<Texture, Material> customMaterialOverride = new Dictionary<Texture, Material>();
/// <summary>Use this Dictionary to override the Material where the Texture was used at the original atlas.</summary>
public Dictionary<Texture, Material> CustomMaterialOverride { get { return customMaterialOverride; } }
// This is used by the UI system to determine what to put in the MaterialPropertyBlock.
Texture overrideTexture;
public Texture OverrideTexture {
@ -153,6 +176,9 @@ namespace Spine.Unity {
canvasRenderer.SetTexture(this.mainTexture); // Refresh canvasRenderer's texture. Make sure it handles null.
}
}
#endregion
#region Internals
public override Texture mainTexture {
get {
if (overrideTexture != null) return overrideTexture;
@ -181,6 +207,7 @@ namespace Spine.Unity {
base.Rebuild(update);
if (canvasRenderer.cull) return;
if (update == CanvasUpdate.PreRender) UpdateMesh();
if (allowMultipleCanvasRenderers) canvasRenderer.Clear();
}
public virtual void Update () {
@ -223,6 +250,29 @@ namespace Spine.Unity {
//this.SetVerticesDirty(); // Which is better?
UpdateMesh();
}
public void ReapplySeparatorSlotNames () {
if (!IsValid)
return;
separatorSlots.Clear();
for (int i = 0, n = separatorSlotNames.Length; i < n; i++) {
string slotName = separatorSlotNames[i];
if (slotName == "")
continue;
var slot = skeleton.FindSlot(slotName);
if (slot != null) {
separatorSlots.Add(slot);
}
#if UNITY_EDITOR
else
{
Debug.LogWarning(slotName + " is not a slot in " + skeletonDataAsset.skeletonJSON.name);
}
#endif
}
UpdateSeparatorPartParents();
}
#endregion
#region API
@ -247,6 +297,7 @@ namespace Spine.Unity {
public Spine.Unity.MeshGenerator MeshGenerator { get { return this.meshGenerator; } }
DoubleBuffered<Spine.Unity.MeshRendererBuffers.SmartMesh> meshBuffers;
SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
readonly ExposedList<Mesh> meshes = new ExposedList<Mesh>();
public Mesh GetLastMesh () {
return meshBuffers.GetCurrent().mesh;
@ -255,21 +306,62 @@ namespace Spine.Unity {
public bool MatchRectTransformWithBounds () {
UpdateMesh();
if (!this.allowMultipleCanvasRenderers)
return MatchRectTransformSingleRenderer();
else
return MatchRectTransformMultipleRenderers();
}
protected bool MatchRectTransformSingleRenderer () {
Mesh mesh = this.GetLastMesh();
if (mesh == null) {
return false;
}
if (mesh.vertexCount == 0) {
this.rectTransform.sizeDelta = new Vector2(50f, 50f);
this.rectTransform.pivot = new Vector2(0.5f, 0.5f);
return false;
}
mesh.RecalculateBounds();
var bounds = mesh.bounds;
var size = bounds.size;
var center = bounds.center;
SetRectTransformBounds(mesh.bounds);
return true;
}
protected bool MatchRectTransformMultipleRenderers () {
bool anyBoundsAdded = false;
Bounds combinedBounds = new Bounds();
for (int i = 0; i < canvasRenderers.Count; ++i) {
var canvasRenderer = canvasRenderers[i];
if (!canvasRenderer.gameObject.activeSelf)
continue;
Mesh mesh = meshes.Items[i];
if (mesh == null || mesh.vertexCount == 0)
continue;
mesh.RecalculateBounds();
var bounds = mesh.bounds;
if (anyBoundsAdded)
combinedBounds.Encapsulate(bounds);
else {
anyBoundsAdded = true;
combinedBounds = bounds;
}
}
if (!anyBoundsAdded) {
this.rectTransform.sizeDelta = new Vector2(50f, 50f);
this.rectTransform.pivot = new Vector2(0.5f, 0.5f);
return false;
}
SetRectTransformBounds(combinedBounds);
return true;
}
private void SetRectTransformBounds (Bounds combinedBounds) {
var size = combinedBounds.size;
var center = combinedBounds.center;
var p = new Vector2(
0.5f - (center.x / size.x),
0.5f - (center.y / size.y)
@ -277,7 +369,6 @@ namespace Spine.Unity {
this.rectTransform.sizeDelta = size;
this.rectTransform.pivot = p;
return true;
}
public event UpdateBonesDelegate UpdateLocal;
@ -290,6 +381,28 @@ namespace Spine.Unity {
public void Clear () {
skeleton = null;
canvasRenderer.Clear();
for (int i = 0; i < canvasRenderers.Count; ++i)
canvasRenderers[i].Clear();
foreach (var mesh in meshes)
Destroy(mesh);
meshes.Clear();
}
public void TrimRenderers () {
var newList = new List<CanvasRenderer>();
foreach (var canvasRenderer in canvasRenderers) {
if (canvasRenderer.gameObject.activeSelf) {
newList.Add(canvasRenderer);
}
else {
if (Application.isEditor && !Application.isPlaying)
DestroyImmediate(canvasRenderer.gameObject);
else
Destroy(canvasRenderer.gameObject);
}
}
canvasRenderers = newList;
}
public void Initialize (bool overwrite) {
@ -321,6 +434,10 @@ namespace Spine.Unity {
if (!string.IsNullOrEmpty(initialSkinName))
skeleton.SetSkin(initialSkinName);
separatorSlots.Clear();
for (int i = 0; i < separatorSlotNames.Length; i++)
separatorSlots.Add(skeleton.FindSlot(separatorSlotNames[i]));
wasUpdatedAfterInit = false;
if (!string.IsNullOrEmpty(startingAnimation)) {
var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(startingAnimation);
@ -341,15 +458,39 @@ namespace Spine.Unity {
if (!this.IsValid) return;
skeleton.SetColor(this.color);
var smartMesh = meshBuffers.GetNext();
var currentInstructions = this.currentInstructions;
if (!this.allowMultipleCanvasRenderers) {
UpdateMeshSingleCanvasRenderer();
}
else {
UpdateMeshMultipleCanvasRenderers(currentInstructions);
}
if (OnMeshAndMaterialsUpdated != null)
OnMeshAndMaterialsUpdated(this);
}
public bool HasMultipleSubmeshInstructions () {
if (!IsValid)
return false;
return MeshGenerator.RequiresMultipleSubmeshesByDrawOrder(skeleton);
}
#endregion
protected void UpdateMeshSingleCanvasRenderer () {
if (canvasRenderers.Count > 0)
DisableUnusedCanvasRenderers(usedCount : 0);
var smartMesh = meshBuffers.GetNext();
MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, null);
bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed);
meshGenerator.Begin();
if (currentInstructions.hasActiveClipping && currentInstructions.submeshInstructions.Count > 0) {
meshGenerator.AddSubmesh(currentInstructions.submeshInstructions.Items[0], updateTriangles);
} else {
}
else {
meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
}
@ -373,10 +514,180 @@ namespace Spine.Unity {
}
}
//this.UpdateMaterial(); // TODO: This allocates memory.
if (OnMeshAndMaterialsUpdated != null)
OnMeshAndMaterialsUpdated(this);
//this.UpdateMaterial(); // note: This would allocate memory.
}
#endregion
protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) {
MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, null,
enableSeparatorSlots ? separatorSlots : null,
enableSeparatorSlots ? separatorSlots.Count > 0 : false,
false);
int submeshCount = currentInstructions.submeshInstructions.Count;
EnsureCanvasRendererCount(submeshCount);
EnsureMeshesCount(submeshCount);
EnsureSeparatorPartCount();
var c = canvas;
float scale = (c == null) ? 100 : c.referencePixelsPerUnit;
// Generate meshes.
var meshesItems = meshes.Items;
bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0);
int separatorSlotGroupIndex = 0;
Transform parent = this.separatorSlots.Count == 0 ? this.transform : this.separatorParts[0];
if (updateSeparatorPartLocation) {
for (int p = 0; p < this.separatorParts.Count; ++p) {
separatorParts[p].position = this.transform.position;
separatorParts[p].rotation = this.transform.rotation;
}
}
int targetSiblingIndex = 0;
for (int i = 0; i < submeshCount; i++) {
var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
meshGenerator.Begin();
meshGenerator.AddSubmesh(submeshInstructionItem);
var targetMesh = meshesItems[i];
meshGenerator.ScaleVertexData(scale);
if (OnPostProcessVertices != null) OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
meshGenerator.FillVertexData(targetMesh);
meshGenerator.FillTriangles(targetMesh);
meshGenerator.FillLateVertexData(targetMesh);
var submeshMaterial = submeshInstructionItem.material;
var canvasRenderer = canvasRenderers[i];
canvasRenderer.gameObject.SetActive(true);
canvasRenderer.SetMesh(targetMesh);
canvasRenderer.materialCount = 1;
if (canvasRenderer.transform.parent != parent.transform) {
canvasRenderer.transform.SetParent(parent.transform, false);
canvasRenderer.transform.localPosition = Vector3.zero;
}
canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++);
if (submeshInstructionItem.forceSeparate) {
targetSiblingIndex = 0;
parent = separatorParts[++separatorSlotGroupIndex];
}
if (useOriginalTextureAndMaterial)
canvasRenderer.SetMaterial(this.materialForRendering, submeshMaterial.mainTexture);
else {
var originalTexture = submeshMaterial.mainTexture;
Material usedMaterial;
Texture usedTexture;
if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial))
usedMaterial = material;
if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture))
usedTexture = originalTexture;
canvasRenderer.SetMaterial(usedMaterial, usedTexture);
}
}
DisableUnusedCanvasRenderers(usedCount : submeshCount);
}
protected void EnsureCanvasRendererCount (int targetCount) {
#if UNITY_EDITOR
RemoveNullCanvasRenderers();
#endif
int currentCount = canvasRenderers.Count;
for (int i = currentCount; i < targetCount; ++i) {
var go = new GameObject(string.Format("Renderer{0}", i), typeof(RectTransform));
go.transform.SetParent(this.transform, false);
go.transform.localPosition = Vector3.zero;
var canvasRenderer = go.AddComponent<CanvasRenderer>();
canvasRenderers.Add(canvasRenderer);
}
}
protected void DisableUnusedCanvasRenderers (int usedCount) {
#if UNITY_EDITOR
RemoveNullCanvasRenderers();
#endif
for (int i = usedCount; i < canvasRenderers.Count; i++) {
canvasRenderers[i].Clear();
canvasRenderers[i].gameObject.SetActive(false);
}
}
#if UNITY_EDITOR
private void RemoveNullCanvasRenderers () {
if (Application.isEditor && !Application.isPlaying) {
for (int i = canvasRenderers.Count - 1; i >= 0; --i) {
if (canvasRenderers[i] == null) {
canvasRenderers.RemoveAt(i);
}
}
}
}
#endif
protected void EnsureMeshesCount (int targetCount) {
int oldCount = meshes.Count;
meshes.EnsureCapacity(targetCount);
var meshesItems = meshes.Items;
for (int i = oldCount; i < targetCount; i++)
if (meshesItems[i] == null) meshesItems[i] = new Mesh();
}
protected void EnsureSeparatorPartCount () {
#if UNITY_EDITOR
RemoveNullSeparatorParts();
#endif
int targetCount = separatorSlots.Count + 1;
if (targetCount == 1)
return;
#if UNITY_EDITOR
if (Application.isEditor && !Application.isPlaying) {
for (int i = separatorParts.Count-1; i >= 0; --i) {
if (separatorParts[i] == null) {
separatorParts.RemoveAt(i);
}
}
}
#endif
int currentCount = separatorParts.Count;
for (int i = currentCount; i < targetCount; ++i) {
var go = new GameObject(string.Format("{0}[{1}]", SeparatorPartGameObjectName, i), typeof(RectTransform));
go.transform.SetParent(this.transform, false);
go.transform.localPosition = Vector3.zero;
separatorParts.Add(go.transform);
}
}
protected void UpdateSeparatorPartParents () {
int usedCount = separatorSlots.Count + 1;
if (usedCount == 1) {
usedCount = 0; // placed directly at the SkeletonGraphic parent
for (int i = 0; i < canvasRenderers.Count; ++i) {
var canvasRenderer = canvasRenderers[i];
if (canvasRenderer.transform.parent.name.Contains(SeparatorPartGameObjectName)) {
canvasRenderer.transform.SetParent(this.transform, false);
canvasRenderer.transform.localPosition = Vector3.zero;
}
}
}
for (int i = 0; i < separatorParts.Count; ++i) {
bool isUsed = i < usedCount;
separatorParts[i].gameObject.SetActive(isUsed);
}
}
#if UNITY_EDITOR
private void RemoveNullSeparatorParts () {
if (Application.isEditor && !Application.isPlaying) {
for (int i = separatorParts.Count - 1; i >= 0; --i) {
if (separatorParts[i] == null) {
separatorParts.RemoveAt(i);
}
}
}
}
#endif
}
}

View File

@ -269,14 +269,14 @@ namespace Spine.Unity {
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, stateInfo.loop, stateInfo.speed < 0), stateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
if (hasNext) {
for (int c = 0; c < nextClipInfoCount; c++) {
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), nextStateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
}
if (isInterruptionActive) {
@ -288,7 +288,7 @@ namespace Spine.Unity {
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0),
interruptingStateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
}
} else { // case MixNext || Hard
@ -298,7 +298,7 @@ namespace Spine.Unity {
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, stateInfo.loop, stateInfo.speed < 0), stateInfo.loop, null, 1f, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
++c; break;
}
// Mix the rest
@ -306,7 +306,7 @@ namespace Spine.Unity {
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, stateInfo.loop, stateInfo.speed < 0), stateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
c = 0;
@ -317,7 +317,7 @@ namespace Spine.Unity {
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), nextStateInfo.loop, null, 1f, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
++c; break;
}
}
@ -326,7 +326,7 @@ namespace Spine.Unity {
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), nextStateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
}
@ -340,7 +340,7 @@ namespace Spine.Unity {
float weight = clipWeight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), interruptingStateInfo.loop, null, 1f, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
++c; break;
}
}
@ -351,7 +351,7 @@ namespace Spine.Unity {
float weight = clipWeight * layerWeight; if (weight == 0) continue;
var clip = GetAnimation(info.clip);
if (clip != null)
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), interruptingStateInfo.loop, null, weight, layerBlendMode, MixDirection.In);
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
}
}
}

View File

@ -1,6 +0,0 @@
SkeletonRenderSeparator
=======================
Dependencies:
- SkeletonPartsRenderer uses the `ArraysMeshGenerator` class in `Spine.Unity.MeshGeneration`
- It requires `SPINE_OPTIONAL_RENDEROVERRIDE` to be #defined in `SkeletonRenderer.cs`.

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: f0e413eeb00eabc46bde6dbd7aaaa76c
timeCreated: 1469110129
licenseType: Free
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,210 @@
/******************************************************************************
* 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Spine.Unity {
#if NEW_PREFAB_SYSTEM
[ExecuteAlways]
#else
[ExecuteInEditMode]
#endif
public class SkeletonGraphicCustomMaterials : MonoBehaviour {
#region Inspector
public SkeletonGraphic skeletonGraphic;
[SerializeField] protected List<AtlasMaterialOverride> customMaterialOverrides = new List<AtlasMaterialOverride>();
[SerializeField] protected List<AtlasTextureOverride> customTextureOverrides = new List<AtlasTextureOverride>();
#if UNITY_EDITOR
void Reset () {
skeletonGraphic = GetComponent<SkeletonGraphic>();
// Populate material list
if (skeletonGraphic != null && skeletonGraphic.skeletonDataAsset != null) {
var atlasAssets = skeletonGraphic.skeletonDataAsset.atlasAssets;
var initialAtlasMaterialOverrides = new List<AtlasMaterialOverride>();
foreach (AtlasAssetBase atlasAsset in atlasAssets) {
foreach (Material atlasMaterial in atlasAsset.Materials) {
var atlasMaterialOverride = new AtlasMaterialOverride {
overrideEnabled = false,
originalTexture = atlasMaterial.mainTexture
};
initialAtlasMaterialOverrides.Add(atlasMaterialOverride);
}
}
customMaterialOverrides = initialAtlasMaterialOverrides;
}
// Populate texture list
if (skeletonGraphic != null && skeletonGraphic.skeletonDataAsset != null) {
var atlasAssets = skeletonGraphic.skeletonDataAsset.atlasAssets;
var initialAtlasTextureOverrides = new List<AtlasTextureOverride>();
foreach (AtlasAssetBase atlasAsset in atlasAssets) {
foreach (Material atlasMaterial in atlasAsset.Materials) {
var atlasTextureOverride = new AtlasTextureOverride {
overrideEnabled = false,
originalTexture = atlasMaterial.mainTexture
};
initialAtlasTextureOverrides.Add(atlasTextureOverride);
}
}
customTextureOverrides = initialAtlasTextureOverrides;
}
}
#endif
#endregion
void SetCustomMaterialOverrides () {
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
for (int i = 0; i < customMaterialOverrides.Count; i++) {
AtlasMaterialOverride atlasMaterialOverride = customMaterialOverrides[i];
if (atlasMaterialOverride.overrideEnabled)
skeletonGraphic.CustomMaterialOverride[atlasMaterialOverride.originalTexture] = atlasMaterialOverride.replacementMaterial;
}
}
void RemoveCustomMaterialOverrides () {
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
for (int i = 0; i < customMaterialOverrides.Count; i++) {
AtlasMaterialOverride atlasMaterialOverride = customMaterialOverrides[i];
Material currentMaterial;
if (!skeletonGraphic.CustomMaterialOverride.TryGetValue(atlasMaterialOverride.originalTexture, out currentMaterial))
continue;
// Do not revert the material if it was changed by something else
if (currentMaterial != atlasMaterialOverride.replacementMaterial)
continue;
skeletonGraphic.CustomMaterialOverride.Remove(atlasMaterialOverride.originalTexture);
}
}
void SetCustomTextureOverrides () {
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
for (int i = 0; i < customTextureOverrides.Count; i++) {
AtlasTextureOverride atlasTextureOverride = customTextureOverrides[i];
if (atlasTextureOverride.overrideEnabled)
skeletonGraphic.CustomTextureOverride[atlasTextureOverride.originalTexture] = atlasTextureOverride.replacementTexture;
}
}
void RemoveCustomTextureOverrides () {
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
for (int i = 0; i < customTextureOverrides.Count; i++) {
AtlasTextureOverride atlasTextureOverride = customTextureOverrides[i];
Texture currentTexture;
if (!skeletonGraphic.CustomTextureOverride.TryGetValue(atlasTextureOverride.originalTexture, out currentTexture))
continue;
// Do not revert the material if it was changed by something else
if (currentTexture != atlasTextureOverride.replacementTexture)
continue;
skeletonGraphic.CustomTextureOverride.Remove(atlasTextureOverride.originalTexture);
}
}
// OnEnable applies the overrides at runtime, and when the editor loads.
void OnEnable () {
if (skeletonGraphic == null)
skeletonGraphic = GetComponent<SkeletonGraphic>();
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
skeletonGraphic.Initialize(false);
SetCustomMaterialOverrides();
SetCustomTextureOverrides();
}
// OnDisable removes the overrides at runtime, and in the editor when the component is disabled or destroyed.
void OnDisable () {
if (skeletonGraphic == null) {
Debug.LogError("skeletonGraphic == null");
return;
}
RemoveCustomMaterialOverrides();
RemoveCustomTextureOverrides();
}
[Serializable]
public struct AtlasMaterialOverride : IEquatable<AtlasMaterialOverride> {
public bool overrideEnabled;
public Texture originalTexture;
public Material replacementMaterial;
public bool Equals (AtlasMaterialOverride other) {
return overrideEnabled == other.overrideEnabled && originalTexture == other.originalTexture && replacementMaterial == other.replacementMaterial;
}
}
[Serializable]
public struct AtlasTextureOverride : IEquatable<AtlasTextureOverride> {
public bool overrideEnabled;
public Texture originalTexture;
public Texture replacementTexture;
public bool Equals (AtlasTextureOverride other) {
return overrideEnabled == other.overrideEnabled && originalTexture == other.originalTexture && replacementTexture == other.replacementTexture;
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6c8717e10b272bf42b05d363ac2679a6
timeCreated: 1588789074
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,11 +0,0 @@
SkeletonRendererCustomMaterials by LostPolygon
===============================
This is a basic serialization and inspector implementation for custom material overrides for SkeletonRenderer and its derived classes (SkeletonAnimation, SkeletonAnimator).
## How to use
Right-click on your SkeletonRenderer and select "Add Basic Serialized Custom Materials". This will add and initialize the SkeletonRendererCustomMaterials to the same object.
You can use this to store material override settings for SkeletonRenderer instances/prefabs so they will be applied automatically when your scene starts or when the prefab is instantiated.
This script is not intended for use with code.
To dynamically set materials for your SkeletonRenderer through code, you can directly access `SkeletonRenderer.CustomMaterialOverride` for material array overrides and `SkeletonRenderer.CustomSlotMaterials` for slot material overrides.

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 3d4db6c367e463c4cb5566afc490163c
timeCreated: 1460572571
licenseType: Free
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -227,6 +227,35 @@ namespace Spine.Unity {
}
}
public static bool RequiresMultipleSubmeshesByDrawOrder (Skeleton skeleton) {
#if SPINE_TK2D
return false;
#endif
ExposedList<Slot> drawOrder = skeleton.drawOrder;
int drawOrderCount = drawOrder.Count;
var drawOrderItems = drawOrder.Items;
Material lastRendererMaterial = null;
for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrderItems[i];
if (!slot.bone.active) continue;
Attachment attachment = slot.attachment;
var rendererAttachment = attachment as IHasRendererObject;
if (rendererAttachment != null) {
AtlasRegion atlasRegion = (AtlasRegion)rendererAttachment.RendererObject;
Material material = (Material)atlasRegion.page.rendererObject;
if (lastRendererMaterial != material) {
if (lastRendererMaterial != null)
return true;
else
lastRendererMaterial = material;
}
}
}
return false;
}
public static void GenerateSkeletonRendererInstruction (SkeletonRendererInstruction instructionOutput, Skeleton skeleton, Dictionary<Slot, Material> customSlotMaterials, List<Slot> separatorSlots, bool generateMeshOverride, bool immutableTriangles = false) {
// if (skeleton == null) throw new ArgumentNullException("skeleton");
// if (instructionOutput == null) throw new ArgumentNullException("instructionOutput");