每日自动提交 2026-04-03 18:30

This commit is contained in:
2026-04-03 18:32:19 +08:00
parent 57bdff08a7
commit 4ab7ca2518
477 changed files with 29057 additions and 22756 deletions
File diff suppressed because it is too large Load Diff
@@ -30,6 +30,8 @@ public class MonsterContral : MonoBehaviour
public bool isMove = true;
public bool is3D = false;
public string forwordXYZ;
protected RectTransform uirootRect;
protected Camera mainCamera;
public virtual void DieFish(object obj=null)
{
Destroy(gameObject);
@@ -48,16 +50,18 @@ public class MonsterContral : MonoBehaviour
}
return null;
}
const string YZMoveLineName="鱼阵";
const string PuTongFishMoveLineName="曲线";
public virtual void Init(string pathId, float Time, bool isyuzhen = false, string yzID = "")
{
BezierCurveData bezierCurveData;
if (isyuzhen)
{
bezierCurveData = MonsterMoveLine.dic_BezierCurveDatas["鱼阵" + pathId];
bezierCurveData = MonsterMoveLine.dic_BezierCurveDatas[YZMoveLineName + pathId];
}
else
{
bezierCurveData = MonsterMoveLine.dic_BezierCurveDatas["曲线" + pathId];
bezierCurveData = MonsterMoveLine.dic_BezierCurveDatas[PuTongFishMoveLineName + pathId];
}
monsterData.moveLine.Init(bezierCurveData, Time);
isyz = isyuzhen;
@@ -142,6 +146,8 @@ public class MonsterContral : MonoBehaviour
{
InitAnimList();
ChangeState(CharacterStateType.move);
uirootRect = UIManager.Instance.uiRoot.GetComponent<RectTransform>();
mainCamera = Camera.main;
}
public virtual void OnMoveEnter()
{
@@ -170,7 +176,7 @@ public class MonsterContral : MonoBehaviour
//可优化
var movestart = monsterData.moveLine.bezierCurveData.start;
movestart = CoordinateTransformation.CanvasToWorld(movestart, UIManager.Instance.uiRoot.GetComponent<RectTransform>(), Camera.main);
movestart = CoordinateTransformation.CanvasToWorld(movestart, uirootRect, mainCamera);
//Debug.Log("movestart:"+movestart);
if (monsterData.moveLine.bezierCurveData.start.y > 0)
{
@@ -191,7 +197,7 @@ public class MonsterContral : MonoBehaviour
//可优化
movestart = monsterData.moveLine.bezierCurveData.start;
movestart = CoordinateTransformation.CanvasToWorld(movestart, UIManager.Instance.uiRoot.GetComponent<RectTransform>(), Camera.main);
movestart = CoordinateTransformation.CanvasToWorld(movestart, uirootRect,mainCamera);
//Debug.Log("movestart:" + movestart);
{
Vector2 v2 = movestart + (Vector2)(-1 * transform.up * moveTime * monsterData.moveLine.moveTime);
@@ -43,6 +43,102 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
private Dictionary<GameTypeEnum, Dictionary<string, RoomFishDetailConfig>> createDic;
private Dictionary<string, FishTypeConfig> fishDatas;
public Dictionary<string, MonsterContral> fishDatas_hashCodekey = new Dictionary<string, MonsterContral>();
// ================= 新增缓存字典 =================
private Dictionary<string, FishArrayConfig> fishArrayConfigDic;
private Dictionary<string, FishTypeConfig> fishTypeConfigDic;
private void BuildConfigCache()
{
// 构建 fishArrayConfigs 字典缓存
fishArrayConfigDic = GameManager.Instance.gameConfig.fishArrayConfigs
.ToDictionary(a => a.fishArrayNumber, a => a);
// 构建 fishTypeConfigs 字典缓存
fishTypeConfigDic = GameManager.Instance.gameConfig.fishTypeConfigs
.ToDictionary(f => f.fishNumber, f => f);
}
///// <summary>
///// 懒加载初始化(只执行一次)
///// </summary>
//private void EnsureInit()
//{
// if (roomFishConfig != null)
// return;
// FishYZ.Init();
// roomFishConfig = new Dictionary<GameTypeEnum, RoomFishConfig>();
// createDic = new Dictionary<GameTypeEnum, Dictionary<string, RoomFishDetailConfig>>();
// var list = GameManager.Instance.gameConfig.roomFishConfigs;
// if (list == null || list.Count == 0)
// return;
// foreach (var item in list)
// {
// GameTypeEnum gameType = (GameTypeEnum)item.gameType;
// // 安全添加(避免重复 key 抛异常)
// roomFishConfig[gameType] = item;
// // 初始化子字典
// var fishDic = new Dictionary<string, RoomFishDetailConfig>();
// createDic[gameType] = fishDic;
// // 普通鱼
// if (item.normalFishList != null)
// {
// foreach (var fish in item.normalFishList)
// fishDic[fish.fishNumber] = fish;
// }
// // 等级鱼(若与基础鱼相同素材替换基础的)
// if (item.roomFishLevelList != null)
// {
// foreach (var fish in item.roomFishLevelList)
// fishDic[fish.fishNumber] = fish;
// }
// }
//}
private void EnsureInit()
{
if (roomFishConfig != null)
return;
FishYZ.Init();
roomFishConfig = new Dictionary<GameTypeEnum, RoomFishConfig>();
createDic = new Dictionary<GameTypeEnum, Dictionary<string, RoomFishDetailConfig>>();
var list = GameManager.Instance.gameConfig.roomFishConfigs;
if (list == null || list.Count == 0)
return;
// 初始化缓存字典
BuildConfigCache();
foreach (var item in list)
{
GameTypeEnum gameType = (GameTypeEnum)item.gameType;
roomFishConfig[gameType] = item;
var fishDic = new Dictionary<string, RoomFishDetailConfig>();
createDic[gameType] = fishDic;
if (item.normalFishList != null)
{
foreach (var fish in item.normalFishList)
fishDic[fish.fishNumber] = fish;
}
if (item.roomFishLevelList != null)
{
foreach (var fish in item.roomFishLevelList)
fishDic[fish.fishNumber] = fish;
}
}
}
public Dictionary<string, FishTypeConfig> FishDatas
{
get
@@ -58,48 +154,6 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
}
#region 初始化鱼生成配置
/// <summary>
/// 懒加载初始化(只执行一次)
/// </summary>
private void EnsureInit()
{
if (roomFishConfig != null)
return;
FishYZ.Init();
roomFishConfig = new Dictionary<GameTypeEnum, RoomFishConfig>();
createDic = new Dictionary<GameTypeEnum, Dictionary<string, RoomFishDetailConfig>>();
var list = GameManager.Instance.gameConfig.roomFishConfigs;
if (list == null || list.Count == 0)
return;
foreach (var item in list)
{
GameTypeEnum gameType = (GameTypeEnum)item.gameType;
// 安全添加(避免重复 key 抛异常)
roomFishConfig[gameType] = item;
// 初始化子字典
var fishDic = new Dictionary<string, RoomFishDetailConfig>();
createDic[gameType] = fishDic;
// 普通鱼
if (item.normalFishList != null)
{
foreach (var fish in item.normalFishList)
fishDic[fish.fishNumber] = fish;
}
// 等级鱼(若与基础鱼相同素材替换基础的)
if (item.roomFishLevelList != null)
{
foreach (var fish in item.roomFishLevelList)
fishDic[fish.fishNumber] = fish;
}
}
}
/// <summary>
/// 房间鱼配置(按游戏类型)
@@ -172,14 +226,24 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
if (item.type == 2)
{
var yz = GameManager.Instance.gameConfig.fishArrayConfigs.Find(a => a.fishArrayNumber == item.fishNumber);
if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
//var yz = GameManager.Instance.gameConfig.fishArrayConfigs.Find(a => a.fishArrayNumber == item.fishNumber);
//if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
//{
// yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
//}
//yz_FishConfig_Line[yz.arrayNumber].Add(item);
// ====== 修改点:用字典替代 List.Find ======
if (fishArrayConfigDic.TryGetValue(item.fishNumber, out var yz))
{
yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
{
yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
}
yz_FishConfig_Line[yz.arrayNumber].Add(item);
}
yz_FishConfig_Line[yz.arrayNumber].Add(item);
}
}
foreach (var item in config.roomFishLevelList)
@@ -194,14 +258,24 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
var yz = GameManager.Instance.gameConfig.fishArrayConfigs.Find(a => a.fishArrayNumber == item.fishNumber);
if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
//var yz = GameManager.Instance.gameConfig.fishArrayConfigs.Find(a => a.fishArrayNumber == item.fishNumber);
//if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
//{
// yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
//}
//yz_FishConfig_Line[yz.arrayNumber].Add(item);
// ====== 修改点:用字典替代 List.Find ======
if (fishArrayConfigDic.TryGetValue(item.fishNumber, out var yz))
{
yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
if (!yz_FishConfig_Line.ContainsKey(yz.arrayNumber))
{
yz_FishConfig_Line[yz.arrayNumber] = new List<RoomFishDetailConfig>();
}
yz_FishConfig_Line[yz.arrayNumber].Add(item);
}
yz_FishConfig_Line[yz.arrayNumber].Add(item);
}
@@ -253,7 +327,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
spawnList = null;
for (int i = 0; i < fishRoot.childCount; i++)
{
Destroy( fishRoot.GetChild(i).gameObject);
Destroy(fishRoot.GetChild(i).gameObject);
}
}
#endregion
@@ -327,10 +401,10 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
JobHandle handle = job.Schedule();
handle.Complete();
boss -= Time.deltaTime;
yz_Time -= Time.deltaTime;
pt -= Time.deltaTime;
float deltatime = Time.deltaTime;
boss -= deltatime;
yz_Time -= deltatime;
pt -= deltatime;
if (boss <= 0)
{
if (fishTypeConfig.ContainsKey(FishTypeEnum.Boss鱼))
@@ -488,21 +562,14 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
else if (cfg.type == 2)
{
//cfg.fishNumber;3
var yz = GameManager.Instance.gameConfig.fishArrayConfigs.Find(a => a.fishArrayNumber == cfg.fishNumber);
foreach (var item in GameManager.Instance.gameConfig.fishArrayConfigs)
if (fishArrayConfigDic.TryGetValue(cfg.fishNumber, out var yz))
{
if (item.arrayNumber == cfg.fishNumber)
{
Debug.Log(item);
}
}
FishTypeConfig fishType = null;
foreach (var item in M_GameConfig.fishTypeConfigs)
if (fishTypeConfigDic.TryGetValue(yz.fishNumber, out var ft))
{
if (item.fishNumber == yz.fishNumber)
{
fishType = item;
}
fishType = ft;
}
// 3. 出生点
Vector3 pos = new Vector3(
@@ -512,7 +579,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
int pathId = 0;
int count = 0;
count=yz.fishCount;
count = yz.fishCount;
List<int> list = new List<int>();
switch (yz.arrayNumber.Substring(0, 3))
{
@@ -520,7 +587,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
case "700":
list = FishYZ.dicfishYZ[yz.arrayNumber];
StartCoroutine(IeShanXing(createFishData, yz, pos, prefab, list, time,count));
StartCoroutine(IeShanXing(createFishData, yz, pos, prefab, list, time, count));
break;
case "701":
@@ -534,7 +601,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
foreach (var item in list)
{
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, item, time,count));
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, item, time, count));
}
break;
@@ -542,12 +609,12 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
list = FishYZ.dicfishYZ[yz.arrayNumber];
foreach (var item in list)
{
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, item, time,count));
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, item, time, count));
}
break;
case "710":
list = FishYZ.dicfishYZ[yz.arrayNumber];
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, list[Random.Range(0,list.Count)], time, count));
StartCoroutine(YZ7007(createFishData, yz, pos, prefab, list[Random.Range(0, list.Count)], time, count));
break;
default:
break;
@@ -560,7 +627,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
IEnumerator IeShanXing(FrameData_CreateFish createFishData, FishArrayConfig yz, Vector3 pos, GameObject prefab, List<int> list, long time,int count)
IEnumerator IeShanXing(FrameData_CreateFish createFishData, FishArrayConfig yz, Vector3 pos, GameObject prefab, List<int> list, long time, int count)
{
RoomFishDetailConfig cfg = spawnDic[createFishData.fishNumber];
foreach (var item in list)
@@ -611,7 +678,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
//顺序出
IEnumerator YZ7007(FrameData_CreateFish createFishData, FishArrayConfig yz, Vector3 pos, GameObject prefab, int pathId, long time,int count)
IEnumerator YZ7007(FrameData_CreateFish createFishData, FishArrayConfig yz, Vector3 pos, GameObject prefab, int pathId, long time, int count)
{
RoomFishDetailConfig cfg = spawnDic[createFishData.fishNumber];
List<int> list = FishDatas[yz.fishNumber].pathList;
@@ -650,14 +717,19 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
{
RoomFishDetailConfig cfg = spawnDic[createFishData.fishNumber];
// 1. 找到鱼的基础配置
FishTypeConfig fishType = M_GameConfig.fishTypeConfigs
.Find(f => f.fishNumber == cfg.fishNumber);
if (fishType == null)
//FishTypeConfig fishType = M_GameConfig.fishTypeConfigs
// .Find(f => f.fishNumber == cfg.fishNumber);
// ====== 修改点:用字典替代 List.Find ======
if (!fishTypeConfigDic.TryGetValue(cfg.fishNumber, out var fishType))
{
Debug.LogError($"找不到鱼配置:{cfg.fishNumber}");
return false;
}
//if (fishType == null)
//{
// Debug.LogError($"找不到鱼配置:{cfg.fishNumber}");
// return false;
//}
// 2. 加载 Prefab(imageUrl 你可以换成自己的字段)
//var prefab = await Addressables.LoadAssetAsync<GameObject>(fishType.imageUrl).Task;
@@ -793,7 +865,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
//Destroy(monster.gameObject);
fishDatas_hashCodekey.Remove(fishId);
}
}
}
public void Ws_DieFish(string msg)
{
var killFish = JsonConvert.DeserializeObject<WebSocketResponseBase<RoomKillNotice>>(msg).arguments[0];
+1 -1
View File
@@ -253,7 +253,7 @@ namespace Assets.MyGame.Scripts.Net
Debug.LogError("错误代码:" + code + "错误信息:" + message);
//这里之后补弹窗
UIManager.Instance.ShowBoardError("错误代码:" + code + "错误信息:" + message);
}
}
}
@@ -1,4 +1,7 @@
public class UserBaseInfo
using System;
[Serializable]
public class UserBaseInfo
{
public string userName { get; set; }
public string password { get; set; }
-135
View File
@@ -2888,7 +2888,6 @@ GameObject:
- component: {fileID: 6542561060930485909}
- component: {fileID: 1056885248303844320}
- component: {fileID: 2669359584981438084}
- component: {fileID: 582122759025887289}
m_Layer: 0
m_Name: -h-vip (1)
m_TagString: Untagged
@@ -2953,50 +2952,6 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &582122759025887289
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2570285668878051517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 2669359584981438084}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &2701901445882921336
GameObject:
m_ObjectHideFlags: 0
@@ -5019,7 +4974,6 @@ GameObject:
- component: {fileID: 3604835082534464121}
- component: {fileID: 1020194819284908310}
- component: {fileID: 7546787681005239013}
- component: {fileID: 348958790080805550}
m_Layer: 0
m_Name: -h-vip (2)
m_TagString: Untagged
@@ -5084,50 +5038,6 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &348958790080805550
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4348020444315061542}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 7546787681005239013}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &4587799190945175577
GameObject:
m_ObjectHideFlags: 0
@@ -7145,7 +7055,6 @@ GameObject:
- component: {fileID: 6817559745575328737}
- component: {fileID: 8679119709980567266}
- component: {fileID: 6119523778879306011}
- component: {fileID: 2403343744979405336}
m_Layer: 0
m_Name: -h-vip
m_TagString: Untagged
@@ -7210,50 +7119,6 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &2403343744979405336
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7454928103288557905}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 6119523778879306011}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &7657864743914521669
GameObject:
m_ObjectHideFlags: 0
@@ -17,11 +17,13 @@ public class UIHome_BY_JJJPanel : SubUIBase
public override void Awake()
{
base.Awake();
//添加金币
btn_Receive.onClick.AddListener(() =>
{
APIRequestList.GetRelief((callvack)=>
{
UIManager.Instance.ShowBoardGongGao("救济金领取成功");
//这里弹窗领取成功
});
});
@@ -30,6 +32,7 @@ public class UIHome_BY_JJJPanel : SubUIBase
protected override void OnShow(object args = null)
{
base.OnShow(args);
var jjjData = GameManager.Instance.gameConfig.reliefConfigs;
txt_coinsNum.text = "金币" + jjjData.gold.ToString();
if (GameManager.Instance.user.assets.gold < jjjData.limit&& GameManager.Instance.user.@static.reliefGoldCount>0)
@@ -1,7 +1,14 @@
using UnityEngine;
using UnityEngine;
public class Eff_changE_StageEvent : MonoBehaviour
{
public Transform MoveTargetPosition;
public void eventComeEnd()
{
GetComponent<Animation>().CrossFade("fly",0.3f);
}
/*
Dummy class. This could have happened for several reasons:
+6 -406
View File
@@ -1,409 +1,10 @@
# 3.8
## AS3
* **Breaking changes**
* Renamed `Slot#getAttachmentVertices()` to `Slot#getDeform()`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin#addAttachment()` to `Skin#setAttachment()`.
* Removed `VertexAttachment#applyDeform()` and replaced it with `VertexAttachment#deformAttachment`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* Switched projects from FDT to Visual Studio Code. See updated `README.md` files for instructions.
* **Additions**
* Added `SkeletonBinary` to load binary `.skel` files. See `MixAndMatchExample.as` in `spine-startling-example`.
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin#getAttachments()`. Returns all attachments in the skin.
* Added `Skin#getAttachments(int slotIndex)`. Returns all attachements in the skin for the given slot index.
* Added `Skin#addSkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin#copySkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* Added `Attachment#copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment#newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
### Starling
* Added `MixAndMatchExample.as` to demonstrate the new Skin API additions and how to load binary `.skel` files.
* Switched projects from FDT to Visual Studio Code. See updated `README.md` files for instructions.
## C
* **Breaking changes**
* Renamed `spSlot#attachmentVertices` to `spSlot#deform`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `spSkin_addAttachment()` to `Skin#spSkin_addAttachment()`.
* Removed `spVertexAttachment_applyDeform()` and replaced it with `VertexAttachment#deformAttachment`. The attachment set on this field is used to decide if a `spDeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `spMeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* **Additions**
* Added `x` and `y` coordinates for setup pose AABB in `spSkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `spSkin_getAttachments()`. Returns all attachments in the skin.
* Added `spSkin_getAttachments(int slotIndex)`. Returns all attachements in the skin for the given slot index.
* Added `spSkin_addSkin(spSkin* skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `spSkin_copySkin(spSkin* skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `spVertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* All attachments inserted into skins are reference counted. When the last skin referencing an attachment is disposed, the attachment will also be disposed.
* Added `spAttachment_copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `spMeshAttachment_newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
### Cocos2d-Objc
* Added mix-and-match example to demonstrate the new Skin API.
* Added `IKExample`.
* Added `SkeletonAnimation preUpdateWorldTransformsListener` and `SkeletonAnimation postUpdateWorldTransformsListener`. When set, these callbacks will be invokved before and after the skeleton's `updateWorldTransforms()` method is called. See the `IKExample` how it can be used.
### SFML
* Added mix-and-match example to demonstrate the new Skin API.
* Added `IKExample`.
## C++
* **Breaking Changes**
* Renamed `Slot::getAttachmentVertices()` to `Slot::getDeform()`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin::addAttachment()` to `Skin::setAttachment()`.
* Removed `VertexAttachment::applyDeform()` and replaced it with `VertexAttachment::getDeformAttachment()`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `_inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* **Additions**
* `AnimationState` and `TrackEntry` now also accept a subclass of `AnimationStateListenerObject` as a listener for animation events in the overloaded `setListener()` method.
* `SkeletonBinary` and `SkeletonJson` now parse and set all non-essential data like audio path.
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin#getAttachments()`. Returns all attachments in the skin.
* Added `Skin#getAttachments(int slotIndex)`. Returns all attachements in the skin for the given slot index.
* Added `Skin#addSkin(Skin &skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin#copySkin(Skin &skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* All attachments inserted into skins are reference counted. When the last skin referencing an attachment is disposed, the attachment will also be disposed.
* Added `Attachment#copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment#newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
* Exposed `x` and `y` on `SkeletonData` through getters and setters.
### Cocos2d-x
* Updated to cocos2d-x 3.17.1
* Added mix-and-match example to demonstrate the new Skin API.
* Exmaple project requires Visual Studio 2019 on Windows
* Added `IKExample`.
* Added `SkeletonAnimation::setPreUpdateWorldTransformsListener()` and `SkeletonAnimation::setPreUpdateWorldTransformsListener()`. When set, these callbacks will be invokved before and after the skeleton's `updateWorldTransforms()` method is called. See the `IKExample` how it can be used.
### SFML
* Added mix-and-match example to demonstrate the new Skin API.
### UE4
* Added `bAutoPlaying` flag to `USpineSkeletonAnimationComponent`. When `false`, the component will not update the internal animation state and skeleton.
* Updated example project to UE 4.22.
* (Re-)Importing Spine assets will perform a version compatibility check and alert users about mismatches in editor mode.
* `USpineSkeletonRendererComponent` allows passing a `USpineSkeletonComponent` to update it. This way, the renderer component can be used without a skeleton component on the same actor.
* Added blueprint-callable methods to `SpineSkeletonComponent` and `SpineSkeletonAnimationComponent` to query and set skins, and enumerate bones, slots, and animations.
* Extended skeleton data editor preview. The preview now shows bones, slots, animations, and skins found in the skeleton data. See this [blog post](http://esotericsoftware.com/blog/Unreal-Engine-4-quality-of-life-improvements).
* Added preview animation and skin fields, allowing you to preview animations and skins right in the editor. See this [blog post](http://esotericsoftware.com/blog/Unreal-Engine-4-quality-of-life-improvements).
* Removed dependency on `RHI`, `RenderCore`, and `ShaderCore`.
* Re-importing atlases and their textures now works consistently in all situations.
* Added mix-and-match example to demonstrate the new Skin API.
* Materials on `SkeletonRendererComponent` are now blueprint read and writeable. This allows setting dynamic material instances at runtime.
* Added `InitialSkin` property to `USpineWidget`. This allows previewing different skins in the UMG Designer. Initial skins can still be overridden via blueprint events such as `On Initialized`.
## C# ##
* **Breaking changes**
* **Changed `IkConstraintData.Bones` type from `List<BoneData>` to `ExposedList<BoneData>`** for unification reasons. *Note: this modification will most likely not affect user code.*
* Renamed `Slot.AttachmentVertices` to `Slot.Deform`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin.AddAttachment()` to `Skin.SetAttachment()`.
* Removed `FindAttachmentsForSlot(int slotIndex, List<Attachment> attachments)` and `FindNamesForSlot (int slotIndex, List<string> names)` and replaced it with `Skin.GetAttachments(int slotIndex, List<SkinEntry> attachments)` which returns the combined `SkinEntry` object holding both name and attachment.
* Removed `VertexAttachment.ApplyDeform()` and replaced it with `VertexAttachment.DeformAttachment`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* **Additions**
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin.GetAttachments()`. Returns all attachments in the skin.
* Added `Skin.GetAttachments(int slotIndex, List<SkinEntry> attachments)`. Returns all attachements in the skin for the given slot index. This method replaces `FindAttachmentsForSlot` and `FindNamesForSlot`.
* Added `Skin.AddSkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin.CopySkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* Added `Attachment.Copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment.NewLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
### Unity
* **Breaking changes**
* **Officially supported Unity versions are 2017.1-2020.2**.
* **Spine `.asmdef` files are again active by default**. They have previously been deactivated to `.txt` extension which is now no longer necessary.
* **Removed PoseSkeleton() and PoseWithAnimation()** extension methods to prevent issues where animations are not mixed out. Problem was that these methods did not set AnimationState, leaving incorrect state at e.g. attachments enabled at slots when starting subsequent animations. As a replacement you can use `AnimationState.ClearTrack(0);` followed by `var entry = AnimationState.SetAnimation(0, animation, loop); entry.TrackTime = time` to achieve similar behaviour.
* **The `Shadow alpha cutoff` shader parameter is now respecting slot-color alpha** values at all Spine shaders. A fragment's texture color alpha is multiplied with slot-color alpha before the result is tested against the `Shadow alpha cutoff` threshold.
* **Removed redundant `Attachment.GetClone()` and `MeshAttachment.GetLinkedClone()` extension methods**. Use methods `Attachment.Copy` and `MeshAttachment.NewLinkedMesh()` instead.
* **Renamed extension method `Attachment.GetClone(bool cloneMeshesAsLinked)` to `Attachment.GetCopy(bool cloneMeshesAsLinked)`** to follow the naming scheme of the Spine API.
* `SkeletonDataAsset.atlasAssets` is now an array of the base class `AtlasAssetBase` instead of `SpineAtlasAsset`, which provides `IEnumerable<> Materials` instead of `List<> materials`. Replace any access via `atlasAsset.materials[0]` with `atlasAsset.Materials.First()` and add a `using System.Linq;` statement.
* **Changed `MeshAttachment.GetLinkedMesh()` method signatures:** removed optional parameters `bool inheritDeform = true, bool copyOriginalProperties = false`.
* Changed namespace `Spine.Unity.Modules` to `Spine.Unity` and `Spine.Unity.Examples` after restructuring (see section below) in respective classes:
* When receiving namespace related errors, replace using statements of `using Spine.Unity.Modules.AttachmentTools;` with `using Spine.Unity.AttachmentTools;`. You can remove `using Spine.Unity.Modules;` statements when a `using Spine.Unity` statement is already present in the file.
* `AttachmentTools`, `SkeletonPartsRenderer`, `SkeletonRenderSeparator`, `SkeletonRendererCustomMaterials` changed to namespace `Spine.Unity`.
* `SkeletonGhost`, `SkeletonGhostRenderer`, `AtlasRegionAttacher`, `SkeletonGraphicMirror`, `SkeletonRagdoll`, `SkeletonRagdoll2D`, `SkeletonUtilityEyeConstraint`, `SkeletonUtilityGroundConstraint`, `SkeletonUtilityKinematicShadow` changed to namespace `Spine.Unity.Examples`.
* Split `Editor/Utility/SpineEditorUtilities` class into multiple files with partial class qualifier.
* Nested classes `SpineEditorUtilities.AssetUtility` and `SpineEditorUtilities.EditorInstantiation` are now no longer nested. If you receive namespace related errors, replace any occurrance of
* `SpineEditorUtilities.AssetUtility` with `AssetUtility` and
* `SpineEditorUtilities.EditorInstantiation` with `EditorInstantiation`.
* **Timeline Support has been moved to a separate UPM Package** Previously the Spine Timeline integration was located in the `Modules/Timeline` directory and was deactivated by default, making it necessary to activate it via the Spine Preferences. Now the Timeline integration has been moved to an additional UPM package which can be found under `Modules/com.esotericsoftware.spine.timeline`.
* **Installation:** You can download the Unity Package Manager (UPM) package via the [download page](http://esotericsoftware.com/spine-unity-download) or find it in the [spine-runtimes/spine-unity/Modules](https://github.com/EsotericSoftware/spine-runtimes/tree/3.8-beta/spine-unity/Modules) subdirectory on the git repository. You can then either unzip (copy if using git) the package to
a) the `Packages` directory in your project where it will automatically be loaded, or
b) to an arbitrary directory outside the Assets directory and then open Package Manager in Unity, select the `+` icon, choose `Add package from disk..` and point it to the package.json file.
The Project panel should now show an entry `Spine Timeline Extensions` under `Packages`. If the directory is not yet listed, you will need to close and re-open Unity to have it display the directory and its contents.
* `SkeletonMecanim`'s `Layer Mix Mode` enum name `MixMode.SpineStyle` has been renamed to `MixMode.Hard`. This is most likely not set via code and thus unlikely to be a problem. Serialized scenes and prefabs are unaffected.
* `SkeletonRootMotion` and `SkeletonMecanimRootMotion` components now support arbitrary bones in the hierarchy as `Root Motion Bone`. Previously there were problems when selecting a non-root bone as `Root Motion Bone`. `Skeleton.ScaleX` and `.ScaleY` and parent bone scale is now respected as well.
* **Additions**
* **Spine Preferences stored in Assets/Editor/SpineSettings.asset** Now Spine uses the new `SettingsProvider` API, storing settings in a SpineSettings.asset file which can be shared with team members. Your old preferences are automatically migrated to the new system.
* Added support for Unity's SpriteMask to `SkeletonAnimation` and `SkeletonMecanim`. All mask interaction modes are supported. See this [blog post](http://esotericsoftware.com/blog/Unity-SpriteMask-and-RectMask2D-support).
* Added support for Unity's RectMask2D to SkeletonGraphics. See this [blog post](http://esotericsoftware.com/blog/Unity-SpriteMask-and-RectMask2D-support).
* Added `Create 2D Hinge Chain` button at `SkeletonUtilityBone` inspector, previously only `Create 3D Hinge Chain` was available.
* **Now supporting Lightweight Render Pipeline (LWRP) through an additional UPM package.**
* **Installation:** You can download the Unity Package Manager (UPM) package via the [download page](http://esotericsoftware.com/spine-unity-download) or find it in the [spine-runtimes/spine-unity/Modules](https://github.com/EsotericSoftware/spine-runtimes/tree/3.8-beta/spine-unity/Modules) subdirectory on the git repository. You can then either unzip (copy if using git) the package to
* a) the `Packages` directory in your project where it will automatically be loaded, or
* b) to an arbitrary directory outside the Assets directory and then open Package Manager in Unity, select the `+` icon, choose `Add package from disk..` and point it to the package.json file.
> If you are using git and Unity 2019.2 or newer versions and receive an error that dependencies could not be resolved by the package manager (only higher versions of Unity's `Lightweight RP` package are available, e.g. `6.9.0` and up), please copy the prepared package-UNITYVERSION.json file for your Unity version (e.g. `package-2019.2.json`) over the existing package.json file to change the dependency accordingly. Unfortunately Unity's Package Manager does not provide a way to specify a version range for a dependency like "5.7.2 - 6.9.0" yet, so this manual step is necessary for git users.
The Project panel should now show an entry `Spine Lightweight RP Shaders` under `Packages`. If the directory is not yet listed, you will need to close and re-open Unity to have it display the directory and its contents.
* **Usage:** The package provides two shaders specifically built for the lightweight render pipeline:
* `Lightweight Render Pipeline/Spine/Skeleton`, as a lightweight variant of the `Spine/Skeleton` shader,
* `Lightweight Render Pipeline/Spine/Skeleton Lit`, as a lightweight variant of the `Spine/Skeleton Lit` shader and
* `Lightweight Render Pipeline/Spine/Sprite`, as a lightweight variant of the `Spine/Sprite/Vertex Lit` and `Pixel Lit` shaders, which were not functioning in the lightweight render pipeline. The shaders can be assigned to materials as usual and will respect your settings of the assigned `LightweightRenderPipelineAsset` under `Project Settings - Graphics`.
* **Restrictions** As all Spine shaders, the LWRP shaders **do not support `Premultiply alpha` (PMA) atlas textures in Linear color space**. Please export your atlas textures as `straight alpha` textures with disabled `Premultiply alpha` setting when using Linear color space. You can check the current color space via `Project Settings - Player - Other Settings - Color Space.`.
* **Example:** You can find an example scene in the package under `com.esotericsoftware.spine.lwrp-shaders-3.8/Examples/LWRP Shaders.unity` that demonstrates usage of the LWRP shaders.
* Added `Spine/Skeleton Lit ZWrite` shader. This variant of the `Spine/Skeleton Lit` shader writes to the depth buffer with configurable depth alpha threshold. Apart from that it is identical to `Spine/Skeleton Lit`.
* Additional yield instructions to wait for animation track events `End`, `Complete` and `Interrupt`.
* `WaitForSpineAnimationComplete` now proves an additional `bool includeEndEvent` parameter, defaults to `false` (previous behaviour).
* Added a new `WaitForSpineAnimationEnd` yield instruction.
* Added a new generic `WaitForSpineAnimation` yield instruction which can be configured to wait for any combination of animation track events. It is now used as base class for `WaitForSpineAnimationComplete` and `WaitForSpineAnimationEnd`.
* Additional **Fix Draw Order** parameter at SkeletonRenderer, defaults to `disabled` (previous behaviour).
Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. "A B A").
If true, 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 leave this parameter disabled when everything is drawn correctly to save the additional performance cost.
* **Additional Timeline features.** SpineAnimationStateClip now provides a `Speed Multiplier`, a start time offset parameter `Clip In`, support for blending successive animations by overlapping tracks. An additional `Use Blend Duration` parameter *(defaults to true)* allows for automatic synchronisation of MixDuration with the current overlap blend duration. An additional Spine preferences parameter `Use Blend Duration` has been added which can be disabled to default to the previous behaviour before this update.
* Additional `SpriteMask and RectMask2D` example scene added for demonstration of mask setup and interaction.
* `Real physics hinge chains` for both 2D and 3D physics. The [SkeletonUtilityBone](http://esotericsoftware.com/spine-unity#SkeletonUtilityBone) Inspector provides an interface to create 2D and 3D hinge chains. Previously created chains have only been respecting gravity, but not momentum of the skeleton or parent bones. The new physics rig created when pressing `Create 3D Hinge Chain` and `Create 2D Hinge Chain` creates a more complex setup that also works when flipping the skeleton. Note that the chain root node is no longer parented to bones of the skeleton. This is a requirement in Unity to have momentum applied properly - do not reparent the chain root to bones of your skeleton, or you will loose any momentum applied by the skeleton's movement.
* `Outline rendering functionality for all shaders.` Every shader now provides an additional set of `Outline` parameters to enable custom outline rendering. When outline rendering is enabled via the `Material` inspector, it automatically switches the shader to the respective `Spine/Outline` shader variant. Outlines are generated by sampling neighbour pixels, so be sure to add enough transparent padding when exporting your atlas textures to fit the desired outline width. In order to enable outline rendering at a skeleton, it is recommended to first prepare an additional outline material copy and then switch the material of the target skeleton to this material. This prevents unnecessary additional runtime material copies and drawcalls. Material switching can be prepared via a [SkeletonRendererCustomMaterials](http://esotericsoftware.com/spine-unity#SkeletonRendererCustomMaterials) component and then enabled or disabled at runtime. Alternatively, you can also directly modify the `SkeletonRenderer.CustomMaterialOverride` property.
Outline rendering is fully supported on `SkeletonGraphic` shaders as well.
* Added `SkeletonRenderer.EditorSkipSkinSync` scripting API property to be able to set custom skins in editor scripts. Enable this property when overwriting the Skeleton's skin from an editor script. Without setting this parameter, changes will be overwritten by the next inspector update. Only affects Inspector synchronisation of skin with `initialSkinName`, not startup initialization.
* All `Spine/SkeletonGraphic` shaders now provide a parameter `CanvasGroup Compatible` which can be enabled to support `CanvasGroup` alpha blending. For correct results, you should then disable `Pma Vertex Colors` in the `SkeletonGraphic` Inspector, in section `Advanced` (otherwise Slot alpha will be applied twice).
* **Now supporting Universal Render Pipeline (URP), including the 2D Renderer pipeline, through an additional UPM package.**
* **Installation:** You can download the Unity Package Manager (UPM) package via the [download page](http://esotericsoftware.com/spine-unity-download) or find it in the [spine-runtimes/spine-unity/Modules](https://github.com/EsotericSoftware/spine-runtimes/tree/3.8-beta/spine-unity/Modules) subdirectory on the git repository. You can then either unzip (copy if using git) the package to
* a) the `Packages` directory in your project where it will automatically be loaded, or
* b) to an arbitrary directory outside the Assets directory and then open Package Manager in Unity, select the `+` icon, choose `Add package from disk..` and point it to the package.json file.
The Project panel should now show an entry `Spine Universal RP Shaders` under `Packages`. If the directory is not yet listed, you will need to close and re-open Unity to have it display the directory and its contents.
* **Usage:** The package provides two shaders specifically built for the universal render pipeline:
* `Universal Render Pipeline/Spine/Skeleton`, as a universal variant of the `Spine/Skeleton` shader,
* `Universal Render Pipeline/Spine/Skeleton Lit`, as a universal variant of the `Spine/Skeleton Lit` shader,
* `Universal Render Pipeline/Spine/Sprite`, as a universal variant of the `Spine/Sprite/Vertex Lit` and `Pixel Lit` shaders, which were not functioning in the universal render pipeline,
* `Universal Render Pipeline/2D/Spine/Skeleton Lit`, as a universal 2D Renderer variant of the `Spine/Skeleton Lit` shader, and
* `Universal Render Pipeline/2D/Spine/Sprite`, as a universal 2D Renderer variant of the `Spine/Sprite/Vertex Lit` and `Pixel Lit` shaders.
The shaders can be assigned to materials as usual and will respect your settings of the assigned `UniversalRenderPipelineAsset` under `Project Settings - Graphics`.
* **Restrictions** As all Spine shaders, the URP shaders **do not support `Premultiply alpha` (PMA) atlas textures in Linear color space**. Please export your atlas textures as `straight alpha` textures with disabled `Premultiply alpha` setting when using Linear color space. You can check the current color space via `Project Settings - Player - Other Settings - Color Space.`.
* **Example:** You can find an example scene in the package under `com.esotericsoftware.spine.urp-shaders-3.8/Examples/URP Shaders.unity` that demonstrates usage of the URP shaders.
* Spine Preferences now provide an **`Atlas Texture Settings`** parameter for applying customizable texture import settings at all newly imported Spine atlas textures.
When exporting atlas textures from Spine with `Premultiply alpha` enabled (the default), you can leave it at `PMATexturePreset`. If you have disabled `Premultiply alpha`, set it to the included `StraightAlphaTexturePreset` asset. You can also create your own `TextureImporter` `Preset` asset and assign it here (include `PMA` or `Straight` in the name). In Unity versions before 2018.3 you can use `Texture2D` template assets instead of the newer `Preset` assets. Materials created for imported textures will also have the `Straight Alpha Texture` parameter configured accordingly.
* All `Sprite` shaders (including URP and LWRP extension packages) now provide an additional `Fixed Normal Space` option `World-Space`. PReviously options were limited to `View-Space` and `Model-Space`.
* `SkeletonGraphic` now fully supports [`SkeletonUtility`](http://esotericsoftware.com/spine-unity#SkeletonUtility) for generating a hierarchy of [`SkeletonUtilityBones`](http://esotericsoftware.com/spine-unity#SkeletonUtilityBone) in both modes `Follow` and `Override`. This also enables creating hinge chain physics rigs and using `SkeletonUtilityConstraints` such as `SkeletonUtilityGroundConstraint` and `SkeletonUtilityEyeConstraint` on `SkeletonGraphic`.
* Added `OnMeshAndMaterialsUpdated` callback event to `SkeletonRenderer` and `SkeletonGraphic`. It is issued at the end of `LateUpdate`, before rendering.
* Added `Skeleton-OutlineOnly` single pass shader to LWRP and URP extension modules. It can be assigned to materials as `Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly`. This allows for separate outline child *GameObjects* that reference the existing Mesh of their parent, and re-draw the mesh using this outline shader.
* Added example component `RenderExistingMesh` to render a mesh again with different materials, as required by the new `Skeleton-OutlineOnly` shaders.
In URP the outline has to be rendered via a separate GameObject as URP does not allow multiple render passes. To add an outline to your SkeletenRenderer:
1) Add a child GameObject and move it a bit back (e.g. position Z = 0.01).
2) Add a `RenderExistingMesh` component, provided in the `Spine Examples/Scripts/Sample Components` directory.
3) Copy the original material, add *_Outline* to its name and set the shader to `Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly`.
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.
* 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).
* 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`.
* Added a new `Spine/Outline/OutlineOnly-ZWrite` shader to provide correct outline-only rendering. Note: the shader requires two render passes and is therefore not compatible with URP. The `Spine Examples/Other Examples/Outline Shaders` example scene has been updated to demonstrate the new shader.
* Added `OnMeshAndMaterialsUpdated` callback event to `SkeletonRenderSeparator` and `SkeletonPartsRenderer`. It is issued at the end of `LateUpdate`, before rendering.
* Added `Root Motion Scale X/Y` parameters to `SkeletonRootMotionBase` subclasses (`SkeletonRootMotion` and `SkeletonMecanimRootMotion`). Also providing `AdjustRootMotionToDistance()` and other methods to allow for easy delta compensation. Delta compensation can be used to e.g. stretch a jump to a given distance. Root motion can be adjusted at the start of an animation or every frame via `skeletonRootMotion.AdjustRootMotionToDistance(targetPosition - transform.position, trackIndex);`.
* Now providing a `Canvas Group Tint Black` parameter at the `SkeletonGraphic` Inspector in the `Advanced` section. When using the `Spine/SkeletonGraphic Tint Black` shader you can enable this parameter to receive proper blending results when using `Additive` blend mode under a `CanvasGroup`. Be sure to also have the parameter `CanvasGroup Compatible` enabled at the shader. Note that the normal `Spine/SkeletonGraphic` does not support `Additive` blend mode at a `CanvasGroup`, as it requires additional shader channels to work.
* Added `Mix and Match Skins` example scene to demonstrate how the 3.8 Skin API and combining skins can be used for a wardrobe and equipment use case.
* Spine Timeline Extensions: Added `Hold Previous` parameter at `SpineAnimationStateClip`.
* Added more warning messages at incompatible SkeletonRenderer/SkeletonGraphic Component vs Material settings. They appear both as an info box in the Inspector as well as upon initialization in the Console log window. The Inspector box warnings can be disabled via `Edit - Preferences - Spine`.
* Now providing `BeforeApply` update callbacks at all skeleton animation components (`SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`).
* Added `BoundingBoxFollowerGraphic` component. This class is a counterpart of `BoundingBoxFollower` that can be used with `SkeletonGraphic`.
* Added Inspector context menu functions `SkeletonRenderer - Add all BoundingBoxFollower GameObjects` and `SkeletonGraphic - Add all BoundingBoxFollowerGraphic GameObjects` that automatically generate bounding box follower GameObjects for every `BoundingBoxAttachment` for all skins of a skeleton.
* `GetRemappedClone()` now provides an additional parameter `pivotShiftsMeshUVCoords` for `MeshAttachment` to prevent uv shifts at a non-central Sprite pivot. This parameter defaults to `true` to maintain previous behaviour.
* `SkeletonRenderer` components now provide an additional update mode `Only Event Timelines` at the `Update When Invisible` property. This mode saves additional timeline updates compared to update mode `Everything Except Mesh`.
* Now all URP (Universal Render Pipeline) and LWRP (Lightweight Render Pipeline) shaders support SRP (Scriptable Render Pipeline) batching. See [Unity SRPBatcher documentation pages](https://docs.unity3d.com/Manual/SRPBatcher.html) for additional information.
* Sprite shaders now provide four `Diffuse Ramp` modes as an Inspector Material parameter: `Hard`, `Soft`, `Old Hard` and `Old Soft`. In spine-unity 3.8 it defaults to `Old Hard` to keep the behaviour of existing projects unchanged. Note that `Old Hard` and `Old Soft` ramp versions were using only the right half of the ramp texture, and additionally multiplying the light intensity by 2, both leading to brighter lighting than without a ramp texture active. The new ramp modes `Hard` and `Soft` use the full ramp texture and do not modify light intensity, being consistent with lighting without a ramp texture active.
* Added **native support for slot blend modes** `Additive`, `Multiply` and `Screen` with automatic assignment at newly imported skeleton assets. `BlendModeMaterialAssets` are now obsolete and replaced by the native properties at `SkeletonDataAsset`. The `SkeletonDataAsset` Inspector provides a new `Blend Modes - Upgrade` button to upgrade an obsolete `BlendModeMaterialAsset` to the native blend modes properties. This upgrade will be performed automatically on imported and re-imported assets in Unity 2020.1 and newer to prevent reported `BlendModeMaterialAsset` issues in these Unity versions. spine-unity 4.0 and newer will automatically perform this upgrade regardless of the Unity version.
* `BoneFollower` and `BoneFollowerGraphic` components now provide better support for following bones when the skeleton's Transform is not the parent of the follower's Transform. Previously e.g. rotating a common parent Transform did not lead to the desired result, as well as negatively scaling a skeleton's Transform when it is not a parent of the follower's Transform.
* URP and LWRP `Sprite` and `SkeletonLit` shaders no longer require `Advanced - Add Normals` enabled to properly cast and receive shadows. It is recommended to disable `Add Normals` if normals are otherwise not needed.
* Added an example component `RootMotionDeltaCompensation` located in `Spine Examples/Scripts/Sample Components` which can be used for applying simple delta compensation. You can enable and disable the component to toggle delta compensation of the currently playing animation on and off.
* Root motion delta compensation now allows to only adjust X or Y components instead of both. Adds two parameters to `SkeletonRootMotionBase.AdjustRootMotionToDistance()` which default to adjusting both X and Y as before. The `RootMotionDeltaCompensation` example component exposes these parameters as public attributes.
* Root motion delta compensation now allows to also add translation root motion to e.g. adjust a horizontal jump upwards or downwards over time. This is necessary because a Y root motion of zero cannot be scaled to become non-zero.
* `Attachment.GetRemappedClone(Sprite)` method now provides an additional optional parameter `useOriginalRegionScale`. When set to `true`, the replaced attachment's scale is used instead of the Sprite's `Pixel per Unity` setting, allowing for more consistent scaling. *Note:* When remapping Sprites, be sure to set the Sprite's `Mesh Type` to `Full Rect` and not `Tight`, otherwise the scale will be wrong.
* **Changes of default values**
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
* `BlendModeMaterialAsset` and it's instance `Default BlendModeMaterials.asset` now have `Apply Additive Material` set to `true` by default in order to apply all blend modes by default.
* **Deprecated**
* Deprecated `Modules/SlotBlendModes/SlotBlendModes` component. Changed namespace from `Spine.Unity.Modules` to `Spine.Unity.Deprecated`. Moved to `Deprecated/SlotBlendModes`.
* **Restructuring (Non-Breaking)**
Note: The following changes will most likely not affect users of the Spine-Unity runtime as the API remains unchanged and no references are invalidated.
* Removed duplicates of `.cginc` files in `Modules/Shaders/Sprite` that were also present in the `Modules/Shaders/Sprite/CGIncludes` directory.
* Moved shaders from `Modules/Shaders` to `Shaders` directory.
* Moved shaders from `Modules/SkeletonGraphic/Shaders` to `Shaders/SkeletonGraphic`.
* Renamed shader `Shaders/Spine-SkeletonLit.shader` to `Shaders/Spine-Skeleton-Lit.shader`.
* Moved components from `SkeletonGraphic` to `Components` and `Components/Following` except for `SkeletonGraphicMirror` which was moved to `Spine Examples/Scripts/Sample Components`.
* Moved `BoneFollower`, `BoneFollowerGraphic` and `PointFollower` from `Components` directory to `Components/Following`.
* Moved `BoundingBoxFollower` component from `Modules/BoundingBoxFollower` to `Components/Following`.
* Moved `Modules/SkeletonRenderSeparator` directory to `Components/SkeletonRenderSeparator`.
* Moved `Modules/CustomMaterials` directory to `Components/SkeletonRendererCustomMaterials`.
* Moved `Asset Types/BlendModeMaterialsAsset.cs` class, `Shaders/BlendModes/Default BlendModeMaterials.asset` and materials from `Shaders/BlendModes` to `SkeletonDataModifierAssets/BlendModeMaterials` directory.
* Moved `Modules/Ghost` directory to `Spine Examples/Scripts/Sample Components/Ghost`.
* Moved `Modules/SkeletonUtility Modules` directory to `Spine Examples/Scripts/Sample Components/SkeletonUtility Modules`.
* Moved `Modules/AnimationMatchModifier` directory to `Spine Examples/Scripts/MecanimAnimationMatchModifier`.
* Moved `SkeletonRagdoll` and `SkeletonRagdoll2D` components from `Modules/Ragdoll` directory to `Spine Examples/Scripts/Sample Components/SkeletonUtility Modules`.
* Moved `AttachmentTools.cs` to `Utility` directory.
* Split the file `AttachmentTools` into 5 separate files for each contained class. No namespace or other API changes performed.
* Split the file `Mesh Generation/SpineMesh` into 4 separate files for each contained class. No namespace or other API changes performed.
* Moved `SkeletonExtensions.cs` to `Utility` directory.
* Moved `Modules/YieldInstructions` directory to `Utility/YieldInstructions`.
* Moved corresponding editor scripts of the above components to restructured directories as well.
* Renamed inspector editor class `PointFollowerEditor` to `PointFollowerInspector` for consistency reasons.
### XNA/MonoGame
* Updated to latest MonoGame version 3.7.1
* Rewrote example project to be cleaner and better demonstrate basic Spine features.
* Added mix-and-match example to demonstrate the new Skin API.
* Added normalmap support via `SpineEffectNormalmap` and support for loading multiple texture layers following a suffix-pattern. Please see the example code on how to use them.
## Java
* **Breaking changes**
* Renamed `Slot#getAttachmentVertices()` to `Slot#getDeform()`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin#addAttachment()` to `Skin#setAttachment()`.
* Removed `VertexAttachment#applyDeform()` and replaced it with `VertexAttachment#deformAttachment`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* `JsonRollback` tool now converts from 3.8 JSON to 3.7.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* **Additions**
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin#getAttachments()`. Returns all attachments in the skin.
* Added `Skin#getAttachments(int slotIndex)`. Returns all attachements in the skin for the given slot index.
* Added `Skin#addSkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin#copySkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* Added `Attachment#copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment#newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
### libGDX
* `SkeletonViewer` can load a skeleton by specifying it as the first argument on the command line.
* Added mix-and-match example to demonstrate the new Skin API.
## Lua
* **Breaking changes**
* Renamed `Slot:getAttachmentVertices()` to `Slot#deform`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin:addAttachment()` to `Skin#setAttachment()`.
* Removed `VertexAttachment:applyDeform()` and replaced it with `VertexAttachment#deformAttachment`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed the `.json` file format to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* **Additions**
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin:getAttachments()`. Returns all attachments in the skin.
* Added `Skin:getAttachments(slotIndex)`. Returns all attachements in the skin for the given slot index.
* Added `Skin:addSkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin:copySkin(Skin skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* Added `Attachment:copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment:newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
### Love2D
* Added support for 0-1 RGBA color component range change in Löve 0.11+. Older Löve versions using the 0-255 range are still supported!
* Added mix-and-match example to demonstrate the new Skin API.
### Corona
* Added mix-and-match example to demonstrate the new Skin API.
## Typescript/Javascript
* **Breaking changes**
* Renamed `MixDirection.in/out` to `MixDirection.mixIn/mixOut` as it was crashing a JS compressor.
* Renamed `Slot#getAttachmentVertices()` to `Slot#getDeform()`.
* Changed the `.json` curve format and added more assumptions for omitted values, reducing the average size of JSON exports.
* Renamed `Skin#addAttachment()` to `Skin#setAttachment()`.
* Removed `VertexAttachment#applyDeform()` and replaced it with `VertexAttachment#deformAttachment`. The attachment set on this field is used to decide if a `DeformTimeline` should be applied to the attachment active on the slot to which the timeline is applied.
* Removed `inheritDeform` field, getter, and setter from `MeshAttachment`.
* Changed `.skel` binary format, added a string table. References to strings in the data resolve to this string table, reducing storage size of binary files considerably.
* Changed the `.json` and `.skel` file formats to accomodate the new feature and file size optimiations. Old projects must be exported with Spine 3.8.20+ to be compatible with the 3.8 Spine runtimes.
* Updated runtime to be compatible with TypeScript 3.6.3.
* **Additions**
* Added support for loading binary data via `AssetManager#loadBinary()`. `AssetManager#get()` will return a `Uint8Array` for such assets.
* Added support for loading binaries via new `SkeletonBinary`. Parses a `Uint8Array`.
* Added `x` and `y` coordinates for setup pose AABB in `SkeletonData`.
* Added support for rotated mesh region UVs.
* Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them.
* Improved Skin API to make it easier to handle mix-and-match use cases.
* Added `Skin#getAttachments()`. Returns all attachments in the skin.
* Added `Skin#getAttachments(slotIndex: number)`. Returns all attachements in the skin for the given slot index.
* Added `Skin#addSkin(skin: Skin)`. Adds all attachments, bones, and skins from the specified skin to this skin.
* Added `Skin#copySkin(skin: Skin)`. Adds all attachments, bones, and skins from the specified skin to this skin. `VertexAttachment` are shallowly copied and will retain any parent mesh relationship. All other attachment types are deep copied.
* Added `Attachment#copy()` to all attachment type implementations. This lets you deep copy an attachment to modify it independently from the original, i.e. when programmatically changing texture coordinates or mesh vertices.
* Added `MeshAttachment#newLinkedMesh()`, creates a linked mesh linkted to either the original mesh, or the parent of the original mesh.
* Added IK softness.
* Added `AssetManager.setRawDataURI(path, data)`. Allows to embed data URIs for skeletons, atlases and atlas page images directly in the HTML/JS without needing to load it from a separate file.
### WebGL backend
* `Input` can now take a partially defined implementation of `InputListener`.
* Added mix-and-match example to demonstrate the new Skin API.
### Canvas backend
### Three.js backend
* `SkeletonMesh` now takes an optional `SkeletonMeshMaterialParametersCustomizer` function that allows you to modify the `ShaderMaterialParameters` before the material is finalized. Use it to modify things like THREEJS' `Material.depthTest` etc. See #1590.
### Player
* `SpinePlayer#setAnimation()` can now be called directly to set the animation being displayed.
* The player supports loading `.skel` binary skeleton files by setting the `SpinePlayerConfig#skelUrl` field instead of `SpinePlayerConfig#jsonUrl`.
* Added `SpinePlayerConfig#rawDataURIs`. Allows to embed data URIs for skeletons, atlases and atlas page images directly in the HTML/JS without needing to load it from a separate file. See the example for a demonstration.
# 3.7
## AS3
* **Breaking changes**
* The completion event will fire for looped 0 duration animations every frame.
* `MixPose` is now called `MixBlend`
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* **Additions**
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
@@ -430,7 +31,7 @@
* Listeners on `spAnimationState` and `spTrackEntry` will now also be called if a track entry gets disposed as part of disposing an animation state.
* The completion event will fire for looped 0 duration animations every frame.
* The spine-cocos2dx and spine-ue4 runtimes are now based on spine-cpp. See below for changes.
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* `spMeshAttachment` has two new fields `regionTextureWith` and `regionTextureHeight`. These must be set in custom attachment loader. See `AtlasAttachmentLoader`.
* **Additions**
@@ -504,7 +105,7 @@
## C# ##
* **Breaking changes**
* The completion event will fire for looped 0 duration animations every frame.
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* **Additions**
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#MixBlend = MixBlend.add` on each track. To specify the blend percentage, set `TrackEntry#Alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
@@ -575,7 +176,7 @@ This will automatically:
* Skeleton attachments: Moved update of attached skeleton out of libGDX `SkeletonRenderer`, added overloaded method `Skeleton#updateWorldTransform(Bone)`, used for `SkeletonAttachment`. You now MUST call this new method with the bone of the parent skeleton to which the child skeleton is attached. See `SkeletonAttachmentTest` for and example.
* The completion event will fire for looped 0 duration animations every frame.
* `MixPose` is now called `MixBlend`.
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* **Additions**
* Added `EventData#audioPath` field. This field contains the file name of the audio file used for the event.
@@ -596,7 +197,7 @@ This will automatically:
## Lua
* **Breaking changes**
* The completion event will fire for looped 0 duration animations every frame.
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* **Additions**
* Added `JitterEffect` and `SwirlEffect` and support for vertex effects in Corona and Love
@@ -614,7 +215,7 @@ This will automatically:
## Typescript/Javascript
* **Breaking changes**
* The completion event will fire for looped 0 duration animations every frame.
* Skeleton `flipX/flipY` has been replaced with `scaleX/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Skeleton `flipX/flipY` has been replaced with `scaleY/scaleY`. This cleans up applying transforms and is more powerful. Allows scaling a whole skeleton which has bones that disallow scale inheritance
* Mix time is no longer affected by `TrackEntry#timeScale`. See https://github.com/EsotericSoftware/spine-runtimes/issues/1194
* **Additions**
* Added `AssetManager.loadTextureAtlas`. Instead of loading the `.atlas` and corresponding image files manually, you can simply specify the location of the `.atlas` file and AssetManager will load the atlas and all its images automatically. `AssetManager.get("atlasname.atlas")` will then return an instance of `spine.TextureAtlas`.
@@ -623,7 +224,6 @@ This will automatically:
* Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
* `TrackEntry` has an additional field called `holdPrevious`. It can be used to counter act a limitation of `AnimationState` resulting in "dipping" of parts of the animation. For a full discussion of the problem and the solution we've implemented, see this [forum thread](http://esotericsoftware.com/forum/Probably-Easy-Animation-mixing-with-multiple-tracks-10682?p=48130&hilit=holdprevious#p48130).
* Added `AssetManager#setRawDataURI(path, data)`. Allows to set raw data URIs for a specific path, which in turn enables embedding assets into JavaScript/HTML.
### WebGL backend
* Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`, and the example which allows to set effects.
+2 -2
View File
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 3a206f1c4d5fd9e49a16634698666cfe
timeCreated: 1636570215
guid: 83bddfd68c7abf74e8db4deaa82e3024
timeCreated: 1565024968
licenseType: Free
DefaultImporter:
userData:
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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 System.Collections;
@@ -33,7 +33,6 @@ using UnityEngine;
using UnityEditor;
using System.Reflection;
using System;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
@@ -59,11 +58,7 @@ namespace Spine.Unity.Editor {
SkeletonData lastSkeletonData;
void OnEnable () { HandleOnEnablePreview(); }
void OnDestroy () {
HandleOnDestroyPreview();
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
EditorApplication.update -= preview.HandleEditorUpdate;
}
void OnDestroy () { HandleOnDestroyPreview(); }
public override void OnInspectorGUI () {
animationNameProperty = animationNameProperty ?? serializedObject.FindProperty("animationName");
@@ -118,7 +113,7 @@ namespace Spine.Unity.Editor {
EditorGUILayout.HelpBox(string.Format("Animation named {0} was not found for this Skeleton.", animationNameProperty.stringValue), MessageType.Warning);
} else {
using (new SpineInspectorUtility.BoxScope()) {
if (!string.Equals(AssetUtility.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase))
if (!string.Equals(SpineEditorUtilities.AssetUtility.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase))
EditorGUILayout.HelpBox("Animation name value does not match this asset's name. Inspectors using this asset may be misleading.", MessageType.None);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(animationName, SpineEditorUtilities.Icons.animation));
@@ -138,11 +133,6 @@ namespace Spine.Unity.Editor {
void HandleOnEnablePreview () {
if (ThisSkeletonDataAsset != null && ThisSkeletonDataAsset.skeletonJSON == null)
return;
SpineEditorUtilities.ConfirmInitialization();
// This handles the case where the managed editor assembly is unloaded before recompilation when code changes.
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
preview.Initialize(this.Repaint, ThisSkeletonDataAsset, LastSkinName);
preview.PlayPauseAnimation(ThisAnimationName, true);
@@ -152,10 +142,6 @@ namespace Spine.Unity.Editor {
EditorApplication.update += preview.HandleEditorUpdate;
}
private void OnDomainUnload (object sender, EventArgs e) {
OnDestroy();
}
private void HandleOnSkinChanged (string skinName) {
EditorPrefs.SetString(LastSkinKey, skinName);
preview.PlayPauseAnimation(ThisAnimationName, true);
@@ -1,153 +0,0 @@
/******************************************************************************
* 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.Reflection;
using UnityEditor;
using UnityEngine;
using Spine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
[CustomEditor(typeof(SpineSpriteAtlasAsset)), CanEditMultipleObjects]
public class SpineSpriteAtlasAssetInspector : UnityEditor.Editor {
SerializedProperty atlasFile, materials;
SpineSpriteAtlasAsset atlasAsset;
static List<AtlasRegion> GetRegions (Atlas atlas) {
FieldInfo regionsField = SpineInspectorUtility.GetNonPublicField(typeof(Atlas), "regions");
return (List<AtlasRegion>)regionsField.GetValue(atlas);
}
void OnEnable () {
SpineEditorUtilities.ConfirmInitialization();
atlasFile = serializedObject.FindProperty("spriteAtlasFile");
materials = serializedObject.FindProperty("materials");
materials.isExpanded = true;
atlasAsset = (SpineSpriteAtlasAsset)target;
if (!SpineSpriteAtlasAsset.AnySpriteAtlasNeedsRegionsLoaded())
return;
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
EditorApplication.update += SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
void OnDisable () {
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
DrawDefaultInspector();
return;
}
serializedObject.Update();
atlasAsset = (atlasAsset == null) ? (SpineSpriteAtlasAsset)target : atlasAsset;
if (atlasAsset.RegionsNeedLoading) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) {
EditorApplication.isPlaying = true;
}
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
atlasAsset.Clear();
atlasAsset.GetAtlas();
atlasAsset.updateRegionsInPlayMode = true;
}
if (materials.arraySize == 0) {
EditorGUILayout.HelpBox("No materials", MessageType.Error);
return;
}
for (int i = 0; i < materials.arraySize; i++) {
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
var material = (Material)prop.objectReferenceValue;
if (material == null) {
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
return;
}
}
if (atlasFile.objectReferenceValue != null) {
int baseIndent = EditorGUI.indentLevel;
var regions = SpineSpriteAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas());
int regionsCount = regions.Count;
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel);
EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount));
}
AtlasPage lastPage = null;
for (int i = 0; i < regionsCount; i++) {
if (lastPage != regions[i].page) {
if (lastPage != null) {
EditorGUILayout.Separator();
EditorGUILayout.Separator();
}
lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject);
if (mat != null) {
EditorGUI.indentLevel = baseIndent;
using (new GUILayout.HorizontalScope())
using (new EditorGUI.DisabledGroupScope(true))
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.indentLevel = baseIndent + 1;
} else {
EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning);
}
}
string regionName = regions[i].name;
Texture2D icon = SpineEditorUtilities.Icons.image;
if (regionName.EndsWith(" ")) {
regionName = string.Format("'{0}'", regions[i].name);
icon = SpineEditorUtilities.Icons.warning;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames."));
} else {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon));
}
}
EditorGUI.indentLevel = baseIndent;
}
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current))
atlasAsset.Clear();
}
}
}
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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;
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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 UnityEditor;
@@ -37,8 +37,7 @@ namespace Spine.Unity.Editor {
[CustomEditor(typeof(BoneFollower)), CanEditMultipleObjects]
public class BoneFollowerInspector : Editor {
SerializedProperty boneName, skeletonRenderer, followXYPosition, followZPosition, followBoneRotation,
followLocalScale, followSkeletonFlip, maintainedAxisOrientation;
SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation, followLocalScale, followSkeletonFlip;
BoneFollower targetBoneFollower;
bool needsReset;
@@ -46,7 +45,7 @@ namespace Spine.Unity.Editor {
[MenuItem ("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
var skeletonRenderer = cmd.context as SkeletonRenderer;
var go = EditorInstantiation.NewGameObject("New BoneFollower", true);
var go = SpineEditorUtilities.EditorInstantiation.NewGameObject("New BoneFollower");
var t = go.transform;
t.SetParent(skeletonRenderer.transform);
t.localPosition = Vector3.zero;
@@ -83,11 +82,9 @@ namespace Spine.Unity.Editor {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
boneName = serializedObject.FindProperty("boneName");
followBoneRotation = serializedObject.FindProperty("followBoneRotation");
followXYPosition = serializedObject.FindProperty("followXYPosition");
followZPosition = serializedObject.FindProperty("followZPosition");
followLocalScale = serializedObject.FindProperty("followLocalScale");
followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip");
maintainedAxisOrientation = serializedObject.FindProperty("maintainedAxisOrientation");
targetBoneFollower = (BoneFollower)target;
if (targetBoneFollower.SkeletonRenderer != null)
@@ -175,21 +172,15 @@ namespace Spine.Unity.Editor {
needsReset |= EditorGUI.EndChangeCheck();
EditorGUILayout.PropertyField(followBoneRotation);
EditorGUILayout.PropertyField(followXYPosition);
EditorGUILayout.PropertyField(followZPosition);
EditorGUILayout.PropertyField(followLocalScale);
EditorGUILayout.PropertyField(followSkeletonFlip);
if ((followSkeletonFlip.hasMultipleDifferentValues || followSkeletonFlip.boolValue == false) &&
(followBoneRotation.hasMultipleDifferentValues || followBoneRotation.boolValue == true)) {
using (new SpineInspectorUtility.IndentScope())
EditorGUILayout.PropertyField(maintainedAxisOrientation);
}
BoneFollowerInspector.RecommendRigidbodyButton(targetBoneFollower);
} else {
var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer;
if (boneFollowerSkeletonRenderer == null) {
EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonMecanim).", MessageType.Warning);
EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonAnimator).", MessageType.Warning);
} else {
boneFollowerSkeletonRenderer.Initialize(false);
@@ -1,261 +0,0 @@
/******************************************************************************
* 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 UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(BoundingBoxFollowerGraphic))]
public class BoundingBoxFollowerGraphicInspector : UnityEditor.Editor {
SerializedProperty skeletonGraphic, slotName, isTrigger, clearStateOnDisable;
BoundingBoxFollowerGraphic follower;
bool rebuildRequired = false;
bool addBoneFollower = false;
bool sceneRepaintRequired = false;
bool debugIsExpanded;
GUIContent addBoneFollowerLabel;
GUIContent AddBoneFollowerLabel {
get {
if (addBoneFollowerLabel == null) addBoneFollowerLabel = new GUIContent("Add Bone Follower", Icons.bone);
return addBoneFollowerLabel;
}
}
void InitializeEditor () {
skeletonGraphic = serializedObject.FindProperty("skeletonGraphic");
slotName = serializedObject.FindProperty("slotName");
isTrigger = serializedObject.FindProperty("isTrigger");
clearStateOnDisable = serializedObject.FindProperty("clearStateOnDisable");
follower = (BoundingBoxFollowerGraphic)target;
}
public override void OnInspectorGUI () {
#if !NEW_PREFAB_SYSTEM
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#else
bool isInspectingPrefab = false;
#endif
// Note: when calling InitializeEditor() in OnEnable, it throws exception
// "SerializedObjectNotCreatableException: Object at index 0 is null".
InitializeEditor();
// Try to auto-assign SkeletonGraphic field.
if (skeletonGraphic.objectReferenceValue == null) {
var foundSkeletonGraphic = follower.GetComponentInParent<SkeletonGraphic>();
if (foundSkeletonGraphic != null)
Debug.Log("BoundingBoxFollowerGraphic automatically assigned: " + foundSkeletonGraphic.gameObject.name);
else if (Event.current.type == EventType.Repaint)
Debug.Log("No Spine GameObject detected. Make sure to set this GameObject as a child of the Spine GameObject; or set BoundingBoxFollowerGraphic's 'Skeleton Graphic' field in the inspector.");
skeletonGraphic.objectReferenceValue = foundSkeletonGraphic;
serializedObject.ApplyModifiedProperties();
InitializeEditor();
}
var skeletonGraphicValue = skeletonGraphic.objectReferenceValue as SkeletonGraphic;
if (skeletonGraphicValue != null && skeletonGraphicValue.gameObject == follower.gameObject) {
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollowerGraphic to a separate child GameObject of the Spine GameObject.", MessageType.Warning);
if (GUILayout.Button(new GUIContent("Move BoundingBoxFollowerGraphic to new GameObject", Icons.boundingBox), GUILayout.Height(30f))) {
AddBoundingBoxFollowerGraphicChild(skeletonGraphicValue, follower);
DestroyImmediate(follower);
return;
}
}
EditorGUILayout.Space();
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(skeletonGraphic);
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
#if !NEW_PREFAB_SYSTEM
if (!isInspectingPrefab)
rebuildRequired = true;
#endif
}
using (new SpineInspectorUtility.LabelWidthScope(150f)) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(isTrigger);
bool triggerChanged = EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(clearStateOnDisable, new GUIContent(clearStateOnDisable.displayName, "Enable this if you are pooling your Spine GameObject"));
bool clearStateChanged = EditorGUI.EndChangeCheck();
if (clearStateChanged || triggerChanged) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
if (triggerChanged)
foreach (var col in follower.colliderTable.Values)
col.isTrigger = isTrigger.boolValue;
}
}
if (isInspectingPrefab) {
follower.colliderTable.Clear();
follower.nameTable.Clear();
EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info);
// How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work.
var collider = follower.GetComponent<PolygonCollider2D>();
if (collider != null) Debug.LogWarning("Found BoundingBoxFollowerGraphic collider components in prefab. These are disposed and regenerated at runtime.");
} else {
using (new SpineInspectorUtility.BoxScope()) {
if (debugIsExpanded = EditorGUILayout.Foldout(debugIsExpanded, "Debug Colliders")) {
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count));
EditorGUI.BeginChangeCheck();
foreach (var kp in follower.nameTable) {
string attachmentName = kp.Value;
var collider = follower.colliderTable[kp.Key];
bool isPlaceholder = attachmentName != kp.Key.Name;
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : string.Format("{0} [{1}]", attachmentName, kp.Key.Name), isPlaceholder ? Icons.skinPlaceholder : Icons.boundingBox), collider.enabled);
}
sceneRepaintRequired |= EditorGUI.EndChangeCheck();
EditorGUI.indentLevel--;
}
}
}
if (follower.Slot == null)
follower.Initialize(false);
bool hasBoneFollower = follower.GetComponent<BoneFollowerGraphic>() != null;
if (!hasBoneFollower) {
bool buttonDisabled = follower.Slot == null;
using (new EditorGUI.DisabledGroupScope(buttonDisabled)) {
addBoneFollower |= SpineInspectorUtility.LargeCenteredButton(AddBoneFollowerLabel, true);
EditorGUILayout.Space();
}
}
if (Event.current.type == EventType.Repaint) {
if (addBoneFollower) {
var boneFollower = follower.gameObject.AddComponent<BoneFollowerGraphic>();
boneFollower.skeletonGraphic = skeletonGraphicValue;
boneFollower.SetBone(follower.Slot.Data.BoneData.Name);
addBoneFollower = false;
}
if (sceneRepaintRequired) {
SceneView.RepaintAll();
sceneRepaintRequired = false;
}
if (rebuildRequired) {
follower.Initialize();
rebuildRequired = false;
}
}
}
#region Menus
[MenuItem("CONTEXT/SkeletonGraphic/Add BoundingBoxFollowerGraphic GameObject")]
static void AddBoundingBoxFollowerGraphicChild (MenuCommand command) {
var go = AddBoundingBoxFollowerGraphicChild((SkeletonGraphic)command.context);
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollowerGraphic");
}
[MenuItem("CONTEXT/SkeletonGraphic/Add all BoundingBoxFollowerGraphic GameObjects")]
static void AddAllBoundingBoxFollowerGraphicChildren (MenuCommand command) {
var objects = AddAllBoundingBoxFollowerGraphicChildren((SkeletonGraphic)command.context);
foreach (var go in objects)
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollowerGraphic");
}
#endregion
public static GameObject AddBoundingBoxFollowerGraphicChild (SkeletonGraphic skeletonGraphic,
BoundingBoxFollowerGraphic original = null, string name = "BoundingBoxFollowerGraphic",
string slotName = null) {
var go = EditorInstantiation.NewGameObject(name, true);
go.transform.SetParent(skeletonGraphic.transform, false);
go.AddComponent<RectTransform>();
var newFollower = go.AddComponent<BoundingBoxFollowerGraphic>();
if (original != null) {
newFollower.slotName = original.slotName;
newFollower.isTrigger = original.isTrigger;
newFollower.clearStateOnDisable = original.clearStateOnDisable;
}
if (slotName != null)
newFollower.slotName = slotName;
newFollower.skeletonGraphic = skeletonGraphic;
newFollower.Initialize();
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
return go;
}
public static List<GameObject> AddAllBoundingBoxFollowerGraphicChildren (
SkeletonGraphic skeletonGraphic, BoundingBoxFollowerGraphic original = null) {
List<GameObject> createdGameObjects = new List<GameObject>();
foreach (var skin in skeletonGraphic.Skeleton.Data.Skins) {
var attachments = skin.Attachments;
foreach (var entry in attachments) {
var boundingBoxAttachment = entry.Value as BoundingBoxAttachment;
if (boundingBoxAttachment == null)
continue;
int slotIndex = entry.Key.SlotIndex;
var slot = skeletonGraphic.Skeleton.Slots.Items[slotIndex];
string slotName = slot.Data.Name;
GameObject go = AddBoundingBoxFollowerGraphicChild(skeletonGraphic,
original, boundingBoxAttachment.Name, slotName);
var boneFollower = go.AddComponent<BoneFollowerGraphic>();
boneFollower.skeletonGraphic = skeletonGraphic;
boneFollower.SetBone(slot.Data.BoneData.Name);
createdGameObjects.Add(go);
}
}
return createdGameObjects;
}
}
}
@@ -1,159 +0,0 @@
/******************************************************************************
* 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);
}
}
}
@@ -1,436 +0,0 @@
/******************************************************************************
* 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 UnityEngine;
using UnityEditor;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonGraphic))]
[CanEditMultipleObjects]
public class SkeletonGraphicInspector : UnityEditor.Editor {
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
const string ReloadButtonString = "Reload";
protected GUIContent SkeletonDataAssetLabel;
static GUILayoutOption reloadButtonWidth;
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
SerializedProperty material, color;
SerializedProperty skeletonDataAsset, initialSkinName;
SerializedProperty startingAnimation, startingLoop, timeScale, freeze, updateWhenInvisible, 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 forceReloadQueued = false;
protected bool TargetIsValid {
get {
if (serializedObject.isEditingMultipleObjects) {
foreach (var o in targets) {
var component = (SkeletonGraphic)o;
if (!component.IsValid)
return false;
}
return true;
}
else {
var component = (SkeletonGraphic)target;
return component.IsValid;
}
}
}
void OnEnable () {
#if NEW_PREFAB_SYSTEM
isInspectingPrefab = false;
#else
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#endif
SpineEditorUtilities.ConfirmInitialization();
// Labels
SkeletonDataAssetLabel = new GUIContent("SkeletonData Asset", Icons.spine);
var so = this.serializedObject;
thisSkeletonGraphic = target as SkeletonGraphic;
// MaskableGraphic
material = so.FindProperty("m_Material");
color = so.FindProperty("m_Color");
raycastTarget = so.FindProperty("m_RaycastTarget");
// SkeletonRenderer
skeletonDataAsset = so.FindProperty("skeletonDataAsset");
initialSkinName = so.FindProperty("initialSkinName");
initialFlipX = so.FindProperty("initialFlipX");
initialFlipY = so.FindProperty("initialFlipY");
// SkeletonAnimation
startingAnimation = so.FindProperty("startingAnimation");
startingLoop = so.FindProperty("startingLoop");
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;
allowMultipleCanvasRenderers = so.FindProperty("allowMultipleCanvasRenderers");
updateSeparatorPartLocation = so.FindProperty("updateSeparatorPartLocation");
enableSeparatorSlots = so.FindProperty("enableSeparatorSlots");
separatorSlotNames = so.FindProperty("separatorSlotNames");
separatorSlotNames.isExpanded = true;
}
public override void OnInspectorGUI () {
if (UnityEngine.Event.current.type == EventType.Layout) {
if (forceReloadQueued) {
forceReloadQueued = false;
foreach (var c in targets) {
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonGraphic);
}
}
else {
foreach (var c in targets) {
var component = c as SkeletonGraphic;
if (!component.IsValid) {
SpineEditorUtilities.ReinitializeComponent(component);
if (!component.IsValid) continue;
}
}
}
}
bool wasChanged = false;
EditorGUI.BeginChangeCheck();
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) {
SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel);
if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth))
forceReloadQueued = true;
}
EditorGUILayout.PropertyField(material);
EditorGUILayout.PropertyField(color);
if (thisSkeletonGraphic.skeletonDataAsset == null) {
EditorGUILayout.HelpBox("You need to assign a SkeletonDataAsset first.", MessageType.Info);
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
return;
}
string errorMessage = null;
if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic(thisSkeletonGraphic, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
}
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();
EditorGUILayout.PropertyField(updateWhenInvisible);
// 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();
EditorGUILayout.PropertyField(initialSkinName);
{
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent("Initial Flip"));
rect.x += EditorGUIUtility.labelWidth;
rect.width = 30f;
SpineInspectorUtility.ToggleLeft(rect, initialFlipX, SpineInspectorUtility.TempContent("X", tooltip: "initialFlipX"));
rect.x += 35f;
SpineInspectorUtility.ToggleLeft(rect, initialFlipY, SpineInspectorUtility.TempContent("Y", tooltip: "initialFlipY"));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(startingAnimation);
EditorGUILayout.PropertyField(startingLoop);
EditorGUILayout.PropertyField(timeScale);
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.Space();
SkeletonRendererInspector.SkeletonRootMotionParameter(targets);
EditorGUILayout.Space();
EditorGUILayout.LabelField("UI", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(raycastTarget);
EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
EditorGUILayout.PrefixLabel("Match RectTransform with Mesh");
if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) {
foreach (var skeletonGraphic in targets) {
MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic);
}
}
EditorGUILayout.EndHorizontal();
if (TargetIsValid && !isInspectingPrefab) {
EditorGUILayout.Space();
if (SpineInspectorUtility.CenteredButton(new GUIContent("Add Skeleton Utility", Icons.skeletonUtility), 21, true, 200f))
foreach (var t in targets) {
var component = t as Component;
if (component.GetComponent<SkeletonUtility>() == null) {
component.gameObject.AddComponent<SkeletonUtility>();
}
}
}
wasChanged |= EditorGUI.EndChangeCheck();
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
[MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")]
static void MatchRectTransformWithBounds (MenuCommand command) {
var skeletonGraphic = (SkeletonGraphic)command.context;
MatchRectTransformWithBounds(skeletonGraphic);
}
static void MatchRectTransformWithBounds (SkeletonGraphic skeletonGraphic) {
if (!skeletonGraphic.MatchRectTransformWithBounds())
Debug.Log("Mesh was not previously generated.");
}
[MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 15)]
static public void SkeletonGraphicCreateMenuItem () {
var parentGameObject = Selection.activeObject as GameObject;
var parentTransform = parentGameObject == null ? null : parentGameObject.GetComponent<RectTransform>();
if (parentTransform == null)
Debug.LogWarning("Your new SkeletonGraphic will not be visible until it is placed under a Canvas");
var gameObject = NewSkeletonGraphicGameObject("New SkeletonGraphic");
gameObject.transform.SetParent(parentTransform, false);
EditorUtility.FocusProjectWindow();
Selection.activeObject = gameObject;
EditorGUIUtility.PingObject(Selection.activeObject);
}
// SpineEditorUtilities.InstantiateDelegate. Used by drag and drop.
public static Component SpawnSkeletonGraphicFromDrop (SkeletonDataAsset data) {
return InstantiateSkeletonGraphic(data);
}
public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, string skinName) {
return InstantiateSkeletonGraphic(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName));
}
public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
string spineGameObjectName = string.Format("SkeletonGraphic ({0})", skeletonDataAsset.name.Replace("_SkeletonData", ""));
var go = NewSkeletonGraphicGameObject(spineGameObjectName);
var graphic = go.GetComponent<SkeletonGraphic>();
graphic.skeletonDataAsset = skeletonDataAsset;
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
if (data == null) {
for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) {
string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]);
skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase));
}
data = skeletonDataAsset.GetSkeletonData(true);
}
skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0];
graphic.MeshGenerator.settings.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing;
graphic.startingLoop = SpineEditorUtilities.Preferences.defaultInstantiateLoop;
graphic.Initialize(false);
if (skin != null) graphic.Skeleton.SetSkin(skin);
graphic.initialSkinName = skin.Name;
graphic.Skeleton.UpdateWorldTransform();
graphic.UpdateMesh();
return graphic;
}
static GameObject NewSkeletonGraphicGameObject (string gameObjectName) {
var go = EditorInstantiation.NewGameObject(gameObjectName, true, typeof(RectTransform), typeof(CanvasRenderer), typeof(SkeletonGraphic));
var graphic = go.GetComponent<SkeletonGraphic>();
graphic.material = SkeletonGraphicInspector.DefaultSkeletonGraphicMaterial;
return go;
}
public static Material DefaultSkeletonGraphicMaterial {
get {
var guids = AssetDatabase.FindAssets("SkeletonGraphicDefault t:material");
if (guids.Length <= 0) return null;
var firstAssetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
if (string.IsNullOrEmpty(firstAssetPath)) return null;
var firstMaterial = AssetDatabase.LoadAssetAtPath<Material>(firstAssetPath);
return firstMaterial;
}
}
#endregion
}
}
@@ -1,153 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonMecanim))]
[CanEditMultipleObjects]
public class SkeletonMecanimInspector : SkeletonRendererInspector {
public static bool mecanimSettingsFoldout;
protected SerializedProperty autoReset;
protected SerializedProperty useCustomMixMode;
protected SerializedProperty layerMixModes;
protected SerializedProperty layerBlendModes;
protected override void OnEnable () {
base.OnEnable();
SerializedProperty mecanimTranslator = serializedObject.FindProperty("translator");
autoReset = mecanimTranslator.FindPropertyRelative("autoReset");
useCustomMixMode = mecanimTranslator.FindPropertyRelative("useCustomMixMode");
layerMixModes = mecanimTranslator.FindPropertyRelative("layerMixModes");
layerBlendModes = mecanimTranslator.FindPropertyRelative("layerBlendModes");
}
protected override void DrawInspectorGUI (bool multi) {
AddRootMotionComponentIfEnabled();
base.DrawInspectorGUI(multi);
using (new SpineInspectorUtility.BoxScope()) {
mecanimSettingsFoldout = EditorGUILayout.Foldout(mecanimSettingsFoldout, "Mecanim Translator");
if (mecanimSettingsFoldout) {
EditorGUILayout.PropertyField(autoReset, new GUIContent("Auto Reset",
"When set to true, the skeleton state is mixed out to setup-" +
"pose when an animation finishes, according to the " +
"animation's keyed items."));
EditorGUILayout.PropertyField(useCustomMixMode, new GUIContent("Custom MixMode",
"When disabled, the recommended MixMode is used according to the layer blend mode. Enable to specify a custom MixMode for each Mecanim layer."));
if (useCustomMixMode.hasMultipleDifferentValues || useCustomMixMode.boolValue == true) {
DrawLayerSettings();
EditorGUILayout.Space();
}
}
}
}
protected void AddRootMotionComponentIfEnabled () {
foreach (var t in targets) {
var component = t as Component;
var animator = component.GetComponent<Animator>();
if (animator != null && animator.applyRootMotion) {
if (component.GetComponent<SkeletonMecanimRootMotion>() == null) {
component.gameObject.AddComponent<SkeletonMecanimRootMotion>();
}
}
}
}
protected void DrawLayerSettings () {
string[] layerNames = GetLayerNames();
float widthLayerColumn = 140;
float widthMixColumn = 84;
using (new GUILayout.HorizontalScope()) {
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
rect.width = widthLayerColumn;
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mecanim Layer"), EditorStyles.boldLabel);
var savedIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
rect.position += new Vector2(rect.width, 0);
rect.width = widthMixColumn;
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mix Mode"), EditorStyles.boldLabel);
EditorGUI.indentLevel = savedIndent;
}
using (new SpineInspectorUtility.IndentScope()) {
int layerCount = layerMixModes.arraySize;
for (int i = 0; i < layerCount; ++i) {
using (new GUILayout.HorizontalScope()) {
string layerName = i < layerNames.Length ? layerNames[i] : ("Layer " + i);
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
rect.width = widthLayerColumn;
EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent(layerName));
var savedIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
var mixMode = layerMixModes.GetArrayElementAtIndex(i);
rect.position += new Vector2(rect.width, 0);
rect.width = widthMixColumn;
EditorGUI.PropertyField(rect, mixMode, GUIContent.none);
EditorGUI.indentLevel = savedIndent;
}
}
}
}
protected string[] GetLayerNames () {
int maxLayerCount = 0;
int maxIndex = 0;
for (int i = 0; i < targets.Length; ++i) {
var skeletonMecanim = ((SkeletonMecanim)targets[i]);
int count = skeletonMecanim.Translator.MecanimLayerCount;
if (count > maxLayerCount) {
maxLayerCount = count;
maxIndex = i;
}
}
if (maxLayerCount == 0)
return new string[0];
var skeletonMecanimMaxLayers = ((SkeletonMecanim)targets[maxIndex]);
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
}
}
}
@@ -1,81 +0,0 @@
/******************************************************************************
* 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonMecanimRootMotion))]
[CanEditMultipleObjects]
public class SkeletonMecanimRootMotionInspector : SkeletonRootMotionBaseInspector {
protected SerializedProperty mecanimLayerFlags;
protected GUIContent mecanimLayersLabel;
protected override void OnEnable () {
base.OnEnable();
mecanimLayerFlags = serializedObject.FindProperty("mecanimLayerFlags");
mecanimLayersLabel = new UnityEngine.GUIContent("Mecanim Layers", "Mecanim layers to apply root motion at. Defaults to the first Mecanim layer.");
}
override public void OnInspectorGUI () {
base.MainPropertyFields();
MecanimLayerMaskPropertyField();
base.OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected string[] GetLayerNames () {
int maxLayerCount = 0;
int maxIndex = 0;
for (int i = 0; i < targets.Length; ++i) {
var skeletonMecanim = ((SkeletonMecanimRootMotion)targets[i]).SkeletonMecanim;
int count = skeletonMecanim.Translator.MecanimLayerCount;
if (count > maxLayerCount) {
maxLayerCount = count;
maxIndex = i;
}
}
if (maxLayerCount == 0)
return new string[0];
var skeletonMecanimMaxLayers = ((SkeletonMecanimRootMotion)targets[maxIndex]).SkeletonMecanim;
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
}
protected void MecanimLayerMaskPropertyField () {
string[] layerNames = GetLayerNames();
if (layerNames.Length > 0)
mecanimLayerFlags.intValue = EditorGUILayout.MaskField(
mecanimLayersLabel, mecanimLayerFlags.intValue, layerNames);
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 4613924c50d66cf458f0db803776dd2f
timeCreated: 1593175106
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,113 +0,0 @@
/******************************************************************************
* 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonRootMotionBase))]
[CanEditMultipleObjects]
public class SkeletonRootMotionBaseInspector : UnityEditor.Editor {
protected SerializedProperty rootMotionBoneName;
protected SerializedProperty transformPositionX;
protected SerializedProperty transformPositionY;
protected SerializedProperty rootMotionScaleX;
protected SerializedProperty rootMotionScaleY;
protected SerializedProperty rootMotionTranslateXPerY;
protected SerializedProperty rootMotionTranslateYPerX;
protected SerializedProperty rigidBody2D;
protected SerializedProperty rigidBody;
protected GUIContent rootMotionBoneNameLabel;
protected GUIContent transformPositionXLabel;
protected GUIContent transformPositionYLabel;
protected GUIContent rootMotionScaleXLabel;
protected GUIContent rootMotionScaleYLabel;
protected GUIContent rootMotionTranslateXPerYLabel;
protected GUIContent rootMotionTranslateYPerXLabel;
protected GUIContent rigidBody2DLabel;
protected GUIContent rigidBodyLabel;
protected virtual void OnEnable () {
rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName");
transformPositionX = serializedObject.FindProperty("transformPositionX");
transformPositionY = serializedObject.FindProperty("transformPositionY");
rootMotionScaleX = serializedObject.FindProperty("rootMotionScaleX");
rootMotionScaleY = serializedObject.FindProperty("rootMotionScaleY");
rootMotionTranslateXPerY = serializedObject.FindProperty("rootMotionTranslateXPerY");
rootMotionTranslateYPerX = serializedObject.FindProperty("rootMotionTranslateYPerX");
rigidBody2D = serializedObject.FindProperty("rigidBody2D");
rigidBody = serializedObject.FindProperty("rigidBody");
rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from.");
transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)");
transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone.");
rootMotionScaleXLabel = new UnityEngine.GUIContent("Root Motion Scale (X)", "Scale applied to the horizontal root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rootMotionScaleYLabel = new UnityEngine.GUIContent("Root Motion Scale (Y)", "Scale applied to the vertical root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rootMotionTranslateXPerYLabel = new UnityEngine.GUIContent("Root Motion Translate (X)", "Added X translation per root motion Y delta. Can be used for delta compensation when scaling is not enough, to e.g. offset a horizontal jump to a vertically different goal.");
rootMotionTranslateYPerXLabel = new UnityEngine.GUIContent("Root Motion Translate (Y)", "Added Y translation per root motion X delta. Can be used for delta compensation when scaling is not enough, to e.g. offset a horizontal jump to a vertically different goal.");
rigidBody2DLabel = new UnityEngine.GUIContent("Rigidbody2D",
"Optional Rigidbody2D: Assign a Rigidbody2D here if you want " +
" to apply the root motion to the rigidbody instead of the Transform." +
"\n\n" +
"Note that animation and physics updates are not always in sync." +
"Some jitter may result at certain framerates.");
rigidBodyLabel = new UnityEngine.GUIContent("Rigidbody",
"Optional Rigidbody: Assign a Rigidbody here if you want " +
" to apply the root motion to the rigidbody instead of the Transform." +
"\n\n" +
"Note that animation and physics updates are not always in sync." +
"Some jitter may result at certain framerates.");
}
public override void OnInspectorGUI () {
MainPropertyFields();
OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected virtual void MainPropertyFields () {
EditorGUILayout.PropertyField(rootMotionBoneName, rootMotionBoneNameLabel);
EditorGUILayout.PropertyField(transformPositionX, transformPositionXLabel);
EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel);
EditorGUILayout.PropertyField(rootMotionScaleX, rootMotionScaleXLabel);
EditorGUILayout.PropertyField(rootMotionScaleY, rootMotionScaleYLabel);
EditorGUILayout.PropertyField(rootMotionTranslateXPerY, rootMotionTranslateXPerYLabel);
EditorGUILayout.PropertyField(rootMotionTranslateYPerX, rootMotionTranslateYPerXLabel);
}
protected virtual void OptionalPropertyFields () {
EditorGUILayout.PropertyField(rigidBody2D, rigidBody2DLabel);
EditorGUILayout.PropertyField(rigidBody, rigidBodyLabel);
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: f2cba83baf6afdf44a996e40017c6325
timeCreated: 1593175106
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,79 +0,0 @@
/******************************************************************************
* 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonRootMotion))]
[CanEditMultipleObjects]
public class SkeletonRootMotionInspector : SkeletonRootMotionBaseInspector {
protected SerializedProperty animationTrackFlags;
protected GUIContent animationTrackFlagsLabel;
string[] TrackNames;
protected override void OnEnable () {
base.OnEnable();
animationTrackFlags = serializedObject.FindProperty("animationTrackFlags");
animationTrackFlagsLabel = new UnityEngine.GUIContent("Animation Tracks",
"Animation tracks to apply root motion at. Defaults to the first" +
" animation track (index 0).");
}
override public void OnInspectorGUI () {
base.MainPropertyFields();
AnimationTracksPropertyField();
base.OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected void AnimationTracksPropertyField () {
if (TrackNames == null) {
InitTrackNames();
}
animationTrackFlags.intValue = EditorGUILayout.MaskField(
animationTrackFlagsLabel, animationTrackFlags.intValue, TrackNames);
}
protected void InitTrackNames () {
int numEntries = 32;
TrackNames = new string[numEntries];
for (int i = 0; i < numEntries; ++i) {
TrackNames[i] = string.Format("Track {0}", i);
}
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: e4836100aed984c4a9af11d39c63cb6b
timeCreated: 1593183609
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,541 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
#if UNITY_2019_2_OR_NEWER
#define HINGE_JOINT_NEW_BEHAVIOUR
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Spine;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonUtilityBone)), CanEditMultipleObjects]
public class SkeletonUtilityBoneInspector : UnityEditor.Editor {
SerializedProperty mode, boneName, zPosition, position, rotation, scale, overrideAlpha, hierarchy, parentReference;
GUIContent hierarchyLabel;
//multi selected flags
bool containsFollows, containsOverrides, multiObject;
//single selected helpers
SkeletonUtilityBone utilityBone;
SkeletonUtility skeletonUtility;
bool canCreateHingeChain = false;
Dictionary<Slot, List<BoundingBoxAttachment>> boundingBoxTable = new Dictionary<Slot, List<BoundingBoxAttachment>>();
void OnEnable () {
mode = this.serializedObject.FindProperty("mode");
boneName = this.serializedObject.FindProperty("boneName");
zPosition = this.serializedObject.FindProperty("zPosition");
position = this.serializedObject.FindProperty("position");
rotation = this.serializedObject.FindProperty("rotation");
scale = this.serializedObject.FindProperty("scale");
overrideAlpha = this.serializedObject.FindProperty("overrideAlpha");
hierarchy = this.serializedObject.FindProperty("hierarchy");
hierarchyLabel = new GUIContent("Skeleton Utility Parent");
parentReference = this.serializedObject.FindProperty("parentReference");
utilityBone = (SkeletonUtilityBone)target;
skeletonUtility = utilityBone.hierarchy;
EvaluateFlags();
if (!utilityBone.valid && skeletonUtility != null) {
if (skeletonUtility.skeletonRenderer != null)
skeletonUtility.skeletonRenderer.Initialize(false);
if (skeletonUtility.skeletonGraphic != null)
skeletonUtility.skeletonGraphic.Initialize(false);
}
canCreateHingeChain = CanCreateHingeChain();
boundingBoxTable.Clear();
if (multiObject) return;
if (utilityBone.bone == null) return;
var skeleton = utilityBone.bone.Skeleton;
int slotCount = skeleton.Slots.Count;
Skin skin = skeleton.Skin;
if (skeleton.Skin == null)
skin = skeleton.Data.DefaultSkin;
for(int i = 0; i < slotCount; i++){
Slot slot = skeletonUtility.Skeleton.Slots.Items[i];
if (slot.Bone == utilityBone.bone) {
var slotAttachments = new List<Skin.SkinEntry>();
int slotIndex = skeleton.FindSlotIndex(slot.Data.Name);
skin.GetAttachments(slotIndex, slotAttachments);
var boundingBoxes = new List<BoundingBoxAttachment>();
foreach (var att in slotAttachments) {
var boundingBoxAttachment = att.Attachment as BoundingBoxAttachment;
if (boundingBoxAttachment != null)
boundingBoxes.Add(boundingBoxAttachment);
}
if (boundingBoxes.Count > 0)
boundingBoxTable.Add(slot, boundingBoxes);
}
}
}
void EvaluateFlags () {
if (Selection.objects.Length == 1) {
containsFollows = utilityBone.mode == SkeletonUtilityBone.Mode.Follow;
containsOverrides = utilityBone.mode == SkeletonUtilityBone.Mode.Override;
} else {
int boneCount = 0;
foreach (Object o in Selection.objects) {
var go = o as GameObject;
if (go != null) {
SkeletonUtilityBone sub = go.GetComponent<SkeletonUtilityBone>();
if (sub != null) {
boneCount++;
containsFollows |= (sub.mode == SkeletonUtilityBone.Mode.Follow);
containsOverrides |= (sub.mode == SkeletonUtilityBone.Mode.Override);
}
}
}
multiObject |= (boneCount > 1);
}
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(mode);
if (EditorGUI.EndChangeCheck()) {
containsOverrides = mode.enumValueIndex == 1;
containsFollows = mode.enumValueIndex == 0;
}
using (new EditorGUI.DisabledGroupScope(multiObject)) {
string str = boneName.stringValue;
if (str == "")
str = "<None>";
if (multiObject)
str = "<Multiple>";
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Bone");
if (GUILayout.Button(str, EditorStyles.popup)) {
BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.Skeleton.Bones, "<None>", TargetBoneSelected);
}
}
}
EditorGUILayout.PropertyField(zPosition);
EditorGUILayout.PropertyField(position);
EditorGUILayout.PropertyField(rotation);
EditorGUILayout.PropertyField(scale);
using (new EditorGUI.DisabledGroupScope(containsFollows)) {
EditorGUILayout.PropertyField(overrideAlpha);
EditorGUILayout.PropertyField(parentReference);
EditorGUILayout.PropertyField(hierarchy, hierarchyLabel);
}
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child Bone", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24)))
BoneSelectorContextMenu("", utilityBone.bone.Children, "<Recursively>", SpawnChildBoneSelected);
}
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24)))
SpawnOverride();
}
EditorGUILayout.Space();
}
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || !canCreateHingeChain)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 3D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
CreateHingeChain();
if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 2D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
CreateHingeChain2D();
}
EditorGUILayout.Space();
}
using (new EditorGUI.DisabledGroupScope(multiObject || boundingBoxTable.Count == 0)) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel);
foreach (var entry in boundingBoxTable){
Slot slot = entry.Key;
var boundingBoxes = entry.Value;
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(slot.Data.Name);
EditorGUI.indentLevel++;
{
foreach (var box in boundingBoxes) {
using (new GUILayout.HorizontalScope()) {
GUILayout.Space(30);
string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name;
if (GUILayout.Button(buttonLabel, GUILayout.Width(200))) {
utilityBone.bone.Skeleton.UpdateWorldTransform();
var bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name); // Use FindChild in older versions of Unity.
if (bbTransform != null) {
var originalCollider = bbTransform.GetComponent<PolygonCollider2D>();
if (originalCollider != null)
SkeletonUtility.SetColliderPointsLocal(originalCollider, slot, box);
else
SkeletonUtility.AddBoundingBoxAsComponent(box, slot, bbTransform.gameObject);
} else {
var newPolygonCollider = SkeletonUtility.AddBoundingBoxGameObject(null, box, slot, utilityBone.transform);
bbTransform = newPolygonCollider.transform;
}
EditorGUIUtility.PingObject(bbTransform);
}
}
}
}
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
}
}
BoneFollowerInspector.RecommendRigidbodyButton(utilityBone);
serializedObject.ApplyModifiedProperties();
}
static void BoneSelectorContextMenu (string current, ExposedList<Bone> bones, string topValue, GenericMenu.MenuFunction2 callback) {
var menu = new GenericMenu();
if (topValue != "")
menu.AddItem(new GUIContent(topValue), current == topValue, callback, null);
for (int i = 0; i < bones.Count; i++)
menu.AddItem(new GUIContent(bones.Items[i].Data.Name), bones.Items[i].Data.Name == current, callback, bones.Items[i]);
menu.ShowAsContext();
}
void TargetBoneSelected (object obj) {
if (obj == null) {
boneName.stringValue = "";
serializedObject.ApplyModifiedProperties();
} else {
var bone = (Bone)obj;
boneName.stringValue = bone.Data.Name;
serializedObject.ApplyModifiedProperties();
utilityBone.Reset();
}
}
void SpawnChildBoneSelected (object obj) {
if (obj == null) {
// Add recursively
foreach (var bone in utilityBone.bone.Children) {
GameObject go = skeletonUtility.SpawnBoneRecursively(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
SkeletonUtilityBone[] newUtilityBones = go.GetComponentsInChildren<SkeletonUtilityBone>();
foreach (SkeletonUtilityBone utilBone in newUtilityBones)
SkeletonUtilityInspector.AttachIcon(utilBone);
}
} else {
var bone = (Bone)obj;
GameObject go = skeletonUtility.SpawnBone(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
}
}
void SpawnOverride () {
GameObject go = skeletonUtility.SpawnBone(utilityBone.bone, utilityBone.transform.parent, SkeletonUtilityBone.Mode.Override, utilityBone.position, utilityBone.rotation, utilityBone.scale);
go.name = go.name + " [Override]";
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
}
bool CanCreateHingeChain () {
if (utilityBone == null)
return false;
if (utilityBone.GetComponent<Rigidbody>() != null || utilityBone.GetComponent<Rigidbody2D>() != null)
return false;
if (utilityBone.bone != null && utilityBone.bone.Children.Count == 0)
return false;
var rigidbodies = utilityBone.GetComponentsInChildren<Rigidbody>();
var rigidbodies2D = utilityBone.GetComponentsInChildren<Rigidbody2D>();
return rigidbodies.Length <= 0 && rigidbodies2D.Length <= 0;
}
void CreateHingeChain2D () {
var kinematicParentUtilityBone = utilityBone.transform.parent.GetComponent<SkeletonUtilityBone>();
if (kinematicParentUtilityBone == null) {
UnityEditor.EditorUtility.DisplayDialog("No parent SkeletonUtilityBone found!", "Please select the first physically moving chain node, having a parent GameObject with a SkeletonUtilityBone component attached.", "OK");
return;
}
float mass = 10;
const float rotationLimit = 20.0f;
SetSkeletonUtilityToFlipByRotation();
kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true;
GameObject commonParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
var commonParentActivateOnFlip = commonParentObject.AddComponent<ActivateBasedOnFlipDirection>();
commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.skeletonRenderer;
commonParentActivateOnFlip.skeletonGraphic = skeletonUtility.skeletonGraphic;
// HingeChain Parent
// Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum.
GameObject normalChainParentObject = new GameObject("HingeChain");
normalChainParentObject.transform.SetParent(commonParentObject.transform);
commonParentActivateOnFlip.activeOnNormalX = normalChainParentObject;
//var followRotationComponent = normalChainParentObject.AddComponent<FollowSkeletonUtilityRootRotation>();
//followRotationComponent.reference = skeletonUtility.boneRoot;
// Follower Kinematic Rigidbody
GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower");
followerKinematicObject.transform.parent = normalChainParentObject.transform;
var followerRigidbody = followerKinematicObject.AddComponent<Rigidbody2D>();
followerRigidbody.mass = mass;
followerRigidbody.isKinematic = true;
followerKinematicObject.AddComponent<FollowLocationRigidbody2D>().reference = kinematicParentUtilityBone.transform;
followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position;
followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation;
// Child Bones
var utilityBones = utilityBone.GetComponentsInChildren<SkeletonUtilityBone>();
var childBoneParentReference = followerKinematicObject.transform;
for (int i = 0; i < utilityBones.Length; ++i) {
var childBone = utilityBones[i];
mass *= 0.75f;
childBone.parentReference = (i == 0) ? kinematicParentUtilityBone.transform : childBoneParentReference;
childBone.transform.SetParent(normalChainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity.
AttachRigidbodyAndCollider2D(childBone);
childBone.mode = SkeletonUtilityBone.Mode.Override;
childBone.scale = childBone.position = childBone.zPosition = false;
HingeJoint2D joint = childBone.gameObject.AddComponent<HingeJoint2D>();
joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody2D>();
joint.useLimits = true;
ApplyJoint2DAngleLimits(joint, rotationLimit, childBoneParentReference, childBone.transform);
childBone.GetComponent<Rigidbody2D>().mass = mass;
childBoneParentReference = childBone.transform;
}
Duplicate2DHierarchyForFlippedChains(normalChainParentObject, commonParentActivateOnFlip, skeletonUtility.transform, rotationLimit);
UnityEditor.Selection.activeGameObject = commonParentObject;
}
void ApplyJoint2DAngleLimits (HingeJoint2D joint, float rotationLimit, Transform parentBone, Transform bone) {
#if HINGE_JOINT_NEW_BEHAVIOUR
float referenceAngle = (parentBone.eulerAngles.z - bone.eulerAngles.z + 360f) % 360f;
float minAngle = referenceAngle - rotationLimit;
float maxAngle = referenceAngle + rotationLimit;
if (maxAngle > 270f) {
minAngle -= 360f;
maxAngle -= 360f;
}
if (minAngle < -90f) {
minAngle += 360f;
maxAngle += 360f;
}
#else
float minAngle = - rotationLimit;
float maxAngle = rotationLimit;
#endif
joint.limits = new JointAngleLimits2D {
min = minAngle,
max = maxAngle
};
}
void Duplicate2DHierarchyForFlippedChains (GameObject normalChainParentObject, ActivateBasedOnFlipDirection commonParentActivateOnFlip,
Transform skeletonUtilityRoot, float rotationLimit) {
GameObject mirroredChain = GameObject.Instantiate(normalChainParentObject, normalChainParentObject.transform.position,
normalChainParentObject.transform.rotation, commonParentActivateOnFlip.transform);
mirroredChain.name = normalChainParentObject.name + " FlippedX";
commonParentActivateOnFlip.activeOnFlippedX = mirroredChain;
var followerKinematicObject = mirroredChain.GetComponentInChildren<FollowLocationRigidbody2D>();
followerKinematicObject.followFlippedX = true;
FlipBone2DHorizontal(followerKinematicObject.transform, skeletonUtilityRoot);
var childBoneJoints = mirroredChain.GetComponentsInChildren<HingeJoint2D>();
Transform prevRotatedChild = null;
Transform parentTransformForAngles = followerKinematicObject.transform;
for (int i = 0; i < childBoneJoints.Length; ++i) {
var joint = childBoneJoints[i];
FlipBone2DHorizontal(joint.transform, skeletonUtilityRoot);
ApplyJoint2DAngleLimits(joint, rotationLimit, parentTransformForAngles, joint.transform);
GameObject rotatedChild = GameObject.Instantiate(joint.gameObject, joint.transform, true);
rotatedChild.name = joint.name + " rotated";
var rotationEulerAngles = rotatedChild.transform.localEulerAngles;
rotationEulerAngles.x = 180;
rotatedChild.transform.localEulerAngles = rotationEulerAngles;
DestroyImmediate(rotatedChild.GetComponent<HingeJoint2D>());
DestroyImmediate(rotatedChild.GetComponent<BoxCollider2D>());
DestroyImmediate(rotatedChild.GetComponent<Rigidbody2D>());
DestroyImmediate(joint.gameObject.GetComponent<SkeletonUtilityBone>());
if (i > 0) {
var utilityBone = rotatedChild.GetComponent<SkeletonUtilityBone>();
utilityBone.parentReference = prevRotatedChild;
}
prevRotatedChild = rotatedChild.transform;
parentTransformForAngles = joint.transform;
}
mirroredChain.SetActive(false);
}
void FlipBone2DHorizontal(Transform bone, Transform mirrorPosition) {
Vector3 position = bone.position;
position.x = 2 * mirrorPosition.position.x - position.x; // = mirrorPosition + (mirrorPosition - bone.position)
bone.position = position;
Vector3 boneZ = bone.forward;
Vector3 boneX = bone.right;
boneX.x *= -1;
bone.rotation = Quaternion.LookRotation(boneZ, Vector3.Cross(boneZ, boneX));
}
void CreateHingeChain () {
var kinematicParentUtilityBone = utilityBone.transform.parent.GetComponent<SkeletonUtilityBone>();
if (kinematicParentUtilityBone == null) {
UnityEditor.EditorUtility.DisplayDialog("No parent SkeletonUtilityBone found!", "Please select the first physically moving chain node, having a parent GameObject with a SkeletonUtilityBone component attached.", "OK");
return;
}
SetSkeletonUtilityToFlipByRotation();
kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true;
// HingeChain Parent
// Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum.
GameObject chainParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
var followRotationComponent = chainParentObject.AddComponent<FollowSkeletonUtilityRootRotation>();
followRotationComponent.reference = skeletonUtility.boneRoot;
// Follower Kinematic Rigidbody
GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower");
followerKinematicObject.transform.parent = chainParentObject.transform;
var followerRigidbody = followerKinematicObject.AddComponent<Rigidbody>();
followerRigidbody.mass = 10;
followerRigidbody.isKinematic = true;
followerKinematicObject.AddComponent<FollowLocationRigidbody>().reference = kinematicParentUtilityBone.transform;
followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position;
followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation;
// Child Bones
var utilityBones = utilityBone.GetComponentsInChildren<SkeletonUtilityBone>();
var childBoneParentReference = followerKinematicObject.transform;
foreach (var childBone in utilityBones) {
childBone.parentReference = childBoneParentReference;
childBone.transform.SetParent(chainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity.
AttachRigidbodyAndCollider(childBone);
childBone.mode = SkeletonUtilityBone.Mode.Override;
HingeJoint joint = childBone.gameObject.AddComponent<HingeJoint>();
joint.axis = Vector3.forward;
joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody>();
joint.useLimits = true;
joint.limits = new JointLimits {
min = -20,
max = 20
};
childBone.GetComponent<Rigidbody>().mass = childBoneParentReference.transform.GetComponent<Rigidbody>().mass * 0.75f;
childBoneParentReference = childBone.transform;
}
UnityEditor.Selection.activeGameObject = chainParentObject;
}
void SetSkeletonUtilityToFlipByRotation () {
if (!skeletonUtility.flipBy180DegreeRotation) {
skeletonUtility.flipBy180DegreeRotation = true;
Debug.Log("Set SkeletonUtility " + skeletonUtility.name + " to flip by rotation instead of negative scale (required).", skeletonUtility);
}
}
static void AttachRigidbodyAndCollider (SkeletonUtilityBone utilBone, bool enableCollider = false) {
if (utilBone.GetComponent<Collider>() == null) {
if (utilBone.bone.Data.Length == 0) {
SphereCollider sphere = utilBone.gameObject.AddComponent<SphereCollider>();
sphere.radius = 0.1f;
sphere.enabled = enableCollider;
} else {
float length = utilBone.bone.Data.Length;
BoxCollider box = utilBone.gameObject.AddComponent<BoxCollider>();
box.size = new Vector3(length, length / 3f, 0.2f);
box.center = new Vector3(length / 2f, 0, 0);
box.enabled = enableCollider;
}
}
utilBone.gameObject.AddComponent<Rigidbody>();
}
static void AttachRigidbodyAndCollider2D(SkeletonUtilityBone utilBone, bool enableCollider = false) {
if (utilBone.GetComponent<Collider2D>() == null) {
if (utilBone.bone.Data.Length == 0) {
var sphere = utilBone.gameObject.AddComponent<CircleCollider2D>();
sphere.radius = 0.1f;
sphere.enabled = enableCollider;
}
else {
float length = utilBone.bone.Data.Length;
var box = utilBone.gameObject.AddComponent<BoxCollider2D>();
box.size = new Vector3(length, length / 3f, 0.2f);
box.offset = new Vector3(length / 2f, 0, 0);
box.enabled = enableCollider;
}
}
utilBone.gameObject.AddComponent<Rigidbody2D>();
}
}
}
@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: a018d561e5df35848bcabbe2809c7549
folderAsset: yes
timeCreated: 1580402759
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

@@ -1,390 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!181963792 &2655988077585873504
Preset:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: PMATexturePreset
m_TargetType:
m_NativeTypeID: 1006
m_ManagedTypePPtr: {fileID: 0}
m_ManagedTypeFallback:
m_Properties:
- target: {fileID: 0}
propertyPath: m_ExternalObjects.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapMode
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_EnableMipMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_sRGBTexture
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_LinearTexture
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_FadeOut
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_BorderMipMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapsPreserveCoverage
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaTestReferenceValue
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapFadeDistanceStart
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapFadeDistanceEnd
value: 3
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_ConvertToNormalMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_ExternalNormalMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_HeightScale
value: 0.25
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_NormalMapFilter
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_IsReadable
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_StreamingMipmaps
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_StreamingMipmapsPriority
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_GrayScaleToAlpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_GenerateCubemap
value: 6
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CubemapConvolution
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SeamlessCubemap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureFormat
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_FilterMode
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_Aniso
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_MipBias
value: -100
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapU
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapV
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapW
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_NPOTScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_Lightmap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteMode
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteExtrude
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteMeshType
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_Alignment
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePixelsToUnits
value: 100
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteGenerateFallbackPhysicsShape
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaUsage
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaIsTransparency
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteTessellationDetail
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureType
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureShape
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SingleChannelComponent
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MaxTextureSizeSet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CompressionQualitySet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureFormatSet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.size
value: 2
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_BuildTarget
value: DefaultTexturePlatform
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_ResizeAlgorithm
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_TextureFormat
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_TextureCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_CrunchedCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_AllowsAlphaSplitting
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_Overridden
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_AndroidETC2FallbackOverride
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_ForceMaximumCompressionQuality_BC6H_BC7
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_BuildTarget
value: Standalone
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_ResizeAlgorithm
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_TextureFormat
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_TextureCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_CrunchedCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_AllowsAlphaSplitting
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_Overridden
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_AndroidETC2FallbackOverride
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_ForceMaximumCompressionQuality_BC6H_BC7
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Sprites.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Outline.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_PhysicsShape.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Bones.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_SpriteID
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_InternalID
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Vertices.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Indices.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Edges.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Weights.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_SecondaryTextures.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePackingTag
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PSDRemoveMatte
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PSDShowRemoveMatteOption
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_UserData
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AssetBundleName
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AssetBundleVariant
value:
objectReference: {fileID: 0}
@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 665f49f3e2dc7b645b6577f14455f445
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -1,390 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!181963792 &2655988077585873504
Preset:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: StraightAlphaPreset
m_TargetType:
m_NativeTypeID: 1006
m_ManagedTypePPtr: {fileID: 0}
m_ManagedTypeFallback:
m_Properties:
- target: {fileID: 0}
propertyPath: m_ExternalObjects.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapMode
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_EnableMipMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_sRGBTexture
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_LinearTexture
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_FadeOut
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_BorderMipMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapsPreserveCoverage
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaTestReferenceValue
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapFadeDistanceStart
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MipMapFadeDistanceEnd
value: 3
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_ConvertToNormalMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_ExternalNormalMap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_HeightScale
value: 0.25
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_NormalMapFilter
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_IsReadable
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_StreamingMipmaps
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_StreamingMipmapsPriority
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_GrayScaleToAlpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_GenerateCubemap
value: 6
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CubemapConvolution
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SeamlessCubemap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureFormat
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_FilterMode
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_Aniso
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_MipBias
value: -100
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapU
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapV
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureSettings.m_WrapW
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_NPOTScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_Lightmap
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteMode
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteExtrude
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteMeshType
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_Alignment
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePixelsToUnits
value: 100
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteBorder.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteGenerateFallbackPhysicsShape
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaUsage
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AlphaIsTransparency
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteTessellationDetail
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureType
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureShape
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SingleChannelComponent
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_MaxTextureSizeSet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_CompressionQualitySet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_TextureFormatSet
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.size
value: 2
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_BuildTarget
value: DefaultTexturePlatform
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_ResizeAlgorithm
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_TextureFormat
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_TextureCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_CrunchedCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_AllowsAlphaSplitting
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_Overridden
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_AndroidETC2FallbackOverride
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[0].m_ForceMaximumCompressionQuality_BC6H_BC7
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_BuildTarget
value: Standalone
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_MaxTextureSize
value: 2048
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_ResizeAlgorithm
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_TextureFormat
value: -1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_TextureCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_CompressionQuality
value: 50
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_CrunchedCompression
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_AllowsAlphaSplitting
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_Overridden
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_AndroidETC2FallbackOverride
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PlatformSettings.Array.data[1].m_ForceMaximumCompressionQuality_BC6H_BC7
value: 1
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Sprites.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Outline.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_PhysicsShape.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Bones.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_SpriteID
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_InternalID
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Vertices.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Indices.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Edges.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_Weights.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpriteSheet.m_SecondaryTextures.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_SpritePackingTag
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PSDRemoveMatte
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_PSDShowRemoveMatteOption
value: 0
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_UserData
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AssetBundleName
value:
objectReference: {fileID: 0}
- target: {fileID: 0}
propertyPath: m_AssetBundleVariant
value:
objectReference: {fileID: 0}
@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b3fe5ce49a7c8c041a9d60e4f7f403de
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

+14 -14
View File
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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 System;
@@ -36,12 +36,12 @@ namespace Spine.Unity.Editor {
public static class Menus {
[MenuItem("GameObject/Spine/SkeletonRenderer", false, 10)]
static public void CreateSkeletonRendererGameObject () {
EditorInstantiation.InstantiateEmptySpineGameObject<SkeletonRenderer>("New SkeletonRenderer", true);
SpineEditorUtilities.EditorInstantiation.InstantiateEmptySpineGameObject<SkeletonRenderer>("New SkeletonRenderer");
}
[MenuItem("GameObject/Spine/SkeletonAnimation", false, 10)]
static public void CreateSkeletonAnimationGameObject () {
EditorInstantiation.InstantiateEmptySpineGameObject<SkeletonAnimation>("New SkeletonAnimation", true);
SpineEditorUtilities.EditorInstantiation.InstantiateEmptySpineGameObject<SkeletonAnimation>("New SkeletonAnimation");
}
}
}
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,19 +15,18 @@
* 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.
* 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 System.Collections;
using UnityEditor;
using UnityEngine;
@@ -37,7 +36,7 @@ namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
[CustomEditor(typeof(PointFollower)), CanEditMultipleObjects]
public class PointFollowerInspector : Editor {
public class PointFollowerEditor : Editor {
SerializedProperty slotName, pointAttachmentName, skeletonRenderer, followZPosition, followBoneRotation, followSkeletonFlip;
PointFollower targetPointFollower;
bool needsReset;
@@ -46,7 +45,7 @@ namespace Spine.Unity.Editor {
[MenuItem("CONTEXT/SkeletonRenderer/Add PointFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
var skeletonRenderer = cmd.context as SkeletonRenderer;
var go = EditorInstantiation.NewGameObject("PointFollower", true);
var go = SpineEditorUtilities.EditorInstantiation.NewGameObject("PointFollower");
var t = go.transform;
t.SetParent(skeletonRenderer.transform);
t.localPosition = Vector3.zero;
@@ -114,8 +113,8 @@ namespace Spine.Unity.Editor {
foreach (var skinEntry in skin.Attachments) {
var attachment = skinEntry.Value as PointAttachment;
if (attachment != null) {
var skinKey = (Skin.SkinEntry)skinEntry.Key;
var slot = skeleton.Slots.Items[skinKey.SlotIndex];
var skinKey = skinEntry.Key;
var slot = skeleton.Slots.Items[skinKey.slotIndex];
DrawPointAttachmentWithLabel(attachment, slot.Bone, transform);
}
}
@@ -1,226 +0,0 @@
/******************************************************************************
* 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 UnityEditor;
using Spine.Unity;
using SpineInspectorUtility = Spine.Unity.Editor.SpineInspectorUtility;
public class SpineShaderWithOutlineGUI : ShaderGUI {
protected MaterialEditor _materialEditor;
bool _showAdvancedOutlineSettings = false;
bool _showStencilSettings = false;
MaterialProperty _OutlineWidth = null;
MaterialProperty _OutlineColor = null;
MaterialProperty _OutlineReferenceTexWidth = null;
MaterialProperty _ThresholdEnd = null;
MaterialProperty _OutlineSmoothness = null;
MaterialProperty _Use8Neighbourhood = null;
MaterialProperty _OutlineMipLevel = null;
MaterialProperty _StencilComp = null;
MaterialProperty _StencilRef = null;
static GUIContent _EnableOutlineText = new GUIContent("Outline", "Enable outline rendering. Draws an outline by sampling 4 or 8 neighbourhood pixels at a given distance specified via 'Outline Width'.");
static GUIContent _OutlineWidthText = new GUIContent("Outline Width", "");
static GUIContent _OutlineColorText = new GUIContent("Outline Color", "");
static GUIContent _OutlineReferenceTexWidthText = new GUIContent("Reference Texture Width", "");
static GUIContent _ThresholdEndText = new GUIContent("Outline Threshold", "");
static GUIContent _OutlineSmoothnessText = new GUIContent("Outline Smoothness", "");
static GUIContent _Use8NeighbourhoodText = new GUIContent("Sample 8 Neighbours", "");
static GUIContent _OutlineMipLevelText = new GUIContent("Outline Mip Level", "");
static GUIContent _StencilCompText = new GUIContent("Stencil Comparison", "");
static GUIContent _StencilRefText = new GUIContent("Stencil Reference", "");
static GUIContent _OutlineAdvancedText = new GUIContent("Advanced", "");
static GUIContent _ShowStencilText = new GUIContent("Stencil", "Stencil parameters for mask interaction.");
protected const string ShaderOutlineNamePrefix = "Spine/Outline/";
protected const string ShaderNormalNamePrefix = "Spine/";
protected const string ShaderWithoutStandardVariantSuffix = "OutlineOnly";
#region ShaderGUI
public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] properties) {
FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
_materialEditor = materialEditor;
base.OnGUI(materialEditor, properties);
EditorGUILayout.Space();
RenderStencilProperties();
EditorGUILayout.Space();
RenderOutlineProperties();
}
#endregion
#region Virtual Interface
protected virtual void FindProperties (MaterialProperty[] props) {
_OutlineWidth = FindProperty("_OutlineWidth", props, false);
_OutlineReferenceTexWidth = FindProperty("_OutlineReferenceTexWidth", props, false);
_OutlineColor = FindProperty("_OutlineColor", props, false);
_ThresholdEnd = FindProperty("_ThresholdEnd", props, false);
_OutlineSmoothness = FindProperty("_OutlineSmoothness", props, false);
_Use8Neighbourhood = FindProperty("_Use8Neighbourhood", props, false);
_OutlineMipLevel = FindProperty("_OutlineMipLevel", props, false);
_StencilComp = FindProperty("_StencilComp", props, false);
_StencilRef = FindProperty("_StencilRef", props, false);
if (_StencilRef == null)
_StencilRef = FindProperty("_Stencil", props, false);
}
protected virtual void RenderStencilProperties () {
if (_StencilComp == null)
return; // not a shader supporting custom stencil operations
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
_showStencilSettings = EditorGUILayout.Foldout(_showStencilSettings, _ShowStencilText);
if (_showStencilSettings) {
using (new SpineInspectorUtility.IndentScope()) {
_materialEditor.ShaderProperty(_StencilComp, _StencilCompText);
_materialEditor.ShaderProperty(_StencilRef, _StencilRefText);
}
}
}
protected virtual void RenderOutlineProperties () {
if (_OutlineWidth == null)
return; // not an outline shader
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
bool mixedValue;
bool hasOutlineVariant = !IsShaderWithoutStandardVariantShader(_materialEditor, out mixedValue);
bool isOutlineEnabled = true;
if (hasOutlineVariant) {
isOutlineEnabled = IsOutlineEnabled(_materialEditor, out mixedValue);
EditorGUI.showMixedValue = mixedValue;
EditorGUI.BeginChangeCheck();
var origFontStyle = EditorStyles.label.fontStyle;
EditorStyles.label.fontStyle = FontStyle.Bold;
isOutlineEnabled = EditorGUILayout.Toggle(_EnableOutlineText, isOutlineEnabled);
EditorStyles.label.fontStyle = origFontStyle;
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck()) {
foreach (Material material in _materialEditor.targets) {
SwitchShaderToOutlineSettings(material, isOutlineEnabled);
}
}
}
else {
var origFontStyle = EditorStyles.label.fontStyle;
EditorStyles.label.fontStyle = FontStyle.Bold;
EditorGUILayout.LabelField(_EnableOutlineText);
EditorStyles.label.fontStyle = origFontStyle;
}
if (isOutlineEnabled) {
_materialEditor.ShaderProperty(_OutlineWidth, _OutlineWidthText);
_materialEditor.ShaderProperty(_OutlineColor, _OutlineColorText);
_showAdvancedOutlineSettings = EditorGUILayout.Foldout(_showAdvancedOutlineSettings, _OutlineAdvancedText);
if (_showAdvancedOutlineSettings) {
using (new SpineInspectorUtility.IndentScope()) {
_materialEditor.ShaderProperty(_OutlineReferenceTexWidth, _OutlineReferenceTexWidthText);
_materialEditor.ShaderProperty(_ThresholdEnd, _ThresholdEndText);
_materialEditor.ShaderProperty(_OutlineSmoothness, _OutlineSmoothnessText);
_materialEditor.ShaderProperty(_Use8Neighbourhood, _Use8NeighbourhoodText);
_materialEditor.ShaderProperty(_OutlineMipLevel, _OutlineMipLevelText);
}
}
}
}
#endregion
#region Private Functions
void SwitchShaderToOutlineSettings (Material material, bool enableOutline) {
var shaderName = material.shader.name;
bool isSetToOutlineShader = shaderName.Contains(ShaderOutlineNamePrefix);
if (isSetToOutlineShader && !enableOutline) {
shaderName = shaderName.Replace(ShaderOutlineNamePrefix, ShaderNormalNamePrefix);
_materialEditor.SetShader(Shader.Find(shaderName), false);
return;
}
else if (!isSetToOutlineShader && enableOutline) {
shaderName = shaderName.Replace(ShaderNormalNamePrefix, ShaderOutlineNamePrefix);
_materialEditor.SetShader(Shader.Find(shaderName), false);
return;
}
}
static bool IsOutlineEnabled (MaterialEditor editor, out bool mixedValue) {
mixedValue = false;
bool isAnyEnabled = false;
foreach (Material material in editor.targets) {
if (material.shader.name.Contains(ShaderOutlineNamePrefix)) {
isAnyEnabled = true;
}
else if (isAnyEnabled) {
mixedValue = true;
}
}
return isAnyEnabled;
}
static bool IsShaderWithoutStandardVariantShader (MaterialEditor editor, out bool mixedValue) {
mixedValue = false;
bool isAnyShaderWithoutVariant = false;
foreach (Material material in editor.targets) {
if (material.shader.name.Contains(ShaderWithoutStandardVariantSuffix)) {
isAnyShaderWithoutVariant = true;
}
else if (isAnyShaderWithoutVariant) {
mixedValue = true;
}
}
return isAnyShaderWithoutVariant;
}
static bool BoldToggleField (GUIContent label, bool value) {
FontStyle origFontStyle = EditorStyles.label.fontStyle;
EditorStyles.label.fontStyle = FontStyle.Bold;
value = EditorGUILayout.Toggle(label, value, EditorStyles.toggle);
EditorStyles.label.fontStyle = origFontStyle;
return value;
}
#endregion
}
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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 UnityEditor;
@@ -37,7 +37,7 @@ namespace Spine.Unity.Editor {
[CanEditMultipleObjects]
public class SkeletonAnimationInspector : SkeletonRendererInspector {
protected SerializedProperty animationName, loop, timeScale, autoReset;
protected bool wasAnimationParameterChanged = false;
protected bool wasAnimationNameChanged;
protected bool requireRepaint;
readonly GUIContent LoopLabel = new GUIContent("Loop", "Whether or not .AnimationName should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.");
readonly GUIContent TimeScaleLabel = new GUIContent("Time Scale", "The rate at which animations progress over time. 1 means normal speed. 0.5 means 50% speed.");
@@ -54,53 +54,53 @@ namespace Spine.Unity.Editor {
if (!TargetIsValid) return;
bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject);
foreach (var o in targets)
TrySetAnimation(o as SkeletonAnimation);
if (multi) {
foreach (var o in targets)
TrySetAnimation(o as SkeletonAnimation, multi);
EditorGUILayout.Space();
if (!sameData) {
EditorGUILayout.DelayedTextField(animationName);
EditorGUILayout.Space();
if (!sameData) {
EditorGUILayout.DelayedTextField(animationName);
} else {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(animationName);
wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
}
EditorGUILayout.PropertyField(loop);
EditorGUILayout.PropertyField(timeScale);
foreach (var o in targets) {
var component = o as SkeletonAnimation;
component.timeScale = Mathf.Max(component.timeScale, 0);
}
} else {
TrySetAnimation(target as SkeletonAnimation, multi);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(animationName);
wasAnimationParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(loop, LoopLabel);
wasAnimationParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
EditorGUILayout.PropertyField(timeScale, TimeScaleLabel);
foreach (var o in targets) {
var component = o as SkeletonAnimation;
wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
EditorGUILayout.PropertyField(loop, LoopLabel);
EditorGUILayout.PropertyField(timeScale, TimeScaleLabel);
var component = (SkeletonAnimation)target;
component.timeScale = Mathf.Max(component.timeScale, 0);
EditorGUILayout.Space();
}
EditorGUILayout.Space();
SkeletonRootMotionParameter();
serializedObject.ApplyModifiedProperties();
if (!isInspectingPrefab) {
if (requireRepaint) {
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
SceneView.RepaintAll();
requireRepaint = false;
}
}
}
protected void TrySetAnimation (SkeletonAnimation skeletonAnimation) {
protected void TrySetAnimation (SkeletonAnimation skeletonAnimation, bool multi) {
if (skeletonAnimation == null) return;
if (!skeletonAnimation.valid || skeletonAnimation.AnimationState == null)
if (!skeletonAnimation.valid)
return;
TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0);
if (!isInspectingPrefab) {
string activeAnimation = (current != null) ? current.Animation.Name : "";
bool activeLoop = (current != null) ? current.Loop : false;
bool animationParameterChanged = this.wasAnimationParameterChanged &&
((activeAnimation != animationName.stringValue) || (activeLoop != loop.boolValue));
if (animationParameterChanged) {
this.wasAnimationParameterChanged = false;
if (wasAnimationNameChanged) {
var skeleton = skeletonAnimation.Skeleton;
var state = skeletonAnimation.AnimationState;
@@ -112,10 +112,8 @@ namespace Spine.Unity.Editor {
Spine.Animation animationToUse = skeleton.Data.FindAnimation(animationName.stringValue);
if (!Application.isPlaying) {
if (animationToUse != null) {
skeletonAnimation.AnimationState.SetAnimation(0, animationToUse, loop.boolValue);
}
skeletonAnimation.Update(0);
if (animationToUse != null) animationToUse.PoseSkeleton(skeleton, 0f);
skeleton.UpdateWorldTransform();
skeletonAnimation.LateUpdate();
requireRepaint = true;
} else {
@@ -124,11 +122,14 @@ namespace Spine.Unity.Editor {
else
state.ClearTrack(0);
}
wasAnimationNameChanged = false;
}
// Reflect animationName serialized property in the inspector even if SetAnimation API was used.
if (Application.isPlaying) {
if (current != null && current.Animation != null) {
if (!multi && Application.isPlaying) {
TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0);
if (current != null) {
if (skeletonAnimation.AnimationName != animationName.stringValue)
animationName.stringValue = current.Animation.Name;
}
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
@@ -71,7 +71,7 @@ namespace Spine.Unity.Editor {
/// </summary>
public static class SkeletonBaker {
#region SkeletonMecanim's Mecanim Clips
#region SkeletonAnimator's Mecanim Clips
#if SPINE_SKELETONMECANIM
public static void UpdateMecanimClips (SkeletonDataAsset skeletonDataAsset) {
if (skeletonDataAsset.controller == null)
@@ -88,7 +88,7 @@ namespace Spine.Unity.Editor {
}
string dataPath = AssetDatabase.GetAssetPath(skeletonDataAsset);
string controllerPath = dataPath.Replace(AssetUtility.SkeletonDataSuffix, "_Controller").Replace(".asset", ".controller");
string controllerPath = dataPath.Replace(SpineEditorUtilities.AssetUtility.SkeletonDataSuffix, "_Controller").Replace(".asset", ".controller");
UnityEditor.Animations.AnimatorController controller;
if (skeletonDataAsset.controller != null) {
controller = (UnityEditor.Animations.AnimatorController)skeletonDataAsset.controller;
@@ -185,8 +185,10 @@ namespace Spine.Unity.Editor {
return;
}
#if !NEW_PREFAB_SYSTEM
if (outputPath == "") {
outputPath = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(skeletonDataAsset)).Replace('\\', '/') + "/Baked";
outputPath = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(skeletonDataAsset)) + "/Baked";
System.IO.Directory.CreateDirectory(outputPath);
}
@@ -226,11 +228,11 @@ namespace Spine.Unity.Editor {
List<string> attachmentNames = new List<string>();
for (int i = 0; i < skinCount; i++) {
var skin = skins.Items[i];
var skinEntries = new List<Skin.SkinEntry>();
skin.GetAttachments(s, skinEntries);
foreach (var entry in skinEntries) {
if (!attachmentNames.Contains(entry.Name))
attachmentNames.Add(entry.Name);
List<string> temp = new List<string>();
skin.FindNamesForSlot(s, temp);
foreach (string str in temp) {
if (!attachmentNames.Contains(str))
attachmentNames.Add(str);
}
}
slotLookup.Add(s, attachmentNames);
@@ -279,13 +281,7 @@ namespace Spine.Unity.Editor {
Object prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
if (prefab == null) {
#if NEW_PREFAB_SYSTEM
GameObject emptyGameObject = new GameObject();
prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(emptyGameObject, prefabPath, InteractionMode.AutomatedAction);
GameObject.DestroyImmediate(emptyGameObject);
#else
prefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
#endif
newPrefab = true;
}
@@ -299,7 +295,7 @@ namespace Spine.Unity.Editor {
}
}
GameObject prefabRoot = EditorInstantiation.NewGameObject("root", true);
GameObject prefabRoot = SpineEditorUtilities.EditorInstantiation.NewGameObject("root");
Dictionary<string, Transform> slotTable = new Dictionary<string, Transform>();
Dictionary<string, Transform> boneTable = new Dictionary<string, Transform>();
@@ -308,7 +304,7 @@ namespace Spine.Unity.Editor {
//create bones
for (int i = 0; i < skeletonData.Bones.Count; i++) {
var boneData = skeletonData.Bones.Items[i];
Transform boneTransform = EditorInstantiation.NewGameObject(boneData.Name, true).transform;
Transform boneTransform = SpineEditorUtilities.EditorInstantiation.NewGameObject(boneData.Name).transform;
boneTransform.parent = prefabRoot.transform;
boneTable.Add(boneTransform.name, boneTransform);
boneList.Add(boneTransform);
@@ -337,20 +333,26 @@ namespace Spine.Unity.Editor {
}
//create slots and attachments
for (int slotIndex = 0; slotIndex < skeletonData.Slots.Count; slotIndex++) {
var slotData = skeletonData.Slots.Items[slotIndex];
Transform slotTransform = EditorInstantiation.NewGameObject(slotData.Name, true).transform;
for (int i = 0; i < skeletonData.Slots.Count; i++) {
var slotData = skeletonData.Slots.Items[i];
Transform slotTransform = SpineEditorUtilities.EditorInstantiation.NewGameObject(slotData.Name).transform;
slotTransform.parent = prefabRoot.transform;
slotTable.Add(slotData.Name, slotTransform);
var skinEntries = new List<Skin.SkinEntry>();
skin.GetAttachments(slotIndex, skinEntries);
if (skin != skeletonData.DefaultSkin)
skeletonData.DefaultSkin.GetAttachments(slotIndex, skinEntries);
List<Attachment> attachments = new List<Attachment>();
List<string> attachmentNames = new List<string>();
for (int a = 0; a < skinEntries.Count; a++) {
var attachment = skinEntries[a].Attachment;
string attachmentName = skinEntries[a].Name;
skin.FindAttachmentsForSlot(i, attachments);
skin.FindNamesForSlot(i, attachmentNames);
if (skin != skeletonData.DefaultSkin) {
skeletonData.DefaultSkin.FindAttachmentsForSlot(i, attachments);
skeletonData.DefaultSkin.FindNamesForSlot(i, attachmentNames);
}
for (int a = 0; a < attachments.Count; a++) {
var attachment = attachments[a];
string attachmentName = attachmentNames[a];
string attachmentMeshName = "[" + slotData.Name + "] " + attachmentName;
Vector3 offset = Vector3.zero;
float rotation = 0;
@@ -378,7 +380,7 @@ namespace Spine.Unity.Editor {
rotation = 0;
if (isWeightedMesh)
mesh = ExtractWeightedMeshAttachment(attachmentMeshName, meshAttachment, slotIndex, skeletonData, boneList, mesh);
mesh = ExtractWeightedMeshAttachment(attachmentMeshName, meshAttachment, i, skeletonData, boneList, mesh);
else
mesh = ExtractMeshAttachment(attachmentMeshName, meshAttachment, mesh);
@@ -389,7 +391,7 @@ namespace Spine.Unity.Editor {
} else
continue;
Transform attachmentTransform = EditorInstantiation.NewGameObject(attachmentName, true).transform;
Transform attachmentTransform = SpineEditorUtilities.EditorInstantiation.NewGameObject(attachmentName).transform;
attachmentTransform.parent = slotTransform;
attachmentTransform.localPosition = offset;
@@ -408,7 +410,7 @@ namespace Spine.Unity.Editor {
}
attachmentTransform.GetComponent<Renderer>().sharedMaterial = material;
attachmentTransform.GetComponent<Renderer>().sortingOrder = slotIndex;
attachmentTransform.GetComponent<Renderer>().sortingOrder = i;
if (attachmentName != slotData.AttachmentName)
attachmentTransform.gameObject.SetActive(false);
@@ -432,22 +434,14 @@ namespace Spine.Unity.Editor {
}
if (newPrefab) {
#if NEW_PREFAB_SYSTEM
PrefabUtility.SaveAsPrefabAssetAndConnect(prefabRoot, prefabPath, InteractionMode.AutomatedAction);
#else
PrefabUtility.ReplacePrefab(prefabRoot, prefab, ReplacePrefabOptions.ConnectToPrefab);
#endif
} else {
foreach (string str in unusedMeshNames) {
Mesh.DestroyImmediate(meshTable[str], true);
}
#if NEW_PREFAB_SYSTEM
PrefabUtility.SaveAsPrefabAssetAndConnect(prefabRoot, prefabPath, InteractionMode.AutomatedAction);
#else
PrefabUtility.ReplacePrefab(prefabRoot, prefab, ReplacePrefabOptions.ReplaceNameBased);
#endif
}
@@ -459,6 +453,8 @@ namespace Spine.Unity.Editor {
GameObject.DestroyImmediate(prefabRoot);
}
#endif
}
#region Attachment Baking
@@ -621,7 +617,7 @@ namespace Spine.Unity.Editor {
int[] triangles = attachment.Triangles;
Color color = new Color(attachment.R, attachment.G, attachment.B, attachment.A);
mesh = (mesh == null) ? new Mesh() : mesh;
mesh = mesh ?? new Mesh();
mesh.triangles = new int[0];
@@ -673,7 +669,7 @@ namespace Spine.Unity.Editor {
for (int b = 0; b < pairs.Count; b++) {
if (b > 3) {
if (warningBuilder.Length == 0)
warningBuilder.Insert(0, "[Weighted Mesh: " + name + "]\r\nUnity only supports 4 weight influences per vertex! The 4 strongest influences will be used.\r\n");
warningBuilder.Insert(0, "[Weighted Mesh: " + name + "]\r\nUnity only supports 4 weight influences per vertex! The 4 strongest influences will be used.\r\n");
warningBuilder.AppendFormat("{0} ignored on vertex {1}!\r\n", pairs[b].bone.name, i);
continue;
@@ -834,7 +830,7 @@ namespace Spine.Unity.Editor {
Skeleton skeleton = bone.Skeleton;
bool inheritRotation = bone.Data.TransformMode.InheritsRotation();
animation.Apply(skeleton, 0, 0, false, null, 1f, MixBlend.Setup, MixDirection.In);
animation.PoseSkeleton(skeleton, 0);
skeleton.UpdateWorldTransform();
float duration = animation.Duration;
@@ -862,7 +858,7 @@ namespace Spine.Unity.Editor {
if (i == steps)
currentTime = duration;
animation.Apply(skeleton, 0, currentTime, true, null, 1f, MixBlend.Setup, MixDirection.In);
animation.PoseSkeleton(skeleton, currentTime, true);
skeleton.UpdateWorldTransform();
int pIndex = listIndex - 1;
@@ -1311,14 +1307,9 @@ namespace Spine.Unity.Editor {
var animEvents = new List<AnimationEvent>();
for (int i = 0, n = frames.Length; i < n; i++) {
var spineEvent = events[i];
string eventName = spineEvent.Data.Name;
if (SpineEditorUtilities.Preferences.mecanimEventIncludeFolderName)
eventName = eventName.Replace("/", ""); // calls method FolderNameEventName()
else
eventName = eventName.Substring(eventName.LastIndexOf('/') + 1); // calls method EventName()
var unityAnimationEvent = new AnimationEvent {
time = frames[i],
functionName = eventName,
functionName = spineEvent.Data.Name,
messageOptions = eventOptions
};
@@ -1424,9 +1415,9 @@ namespace Spine.Unity.Editor {
atlasAsset.GetAtlas(); // Initializes atlasAsset.
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath).Replace('\\', '/');
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
string bakedPrefabPath = Path.Combine(bakedDirPath, AssetUtility.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/");
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.AssetUtility.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/");
GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject));
GameObject root;
@@ -1437,7 +1428,7 @@ namespace Spine.Unity.Editor {
Directory.CreateDirectory(bakedDirPath);
if (prefab == null) {
root = EditorInstantiation.NewGameObject("temp", true, typeof(MeshFilter), typeof(MeshRenderer));
root = SpineEditorUtilities.EditorInstantiation.NewGameObject("temp", typeof(MeshFilter), typeof(MeshRenderer));
#if NEW_PREFAB_SYSTEM
prefab = PrefabUtility.SaveAsPrefabAsset(root, bakedPrefabPath);
#else
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,18 +15,22 @@
* 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.
* 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@@ -40,6 +44,7 @@ namespace Spine.Unity.Editor {
public class SkeletonBakingWindow : EditorWindow {
const bool IsUtilityWindow = true;
#if !NEW_PREFAB_SYSTEM
[MenuItem("CONTEXT/SkeletonDataAsset/Skeleton Baking", false, 5000)]
public static void Init (MenuCommand command) {
var window = EditorWindow.GetWindow<SkeletonBakingWindow>(IsUtilityWindow);
@@ -49,6 +54,7 @@ namespace Spine.Unity.Editor {
window.skeletonDataAsset = command.context as SkeletonDataAsset;
window.Show();
}
#endif
public SkeletonDataAsset skeletonDataAsset;
[SpineSkin(dataField:"skeletonDataAsset")]
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#define SPINE_SKELETON_MECANIM
@@ -40,7 +40,7 @@ using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
using Spine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
@@ -56,7 +56,6 @@ namespace Spine.Unity.Editor {
SerializedProperty atlasAssets, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
SerializedProperty skeletonDataModifiers;
SerializedProperty blendModeMaterials;
#if SPINE_TK2D
SerializedProperty spriteCollection;
#endif
@@ -70,7 +69,6 @@ namespace Spine.Unity.Editor {
SkeletonData targetSkeletonData;
readonly List<string> warnings = new List<string>();
CompatibilityProblemInfo compatibilityProblemInfo = null;
readonly SkeletonInspectorPreview preview = new SkeletonInspectorPreview();
GUIStyle activePlayButtonStyle, idlePlayButtonStyle;
@@ -97,8 +95,7 @@ namespace Spine.Unity.Editor {
public void UpdateSkeletonData () {
preview.Clear();
InitializeEditor();
if (targetSkeletonDataAsset)
EditorUtility.SetDirty(targetSkeletonDataAsset);
EditorUtility.SetDirty(targetSkeletonDataAsset);
}
void InitializeEditor () {
@@ -115,7 +112,6 @@ namespace Spine.Unity.Editor {
defaultMix = serializedObject.FindProperty("defaultMix");
skeletonDataModifiers = serializedObject.FindProperty("skeletonDataModifiers");
blendModeMaterials = serializedObject.FindProperty("blendModeMaterials");
#if SPINE_SKELETON_MECANIM
controller = serializedObject.FindProperty("controller");
@@ -127,7 +123,7 @@ namespace Spine.Unity.Editor {
#else
// Analysis disable once ConvertIfToOrExpression
if (newAtlasAssets) atlasAssets.isExpanded = true;
#endif
#endif
// This handles the case where the managed editor assembly is unloaded before recompilation when code changes.
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
@@ -144,9 +140,9 @@ namespace Spine.Unity.Editor {
return;
}
targetSkeletonData = NoProblems() ? targetSkeletonDataAsset.GetSkeletonData(false) : null;
targetSkeletonData = warnings.Count == 0 ? targetSkeletonDataAsset.GetSkeletonData(false) : null;
if (targetSkeletonData != null && NoProblems()) {
if (targetSkeletonData != null && warnings.Count <= 0) {
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
}
@@ -184,9 +180,6 @@ namespace Spine.Unity.Editor {
using (new SpineInspectorUtility.BoxScope())
DrawSkeletonDataFields();
if (compatibilityProblemInfo != null)
return;
using (new SpineInspectorUtility.BoxScope()) {
DrawAtlasAssetsFields();
HandleAtlasAssetsNulls();
@@ -206,7 +199,7 @@ namespace Spine.Unity.Editor {
}
// Unity Quirk: Some code depends on valid preview. If preview is initialized elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors.
if (NoProblems())
if (warnings.Count <= 0)
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
if (targetSkeletonData != null) {
@@ -222,7 +215,7 @@ namespace Spine.Unity.Editor {
DrawAnimationList();
if (targetSkeletonData.Animations.Count > 0) {
const string AnimationReferenceButtonText = "Create Animation Reference Assets";
const string AnimationReferenceTooltipText = "AnimationReferenceAsset acts as Unity asset for a reference to a Spine.Animation. This can be used in inspectors.\n\nIt serializes a reference to a SkeletonDataAsset and an animationName.\n\nAt runtime, a reference to its Spine.Animation is loaded and cached into the object to be used as needed. This skips the need to find and cache animation references in individual MonoBehaviours.";
const string AnimationReferenceTooltipText = "AnimationReferenceAsset acts as Unity asset for a reference to a Spine.Animation. This can be used in inspectors.\n\nIt serializes a reference to a SkeletonDataAsset and an animationName.\n\nAt runtime, a reference to its Spine.Animation is loaded and cached into the object to be used as needed. This skips the need to find and cache animation references in individual MonoBehaviours.";
if (GUILayout.Button(SpineInspectorUtility.TempContent(AnimationReferenceButtonText, Icons.animationRoot, AnimationReferenceTooltipText), GUILayout.Width(250), GUILayout.Height(26))) {
CreateAnimationReferenceAssets();
}
@@ -262,7 +255,7 @@ namespace Spine.Unity.Editor {
FieldInfo nameField = typeof(AnimationReferenceAsset).GetField("animationName", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo skeletonDataAssetField = typeof(AnimationReferenceAsset).GetField("skeletonDataAsset", BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var animation in targetSkeletonData.Animations) {
string assetPath = string.Format("{0}/{1}.asset", dataPath, AssetUtility.GetPathSafeName(animation.Name));
string assetPath = string.Format("{0}/{1}.asset", dataPath, SpineEditorUtilities.AssetUtility.GetPathSafeName(animation.Name));
AnimationReferenceAsset existingAsset = AssetDatabase.LoadAssetAtPath<AnimationReferenceAsset>(assetPath);
if (existingAsset == null) {
AnimationReferenceAsset newAsset = ScriptableObject.CreateInstance<AnimationReferenceAsset>();
@@ -288,8 +281,6 @@ namespace Spine.Unity.Editor {
EditorGUILayout.DelayedFloatField(scale); //EditorGUILayout.PropertyField(scale);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(skeletonDataModifiers, true);
DrawBlendModeMaterialProperties();
}
// Texture source field.
@@ -315,27 +306,6 @@ namespace Spine.Unity.Editor {
}
void DrawBlendModeMaterialProperties () {
if (skeletonDataModifiers.arraySize > 0) {
EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
EditorGUILayout.PrefixLabel("Blend Modes");
if (GUILayout.Button(new GUIContent("Upgrade", "Upgrade BlendModeMaterialAsset to built-in BlendModeMaterials."), EditorStyles.miniButton, GUILayout.Width(65f))) {
foreach (SkeletonDataAsset skeletonData in targets) {
BlendModeMaterialsUtility.UpgradeBlendModeMaterials(skeletonData);
}
}
EditorGUILayout.EndHorizontal();
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(blendModeMaterials, true);
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
foreach (SkeletonDataAsset skeletonData in targets) {
BlendModeMaterialsUtility.UpdateBlendModeMaterials(skeletonData);
}
}
}
void DrawSkeletonDataFields () {
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel);
@@ -347,17 +317,9 @@ namespace Spine.Unity.Editor {
}
}
EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine));
if (compatibilityProblemInfo != null) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(compatibilityProblemInfo.DescriptionString(), Icons.warning), GUILayout.Height(52));
return;
}
EditorGUILayout.DelayedFloatField(scale); //EditorGUILayout.PropertyField(scale);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(skeletonDataModifiers, true);
DrawBlendModeMaterialProperties();
}
void DrawAtlasAssetsFields () {
@@ -522,35 +484,36 @@ namespace Spine.Unity.Editor {
}
}
var slotAttachments = new List<Skin.SkinEntry>();
var defaultSkinAttachments = new List<Skin.SkinEntry>();
var slotAttachments = new List<Attachment>();
var slotAttachmentNames = new List<string>();
var defaultSkinAttachmentNames = new List<string>();
var slotsItems = preview.Skeleton.Slots.Items;
for (int i = preview.Skeleton.Slots.Count - 1; i >= 0; i--) {
Slot slot = slotsItems[i];
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot));
if (showAttachments) {
slotAttachments.Clear();
defaultSkinAttachments.Clear();
slotAttachmentNames.Clear();
defaultSkinAttachmentNames.Clear();
using (new SpineInspectorUtility.IndentScope()) {
{
skin.GetAttachments(i, slotAttachments);
if (defaultSkin != null) {
if (skin != defaultSkin) {
defaultSkin.GetAttachments(i, slotAttachments);
defaultSkin.GetAttachments(i, defaultSkinAttachments);
}
else {
defaultSkin.GetAttachments(i, defaultSkinAttachments);
}
skin.FindNamesForSlot(i, slotAttachmentNames);
skin.FindAttachmentsForSlot(i, slotAttachments);
if (skin != defaultSkin) {
defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
defaultSkin.FindNamesForSlot(i, slotAttachmentNames);
defaultSkin.FindAttachmentsForSlot(i, slotAttachments);
} else {
defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
}
}
for (int a = 0; a < slotAttachments.Count; a++) {
var skinEntry = slotAttachments[a];
Attachment attachment = skinEntry.Attachment;
string attachmentName = skinEntry.Name;
bool attachmentIsFromSkin = !defaultSkinAttachments.Contains(skinEntry);
Attachment attachment = slotAttachments[a];
string attachmentName = slotAttachmentNames[a];
bool attachmentIsFromSkin = !defaultSkinAttachmentNames.Contains(attachmentName);
Texture2D attachmentTypeIcon = Icons.GetAttachmentIcon(attachment);
bool initialState = slot.Attachment == attachment;
@@ -582,7 +545,7 @@ namespace Spine.Unity.Editor {
void DrawUnityTools () {
#if SPINE_SKELETON_MECANIM
using (new SpineInspectorUtility.BoxScope()) {
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonMecanim", SpineInspectorUtility.UnityIcon<SceneAsset>()));
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon<SceneAsset>()));
if (isMecanimExpanded) {
using (new SpineInspectorUtility.IndentScope()) {
EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon<Animator>()));
@@ -594,7 +557,7 @@ namespace Spine.Unity.Editor {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Generate Mecanim Controller"), GUILayout.Height(20)))
SkeletonBaker.GenerateMecanimAnimationClips(targetSkeletonDataAsset);
}
EditorGUILayout.HelpBox("SkeletonMecanim is the Mecanim alternative to SkeletonAnimation.\nIt is not required.", MessageType.Info);
EditorGUILayout.HelpBox("SkeletonAnimator is the Mecanim alternative to SkeletonAnimation.\nIt is not required.", MessageType.Info);
} else {
@@ -619,18 +582,13 @@ namespace Spine.Unity.Editor {
void PopulateWarnings () {
warnings.Clear();
compatibilityProblemInfo = null;
if (skeletonJSON.objectReferenceValue == null) {
warnings.Add("Missing Skeleton JSON");
} else {
var fieldValue = (TextAsset)skeletonJSON.objectReferenceValue;
string problemDescription = null;
if (!AssetUtility.IsSpineData(fieldValue, out compatibilityProblemInfo, ref problemDescription)) {
if (problemDescription != null)
warnings.Add(problemDescription);
else
warnings.Add("Skeleton data file is not a valid Spine JSON or binary file.");
if (!SpineEditorUtilities.AssetUtility.IsSpineData(fieldValue)) {
warnings.Add("Skeleton data file is not a valid Spine JSON or binary file.");
} else {
#if SPINE_TK2D
bool searchForSpineAtlasAssets = true;
@@ -647,12 +605,11 @@ namespace Spine.Unity.Editor {
var actualAtlasAssets = targetSkeletonDataAsset.atlasAssets;
for (int i = 0; i < actualAtlasAssets.Length; i++) {
if (actualAtlasAssets[i] == null) {
if (targetSkeletonDataAsset.atlasAssets[i] == null) {
detectedNullAtlasEntry = true;
break;
} else {
if (actualAtlasAssets[i].MaterialCount > 0)
atlasList.Add(actualAtlasAssets[i].GetAtlas());
atlasList.Add(actualAtlasAssets[i].GetAtlas());
}
}
@@ -661,10 +618,9 @@ namespace Spine.Unity.Editor {
} else {
List<string> missingPaths = null;
if (atlasAssets.arraySize > 0) {
missingPaths = AssetUtility.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue));
missingPaths = SpineEditorUtilities.AssetUtility.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue));
foreach (var atlas in atlasList) {
if (atlas == null)
continue;
for (int i = 0; i < missingPaths.Count; i++) {
if (atlas.FindRegion(missingPaths[i]) != null) {
missingPaths.RemoveAt(i);
@@ -692,7 +648,7 @@ namespace Spine.Unity.Editor {
}
void DoReimport () {
AssetUtility.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, null, true);
SpineEditorUtilities.AssetUtility.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true);
preview.Clear();
InitializeEditor();
EditorUtility.SetDirty(targetSkeletonDataAsset);
@@ -702,10 +658,6 @@ namespace Spine.Unity.Editor {
EditorPrefs.SetString(LastSkinKey, skinName);
}
bool NoProblems() {
return warnings.Count == 0 && compatibilityProblemInfo == null;
}
#region Preview Handlers
void HandleOnDestroyPreview () {
EditorApplication.update -= preview.HandleEditorUpdate;
@@ -726,7 +678,7 @@ namespace Spine.Unity.Editor {
}
override public void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
if (NoProblems()) {
if (warnings.Count <= 0) {
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
preview.HandleInteractivePreviewGUI(r, background);
}
@@ -748,7 +700,10 @@ namespace Spine.Unity.Editor {
SkeletonAnimation skeletonAnimation;
GameObject previewGameObject;
internal bool requiresRefresh;
#if !SPINE_UNITY_2018_PREVIEW_API
float animationLastTime;
#endif
static float CurrentTime { get { return (float)EditorApplication.timeSinceStartup; } }
@@ -840,12 +795,14 @@ namespace Spine.Unity.Editor {
return;
}
const int PreviewLayer = 30;
const int PreviewCameraCullingMask = 1 << PreviewLayer;
if (previewRenderUtility == null) {
previewRenderUtility = new PreviewRenderUtility(true);
#if !SPINE_UNITY_2018_PREVIEW_API
animationLastTime = CurrentTime;
#endif
const int PreviewLayer = 30;
const int PreviewCameraCullingMask = 1 << PreviewLayer;
{
var c = this.PreviewUtilityCamera;
@@ -858,32 +815,32 @@ namespace Spine.Unity.Editor {
}
DestroyPreviewGameObject();
}
if (previewGameObject == null) {
try {
previewGameObject = EditorInstantiation.InstantiateSkeletonAnimation(skeletonDataAsset, skinName, useObjectFactory:false).gameObject;
if (previewGameObject == null) {
try {
previewGameObject = SpineEditorUtilities.EditorInstantiation.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject;
if (previewGameObject != null) {
previewGameObject.hideFlags = HideFlags.HideAndDontSave;
previewGameObject.layer = PreviewLayer;
skeletonAnimation = previewGameObject.GetComponent<SkeletonAnimation>();
skeletonAnimation.initialSkinName = skinName;
skeletonAnimation.LateUpdate();
previewGameObject.GetComponent<Renderer>().enabled = false;
if (previewGameObject != null) {
previewGameObject.hideFlags = HideFlags.HideAndDontSave;
previewGameObject.layer = PreviewLayer;
skeletonAnimation = previewGameObject.GetComponent<SkeletonAnimation>();
skeletonAnimation.initialSkinName = skinName;
skeletonAnimation.LateUpdate();
previewGameObject.GetComponent<Renderer>().enabled = false;
#if SPINE_UNITY_2018_PREVIEW_API
previewRenderUtility.AddSingleGO(previewGameObject);
#endif
#if SPINE_UNITY_2018_PREVIEW_API
previewRenderUtility.AddSingleGO(previewGameObject);
#endif
}
if (this.ActiveTrack != null) cameraAdjustEndFrame = EditorApplication.timeSinceStartup + skeletonAnimation.AnimationState.GetCurrent(0).Alpha;
AdjustCameraGoals();
} catch {
DestroyPreviewGameObject();
}
if (this.ActiveTrack != null) cameraAdjustEndFrame = EditorApplication.timeSinceStartup + skeletonAnimation.AnimationState.GetCurrent(0).Alpha;
AdjustCameraGoals();
} catch {
DestroyPreviewGameObject();
RefreshOnNextUpdate();
}
RefreshOnNextUpdate();
}
}
@@ -932,10 +889,12 @@ namespace Spine.Unity.Editor {
if (!EditorApplication.isPlaying) {
#if !SPINE_UNITY_2018_PREVIEW_API
float current = CurrentTime;
float deltaTime = (current - animationLastTime);
skeletonAnimation.Update(deltaTime);
animationLastTime = current;
#endif
skeletonAnimation.LateUpdate();
}
@@ -1158,7 +1117,7 @@ namespace Spine.Unity.Editor {
float lineRectWidth = lineRect.width;
TrackEntry t = skeletonAnimation.AnimationState.GetCurrent(0);
if (t != null && Icons.userEvent != null) { // when changing to play mode, Icons.userEvent will not be reset
if (t != null) {
int loopCount = (int)(t.TrackTime / t.TrackEnd);
float currentTime = t.TrackTime - (t.TrackEnd * loopCount);
float normalizedTime = currentTime / t.Animation.Duration;
@@ -1176,15 +1135,14 @@ namespace Spine.Unity.Editor {
for (int i = 0; i < currentAnimationEvents.Count; i++) {
float eventTime = currentAnimationEventTimes[i];
var userEventIcon = Icons.userEvent;
float iconX = Mathf.Max(((eventTime / t.Animation.Duration) * lineRectWidth) - (userEventIcon.width / 2), barRect.x);
float iconY = barRect.y + userEventIcon.height;
var evRect = new Rect(barRect) {
x = iconX,
y = iconY,
x = Mathf.Max(((eventTime / t.Animation.Duration) * lineRectWidth) - (userEventIcon.width / 2), barRect.x),
y = barRect.y + userEventIcon.height,
width = userEventIcon.width,
height = userEventIcon.height
};
GUI.DrawTexture(evRect, userEventIcon);
Event ev = Event.current;
if (ev.type == EventType.Repaint) {
if (evRect.Contains(ev.mousePosition)) {
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
// With contributions from: Mitch Thompson
@@ -84,7 +84,7 @@ namespace Spine.Unity.Editor {
[SpineBone(dataField:"skeletonRenderer")]
public string boneName;
readonly Dictionary<Slot, List<Skin.SkinEntry>> attachmentTable = new Dictionary<Slot, List<Skin.SkinEntry>>();
readonly Dictionary<Slot, List<Attachment>> attachmentTable = new Dictionary<Slot, List<Attachment>>();
static bool staticLostValues = true;
@@ -194,7 +194,7 @@ namespace Spine.Unity.Editor {
EditorGUILayout.Space();
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(SpineInspectorUtility.TempContent("Debug Selection", Icons.spine), skeletonRenderer, typeof(SkeletonRenderer), true);
EditorGUILayout.ObjectField(SpineInspectorUtility.TempContent("Debug Selection", Icons.spine), skeletonRenderer, typeof(SkeletonRenderer), true);
EditorGUI.EndDisabledGroup();
if (skeleton == null || skeletonRenderer == null) {
@@ -338,7 +338,7 @@ namespace Spine.Unity.Editor {
}
int baseIndent = EditorGUI.indentLevel;
foreach (KeyValuePair<Slot, List<Skin.SkinEntry>> pair in attachmentTable) {
foreach (KeyValuePair<Slot, List<Attachment>> pair in attachmentTable) {
Slot slot = pair.Key;
using (new EditorGUILayout.HorizontalScope()) {
@@ -352,8 +352,7 @@ namespace Spine.Unity.Editor {
}
}
foreach (var skinEntry in pair.Value) {
var attachment = skinEntry.Attachment;
foreach (var attachment in pair.Value) {
GUI.contentColor = slot.Attachment == attachment ? Color.white : Color.grey;
EditorGUI.indentLevel = baseIndent + 2;
var icon = Icons.GetAttachmentIcon(attachment);
@@ -482,10 +481,7 @@ namespace Spine.Unity.Editor {
if (Application.isPlaying) {
foreach (var slot in skeleton.DrawOrder) {
if (skeletonRenderer.separatorSlots.Contains(slot)) EditorGUILayout.LabelField(SeparatorString);
using (new EditorGUI.DisabledScope(!slot.Bone.Active)) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
} else {
foreach (var slot in skeleton.DrawOrder) {
@@ -496,9 +492,7 @@ namespace Spine.Unity.Editor {
break;
}
}
using (new EditorGUI.DisabledScope(!slot.Bone.Active)) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
}
@@ -578,12 +572,10 @@ namespace Spine.Unity.Editor {
attachmentTable.Clear();
for (int i = skeleton.Slots.Count - 1; i >= 0; i--) {
var attachments = new List<Skin.SkinEntry>();
var attachments = new List<Attachment>();
attachmentTable.Add(skeleton.Slots.Items[i], attachments);
// Add skin attachments.
skin.GetAttachments(i, attachments);
if (notDefaultSkin && defaultSkin != null) // Add default skin attachments.
defaultSkin.GetAttachments(i, attachments);
skin.FindAttachmentsForSlot(i, attachments); // Add skin attachments.
if (notDefaultSkin) defaultSkin.FindAttachmentsForSlot(i, attachments); // Add default skin attachments.
}
activeSkin = skeleton.Skin;
@@ -0,0 +1,50 @@
/******************************************************************************
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
using UnityEditor;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonMecanim))]
[CanEditMultipleObjects]
public class SkeletonMecanimInspector : SkeletonRendererInspector {
protected SerializedProperty mecanimTranslator;
protected override void OnEnable () {
base.OnEnable();
mecanimTranslator = serializedObject.FindProperty("translator");
}
protected override void DrawInspectorGUI (bool multi) {
base.DrawInspectorGUI(multi);
EditorGUILayout.PropertyField(mecanimTranslator, true);
}
}
}
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
@@ -33,10 +33,6 @@
#define NO_PREFAB_MESH
#endif
#if UNITY_2018_1_OR_NEWER
#define PER_MATERIAL_PROPERTY_BLOCKS
#endif
#if UNITY_2017_1_OR_NEWER
#define BUILT_IN_SPRITE_MASK_COMPONENT
#endif
@@ -59,7 +55,7 @@ namespace Spine.Unity.Editor {
protected SerializedProperty skeletonDataAsset, initialSkinName;
protected SerializedProperty initialFlipX, initialFlipY;
protected SerializedProperty updateWhenInvisible, singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles, fixDrawOrder;
protected SerializedProperty singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles;
protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings
protected SerializedProperty maskInteraction;
protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside;
@@ -74,7 +70,7 @@ namespace Spine.Unity.Editor {
protected bool deleteOutsideMaskMaterialsQueued = false;
protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, UpdateWhenInvisibleLabel, SingleSubmeshLabel, FixDrawOrderLabel;
protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, SingleSubmeshLabel;
protected GUIContent NormalsLabel, TangentsLabel, MaskInteractionLabel;
protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel;
protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel;
@@ -82,7 +78,7 @@ namespace Spine.Unity.Editor {
const string ReloadButtonString = "Reload";
static GUILayoutOption reloadButtonWidth;
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButtonRight; } }
protected bool TargetIsValid {
get {
@@ -106,6 +102,7 @@ namespace Spine.Unity.Editor {
#else
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#endif
SpineEditorUtilities.ConfirmInitialization();
// Labels
@@ -119,8 +116,6 @@ 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.");
MaskMaterialsNoneLabel = new GUIContent("Normal Materials", "Normal materials used when Mask Interaction is set to None.");
@@ -128,7 +123,7 @@ namespace Spine.Unity.Editor {
MaskMaterialsOutsideLabel = new GUIContent("Outside Mask", "Materials used when Mask Interaction is set to Outside Mask.");
SetMaterialButtonLabel = new GUIContent("Set", "Prepares material references for switching to the corresponding Mask Interaction mode at runtime. Creates the required materials if they do not exist.");
ClearMaterialButtonLabel = new GUIContent("Clear", "Clears unused material references. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly.");
DeleteMaterialButtonLabel = new GUIContent("Delete", "Clears unused material references and deletes the corresponding assets. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly.");
DeleteMaterialButtonLabel = new GUIContent("Delete", "Clears unused material references and deletes the corresponding assets. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly.");
var so = this.serializedObject;
skeletonDataAsset = so.FindProperty("skeletonDataAsset");
@@ -141,9 +136,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");
maskMaterialsNone = so.FindProperty("maskMaterials.materialsMaskDisabled");
maskMaterialsInside = so.FindProperty("maskMaterials.materialsInsideMask");
@@ -170,12 +163,29 @@ namespace Spine.Unity.Editor {
override public void OnInspectorGUI () {
bool multi = serializedObject.isEditingMultipleObjects;
DrawInspectorGUI(multi);
HandleSkinChange();
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current) ||
AreAnyMaskMaterialsMissing()) {
if (!Application.isPlaying) {
if (multi) {
foreach (var o in targets) EditorForceInitializeComponent((SkeletonRenderer)o);
} else {
EditorForceInitializeComponent((SkeletonRenderer)target);
}
SceneView.RepaintAll();
}
}
if (!Application.isPlaying && Event.current.type == EventType.Layout) {
bool mismatchDetected = false;
if (multi) {
foreach (var o in targets)
SpineEditorUtilities.ReinitializeComponent((SkeletonRenderer)o);
mismatchDetected |= UpdateIfSkinMismatch((SkeletonRenderer)o);
} else {
mismatchDetected |= UpdateIfSkinMismatch(target as SkeletonRenderer);
}
if (mismatchDetected) {
mismatchDetected = false;
SceneView.RepaintAll();
}
}
@@ -186,16 +196,25 @@ namespace Spine.Unity.Editor {
if (Event.current.type == EventType.Layout) {
if (forceReloadQueued) {
forceReloadQueued = false;
foreach (var c in targets) {
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer);
if (multi) {
foreach (var c in targets)
EditorForceReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer);
} else {
EditorForceReloadSkeletonDataAssetAndComponent(target as SkeletonRenderer);
}
} else {
foreach (var c in targets) {
var component = c as SkeletonRenderer;
if (!component.valid) {
SpineEditorUtilities.ReinitializeComponent(component);
if (!component.valid) continue;
if (multi) {
foreach (var c in targets) {
var component = c as SkeletonRenderer;
if (!component.valid) {
EditorForceInitializeComponent(component);
if (!component.valid) continue;
}
}
} else {
var component = (SkeletonRenderer)target;
if (!component.valid)
EditorForceInitializeComponent(component);
}
}
@@ -230,8 +249,15 @@ namespace Spine.Unity.Editor {
#if NO_PREFAB_MESH
if (isInspectingPrefab) {
foreach (var c in targets) {
var component = (SkeletonRenderer)c;
if (multi) {
foreach (var c in targets) {
var component = (SkeletonRenderer)c;
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
meshFilter.sharedMesh = null;
}
} else {
var component = (SkeletonRenderer)target;
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
meshFilter.sharedMesh = null;
@@ -268,7 +294,7 @@ namespace Spine.Unity.Editor {
return;
}
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.skeletonDataAsset)) {
if (!SkeletonDataAssetIsValid(component.skeletonDataAsset)) {
EditorGUILayout.HelpBox("Skeleton Data Asset error. Please check Skeleton Data Asset.", MessageType.Error);
return;
}
@@ -288,12 +314,6 @@ namespace Spine.Unity.Editor {
if (!valid)
return;
string errorMessage = null;
if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic((SkeletonRenderer)this.target, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
}
// More Render Options...
using (new SpineInspectorUtility.BoxScope()) {
EditorGUI.BeginChangeCheck();
@@ -322,12 +342,7 @@ 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);
#endif
if (immutableTriangles != null) EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
EditorGUILayout.Space();
@@ -399,48 +414,6 @@ namespace Spine.Unity.Editor {
}
}
protected void SkeletonRootMotionParameter() {
SkeletonRootMotionParameter(targets);
}
public static void SkeletonRootMotionParameter(Object[] targets) {
int rootMotionComponentCount = 0;
foreach (var t in targets) {
var component = t as Component;
if (component.GetComponent<SkeletonRootMotion>() != null) {
++rootMotionComponentCount;
}
}
bool allHaveRootMotion = rootMotionComponentCount == targets.Length;
bool anyHaveRootMotion = rootMotionComponentCount > 0;
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Root Motion");
if (!allHaveRootMotion) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Component", Icons.constraintTransform), GUILayout.MaxWidth(130), GUILayout.Height(18))) {
foreach (var t in targets) {
var component = t as Component;
if (component.GetComponent<SkeletonRootMotion>() == null) {
component.gameObject.AddComponent<SkeletonRootMotion>();
}
}
}
}
if (anyHaveRootMotion) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Remove Component", Icons.constraintTransform), GUILayout.MaxWidth(140), GUILayout.Height(18))) {
foreach (var t in targets) {
var component = t as Component;
var rootMotionComponent = component.GetComponent<SkeletonRootMotion>();
if (rootMotionComponent != null) {
DestroyImmediate(rootMotionComponent);
}
}
}
}
}
}
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
field.SetValue(skeletonRenderer, newSlotNames);
@@ -520,48 +493,57 @@ namespace Spine.Unity.Editor {
}
}
void HandleSkinChange() {
if (!Application.isPlaying && Event.current.type == EventType.Layout && !initialSkinName.hasMultipleDifferentValues) {
bool mismatchDetected = false;
string newSkinName = initialSkinName.stringValue;
foreach (var o in targets) {
mismatchDetected |= UpdateIfSkinMismatch((SkeletonRenderer)o, newSkinName);
}
if (mismatchDetected) {
mismatchDetected = false;
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
}
}
static bool UpdateIfSkinMismatch (SkeletonRenderer skeletonRenderer, string componentSkinName) {
if (!skeletonRenderer.valid || skeletonRenderer.EditorSkipSkinSync) return false;
static bool UpdateIfSkinMismatch (SkeletonRenderer skeletonRenderer) {
if (!skeletonRenderer.valid) return false;
var skin = skeletonRenderer.Skeleton.Skin;
string skeletonSkinName = skin != null ? skin.Name : null;
string componentSkinName = skeletonRenderer.initialSkinName;
bool defaultCase = skin == null && string.IsNullOrEmpty(componentSkinName);
bool fieldMatchesSkin = defaultCase || string.Equals(componentSkinName, skeletonSkinName, System.StringComparison.Ordinal);
if (!fieldMatchesSkin) {
Skin skinToSet = string.IsNullOrEmpty(componentSkinName) ? null : skeletonRenderer.Skeleton.Data.FindSkin(componentSkinName);
skeletonRenderer.Skeleton.SetSkin(skinToSet);
skeletonRenderer.Skeleton.Skin = skinToSet;
skeletonRenderer.Skeleton.SetSlotsToSetupPose();
// Note: the UpdateIfSkinMismatch concept shall be replaced with e.g. an OnValidate based
// solution or in a separate commit. The current solution does not repaint the Game view because
// it is first applying values and in the next editor pass is calling this skin-changing method.
if (skeletonRenderer is SkeletonAnimation)
((SkeletonAnimation) skeletonRenderer).Update(0f);
else if (skeletonRenderer is SkeletonMecanim)
((SkeletonMecanim) skeletonRenderer).Update();
skeletonRenderer.LateUpdate();
return true;
}
return false;
}
static void EditorForceReloadSkeletonDataAssetAndComponent (SkeletonRenderer component) {
if (component == null) return;
// Clear all and reload.
if (component.skeletonDataAsset != null) {
foreach (AtlasAssetBase aa in component.skeletonDataAsset.atlasAssets) {
if (aa != null) aa.Clear();
}
component.skeletonDataAsset.Clear();
}
component.skeletonDataAsset.GetSkeletonData(true);
// Reinitialize.
EditorForceInitializeComponent(component);
}
static void EditorForceInitializeComponent (SkeletonRenderer component) {
if (component == null) return;
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
component.Initialize(true);
#if BUILT_IN_SPRITE_MASK_COMPONENT
SpineMaskUtilities.EditorAssignSpriteMaskMaterials(component);
#endif
component.LateUpdate();
}
static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) {
return asset != null && asset.GetSkeletonData(quiet: true) != null;
}
bool AreAnyMaskMaterialsMissing() {
#if BUILT_IN_SPRITE_MASK_COMPONENT
foreach (var o in targets) {
@@ -579,13 +561,13 @@ namespace Spine.Unity.Editor {
static void EditorSetMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType)
{
if (component == null) return;
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType);
}
static void EditorDeleteMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) {
if (component == null) return;
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType);
}
#endif
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
//#define BAKE_ALL_BUTTON
@@ -92,7 +92,7 @@ namespace Spine.Unity.Editor {
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
for (int i = 0; i < regions.Count; i++) {
AtlasRegion region = regions[i];
string bakedPrefabPath = Path.Combine(bakedDirPath, AssetUtility.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/");
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.AssetUtility.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/");
GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject));
baked.Add(prefab != null);
bakedObjects.Add(prefab);
@@ -108,7 +108,7 @@ namespace Spine.Unity.Editor {
}
serializedObject.Update();
atlasAsset = (atlasAsset == null) ? (SpineAtlasAsset)target : atlasAsset;
atlasAsset = atlasAsset ?? (SpineAtlasAsset)target;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);
@@ -133,15 +133,12 @@ namespace Spine.Unity.Editor {
}
EditorGUILayout.Space();
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpinePreferences.DEFAULT_MIPMAPBIAS, tooltip: "This may help textures with mipmaps be less blurry when used for 2D sprites."))) {
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS, tooltip: "This may help textures with mipmaps be less blurry when used for 2D sprites."))) {
foreach (var m in atlasAsset.materials) {
var texture = m.mainTexture;
string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID());
var importer = (TextureImporter)TextureImporter.GetAtPath(texturePath);
importer.mipMapBias = SpinePreferences.DEFAULT_MIPMAPBIAS;
EditorUtility.SetDirty(texture);
texture.mipMapBias = SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS;
}
Debug.Log("Texture mipmap bias set to " + SpinePreferences.DEFAULT_MIPMAPBIAS);
Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS);
}
EditorGUILayout.Space();
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
@@ -35,7 +35,6 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using Spine;
using System.Linq;
namespace Spine.Unity.Editor {
public struct SpineDrawerValuePair {
@@ -178,21 +177,19 @@ namespace Spine.Unity.Editor {
if (TargetAttribute.includeNone)
menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
IEnumerable<SlotData> orderedSlots = data.Slots.Items.OrderBy(slotData => slotData.Name);
foreach (SlotData slotData in orderedSlots) {
int slotIndex = slotData.Index;
string name = slotData.Name;
for (int i = 0; i < data.Slots.Count; i++) {
string name = data.Slots.Items[i].Name;
if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) {
if (targetAttribute.containsBoundingBoxes) {
var skinEntries = new List<Skin.SkinEntry>();
foreach (var skin in data.Skins) {
skin.GetAttachments(slotIndex, skinEntries);
}
int slotIndex = i;
var attachments = new List<Attachment>();
foreach (var skin in data.Skins)
skin.FindAttachmentsForSlot(slotIndex, attachments);
bool hasBoundingBox = false;
foreach (var entry in skinEntries) {
var bbAttachment = entry.Attachment as BoundingBoxAttachment;
foreach (var attachment in attachments) {
var bbAttachment = attachment as BoundingBoxAttachment;
if (bbAttachment != null) {
string menuLabel = bbAttachment.IsWeighted() ? name + " (!)" : name;
menu.AddItem(new GUIContent(menuLabel), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
@@ -473,21 +470,10 @@ namespace Spine.Unity.Editor {
attachmentNames.Clear();
placeholderNames.Clear();
var skinEntries = new List<Skin.SkinEntry>();
skin.GetAttachments(i, skinEntries);
foreach (var entry in skinEntries) {
attachmentNames.Add(entry.Name);
}
skin.FindNamesForSlot(i, attachmentNames);
if (skin != defaultSkin) {
foreach (var entry in skinEntries) {
placeholderNames.Add(entry.Name);
}
skinEntries.Clear();
defaultSkin.GetAttachments(i, skinEntries);
foreach (var entry in skinEntries) {
attachmentNames.Add(entry.Name);
}
defaultSkin.FindNamesForSlot(i, attachmentNames);
skin.FindNamesForSlot(i, placeholderNames);
}
for (int a = 0; a < attachmentNames.Count; a++) {
@@ -524,17 +510,9 @@ 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++) {
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));
}
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));
}
}
File diff suppressed because it is too large Load Diff
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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;
@@ -220,12 +220,13 @@ namespace Spine.Unity.Editor {
#region Button
const float CenterButtonMaxWidth = 270f;
const float CenterButtonHeight = 30f;
const float CenterButtonHeight = 35f;
static GUIStyle spineButtonStyle;
static GUIStyle SpineButtonStyle {
get {
if (spineButtonStyle == null) {
spineButtonStyle = new GUIStyle(GUI.skin.button);
spineButtonStyle.name = "Spine Button";
spineButtonStyle.padding = new RectOffset(10, 10, 10, 10);
}
return spineButtonStyle;
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#pragma warning disable 0219
File diff suppressed because it is too large Load Diff
@@ -1,282 +0,0 @@
/******************************************************************************
* 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_2020_1_OR_NEWER
#define UPGRADE_ALL_BLEND_MODE_MATERIALS
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System;
namespace Spine.Unity.Editor {
public class BlendModeMaterialsUtility {
public const string MATERIAL_SUFFIX_MULTIPLY = "-Multiply";
public const string MATERIAL_SUFFIX_SCREEN = "-Screen";
public const string MATERIAL_SUFFIX_ADDITIVE = "-Additive";
#if UPGRADE_ALL_BLEND_MODE_MATERIALS
public const bool ShallUpgradeBlendModeMaterials = true;
#else
public const bool ShallUpgradeBlendModeMaterials = false;
#endif
protected class TemplateMaterials {
public Material multiplyTemplate;
public Material screenTemplate;
public Material additiveTemplate;
};
public static void UpgradeBlendModeMaterials (SkeletonDataAsset skeletonDataAsset) {
var skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (skeletonData == null)
return;
UpdateBlendModeMaterials(skeletonDataAsset, ref skeletonData, true);
}
public static void UpdateBlendModeMaterials (SkeletonDataAsset skeletonDataAsset) {
var skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (skeletonData == null)
return;
UpdateBlendModeMaterials(skeletonDataAsset, ref skeletonData, false);
}
public static void UpdateBlendModeMaterials (SkeletonDataAsset skeletonDataAsset, ref SkeletonData skeletonData,
bool upgradeFromModifierAssets = ShallUpgradeBlendModeMaterials) {
TemplateMaterials templateMaterials = new TemplateMaterials();
bool anyMaterialsChanged = ClearUndesiredMaterialEntries(skeletonDataAsset);
var blendModesModifierAsset = FindBlendModeMaterialsModifierAsset(skeletonDataAsset);
if (blendModesModifierAsset) {
if (upgradeFromModifierAssets) {
TransferSettingsFromModifierAsset(blendModesModifierAsset,
skeletonDataAsset, templateMaterials);
UpdateBlendmodeMaterialsRequiredState(skeletonDataAsset, skeletonData);
}
else
return;
}
else {
if (!UpdateBlendmodeMaterialsRequiredState(skeletonDataAsset, skeletonData))
return;
AssignPreferencesTemplateMaterials(templateMaterials);
}
bool success = CreateAndAssignMaterials(skeletonDataAsset, templateMaterials, ref anyMaterialsChanged);
if (success) {
if (blendModesModifierAsset != null) {
RemoveObsoleteModifierAsset(blendModesModifierAsset, skeletonDataAsset);
}
}
skeletonDataAsset.Clear();
skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (anyMaterialsChanged)
ReloadSceneSkeletons(skeletonDataAsset);
AssetDatabase.SaveAssets();
}
protected static bool ClearUndesiredMaterialEntries (SkeletonDataAsset skeletonDataAsset) {
Predicate<BlendModeMaterials.ReplacementMaterial> ifMaterialMissing = r => r.material == null;
bool anyMaterialsChanged = false;
if (!skeletonDataAsset.blendModeMaterials.applyAdditiveMaterial) {
anyMaterialsChanged |= skeletonDataAsset.blendModeMaterials.additiveMaterials.Count > 0;
skeletonDataAsset.blendModeMaterials.additiveMaterials.Clear();
}
else
anyMaterialsChanged |= skeletonDataAsset.blendModeMaterials.additiveMaterials.RemoveAll(ifMaterialMissing) != 0;
anyMaterialsChanged |= skeletonDataAsset.blendModeMaterials.multiplyMaterials.RemoveAll(ifMaterialMissing) != 0;
anyMaterialsChanged |= skeletonDataAsset.blendModeMaterials.screenMaterials.RemoveAll(ifMaterialMissing) != 0;
return anyMaterialsChanged;
}
protected static BlendModeMaterialsAsset FindBlendModeMaterialsModifierAsset (SkeletonDataAsset skeletonDataAsset) {
foreach (var modifierAsset in skeletonDataAsset.skeletonDataModifiers) {
if (modifierAsset is BlendModeMaterialsAsset)
return (BlendModeMaterialsAsset)modifierAsset;
}
return null;
}
protected static bool UpdateBlendmodeMaterialsRequiredState (SkeletonDataAsset skeletonDataAsset, SkeletonData skeletonData) {
return skeletonDataAsset.blendModeMaterials.UpdateBlendmodeMaterialsRequiredState(skeletonData);
}
protected static void TransferSettingsFromModifierAsset (BlendModeMaterialsAsset modifierAsset,
SkeletonDataAsset skeletonDataAsset, TemplateMaterials templateMaterials) {
skeletonDataAsset.blendModeMaterials.TransferSettingsFrom(modifierAsset);
templateMaterials.multiplyTemplate = modifierAsset.multiplyMaterialTemplate;
templateMaterials.screenTemplate = modifierAsset.screenMaterialTemplate;
templateMaterials.additiveTemplate = modifierAsset.additiveMaterialTemplate;
}
protected static void RemoveObsoleteModifierAsset (BlendModeMaterialsAsset modifierAsset,
SkeletonDataAsset skeletonDataAsset) {
skeletonDataAsset.skeletonDataModifiers.Remove(modifierAsset);
Debug.Log(string.Format("BlendModeMaterialsAsset upgraded to built-in BlendModeMaterials at SkeletonDataAsset '{0}'.",
skeletonDataAsset.name), skeletonDataAsset);
EditorUtility.SetDirty(skeletonDataAsset);
}
protected static void AssignPreferencesTemplateMaterials (TemplateMaterials templateMaterials) {
templateMaterials.multiplyTemplate = SpineEditorUtilities.Preferences.BlendModeMaterialMultiply;
templateMaterials.screenTemplate = SpineEditorUtilities.Preferences.BlendModeMaterialScreen;
templateMaterials.additiveTemplate = SpineEditorUtilities.Preferences.BlendModeMaterialAdditive;
}
protected static bool CreateAndAssignMaterials (SkeletonDataAsset skeletonDataAsset,
TemplateMaterials templateMaterials, ref bool anyReplacementMaterialsChanged) {
bool anyCreationFailed = false;
var blendModeMaterials = skeletonDataAsset.blendModeMaterials;
bool applyAdditiveMaterial = blendModeMaterials.applyAdditiveMaterial;
var skinEntries = new List<Skin.SkinEntry>();
skeletonDataAsset.Clear();
skeletonDataAsset.isUpgradingBlendModeMaterials = true;
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
var slotsItems = skeletonData.Slots.Items;
for (int slotIndex = 0, slotCount = skeletonData.Slots.Count; slotIndex < slotCount; slotIndex++) {
var slot = slotsItems[slotIndex];
if (slot.BlendMode == BlendMode.Normal) continue;
if (!applyAdditiveMaterial && slot.BlendMode == BlendMode.Additive) continue;
List<BlendModeMaterials.ReplacementMaterial> replacementMaterials = null;
Material materialTemplate = null;
string materialSuffix = null;
switch (slot.BlendMode) {
case BlendMode.Multiply:
replacementMaterials = blendModeMaterials.multiplyMaterials;
materialTemplate = templateMaterials.multiplyTemplate;
materialSuffix = MATERIAL_SUFFIX_MULTIPLY;
break;
case BlendMode.Screen:
replacementMaterials = blendModeMaterials.screenMaterials;
materialTemplate = templateMaterials.screenTemplate;
materialSuffix = MATERIAL_SUFFIX_SCREEN;
break;
case BlendMode.Additive:
replacementMaterials = blendModeMaterials.additiveMaterials;
materialTemplate = templateMaterials.additiveTemplate;
materialSuffix = MATERIAL_SUFFIX_ADDITIVE;
break;
}
skinEntries.Clear();
foreach (var skin in skeletonData.Skins)
skin.GetAttachments(slotIndex, skinEntries);
foreach (var entry in skinEntries) {
var renderableAttachment = entry.Attachment as IHasRendererObject;
if (renderableAttachment != null) {
var originalRegion = (AtlasRegion)renderableAttachment.RendererObject;
bool replacementExists = replacementMaterials.Exists(
replacement => replacement.pageName == originalRegion.page.name);
if (!replacementExists) {
bool createdNewMaterial;
var replacement = CreateOrLoadReplacementMaterial(originalRegion, materialTemplate, materialSuffix, out createdNewMaterial);
if (replacement != null) {
replacementMaterials.Add(replacement);
anyReplacementMaterialsChanged = true;
if (createdNewMaterial) {
Debug.Log(string.Format("Created blend mode Material '{0}' for SkeletonDataAsset '{1}'.",
replacement.material.name, skeletonDataAsset), replacement.material);
}
}
else {
Debug.LogError(string.Format("Failed creating blend mode Material for SkeletonDataAsset '{0}',"+
" atlas page '{1}', template '{2}'.",
skeletonDataAsset.name, originalRegion.page.name, materialTemplate.name),
skeletonDataAsset);
anyCreationFailed = true;
}
}
}
}
}
skeletonDataAsset.isUpgradingBlendModeMaterials = false;
EditorUtility.SetDirty(skeletonDataAsset);
return !anyCreationFailed;
}
protected static string GetBlendModeMaterialPath(AtlasPage originalPage, string materialSuffix) {
var originalMaterial = originalPage.rendererObject as Material;
var originalPath = AssetDatabase.GetAssetPath(originalMaterial);
return originalPath.Replace(".mat", materialSuffix + ".mat");
}
protected static BlendModeMaterials.ReplacementMaterial CreateOrLoadReplacementMaterial (
AtlasRegion originalRegion, Material materialTemplate, string materialSuffix, out bool createdNewMaterial) {
createdNewMaterial = false;
var newReplacement = new BlendModeMaterials.ReplacementMaterial();
var originalPage = originalRegion.page;
var originalMaterial = originalPage.rendererObject as Material;
var blendMaterialPath = GetBlendModeMaterialPath(originalPage, materialSuffix);
newReplacement.pageName = originalPage.name;
if (File.Exists(blendMaterialPath)) {
newReplacement.material = AssetDatabase.LoadAssetAtPath<Material>(blendMaterialPath);
}
else {
var blendModeMaterial = new Material(materialTemplate) {
name = originalMaterial.name + " " + materialTemplate.name,
mainTexture = originalMaterial.mainTexture
};
newReplacement.material = blendModeMaterial;
AssetDatabase.CreateAsset(blendModeMaterial, blendMaterialPath);
EditorUtility.SetDirty(blendModeMaterial);
createdNewMaterial = true;
}
if (newReplacement.material)
return newReplacement;
else
return null;
}
protected static void ReloadSceneSkeletons (SkeletonDataAsset skeletonDataAsset) {
if (SpineEditorUtilities.Preferences.autoReloadSceneSkeletons)
SpineEditorUtilities.DataReloadHandler.ReloadSceneSkeletonComponents(skeletonDataAsset);
}
}
}
@@ -1,182 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2018 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEWHIERARCHYWINDOWCALLBACKS
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
public partial class SpineEditorUtilities {
public static class SpineTK2DEditorUtility {
const string SPINE_TK2D_DEFINE = "SPINE_TK2D";
internal static bool IsTK2DInstalled () {
return (Shader.Find("tk2d/SolidVertexColor") != null ||
Shader.Find("tk2d/AdditiveVertexColor") != null);
}
internal static bool IsTK2DAllowed {
get {
return false; // replace with "return true;" to allow TK2D support
}
}
internal static void EnableTK2D () {
if (!IsTK2DAllowed)
return;
SpineBuildEnvUtility.DisableSpineAsmdefFiles();
SpineBuildEnvUtility.EnableBuildDefine(SPINE_TK2D_DEFINE);
}
internal static void DisableTK2D () {
SpineBuildEnvUtility.EnableSpineAsmdefFiles();
SpineBuildEnvUtility.DisableBuildDefine(SPINE_TK2D_DEFINE);
}
}
}
public static class SpineBuildEnvUtility
{
static bool IsInvalidGroup (BuildTargetGroup group) {
int gi = (int)group;
return
gi == 15 || gi == 16
||
group == BuildTargetGroup.Unknown;
}
public static bool EnableBuildDefine (string define) {
bool wasDefineAdded = false;
Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" below");
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
if (IsInvalidGroup(group))
continue;
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
if (!defines.Contains(define)) {
wasDefineAdded = true;
if (defines.EndsWith(";", System.StringComparison.Ordinal))
defines += define;
else
defines += ";" + define;
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
}
}
Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" above");
if (wasDefineAdded) {
Debug.LogWarning("Setting Scripting Define Symbol " + define);
}
else {
Debug.LogWarning("Already Set Scripting Define Symbol " + define);
}
return wasDefineAdded;
}
public static bool DisableBuildDefine (string define) {
bool wasDefineRemoved = false;
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
if (IsInvalidGroup(group))
continue;
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
if (defines.Contains(define)) {
wasDefineRemoved = true;
if (defines.Contains(define + ";"))
defines = defines.Replace(define + ";", "");
else
defines = defines.Replace(define, "");
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
}
}
if (wasDefineRemoved) {
Debug.LogWarning("Removing Scripting Define Symbol " + define);
}
else {
Debug.LogWarning("Already Removed Scripting Define Symbol " + define);
}
return wasDefineRemoved;
}
public static void DisableSpineAsmdefFiles () {
SetAsmdefFileActive("spine-unity-editor", false);
SetAsmdefFileActive("spine-unity", false);
}
public static void EnableSpineAsmdefFiles () {
SetAsmdefFileActive("spine-unity-editor", true);
SetAsmdefFileActive("spine-unity", true);
}
internal static void SetAsmdefFileActive (string filename, bool setActive) {
string typeSearchString = setActive ? " t:TextAsset" : " t:AssemblyDefinitionAsset";
string extensionBeforeChange = setActive ? ".txt" : ".asmdef";
string[] guids = AssetDatabase.FindAssets(filename + typeSearchString);
foreach (string guid in guids) {
string currentPath = AssetDatabase.GUIDToAssetPath(guid);
if (System.IO.Path.GetExtension(currentPath) != extensionBeforeChange) // asmdef is also found as t:TextAsset, so check
continue;
string targetPath = System.IO.Path.ChangeExtension(currentPath, setActive ? "asmdef" : "txt");
if (System.IO.File.Exists(currentPath) && !System.IO.File.Exists(targetPath)) {
System.IO.File.Copy(currentPath, targetPath);
System.IO.File.Copy(currentPath + ".meta", targetPath + ".meta");
}
AssetDatabase.DeleteAsset(currentPath);
}
}
}
}
@@ -1,145 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
public partial class SpineEditorUtilities {
public static class DataReloadHandler {
internal static Dictionary<int, string> savedSkeletonDataAssetAtSKeletonGraphicID = new Dictionary<int, string>();
#if NEWPLAYMODECALLBACKS
internal static void OnPlaymodeStateChanged (PlayModeStateChange stateChange) {
#else
internal static void OnPlaymodeStateChanged () {
#endif
ReloadAllActiveSkeletonsEditMode();
}
public static void ReloadAllActiveSkeletonsEditMode () {
if (EditorApplication.isPaused) return;
if (EditorApplication.isPlaying) return;
if (EditorApplication.isCompiling) return;
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
var skeletonDataAssetsToReload = new HashSet<SkeletonDataAsset>();
var activeSkeletonRenderers = GameObject.FindObjectsOfType<SkeletonRenderer>();
foreach (var sr in activeSkeletonRenderers) {
var skeletonDataAsset = sr.skeletonDataAsset;
if (skeletonDataAsset != null) skeletonDataAssetsToReload.Add(skeletonDataAsset);
}
// Under some circumstances (e.g. on first import) SkeletonGraphic objects
// have their skeletonGraphic.skeletonDataAsset reference corrupted
// by the instance of the ScriptableObject being destroyed but still assigned.
// Here we save the skeletonGraphic.skeletonDataAsset asset path in order
// to restore it later.
var activeSkeletonGraphics = GameObject.FindObjectsOfType<SkeletonGraphic>();
foreach (var sg in activeSkeletonGraphics) {
var skeletonDataAsset = sg.skeletonDataAsset;
if (skeletonDataAsset != null) {
var assetPath = AssetDatabase.GetAssetPath(skeletonDataAsset);
var sgID = sg.GetInstanceID();
savedSkeletonDataAssetAtSKeletonGraphicID[sgID] = assetPath;
skeletonDataAssetsToReload.Add(skeletonDataAsset);
}
}
foreach (var sda in skeletonDataAssetsToReload) {
sda.Clear();
sda.GetSkeletonData(true);
}
foreach (var sr in activeSkeletonRenderers) {
var meshRenderer = sr.GetComponent<MeshRenderer>();
var sharedMaterials = meshRenderer.sharedMaterials;
foreach (var m in sharedMaterials) {
if (m == null) {
sr.Initialize(true);
break;
}
}
}
foreach (var sg in activeSkeletonGraphics) {
if (sg.mainTexture == null)
sg.Initialize(true);
}
}
public static void ReloadSceneSkeletonComponents (SkeletonDataAsset skeletonDataAsset) {
if (EditorApplication.isPaused) return;
if (EditorApplication.isPlaying) return;
if (EditorApplication.isCompiling) return;
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
var activeSkeletonRenderers = GameObject.FindObjectsOfType<SkeletonRenderer>();
foreach (var sr in activeSkeletonRenderers) {
if (sr.isActiveAndEnabled && sr.skeletonDataAsset == skeletonDataAsset) sr.Initialize(true);
}
var activeSkeletonGraphics = GameObject.FindObjectsOfType<SkeletonGraphic>();
foreach (var sg in activeSkeletonGraphics) {
if (sg.isActiveAndEnabled && sg.skeletonDataAsset == skeletonDataAsset) sg.Initialize(true);
}
}
public static void ReloadAnimationReferenceAssets (SkeletonDataAsset skeletonDataAsset) {
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:AnimationReferenceAsset");
foreach (string guid in guids) {
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
if (!string.IsNullOrEmpty(path)) {
var referenceAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<AnimationReferenceAsset>(path);
if (referenceAsset.SkeletonDataAsset == skeletonDataAsset)
referenceAsset.Initialize();
}
}
}
}
}
}
@@ -1,147 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
public partial class SpineEditorUtilities {
public static class Icons {
public static Texture2D skeleton;
public static Texture2D nullBone;
public static Texture2D bone;
public static Texture2D poseBones;
public static Texture2D boneNib;
public static Texture2D slot;
public static Texture2D slotRoot;
public static Texture2D skinPlaceholder;
public static Texture2D image;
public static Texture2D genericAttachment;
public static Texture2D boundingBox;
public static Texture2D point;
public static Texture2D mesh;
public static Texture2D weights;
public static Texture2D path;
public static Texture2D clipping;
public static Texture2D skin;
public static Texture2D skinsRoot;
public static Texture2D animation;
public static Texture2D animationRoot;
public static Texture2D spine;
public static Texture2D userEvent;
public static Texture2D constraintNib;
public static Texture2D constraintRoot;
public static Texture2D constraintTransform;
public static Texture2D constraintPath;
public static Texture2D constraintIK;
public static Texture2D warning;
public static Texture2D skeletonUtility;
public static Texture2D hingeChain;
public static Texture2D subMeshRenderer;
public static Texture2D skeletonDataAssetIcon;
public static Texture2D info;
public static Texture2D unity;
static Texture2D LoadIcon (string filename) {
return (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/" + filename);
}
public static void Initialize () {
skeleton = LoadIcon("icon-skeleton.png");
nullBone = LoadIcon("icon-null.png");
bone = LoadIcon("icon-bone.png");
poseBones = LoadIcon("icon-poseBones.png");
boneNib = LoadIcon("icon-boneNib.png");
slot = LoadIcon("icon-slot.png");
slotRoot = LoadIcon("icon-slotRoot.png");
skinPlaceholder = LoadIcon("icon-skinPlaceholder.png");
genericAttachment = LoadIcon("icon-attachment.png");
image = LoadIcon("icon-image.png");
boundingBox = LoadIcon("icon-boundingBox.png");
point = LoadIcon("icon-point.png");
mesh = LoadIcon("icon-mesh.png");
weights = LoadIcon("icon-weights.png");
path = LoadIcon("icon-path.png");
clipping = LoadIcon("icon-clipping.png");
skin = LoadIcon("icon-skin.png");
skinsRoot = LoadIcon("icon-skinsRoot.png");
animation = LoadIcon("icon-animation.png");
animationRoot = LoadIcon("icon-animationRoot.png");
spine = LoadIcon("icon-spine.png");
userEvent = LoadIcon("icon-event.png");
constraintNib = LoadIcon("icon-constraintNib.png");
constraintRoot = LoadIcon("icon-constraints.png");
constraintTransform = LoadIcon("icon-constraintTransform.png");
constraintPath = LoadIcon("icon-constraintPath.png");
constraintIK = LoadIcon("icon-constraintIK.png");
warning = LoadIcon("icon-warning.png");
skeletonUtility = LoadIcon("icon-skeletonUtility.png");
hingeChain = LoadIcon("icon-hingeChain.png");
subMeshRenderer = LoadIcon("icon-subMeshRenderer.png");
skeletonDataAssetIcon = LoadIcon("SkeletonDataAsset Icon.png");
info = EditorGUIUtility.FindTexture("console.infoicon.sml");
unity = EditorGUIUtility.FindTexture("SceneAsset Icon");
}
public static Texture2D GetAttachmentIcon (Attachment attachment) {
// Analysis disable once CanBeReplacedWithTryCastAndCheckForNull
if (attachment is RegionAttachment)
return Icons.image;
else if (attachment is MeshAttachment)
return ((MeshAttachment)attachment).IsWeighted() ? Icons.weights : Icons.mesh;
else if (attachment is BoundingBoxAttachment)
return Icons.boundingBox;
else if (attachment is PointAttachment)
return Icons.point;
else if (attachment is PathAttachment)
return Icons.path;
else if (attachment is ClippingAttachment)
return Icons.clipping;
else
return Icons.warning;
}
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 8603301469b2a284db8eaa26dc60ada8
timeCreated: 1563312057
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,193 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
using EventType = UnityEngine.EventType;
public partial class SpineEditorUtilities {
public static class DragAndDropInstantiation {
public struct SpawnMenuData {
public Vector3 spawnPoint;
public Transform parent;
public SkeletonDataAsset skeletonDataAsset;
public EditorInstantiation.InstantiateDelegate instantiateDelegate;
public bool isUI;
}
public static void SceneViewDragAndDrop (SceneView sceneview) {
var current = UnityEngine.Event.current;
var references = DragAndDrop.objectReferences;
if (current.type == EventType.Layout)
return;
// Allow drag and drop of one SkeletonDataAsset.
if (references.Length == 1) {
var skeletonDataAsset = references[0] as SkeletonDataAsset;
if (skeletonDataAsset != null) {
var mousePos = current.mousePosition;
bool invalidSkeletonData = skeletonDataAsset.GetSkeletonData(true) == null;
if (invalidSkeletonData) {
DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
Handles.BeginGUI();
GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 40f)), new GUIContent(string.Format("{0} is invalid.\nCannot create new Spine GameObject.", skeletonDataAsset.name), SpineEditorUtilities.Icons.warning));
Handles.EndGUI();
return;
} else {
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
Handles.BeginGUI();
GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 20f)), new GUIContent(string.Format("Create Spine GameObject ({0})", skeletonDataAsset.skeletonJSON.name), SpineEditorUtilities.Icons.skeletonDataAssetIcon));
Handles.EndGUI();
if (current.type == EventType.DragPerform) {
RectTransform rectTransform = (Selection.activeGameObject == null) ? null : Selection.activeGameObject.GetComponent<RectTransform>();
Plane plane = (rectTransform == null) ? new Plane(Vector3.back, Vector3.zero) : new Plane(-rectTransform.forward, rectTransform.position);
Vector3 spawnPoint = MousePointToWorldPoint2D(mousePos, sceneview.camera, plane);
ShowInstantiateContextMenu(skeletonDataAsset, spawnPoint, null);
DragAndDrop.AcceptDrag();
current.Use();
}
}
}
}
}
public static void ShowInstantiateContextMenu (SkeletonDataAsset skeletonDataAsset, Vector3 spawnPoint, Transform parent) {
var menu = new GenericMenu();
// SkeletonAnimation
menu.AddItem(new GUIContent("SkeletonAnimation"), false, HandleSkeletonComponentDrop, new SpawnMenuData {
skeletonDataAsset = skeletonDataAsset,
spawnPoint = spawnPoint,
parent = parent,
instantiateDelegate = (data) => EditorInstantiation.InstantiateSkeletonAnimation(data),
isUI = false
});
// SkeletonGraphic
var skeletonGraphicInspectorType = System.Type.GetType("Spine.Unity.Editor.SkeletonGraphicInspector");
if (skeletonGraphicInspectorType != null) {
var graphicInstantiateDelegate = skeletonGraphicInspectorType.GetMethod("SpawnSkeletonGraphicFromDrop", BindingFlags.Static | BindingFlags.Public);
if (graphicInstantiateDelegate != null)
menu.AddItem(new GUIContent("SkeletonGraphic (UI)"), false, HandleSkeletonComponentDrop, new SpawnMenuData {
skeletonDataAsset = skeletonDataAsset,
spawnPoint = spawnPoint,
parent = parent,
instantiateDelegate = System.Delegate.CreateDelegate(typeof(EditorInstantiation.InstantiateDelegate), graphicInstantiateDelegate) as EditorInstantiation.InstantiateDelegate,
isUI = true
});
}
#if SPINE_SKELETONMECANIM
menu.AddSeparator("");
// SkeletonMecanim
menu.AddItem(new GUIContent("SkeletonMecanim"), false, HandleSkeletonComponentDrop, new SpawnMenuData {
skeletonDataAsset = skeletonDataAsset,
spawnPoint = spawnPoint,
parent = parent,
instantiateDelegate = (data) => EditorInstantiation.InstantiateSkeletonMecanim(data),
isUI = false
});
#endif
menu.ShowAsContext();
}
public static void HandleSkeletonComponentDrop (object spawnMenuData) {
var data = (SpawnMenuData)spawnMenuData;
if (data.skeletonDataAsset.GetSkeletonData(true) == null) {
EditorUtility.DisplayDialog("Invalid SkeletonDataAsset", "Unable to create Spine GameObject.\n\nPlease check your SkeletonDataAsset.", "Ok");
return;
}
bool isUI = data.isUI;
Component newSkeletonComponent = data.instantiateDelegate.Invoke(data.skeletonDataAsset);
GameObject newGameObject = newSkeletonComponent.gameObject;
Transform newTransform = newGameObject.transform;
var usedParent = data.parent != null ? data.parent.gameObject : isUI ? Selection.activeGameObject : null;
if (usedParent)
newTransform.SetParent(usedParent.transform, false);
newTransform.position = isUI ? data.spawnPoint : RoundVector(data.spawnPoint, 2);
if (isUI) {
if (usedParent != null && usedParent.GetComponent<RectTransform>() != null) {
((SkeletonGraphic)newSkeletonComponent).MatchRectTransformWithBounds();
}
else
Debug.Log("Created a UI Skeleton GameObject not under a RectTransform. It may not be visible until you parent it to a canvas.");
}
if (!isUI && usedParent != null && usedParent.transform.localScale != Vector3.one)
Debug.Log("New Spine GameObject was parented to a scaled Transform. It may not be the intended size.");
Selection.activeGameObject = newGameObject;
//EditorGUIUtility.PingObject(newGameObject); // Doesn't work when setting activeGameObject.
Undo.RegisterCreatedObjectUndo(newGameObject, "Create Spine GameObject");
}
/// <summary>
/// Rounds off vector components to a number of decimal digits.
/// </summary>
public static Vector3 RoundVector (Vector3 vector, int digits) {
vector.x = (float)System.Math.Round(vector.x, digits);
vector.y = (float)System.Math.Round(vector.y, digits);
vector.z = (float)System.Math.Round(vector.z, digits);
return vector;
}
/// <summary>
/// Converts a mouse point to a world point on a plane.
/// </summary>
static Vector3 MousePointToWorldPoint2D (Vector2 mousePosition, Camera camera, Plane plane) {
var screenPos = new Vector3(mousePosition.x, camera.pixelHeight - mousePosition.y, 0f);
var ray = camera.ScreenPointToRay(screenPos);
float distance;
bool hit = plane.Raycast(ray, out distance);
return ray.GetPoint(distance);
}
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 94ecc7f73dfc0484e848a0e6a1a11f2b
timeCreated: 1563311945
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,434 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2018_3_OR_NEWER
#define NEW_PREFERENCES_SETTINGS_PROVIDER
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
public partial class SpineEditorUtilities {
#if NEW_PREFERENCES_SETTINGS_PROVIDER
static class SpineSettingsProviderRegistration
{
[SettingsProvider]
public static SettingsProvider CreateSpineSettingsProvider()
{
var provider = new SettingsProvider("Spine", SettingsScope.User)
{
label = "Spine",
guiHandler = (searchContext) =>
{
var settings = SpinePreferences.GetOrCreateSettings();
var serializedSettings = new SerializedObject(settings);
SpinePreferences.HandlePreferencesGUI(serializedSettings);
if (serializedSettings.ApplyModifiedProperties())
OldPreferences.SaveToEditorPrefs(settings);
},
// Populate the search keywords to enable smart search filtering and label highlighting:
keywords = new HashSet<string>(new[] { "Spine", "Preferences", "Skeleton", "Default", "Mix", "Duration" })
};
return provider;
}
}
#else
// Preferences entry point
[PreferenceItem("Spine")]
static void PreferencesGUI () {
Preferences.HandlePreferencesGUI();
}
#endif
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static SpinePreferences Preferences {
get {
return SpinePreferences.GetOrCreateSettings();
}
}
#endif
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static class OldPreferences {
#else
public static class Preferences {
#endif
const string DEFAULT_SCALE_KEY = "SPINE_DEFAULT_SCALE";
public static float defaultScale = SpinePreferences.DEFAULT_DEFAULT_SCALE;
const string DEFAULT_MIX_KEY = "SPINE_DEFAULT_MIX";
public static float defaultMix = SpinePreferences.DEFAULT_DEFAULT_MIX;
const string DEFAULT_SHADER_KEY = "SPINE_DEFAULT_SHADER";
public static string defaultShader = SpinePreferences.DEFAULT_DEFAULT_SHADER;
const string DEFAULT_ZSPACING_KEY = "SPINE_DEFAULT_ZSPACING";
public static float defaultZSpacing = SpinePreferences.DEFAULT_DEFAULT_ZSPACING;
const string DEFAULT_INSTANTIATE_LOOP_KEY = "SPINE_DEFAULT_INSTANTIATE_LOOP";
public static bool defaultInstantiateLoop = SpinePreferences.DEFAULT_DEFAULT_INSTANTIATE_LOOP;
const string SHOW_HIERARCHY_ICONS_KEY = "SPINE_SHOW_HIERARCHY_ICONS";
public static bool showHierarchyIcons = SpinePreferences.DEFAULT_SHOW_HIERARCHY_ICONS;
const string SET_TEXTUREIMPORTER_SETTINGS_KEY = "SPINE_SET_TEXTUREIMPORTER_SETTINGS";
public static bool setTextureImporterSettings = SpinePreferences.DEFAULT_SET_TEXTUREIMPORTER_SETTINGS;
const string TEXTURE_SETTINGS_REFERENCE_KEY = "SPINE_TEXTURE_SETTINGS_REFERENCE";
public static string textureSettingsReference = SpinePreferences.DEFAULT_TEXTURE_SETTINGS_REFERENCE;
public static bool UsesPMAWorkflow {
get {
return SpinePreferences.IsPMAWorkflow(textureSettingsReference);
}
}
const string BLEND_MODE_MATERIAL_MULTIPLY_KEY = "SPINE_BLENDMODE_MATERIAL_MULTIPLY";
const string BLEND_MODE_MATERIAL_SCREEN_KEY = "SPINE_BLENDMODE_MATERIAL_SCREEN";
const string BLEND_MODE_MATERIAL_ADDITIVE_KEY = "SPINE_BLENDMODE_MATERIAL_ADDITIVE";
public static string blendModeMaterialMultiply = "";
public static string blendModeMaterialScreen = "";
public static string blendModeMaterialAdditive = "";
public const string DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL = SpinePreferences.DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL;
public const string DEFAULT_BLEND_MODE_SCREEN_MATERIAL = SpinePreferences.DEFAULT_BLEND_MODE_SCREEN_MATERIAL;
public const string DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL = SpinePreferences.DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL;
public static Material BlendModeMaterialMultiply {
get { return AssetDatabase.LoadAssetAtPath<Material>(blendModeMaterialMultiply); }
}
public static Material BlendModeMaterialScreen {
get { return AssetDatabase.LoadAssetAtPath<Material>(blendModeMaterialScreen); }
}
public static Material BlendModeMaterialAdditive {
get { return AssetDatabase.LoadAssetAtPath<Material>(blendModeMaterialAdditive); }
}
const string ATLASTXT_WARNING_KEY = "SPINE_ATLASTXT_WARNING";
public static bool atlasTxtImportWarning = SpinePreferences.DEFAULT_ATLASTXT_WARNING;
const string TEXTUREIMPORTER_WARNING_KEY = "SPINE_TEXTUREIMPORTER_WARNING";
public static bool textureImporterWarning = SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING;
const string COMPONENTMATERIAL_WARNING_KEY = "SPINE_COMPONENTMATERIAL_WARNING";
public static bool componentMaterialWarning = SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING;
public const float DEFAULT_MIPMAPBIAS = SpinePreferences.DEFAULT_MIPMAPBIAS;
public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
public static float handleScale = SpinePreferences.DEFAULT_SCENE_ICONS_SCALE;
const string AUTO_RELOAD_SCENESKELETONS_KEY = "SPINE_AUTO_RELOAD_SCENESKELETONS";
public static bool autoReloadSceneSkeletons = SpinePreferences.DEFAULT_AUTO_RELOAD_SCENESKELETONS;
const string MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY = "SPINE_MECANIM_EVENT_INCLUDE_FOLDERNAME";
public static bool mecanimEventIncludeFolderName = SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
const string TIMELINE_USE_BLEND_DURATION_KEY = "SPINE_TIMELINE_USE_BLEND_DURATION_KEY";
public static bool timelineUseBlendDuration = SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION;
static bool preferencesLoaded = false;
public static void Load () {
if (preferencesLoaded)
return;
defaultMix = EditorPrefs.GetFloat(DEFAULT_MIX_KEY, SpinePreferences.DEFAULT_DEFAULT_MIX);
defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, SpinePreferences.DEFAULT_DEFAULT_SCALE);
defaultZSpacing = EditorPrefs.GetFloat(DEFAULT_ZSPACING_KEY, SpinePreferences.DEFAULT_DEFAULT_ZSPACING);
defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, SpinePreferences.DEFAULT_DEFAULT_SHADER);
showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, SpinePreferences.DEFAULT_SHOW_HIERARCHY_ICONS);
setTextureImporterSettings = EditorPrefs.GetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, SpinePreferences.DEFAULT_SET_TEXTUREIMPORTER_SETTINGS);
textureSettingsReference = EditorPrefs.GetString(TEXTURE_SETTINGS_REFERENCE_KEY, SpinePreferences.DEFAULT_TEXTURE_SETTINGS_REFERENCE);
blendModeMaterialMultiply = EditorPrefs.GetString(BLEND_MODE_MATERIAL_MULTIPLY_KEY, "");
blendModeMaterialScreen = EditorPrefs.GetString(BLEND_MODE_MATERIAL_SCREEN_KEY, "");
blendModeMaterialAdditive = EditorPrefs.GetString(BLEND_MODE_MATERIAL_ADDITIVE_KEY, "");
autoReloadSceneSkeletons = EditorPrefs.GetBool(AUTO_RELOAD_SCENESKELETONS_KEY, SpinePreferences.DEFAULT_AUTO_RELOAD_SCENESKELETONS);
mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
componentMaterialWarning = EditorPrefs.GetBool(COMPONENTMATERIAL_WARNING_KEY, SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING);
timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
preferencesLoaded = true;
}
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static void CopyOldToNewPreferences(ref SpinePreferences newPreferences) {
newPreferences.defaultMix = EditorPrefs.GetFloat(DEFAULT_MIX_KEY, SpinePreferences.DEFAULT_DEFAULT_MIX);
newPreferences.defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, SpinePreferences.DEFAULT_DEFAULT_SCALE);
newPreferences.defaultZSpacing = EditorPrefs.GetFloat(DEFAULT_ZSPACING_KEY, SpinePreferences.DEFAULT_DEFAULT_ZSPACING);
newPreferences.defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, SpinePreferences.DEFAULT_DEFAULT_SHADER);
newPreferences.showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, SpinePreferences.DEFAULT_SHOW_HIERARCHY_ICONS);
newPreferences.setTextureImporterSettings = EditorPrefs.GetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, SpinePreferences.DEFAULT_SET_TEXTUREIMPORTER_SETTINGS);
newPreferences.textureSettingsReference = EditorPrefs.GetString(TEXTURE_SETTINGS_REFERENCE_KEY, SpinePreferences.DEFAULT_TEXTURE_SETTINGS_REFERENCE);
newPreferences.autoReloadSceneSkeletons = EditorPrefs.GetBool(AUTO_RELOAD_SCENESKELETONS_KEY, SpinePreferences.DEFAULT_AUTO_RELOAD_SCENESKELETONS);
newPreferences.mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
newPreferences.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
newPreferences.textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
newPreferences.componentMaterialWarning = EditorPrefs.GetBool(COMPONENTMATERIAL_WARNING_KEY, SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING);
newPreferences.timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
newPreferences.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
}
public static void SaveToEditorPrefs(SpinePreferences preferences) {
EditorPrefs.SetFloat(DEFAULT_MIX_KEY, preferences.defaultMix);
EditorPrefs.SetFloat(DEFAULT_SCALE_KEY, preferences.defaultScale);
EditorPrefs.SetFloat(DEFAULT_ZSPACING_KEY, preferences.defaultZSpacing);
EditorPrefs.SetString(DEFAULT_SHADER_KEY, preferences.defaultShader);
EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, preferences.showHierarchyIcons);
EditorPrefs.SetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, preferences.setTextureImporterSettings);
EditorPrefs.SetString(TEXTURE_SETTINGS_REFERENCE_KEY, preferences.textureSettingsReference);
EditorPrefs.SetBool(AUTO_RELOAD_SCENESKELETONS_KEY, preferences.autoReloadSceneSkeletons);
EditorPrefs.SetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, preferences.mecanimEventIncludeFolderName);
EditorPrefs.SetBool(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning);
EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning);
EditorPrefs.SetBool(COMPONENTMATERIAL_WARNING_KEY, preferences.componentMaterialWarning);
EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration);
EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, preferences.handleScale);
}
#endif
#if !NEW_PREFERENCES_SETTINGS_PROVIDER
public static void HandlePreferencesGUI () {
if (!preferencesLoaded)
Load();
EditorGUI.BeginChangeCheck();
showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons);
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons);
#if NEWPLAYMODECALLBACKS
HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
HierarchyHandler.IconsOnPlaymodeStateChanged();
#endif
}
BoolPrefsField(ref autoReloadSceneSkeletons, AUTO_RELOAD_SCENESKELETONS_KEY, new GUIContent("Auto-reload scene components", "Reloads Skeleton components in the scene whenever their SkeletonDataAsset is modified. This makes it so changes in the SkeletonDataAsset inspector are immediately reflected. This may be slow when your scenes have large numbers of SkeletonRenderers or SkeletonGraphic."));
EditorGUILayout.Separator();
EditorGUILayout.LabelField("Auto-Import Settings", EditorStyles.boldLabel);
{
SpineEditorUtilities.FloatPrefsField(ref defaultMix, DEFAULT_MIX_KEY, new GUIContent("Default Mix", "The Default Mix Duration for newly imported SkeletonDataAssets."), min: 0);
SpineEditorUtilities.FloatPrefsField(ref defaultScale, DEFAULT_SCALE_KEY, new GUIContent("Default SkeletonData Scale", "The Default skeleton import scale for newly imported SkeletonDataAssets."), min: 0.0000001f);
EditorGUI.BeginChangeCheck();
var shader = (EditorGUILayout.ObjectField("Default Shader", Shader.Find(defaultShader), typeof(Shader), false) as Shader);
defaultShader = shader != null ? shader.name : SpinePreferences.DEFAULT_DEFAULT_SHADER;
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetString(DEFAULT_SHADER_KEY, defaultShader);
SpineEditorUtilities.BoolPrefsField(ref setTextureImporterSettings, SET_TEXTUREIMPORTER_SETTINGS_KEY, new GUIContent("Apply Atlas Texture Settings", "Apply the recommended settings for Texture Importers."));
SpineEditorUtilities.Texture2DPrefsField(ref textureSettingsReference, TEXTURE_SETTINGS_REFERENCE_KEY, new GUIContent("Atlas Texture Reference Settings", "Apply the selected reference texture import settings at newly imported atlas textures. When exporting atlas textures from Spine with \"Premultiply alpha\" enabled (the default), you can leave it at \"PMAPresetTemplate\". If you have disabled \"Premultiply alpha\", set it to \"StraightAlphaPresetTemplate\". You can also create your own reference texture asset and assign it here."));
if (string.IsNullOrEmpty(textureSettingsReference)) {
var pmaTextureSettingsReferenceGUIDS = AssetDatabase.FindAssets("PMAPresetTemplate");
if (pmaTextureSettingsReferenceGUIDS.Length > 0) {
textureSettingsReference = AssetDatabase.GUIDToAssetPath(pmaTextureSettingsReferenceGUIDS[0]);
EditorPrefs.SetString(TEXTURE_SETTINGS_REFERENCE_KEY, textureSettingsReference);
}
}
SpineEditorUtilities.MaterialPrefsField(ref blendModeMaterialAdditive, BLEND_MODE_MATERIAL_ADDITIVE_KEY, new GUIContent("Additive Material", "Additive blend mode Material template."));
if (string.IsNullOrEmpty(blendModeMaterialAdditive)) {
var blendModeMaterialAdditiveGUIDS = AssetDatabase.FindAssets(DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL);
if (blendModeMaterialAdditiveGUIDS.Length > 0) {
blendModeMaterialAdditive = AssetDatabase.GUIDToAssetPath(blendModeMaterialAdditiveGUIDS[0]);
}
}
SpineEditorUtilities.MaterialPrefsField(ref blendModeMaterialMultiply, BLEND_MODE_MATERIAL_MULTIPLY_KEY, new GUIContent("Multiply Material", "Multiply blend mode Material template."));
if (string.IsNullOrEmpty(blendModeMaterialMultiply)) {
var blendModeMaterialMultiplyGUIDS = AssetDatabase.FindAssets(DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL);
if (blendModeMaterialMultiplyGUIDS.Length > 0) {
blendModeMaterialMultiply = AssetDatabase.GUIDToAssetPath(blendModeMaterialMultiplyGUIDS[0]);
}
}
SpineEditorUtilities.MaterialPrefsField(ref blendModeMaterialScreen, BLEND_MODE_MATERIAL_SCREEN_KEY, new GUIContent("Screen Material", "Screen blend mode Material template."));
if (string.IsNullOrEmpty(blendModeMaterialScreen)) {
var blendModeMaterialScreenGUIDS = AssetDatabase.FindAssets(DEFAULT_BLEND_MODE_SCREEN_MATERIAL);
if (blendModeMaterialScreenGUIDS.Length > 0) {
blendModeMaterialScreen = AssetDatabase.GUIDToAssetPath(blendModeMaterialScreenGUIDS[0]);
}
}
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Warnings", EditorStyles.boldLabel);
{
SpineEditorUtilities.BoolPrefsField(ref atlasTxtImportWarning, ATLASTXT_WARNING_KEY, new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found."));
SpineEditorUtilities.BoolPrefsField(ref textureImporterWarning, TEXTUREIMPORTER_WARNING_KEY, new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts."));
SpineEditorUtilities.BoolPrefsField(ref componentMaterialWarning, COMPONENTMATERIAL_WARNING_KEY, new GUIContent("Component & Material Warning", "Log a warning and recommendation whenever Component and Material settings are not compatible."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor Instantiation", EditorStyles.boldLabel);
{
EditorGUI.BeginChangeCheck();
defaultZSpacing = EditorGUILayout.Slider("Default Slot Z-Spacing", defaultZSpacing, -0.1f, 0f);
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetFloat(DEFAULT_ZSPACING_KEY, defaultZSpacing);
SpineEditorUtilities.BoolPrefsField(ref defaultInstantiateLoop, DEFAULT_INSTANTIATE_LOOP_KEY, new GUIContent("Default Loop", "Spawn Spine GameObjects with loop enabled."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Mecanim Bake Settings", EditorStyles.boldLabel);
{
SpineEditorUtilities.BoolPrefsField(ref mecanimEventIncludeFolderName, MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, new GUIContent("Include Folder Name in Event", "When enabled, Mecanim events will call methods named 'FolderNameEventName', when disabled it will call 'EventName'."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
{
EditorGUI.BeginChangeCheck();
handleScale = EditorGUILayout.Slider("Editor Bone Scale", handleScale, 0.01f, 2f);
handleScale = Mathf.Max(0.01f, handleScale);
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, handleScale);
SceneView.RepaintAll();
}
}
#if SPINE_TK2D_DEFINE
bool isTK2DDefineSet = true;
#else
bool isTK2DDefineSet = false;
#endif
bool isTK2DAllowed = SpineTK2DEditorUtility.IsTK2DAllowed;
if (SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) {
GUILayout.Space(20);
EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel);
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Define TK2D");
if (isTK2DAllowed && GUILayout.Button("Enable", GUILayout.Width(64)))
SpineTK2DEditorUtility.EnableTK2D();
if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineTK2DEditorUtility.DisableTK2D();
}
#if !SPINE_TK2D_DEFINE
if (!isTK2DAllowed) {
EditorGUILayout.LabelField("To allow TK2D support, please modify line 67 in", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Spine/Editor/spine-unity/Editor/Util./BuildSettings.cs", EditorStyles.boldLabel);
}
#endif
}
GUILayout.Space(20);
EditorGUILayout.LabelField("Timeline Extension", EditorStyles.boldLabel);
{
SpineEditorUtilities.BoolPrefsField(ref timelineUseBlendDuration, TIMELINE_USE_BLEND_DURATION_KEY, new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
}
}
#endif // !NEW_PREFERENCES_SETTINGS_PROVIDER
}
static void BoolPrefsField (ref bool currentValue, string editorPrefsKey, GUIContent label) {
EditorGUI.BeginChangeCheck();
currentValue = EditorGUILayout.Toggle(label, currentValue);
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetBool(editorPrefsKey, currentValue);
}
static void FloatPrefsField (ref float currentValue, string editorPrefsKey, GUIContent label, float min = float.NegativeInfinity, float max = float.PositiveInfinity) {
EditorGUI.BeginChangeCheck();
currentValue = EditorGUILayout.DelayedFloatField(label, currentValue);
if (EditorGUI.EndChangeCheck()) {
currentValue = Mathf.Clamp(currentValue, min, max);
EditorPrefs.SetFloat(editorPrefsKey, currentValue);
}
}
static void Texture2DPrefsField (ref string currentValue, string editorPrefsKey, GUIContent label) {
EditorGUI.BeginChangeCheck();
EditorGUIUtility.wideMode = true;
var texture = (EditorGUILayout.ObjectField(label, AssetDatabase.LoadAssetAtPath<Texture2D>(currentValue), typeof(Object), false) as Texture2D);
currentValue = texture != null ? AssetDatabase.GetAssetPath(texture) : "";
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetString(editorPrefsKey, currentValue);
}
}
static void MaterialPrefsField (ref string currentValue, string editorPrefsKey, GUIContent label) {
EditorGUI.BeginChangeCheck();
EditorGUIUtility.wideMode = true;
var material = (EditorGUILayout.ObjectField(label, AssetDatabase.LoadAssetAtPath<Material>(currentValue), typeof(Object), false) as Material);
currentValue = material != null ? AssetDatabase.GetAssetPath(material) : "";
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetString(editorPrefsKey, currentValue);
}
}
public static void FloatPropertyField (SerializedProperty property, GUIContent label, float min = float.NegativeInfinity, float max = float.PositiveInfinity) {
EditorGUI.BeginChangeCheck();
property.floatValue = EditorGUILayout.DelayedFloatField(label, property.floatValue);
if (EditorGUI.EndChangeCheck()) {
property.floatValue = Mathf.Clamp(property.floatValue, min, max);
}
}
public static void ShaderPropertyField (SerializedProperty property, GUIContent label, string fallbackShaderName) {
var shader = (EditorGUILayout.ObjectField(label, Shader.Find(property.stringValue), typeof(Shader), false) as Shader);
property.stringValue = shader != null ? shader.name : fallbackShaderName;
}
public static void MaterialPropertyField (SerializedProperty property, GUIContent label) {
var material = (EditorGUILayout.ObjectField(label, AssetDatabase.LoadAssetAtPath<Material>(property.stringValue), typeof(Material), false) as Material);
property.stringValue = material ? AssetDatabase.GetAssetPath(material) : "";
}
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static void PresetAssetPropertyField (SerializedProperty property, GUIContent label) {
var texturePreset = (EditorGUILayout.ObjectField(label, AssetDatabase.LoadAssetAtPath<UnityEditor.Presets.Preset>(property.stringValue), typeof(UnityEditor.Presets.Preset), false) as UnityEditor.Presets.Preset);
bool isTexturePreset = texturePreset != null && texturePreset.GetTargetTypeName() == "TextureImporter";
property.stringValue = isTexturePreset ? AssetDatabase.GetAssetPath(texturePreset) : "";
}
#endif
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 6d80c945a2e3436459a97b7a9a16ef46
timeCreated: 1563311495
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,459 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#pragma warning disable 0618 // for 3.7 branch only. Avoids "PreferenceItem' is obsolete: '[PreferenceItem] is deprecated. Use [SettingsProvider] instead."
// Original contribution by: Mitch Thompson
#define SPINE_SKELETONMECANIM
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
#if UNITY_2018 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEWHIERARCHYWINDOWCALLBACKS
#endif
#if UNITY_2018_3_OR_NEWER
#define NEW_PREFERENCES_SETTINGS_PROVIDER
#endif
#if UNITY_2017_1_OR_NEWER
#define BUILT_IN_SPRITE_MASK_COMPONENT
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
using EventType = UnityEngine.EventType;
// Analysis disable once ConvertToStaticType
[InitializeOnLoad]
public partial class SpineEditorUtilities : AssetPostprocessor {
public static string editorPath = "";
public static string editorGUIPath = "";
public static bool initialized;
private static List<string> texturesWithoutMetaFile = new List<string>();
// Auto-import entry point for textures
void OnPreprocessTexture () {
#if UNITY_2018_1_OR_NEWER
bool customTextureSettingsExist = !assetImporter.importSettingsMissing;
#else
bool customTextureSettingsExist = System.IO.File.Exists(assetImporter.assetPath + ".meta");
#endif
if (!customTextureSettingsExist) {
texturesWithoutMetaFile.Add(assetImporter.assetPath);
}
}
// Auto-import post process entry point for all assets
static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
if (imported.Length == 0)
return;
// we copy the list here to prevent nested calls to OnPostprocessAllAssets() triggering a Clear() of the list
// in the middle of execution.
var texturesWithoutMetaFileCopy = new List<string>(texturesWithoutMetaFile);
AssetUtility.HandleOnPostprocessAllAssets(imported, texturesWithoutMetaFileCopy);
texturesWithoutMetaFile.Clear();
}
#region Initialization
static SpineEditorUtilities () {
EditorApplication.delayCall += Initialize; // delayed so that AssetDatabase is ready.
}
static void Initialize () {
// Note: Preferences need to be loaded when changing play mode
// to initialize handle scale correctly.
#if !NEW_PREFERENCES_SETTINGS_PROVIDER
Preferences.Load();
#else
SpinePreferences.Load();
#endif
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
string[] assets = AssetDatabase.FindAssets("t:script SpineEditorUtilities");
string assetPath = AssetDatabase.GUIDToAssetPath(assets[0]);
editorPath = Path.GetDirectoryName(assetPath).Replace('\\', '/');
assets = AssetDatabase.FindAssets("t:texture icon-subMeshRenderer");
if (assets.Length > 0) {
assetPath = AssetDatabase.GUIDToAssetPath(assets[0]);
editorGUIPath = Path.GetDirectoryName(assetPath).Replace('\\', '/');
}
else {
editorGUIPath = editorPath.Replace("/Utility", "/GUI");
}
Icons.Initialize();
// Drag and Drop
#if UNITY_2019_1_OR_NEWER
SceneView.duringSceneGui -= DragAndDropInstantiation.SceneViewDragAndDrop;
SceneView.duringSceneGui += DragAndDropInstantiation.SceneViewDragAndDrop;
#else
SceneView.onSceneGUIDelegate -= DragAndDropInstantiation.SceneViewDragAndDrop;
SceneView.onSceneGUIDelegate += DragAndDropInstantiation.SceneViewDragAndDrop;
#endif
EditorApplication.hierarchyWindowItemOnGUI -= HierarchyHandler.HandleDragAndDrop;
EditorApplication.hierarchyWindowItemOnGUI += HierarchyHandler.HandleDragAndDrop;
// Hierarchy Icons
#if NEWPLAYMODECALLBACKS
EditorApplication.playModeStateChanged -= HierarchyHandler.IconsOnPlaymodeStateChanged;
EditorApplication.playModeStateChanged += HierarchyHandler.IconsOnPlaymodeStateChanged;
HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
EditorApplication.playmodeStateChanged -= HierarchyHandler.IconsOnPlaymodeStateChanged;
EditorApplication.playmodeStateChanged += HierarchyHandler.IconsOnPlaymodeStateChanged;
HierarchyHandler.IconsOnPlaymodeStateChanged();
#endif
// Data Refresh Edit Mode.
// This prevents deserialized SkeletonData from persisting from play mode to edit mode.
#if NEWPLAYMODECALLBACKS
EditorApplication.playModeStateChanged -= DataReloadHandler.OnPlaymodeStateChanged;
EditorApplication.playModeStateChanged += DataReloadHandler.OnPlaymodeStateChanged;
DataReloadHandler.OnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
EditorApplication.playmodeStateChanged -= DataReloadHandler.OnPlaymodeStateChanged;
EditorApplication.playmodeStateChanged += DataReloadHandler.OnPlaymodeStateChanged;
DataReloadHandler.OnPlaymodeStateChanged();
#endif
if (SpineEditorUtilities.Preferences.textureImporterWarning) {
IssueWarningsForUnrecommendedTextureSettings();
}
initialized = true;
}
public static void ConfirmInitialization () {
if (!initialized || Icons.skeleton == null)
Initialize();
}
public static void IssueWarningsForUnrecommendedTextureSettings() {
string[] atlasDescriptionGUIDs = AssetDatabase.FindAssets("t:textasset .atlas"); // Note: finds ".atlas.txt" but also ".atlas 1.txt" files.
for (int i = 0; i < atlasDescriptionGUIDs.Length; ++i) {
string atlasDescriptionPath = AssetDatabase.GUIDToAssetPath(atlasDescriptionGUIDs[i]);
if (!atlasDescriptionPath.EndsWith(".atlas.txt"))
continue;
string texturePath = atlasDescriptionPath.Replace(".atlas.txt", ".png");
bool textureExists = IssueWarningsForUnrecommendedTextureSettings(texturePath);
if (!textureExists) {
texturePath = texturePath.Replace(".png", ".jpg");
textureExists = IssueWarningsForUnrecommendedTextureSettings(texturePath);
}
if (!textureExists) {
continue;
}
}
}
public static void ReloadSkeletonDataAssetAndComponent (SkeletonRenderer component) {
if (component == null) return;
ReloadSkeletonDataAsset(component.skeletonDataAsset);
ReinitializeComponent(component);
}
public static void ReloadSkeletonDataAssetAndComponent (SkeletonGraphic component) {
if (component == null) return;
ReloadSkeletonDataAsset(component.skeletonDataAsset);
// Reinitialize.
ReinitializeComponent(component);
}
public static void ReloadSkeletonDataAsset (SkeletonDataAsset skeletonDataAsset) {
if (skeletonDataAsset != null) {
foreach (AtlasAssetBase aa in skeletonDataAsset.atlasAssets) {
if (aa != null) aa.Clear();
}
skeletonDataAsset.Clear();
}
skeletonDataAsset.GetSkeletonData(true);
}
public static void ReinitializeComponent (SkeletonRenderer component) {
if (component == null) return;
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
var stateComponent = component as IAnimationStateComponent;
AnimationState oldAnimationState = null;
if (stateComponent != null) {
oldAnimationState = stateComponent.AnimationState;
}
component.Initialize(true); // implicitly clears any subscribers
if (oldAnimationState != null) {
stateComponent.AnimationState.AssignEventSubscribersFrom(oldAnimationState);
}
#if BUILT_IN_SPRITE_MASK_COMPONENT
SpineMaskUtilities.EditorAssignSpriteMaskMaterials(component);
#endif
component.LateUpdate();
}
public static void ReinitializeComponent (SkeletonGraphic component) {
if (component == null) return;
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
component.Initialize(true);
component.LateUpdate();
}
public static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) {
return asset != null && asset.GetSkeletonData(quiet: true) != null;
}
public static bool IssueWarningsForUnrecommendedTextureSettings(string texturePath)
{
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
if (texImporter == null) {
return false;
}
int extensionPos = texturePath.LastIndexOf('.');
string materialPath = texturePath.Substring(0, extensionPos) + "_Material.mat";
Material material = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
if (material == null)
return true;
string errorMessage = null;
if (MaterialChecks.IsTextureSetupProblematic(material, PlayerSettings.colorSpace,
texImporter. sRGBTexture, texImporter. mipmapEnabled, texImporter. alphaIsTransparency,
texturePath, materialPath, ref errorMessage)) {
Debug.LogWarning(errorMessage, material);
}
return true;
}
#endregion
public static class HierarchyHandler {
static Dictionary<int, GameObject> skeletonRendererTable = new Dictionary<int, GameObject>();
static Dictionary<int, SkeletonUtilityBone> skeletonUtilityBoneTable = new Dictionary<int, SkeletonUtilityBone>();
static Dictionary<int, BoundingBoxFollower> boundingBoxFollowerTable = new Dictionary<int, BoundingBoxFollower>();
static Dictionary<int, BoundingBoxFollowerGraphic> boundingBoxFollowerGraphicTable = new Dictionary<int, BoundingBoxFollowerGraphic>();
#if NEWPLAYMODECALLBACKS
internal static void IconsOnPlaymodeStateChanged (PlayModeStateChange stateChange) {
#else
internal static void IconsOnPlaymodeStateChanged () {
#endif
skeletonRendererTable.Clear();
skeletonUtilityBoneTable.Clear();
boundingBoxFollowerTable.Clear();
boundingBoxFollowerGraphicTable.Clear();
#if NEWHIERARCHYWINDOWCALLBACKS
EditorApplication.hierarchyChanged -= IconsOnChanged;
#else
EditorApplication.hierarchyWindowChanged -= IconsOnChanged;
#endif
EditorApplication.hierarchyWindowItemOnGUI -= IconsOnGUI;
if (!Application.isPlaying && Preferences.showHierarchyIcons) {
#if NEWHIERARCHYWINDOWCALLBACKS
EditorApplication.hierarchyChanged += IconsOnChanged;
#else
EditorApplication.hierarchyWindowChanged += IconsOnChanged;
#endif
EditorApplication.hierarchyWindowItemOnGUI += IconsOnGUI;
IconsOnChanged();
}
}
internal static void IconsOnChanged () {
skeletonRendererTable.Clear();
skeletonUtilityBoneTable.Clear();
boundingBoxFollowerTable.Clear();
boundingBoxFollowerGraphicTable.Clear();
SkeletonRenderer[] arr = Object.FindObjectsOfType<SkeletonRenderer>();
foreach (SkeletonRenderer r in arr)
skeletonRendererTable[r.gameObject.GetInstanceID()] = r.gameObject;
SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType<SkeletonUtilityBone>();
foreach (SkeletonUtilityBone b in boneArr)
skeletonUtilityBoneTable[b.gameObject.GetInstanceID()] = b;
BoundingBoxFollower[] bbfArr = Object.FindObjectsOfType<BoundingBoxFollower>();
foreach (BoundingBoxFollower bbf in bbfArr)
boundingBoxFollowerTable[bbf.gameObject.GetInstanceID()] = bbf;
BoundingBoxFollowerGraphic[] bbfgArr = Object.FindObjectsOfType<BoundingBoxFollowerGraphic>();
foreach (BoundingBoxFollowerGraphic bbf in bbfgArr)
boundingBoxFollowerGraphicTable[bbf.gameObject.GetInstanceID()] = bbf;
}
internal static void IconsOnGUI (int instanceId, Rect selectionRect) {
Rect r = new Rect(selectionRect);
if (skeletonRendererTable.ContainsKey(instanceId)) {
r.x = r.width - 15;
r.width = 15;
GUI.Label(r, Icons.spine);
} else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) {
r.x -= 26;
if (skeletonUtilityBoneTable[instanceId] != null) {
if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0)
r.x += 13;
r.y += 2;
r.width = 13;
r.height = 13;
if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow)
GUI.DrawTexture(r, Icons.bone);
else
GUI.DrawTexture(r, Icons.poseBones);
}
} else if (boundingBoxFollowerTable.ContainsKey(instanceId)) {
r.x -= 26;
if (boundingBoxFollowerTable[instanceId] != null) {
if (boundingBoxFollowerTable[instanceId].transform.childCount == 0)
r.x += 13;
r.y += 2;
r.width = 13;
r.height = 13;
GUI.DrawTexture(r, Icons.boundingBox);
}
} else if (boundingBoxFollowerGraphicTable.ContainsKey(instanceId)) {
r.x -= 26;
if (boundingBoxFollowerGraphicTable[instanceId] != null) {
if (boundingBoxFollowerGraphicTable[instanceId].transform.childCount == 0)
r.x += 13;
r.y += 2;
r.width = 13;
r.height = 13;
GUI.DrawTexture(r, Icons.boundingBox);
}
}
}
internal static void HandleDragAndDrop (int instanceId, Rect selectionRect) {
// HACK: Uses EditorApplication.hierarchyWindowItemOnGUI.
// Only works when there is at least one item in the scene.
var current = UnityEngine.Event.current;
var eventType = current.type;
bool isDraggingEvent = eventType == EventType.DragUpdated;
bool isDropEvent = eventType == EventType.DragPerform;
UnityEditor.DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (isDraggingEvent || isDropEvent) {
var mouseOverWindow = EditorWindow.mouseOverWindow;
if (mouseOverWindow != null) {
// One, existing, valid SkeletonDataAsset
var references = UnityEditor.DragAndDrop.objectReferences;
if (references.Length == 1) {
var skeletonDataAsset = references[0] as SkeletonDataAsset;
if (skeletonDataAsset != null && skeletonDataAsset.GetSkeletonData(true) != null) {
// Allow drag-and-dropping anywhere in the Hierarchy Window.
// HACK: string-compare because we can't get its type via reflection.
const string HierarchyWindow = "UnityEditor.SceneHierarchyWindow";
const string GenericDataTargetID = "target";
if (HierarchyWindow.Equals(mouseOverWindow.GetType().ToString(), System.StringComparison.Ordinal)) {
if (isDraggingEvent) {
var mouseOverTarget = UnityEditor.EditorUtility.InstanceIDToObject(instanceId);
if (mouseOverTarget)
DragAndDrop.SetGenericData(GenericDataTargetID, mouseOverTarget);
// Note: do not call current.Use(), otherwise we get the wrong drop-target parent.
} else if (isDropEvent) {
var parentGameObject = DragAndDrop.GetGenericData(GenericDataTargetID) as UnityEngine.GameObject;
Transform parent = parentGameObject != null ? parentGameObject.transform : null;
// when dragging into empty space in hierarchy below last node, last node would be parent.
if (IsLastNodeInHierarchy(parent))
parent = null;
DragAndDropInstantiation.ShowInstantiateContextMenu(skeletonDataAsset, Vector3.zero, parent);
UnityEditor.DragAndDrop.AcceptDrag();
current.Use();
return;
}
}
}
}
}
}
}
internal static bool IsLastNodeInHierarchy (Transform node) {
if (node == null)
return false;
while (node.parent != null) {
if (node.GetSiblingIndex() != node.parent.childCount - 1)
return false;
node = node.parent;
}
var rootNodes = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
bool isLastNode = (rootNodes.Length > 0 && rootNodes[rootNodes.Length - 1].transform == node);
return isLastNode;
}
}
}
public class TextureModificationWarningProcessor : UnityEditor.AssetModificationProcessor
{
static string[] OnWillSaveAssets(string[] paths)
{
if (SpineEditorUtilities.Preferences.textureImporterWarning) {
foreach (string path in paths) {
if ((path != null) &&
(path.EndsWith(".png.meta", System.StringComparison.Ordinal) ||
path.EndsWith(".jpg.meta", System.StringComparison.Ordinal))) {
string texturePath = System.IO.Path.ChangeExtension(path, null); // .meta removed
string atlasPath = System.IO.Path.ChangeExtension(texturePath, "atlas.txt");
if (System.IO.File.Exists(atlasPath))
SpineEditorUtilities.IssueWarningsForUnrecommendedTextureSettings(texturePath);
}
}
}
return paths;
}
}
}
@@ -1,501 +0,0 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma warning disable 0219
#define SPINE_SKELETONMECANIM
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace Spine.Unity.Editor {
using EventType = UnityEngine.EventType;
public static class SpineHandles {
public static Color BoneColor { get { return new Color(0.8f, 0.8f, 0.8f, 0.4f); } }
public static Color PathColor { get { return new Color(254/255f, 127/255f, 0); } }
public static Color TransformContraintColor { get { return new Color(170/255f, 226/255f, 35/255f); } }
public static Color IkColor { get { return new Color(228/255f,90/255f,43/255f); } }
public static Color PointColor { get { return new Color(1f, 1f, 0f, 1f); } }
static Vector3[] _boneMeshVerts = {
new Vector3(0, 0, 0),
new Vector3(0.1f, 0.1f, 0),
new Vector3(1, 0, 0),
new Vector3(0.1f, -0.1f, 0)
};
static Mesh _boneMesh;
public static Mesh BoneMesh {
get {
if (_boneMesh == null) {
_boneMesh = new Mesh {
vertices = _boneMeshVerts,
uv = new Vector2[4],
triangles = new [] { 0, 1, 2, 2, 3, 0 }
};
_boneMesh.RecalculateBounds();
_boneMesh.RecalculateNormals();
}
return _boneMesh;
}
}
static Mesh _arrowheadMesh;
public static Mesh ArrowheadMesh {
get {
if (_arrowheadMesh == null) {
_arrowheadMesh = new Mesh {
vertices = new [] {
new Vector3(0, 0),
new Vector3(-0.1f, 0.05f),
new Vector3(-0.1f, -0.05f)
},
uv = new Vector2[3],
triangles = new [] { 0, 1, 2 }
};
_arrowheadMesh.RecalculateBounds();
_arrowheadMesh.RecalculateNormals();
}
return _arrowheadMesh;
}
}
static Material _boneMaterial;
static Material BoneMaterial {
get {
if (_boneMaterial == null) {
_boneMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
_boneMaterial.SetColor("_Color", SpineHandles.BoneColor);
}
return _boneMaterial;
}
}
public static Material GetBoneMaterial () {
BoneMaterial.SetColor("_Color", SpineHandles.BoneColor);
return BoneMaterial;
}
public static Material GetBoneMaterial (Color color) {
BoneMaterial.SetColor("_Color", color);
return BoneMaterial;
}
static Material _ikMaterial;
public static Material IKMaterial {
get {
if (_ikMaterial == null) {
_ikMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
_ikMaterial.SetColor("_Color", SpineHandles.IkColor);
}
return _ikMaterial;
}
}
static GUIStyle _boneNameStyle;
public static GUIStyle BoneNameStyle {
get {
if (_boneNameStyle == null) {
_boneNameStyle = new GUIStyle(EditorStyles.whiteMiniLabel) {
alignment = TextAnchor.MiddleCenter,
stretchWidth = true,
padding = new RectOffset(0, 0, 0, 0),
contentOffset = new Vector2(-5f, 0f)
};
}
return _boneNameStyle;
}
}
static GUIStyle _pathNameStyle;
public static GUIStyle PathNameStyle {
get {
if (_pathNameStyle == null) {
_pathNameStyle = new GUIStyle(SpineHandles.BoneNameStyle);
_pathNameStyle.normal.textColor = SpineHandles.PathColor;
}
return _pathNameStyle;
}
}
static GUIStyle _pointNameStyle;
public static GUIStyle PointNameStyle {
get {
if (_pointNameStyle == null) {
_pointNameStyle = new GUIStyle(SpineHandles.BoneNameStyle);
_pointNameStyle.normal.textColor = SpineHandles.PointColor;
}
return _pointNameStyle;
}
}
public static void DrawBoneNames (Transform transform, Skeleton skeleton, float positionScale = 1f) {
GUIStyle style = BoneNameStyle;
foreach (Bone b in skeleton.Bones) {
if (!b.Active) continue;
var pos = new Vector3(b.WorldX * positionScale, b.WorldY * positionScale, 0) + (new Vector3(b.A, b.C) * (b.Data.Length * 0.5f));
pos = transform.TransformPoint(pos);
Handles.Label(pos, b.Data.Name, style);
}
}
public static void DrawBones (Transform transform, Skeleton skeleton, float positionScale = 1f) {
float boneScale = 1.8f; // Draw the root bone largest;
DrawCrosshairs2D(skeleton.Bones.Items[0].GetWorldPosition(transform), 0.08f, positionScale);
foreach (Bone b in skeleton.Bones) {
if (!b.Active) continue;
DrawBone(transform, b, boneScale, positionScale);
boneScale = 1f;
}
}
static Vector3[] _boneWireBuffer = new Vector3[5];
static Vector3[] GetBoneWireBuffer (Matrix4x4 m) {
for (int i = 0, n = _boneMeshVerts.Length; i < n; i++)
_boneWireBuffer[i] = m.MultiplyPoint(_boneMeshVerts[i]);
_boneWireBuffer[4] = _boneWireBuffer[0]; // closed polygon.
return _boneWireBuffer;
}
public static void DrawBoneWireframe (Transform transform, Bone b, Color color, float skeletonRenderScale = 1f) {
Handles.color = color;
var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0);
float length = b.Data.Length;
if (length > 0) {
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
const float my = 1.5f;
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
Handles.DrawPolyLine(GetBoneWireBuffer(transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)));
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale);
} else {
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale);
}
}
public static void DrawBone (Transform transform, Bone b, float boneScale, float skeletonRenderScale = 1f) {
var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0);
float length = b.Data.Length;
if (length > 0) {
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
const float my = 1.5f;
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
SpineHandles.GetBoneMaterial().SetPass(0);
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
} else {
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, SpineHandles.BoneColor, transform.forward, boneScale * skeletonRenderScale);
}
}
public static void DrawBone (Transform transform, Bone b, float boneScale, Color color, float skeletonRenderScale = 1f) {
var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0);
float length = b.Data.Length;
if (length > 0) {
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
Vector3 scale = Vector3.one * length * b.WorldScaleX;
const float my = 1.5f;
scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my, my);
SpineHandles.GetBoneMaterial(color).SetPass(0);
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
} else {
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward, boneScale * skeletonRenderScale);
}
}
public static void DrawPaths (Transform transform, Skeleton skeleton) {
foreach (Slot s in skeleton.DrawOrder) {
var p = s.Attachment as PathAttachment;
if (p != null) SpineHandles.DrawPath(s, p, transform, true);
}
}
static float[] pathVertexBuffer;
public static void DrawPath (Slot s, PathAttachment p, Transform t, bool includeName) {
int worldVerticesLength = p.WorldVerticesLength;
if (pathVertexBuffer == null || pathVertexBuffer.Length < worldVerticesLength)
pathVertexBuffer = new float[worldVerticesLength];
float[] pv = pathVertexBuffer;
p.ComputeWorldVertices(s, pv);
var ocolor = Handles.color;
Handles.color = SpineHandles.PathColor;
Matrix4x4 m = t.localToWorldMatrix;
const int step = 6;
int n = worldVerticesLength - step;
Vector3 p0, p1, p2, p3;
for (int i = 2; i < n; i += step) {
p0 = m.MultiplyPoint(new Vector3(pv[i], pv[i+1]));
p1 = m.MultiplyPoint(new Vector3(pv[i+2], pv[i+3]));
p2 = m.MultiplyPoint(new Vector3(pv[i+4], pv[i+5]));
p3 = m.MultiplyPoint(new Vector3(pv[i+6], pv[i+7]));
DrawCubicBezier(p0, p1, p2, p3);
}
n += step;
if (p.Closed) {
p0 = m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3]));
p1 = m.MultiplyPoint(new Vector3(pv[n - 2], pv[n - 1]));
p2 = m.MultiplyPoint(new Vector3(pv[0], pv[1]));
p3 = m.MultiplyPoint(new Vector3(pv[2], pv[3]));
DrawCubicBezier(p0, p1, p2, p3);
}
const float endCapSize = 0.05f;
Vector3 firstPoint = m.MultiplyPoint(new Vector3(pv[2], pv[3]));
SpineHandles.DrawDot(firstPoint, endCapSize);
//if (!p.Closed) SpineHandles.DrawDot(m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3])), endCapSize);
if (includeName) Handles.Label(firstPoint + new Vector3(0,0.1f), p.Name, PathNameStyle);
Handles.color = ocolor;
}
public static void DrawDot (Vector3 position, float size) {
Handles.DotHandleCap(0, position, Quaternion.identity, size * HandleUtility.GetHandleSize(position), EventType.Ignore); //Handles.DotCap(0, position, Quaternion.identity, size * HandleUtility.GetHandleSize(position));
}
public static void DrawBoundingBoxes (Transform transform, Skeleton skeleton) {
foreach (var slot in skeleton.Slots) {
var bba = slot.Attachment as BoundingBoxAttachment;
if (bba != null) SpineHandles.DrawBoundingBox(slot, bba, transform);
}
}
public static void DrawBoundingBox (Slot slot, BoundingBoxAttachment box, Transform t) {
if (box.Vertices.Length <= 2) return; // Handle cases where user creates a BoundingBoxAttachment but doesn't actually define it.
var worldVerts = new float[box.WorldVerticesLength];
box.ComputeWorldVertices(slot, worldVerts);
Handles.color = Color.green;
Vector3 lastVert = Vector3.zero;
Vector3 vert = Vector3.zero;
Vector3 firstVert = t.TransformPoint(new Vector3(worldVerts[0], worldVerts[1], 0));
for (int i = 0; i < worldVerts.Length; i += 2) {
vert.x = worldVerts[i];
vert.y = worldVerts[i + 1];
vert.z = 0;
vert = t.TransformPoint(vert);
if (i > 0)
Handles.DrawLine(lastVert, vert);
lastVert = vert;
}
Handles.DrawLine(lastVert, firstVert);
}
public static void DrawPointAttachment (Bone bone, PointAttachment pointAttachment, Transform skeletonTransform) {
if (bone == null) return;
if (pointAttachment == null) return;
Vector2 localPos;
pointAttachment.ComputeWorldPosition(bone, out localPos.x, out localPos.y);
float localRotation = pointAttachment.ComputeWorldRotation(bone);
Matrix4x4 m = Matrix4x4.TRS(localPos, Quaternion.Euler(0, 0, localRotation), Vector3.one) * Matrix4x4.TRS(Vector3.right * 0.25f, Quaternion.identity, Vector3.one);
DrawBoneCircle(skeletonTransform.TransformPoint(localPos), SpineHandles.PointColor, Vector3.back, 1.3f);
DrawArrowhead(skeletonTransform.localToWorldMatrix * m);
}
public static void DrawConstraints (Transform transform, Skeleton skeleton, float skeletonRenderScale = 1f) {
Vector3 targetPos;
Vector3 pos;
bool active;
Color handleColor;
const float Thickness = 4f;
Vector3 normal = transform.forward;
// Transform Constraints
handleColor = SpineHandles.TransformContraintColor;
foreach (var tc in skeleton.TransformConstraints) {
var targetBone = tc.Target;
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale);
if (tc.TranslateMix > 0) {
if (tc.TranslateMix != 1f) {
Handles.color = handleColor;
foreach (var b in tc.Bones) {
pos = b.GetWorldPosition(transform, skeletonRenderScale);
Handles.DrawDottedLine(targetPos, pos, Thickness);
}
}
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f * skeletonRenderScale);
Handles.color = handleColor;
SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform, skeletonRenderScale);
}
}
// IK Constraints
handleColor = SpineHandles.IkColor;
foreach (var ikc in skeleton.IkConstraints) {
Bone targetBone = ikc.Target;
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale);
var bones = ikc.Bones;
active = ikc.Mix > 0;
if (active) {
pos = bones.Items[0].GetWorldPosition(transform, skeletonRenderScale);
switch (bones.Count) {
case 1: {
Handles.color = handleColor;
Handles.DrawLine(targetPos, pos);
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal);
var m = bones.Items[0].GetMatrix4x4();
m.m03 = targetBone.WorldX * skeletonRenderScale;
m.m13 = targetBone.WorldY * skeletonRenderScale;
SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m);
break;
}
case 2: {
Bone childBone = bones.Items[1];
Vector3 child = childBone.GetWorldPosition(transform, skeletonRenderScale);
Handles.color = handleColor;
Handles.DrawLine(child, pos);
Handles.DrawLine(targetPos, child);
SpineHandles.DrawBoneCircle(pos, handleColor, normal, 0.5f);
SpineHandles.DrawBoneCircle(child, handleColor, normal, 0.5f);
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal);
var m = childBone.GetMatrix4x4();
m.m03 = targetBone.WorldX * skeletonRenderScale;
m.m13 = targetBone.WorldY * skeletonRenderScale;
SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m);
break;
}
}
}
//Handles.Label(targetPos, ikc.Data.Name, SpineHandles.BoneNameStyle);
}
// Path Constraints
handleColor = SpineHandles.PathColor;
foreach (var pc in skeleton.PathConstraints) {
active = pc.TranslateMix > 0;
if (active)
foreach (var b in pc.Bones)
SpineHandles.DrawBoneCircle(b.GetWorldPosition(transform, skeletonRenderScale), handleColor, normal, 1f * skeletonRenderScale);
}
}
static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) {
scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0));
Handles.DrawLine(position + new Vector3(0, -scale), position + new Vector3(0, scale));
}
static void DrawCrosshairs (Vector3 position, float scale, float a, float b, float c, float d, Transform transform, float skeletonRenderScale = 1f) {
scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
var xOffset = (Vector3)(new Vector2(a, c).normalized * scale);
var yOffset = (Vector3)(new Vector2(b, d).normalized * scale);
xOffset = transform.TransformDirection(xOffset);
yOffset = transform.TransformDirection(yOffset);
Handles.DrawLine(position + xOffset, position - xOffset);
Handles.DrawLine(position + yOffset, position - yOffset);
}
static void DrawArrowhead2D (Vector3 pos, float localRotation, float scale = 1f) {
scale *= SpineEditorUtilities.Preferences.handleScale;
SpineHandles.IKMaterial.SetPass(0);
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, Matrix4x4.TRS(pos, Quaternion.Euler(0, 0, localRotation), new Vector3(scale, scale, scale)));
}
static void DrawArrowhead (Vector3 pos, Quaternion worldQuaternion) {
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, pos, worldQuaternion, 0);
}
static void DrawArrowhead (Matrix4x4 m) {
float s = SpineEditorUtilities.Preferences.handleScale;
m.m00 *= s;
m.m01 *= s;
m.m02 *= s;
m.m10 *= s;
m.m11 *= s;
m.m12 *= s;
m.m20 *= s;
m.m21 *= s;
m.m22 *= s;
SpineHandles.IKMaterial.SetPass(0);
Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, m);
}
static void DrawBoneCircle (Vector3 pos, Color outlineColor, Vector3 normal, float scale = 1f) {
scale *= SpineEditorUtilities.Preferences.handleScale;
Color o = Handles.color;
Handles.color = outlineColor;
float firstScale = 0.08f * scale;
Handles.DrawSolidDisc(pos, normal, firstScale);
const float Thickness = 0.03f;
float secondScale = firstScale - (Thickness * SpineEditorUtilities.Preferences.handleScale * scale);
if (secondScale > 0f) {
Handles.color = new Color(0.3f, 0.3f, 0.3f, 0.5f);
Handles.DrawSolidDisc(pos, normal, secondScale);
}
Handles.color = o;
}
internal static void DrawCubicBezier (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
Handles.DrawBezier(p0, p3, p1, p2, Handles.color, Texture2D.whiteTexture, 2f);
// const float dotSize = 0.01f;
// Quaternion q = Quaternion.identity;
// Handles.DotCap(0, p0, q, dotSize);
// Handles.DotCap(0, p1, q, dotSize);
// Handles.DotCap(0, p2, q, dotSize);
// Handles.DotCap(0, p3, q, dotSize);
// Handles.DrawLine(p0, p1);
// Handles.DrawLine(p3, p2);
}
}
}
@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: f4c97e41d3d90e24bbb40d634e6cc336
timeCreated: 1563313275
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,317 +0,0 @@
/******************************************************************************
* 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_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
#if UNITY_2018_3_OR_NEWER
#define NEW_PREFERENCES_SETTINGS_PROVIDER
#endif
using UnityEngine;
using UnityEditor;
using System.Threading;
namespace Spine.Unity.Editor {
public class SpinePreferences : ScriptableObject {
#if NEW_PREFERENCES_SETTINGS_PROVIDER
static int wasPreferencesDirCreated = 0;
static int wasPreferencesAssetCreated = 0;
#endif
public const string SPINE_SETTINGS_ASSET_PATH = "Assets/Editor/SpineSettings.asset";
#if SPINE_TK2D
internal const float DEFAULT_DEFAULT_SCALE = 1f;
#else
internal const float DEFAULT_DEFAULT_SCALE = 0.01f;
#endif
public float defaultScale = DEFAULT_DEFAULT_SCALE;
internal const float DEFAULT_DEFAULT_MIX = 0.2f;
public float defaultMix = DEFAULT_DEFAULT_MIX;
internal const string DEFAULT_DEFAULT_SHADER = "Spine/Skeleton";
public string defaultShader = DEFAULT_DEFAULT_SHADER;
internal const float DEFAULT_DEFAULT_ZSPACING = 0f;
public float defaultZSpacing = DEFAULT_DEFAULT_ZSPACING;
internal const bool DEFAULT_DEFAULT_INSTANTIATE_LOOP = true;
public bool defaultInstantiateLoop = DEFAULT_DEFAULT_INSTANTIATE_LOOP;
internal const bool DEFAULT_SHOW_HIERARCHY_ICONS = true;
public bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS;
internal const bool DEFAULT_SET_TEXTUREIMPORTER_SETTINGS = true;
public bool setTextureImporterSettings = DEFAULT_SET_TEXTUREIMPORTER_SETTINGS;
internal const string DEFAULT_TEXTURE_SETTINGS_REFERENCE = "";
public string textureSettingsReference = DEFAULT_TEXTURE_SETTINGS_REFERENCE;
public bool UsesPMAWorkflow {
get {
return IsPMAWorkflow(textureSettingsReference);
}
}
public static bool IsPMAWorkflow(string textureSettingsReference) {
if (textureSettingsReference == null)
return true;
string settingsReference = textureSettingsReference.ToLower();
if (settingsReference.Contains("straight") || !settingsReference.Contains("pma"))
return false;
return true;
}
public const string DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL = "SkeletonPMAMultiply";
public const string DEFAULT_BLEND_MODE_SCREEN_MATERIAL = "SkeletonPMAScreen";
public const string DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL = "SkeletonPMAAdditive";
public Material blendModeMaterialMultiply = null;
public Material blendModeMaterialScreen = null;
public Material blendModeMaterialAdditive = null;
public string FindPathOfAsset (string assetName) {
string typeSearchString = assetName;
string[] guids = AssetDatabase.FindAssets(typeSearchString);
if (guids.Length > 0) {
return AssetDatabase.GUIDToAssetPath(guids[0]);
}
return null;
}
public Material BlendModeMaterialMultiply {
get {
if (blendModeMaterialMultiply == null) {
string path = FindPathOfAsset(DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL);
blendModeMaterialMultiply = AssetDatabase.LoadAssetAtPath<Material>(path);
}
return blendModeMaterialMultiply;
}
}
public Material BlendModeMaterialScreen {
get {
if (blendModeMaterialScreen == null) {
string path = FindPathOfAsset(DEFAULT_BLEND_MODE_SCREEN_MATERIAL);
blendModeMaterialScreen = AssetDatabase.LoadAssetAtPath<Material>(path);
}
return blendModeMaterialScreen;
}
}
public Material BlendModeMaterialAdditive {
get {
if (blendModeMaterialAdditive == null) {
string path = FindPathOfAsset(DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL);
blendModeMaterialAdditive = AssetDatabase.LoadAssetAtPath<Material>(path);
}
return blendModeMaterialAdditive;
}
}
internal const bool DEFAULT_ATLASTXT_WARNING = true;
public bool atlasTxtImportWarning = DEFAULT_ATLASTXT_WARNING;
internal const bool DEFAULT_TEXTUREIMPORTER_WARNING = true;
public bool textureImporterWarning = DEFAULT_TEXTUREIMPORTER_WARNING;
internal const bool DEFAULT_COMPONENTMATERIAL_WARNING = true;
public bool componentMaterialWarning = DEFAULT_COMPONENTMATERIAL_WARNING;
public const float DEFAULT_MIPMAPBIAS = -0.5f;
public const bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true;
public bool autoReloadSceneSkeletons = DEFAULT_AUTO_RELOAD_SCENESKELETONS;
public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
internal const float DEFAULT_SCENE_ICONS_SCALE = 1f;
[Range(0.01f, 2f)]
public float handleScale = DEFAULT_SCENE_ICONS_SCALE;
public const bool DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME = true;
public bool mecanimEventIncludeFolderName = DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
// Timeline extension module
public const bool DEFAULT_TIMELINE_USE_BLEND_DURATION = true;
public bool timelineUseBlendDuration = DEFAULT_TIMELINE_USE_BLEND_DURATION;
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static void Load () {
GetOrCreateSettings();
}
static SpinePreferences settings = null;
internal static SpinePreferences GetOrCreateSettings () {
if (settings != null)
return settings;
settings = AssetDatabase.LoadAssetAtPath<SpinePreferences>(SPINE_SETTINGS_ASSET_PATH);
if (settings == null)
settings = FindSpinePreferences();
if (settings == null)
{
settings = ScriptableObject.CreateInstance<SpinePreferences>();
SpineEditorUtilities.OldPreferences.CopyOldToNewPreferences(ref settings);
// Multiple threads may be calling this method during import, creating the folder
// multiple times with ascending number suffix. Atomic wasPreferencesDirCreated int
// variable is used to prevent any redundant create operations.
if (!AssetDatabase.IsValidFolder("Assets/Editor") && Interlocked.Exchange(ref wasPreferencesDirCreated, 1) == 0)
AssetDatabase.CreateFolder("Assets", "Editor");
if (Interlocked.Exchange(ref wasPreferencesAssetCreated, 1) == 0)
AssetDatabase.CreateAsset(settings, SPINE_SETTINGS_ASSET_PATH);
}
return settings;
}
static SpinePreferences FindSpinePreferences () {
string typeSearchString = " t:SpinePreferences";
string[] guids = AssetDatabase.FindAssets(typeSearchString);
foreach (string guid in guids) {
string path = AssetDatabase.GUIDToAssetPath(guid);
var preferences = AssetDatabase.LoadAssetAtPath<SpinePreferences>(path);
if (preferences != null)
return preferences;
}
return null;
}
public static void HandlePreferencesGUI (SerializedObject settings) {
float prevLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 250;
using (new EditorGUI.IndentLevelScope()) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(settings.FindProperty("showHierarchyIcons"), new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."));
if (EditorGUI.EndChangeCheck()) {
#if NEWPLAYMODECALLBACKS
SpineEditorUtilities.HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
SpineEditorUtilities.HierarchyHandler.IconsOnPlaymodeStateChanged();
#endif
}
EditorGUILayout.PropertyField(settings.FindProperty("autoReloadSceneSkeletons"), new GUIContent("Auto-reload scene components", "Reloads Skeleton components in the scene whenever their SkeletonDataAsset is modified. This makes it so changes in the SkeletonDataAsset inspector are immediately reflected. This may be slow when your scenes have large numbers of SkeletonRenderers or SkeletonGraphic."));
EditorGUILayout.Separator();
EditorGUILayout.LabelField("Auto-Import Settings", EditorStyles.boldLabel);
{
SpineEditorUtilities.FloatPropertyField(settings.FindProperty("defaultMix"), new GUIContent("Default Mix", "The Default Mix Duration for newly imported SkeletonDataAssets."), min: 0f);
SpineEditorUtilities.FloatPropertyField(settings.FindProperty("defaultScale"), new GUIContent("Default SkeletonData Scale", "The Default skeleton import scale for newly imported SkeletonDataAssets."), min: 0.0000001f);
SpineEditorUtilities.ShaderPropertyField(settings.FindProperty("defaultShader"), new GUIContent("Default Shader"), SpinePreferences.DEFAULT_DEFAULT_SHADER);
EditorGUILayout.PropertyField(settings.FindProperty("setTextureImporterSettings"), new GUIContent("Apply Atlas Texture Settings", "Apply reference settings for Texture Importers."));
var textureSettingsRef = settings.FindProperty("textureSettingsReference");
SpineEditorUtilities.PresetAssetPropertyField(textureSettingsRef, new GUIContent("Atlas Texture Settings", "Apply the selected texture import settings at newly imported atlas textures. When exporting atlas textures from Spine with \"Premultiply alpha\" enabled (the default), you can leave it at \"PMATexturePreset\". If you have disabled \"Premultiply alpha\", set it to \"StraightAlphaTexturePreset\". You can also create your own TextureImporter Preset asset and assign it here."));
if (string.IsNullOrEmpty(textureSettingsRef.stringValue)) {
var pmaTextureSettingsReferenceGUIDS = AssetDatabase.FindAssets("PMATexturePreset");
if (pmaTextureSettingsReferenceGUIDS.Length > 0) {
var assetPath = AssetDatabase.GUIDToAssetPath(pmaTextureSettingsReferenceGUIDS[0]);
if (!string.IsNullOrEmpty(assetPath))
textureSettingsRef.stringValue = assetPath;
}
}
EditorGUILayout.PropertyField(settings.FindProperty("blendModeMaterialAdditive"), new GUIContent("Additive Material", "Additive blend mode Material template."));
EditorGUILayout.PropertyField(settings.FindProperty("blendModeMaterialMultiply"), new GUIContent("Multiply Material", "Multiply blend mode Material template."));
EditorGUILayout.PropertyField(settings.FindProperty("blendModeMaterialScreen"), new GUIContent("Screen Material", "Screen blend mode Material template."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Warnings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(settings.FindProperty("atlasTxtImportWarning"), new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found."));
EditorGUILayout.PropertyField(settings.FindProperty("textureImporterWarning"), new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts."));
EditorGUILayout.PropertyField(settings.FindProperty("componentMaterialWarning"), new GUIContent("Component & Material Warning", "Log a warning and recommendation whenever Component and Material settings are not compatible."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor Instantiation", EditorStyles.boldLabel);
{
EditorGUILayout.Slider(settings.FindProperty("defaultZSpacing"), -0.1f, 0f, new GUIContent("Default Slot Z-Spacing"));
EditorGUILayout.PropertyField(settings.FindProperty("defaultInstantiateLoop"), new GUIContent("Default Loop", "Spawn Spine GameObjects with loop enabled."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Mecanim Bake Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(settings.FindProperty("mecanimEventIncludeFolderName"), new GUIContent("Include Folder Name in Event", "When enabled, Mecanim events will call methods named 'FolderNameEventName', when disabled it will call 'EventName'."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
{
EditorGUI.BeginChangeCheck();
var scaleProperty = settings.FindProperty("handleScale");
EditorGUILayout.PropertyField(scaleProperty, new GUIContent("Editor Bone Scale"));
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetFloat(SpinePreferences.SCENE_ICONS_SCALE_KEY, scaleProperty.floatValue);
SceneView.RepaintAll();
}
}
#if SPINE_TK2D_DEFINE
bool isTK2DDefineSet = true;
#else
bool isTK2DDefineSet = false;
#endif
bool isTK2DAllowed = SpineEditorUtilities.SpineTK2DEditorUtility.IsTK2DAllowed;
if (SpineEditorUtilities.SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) {
GUILayout.Space(20);
EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel);
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Define TK2D");
if (isTK2DAllowed && GUILayout.Button("Enable", GUILayout.Width(64)))
SpineEditorUtilities.SpineTK2DEditorUtility.EnableTK2D();
if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineEditorUtilities.SpineTK2DEditorUtility.DisableTK2D();
}
#if !SPINE_TK2D_DEFINE
if (!isTK2DAllowed) {
EditorGUILayout.LabelField("To allow TK2D support, please modify line 67 in", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Spine/Editor/spine-unity/Editor/Util./BuildSettings.cs", EditorStyles.boldLabel);
}
#endif
}
GUILayout.Space(20);
EditorGUILayout.LabelField("Timeline Extension", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(settings.FindProperty("timelineUseBlendDuration"), new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
}
}
EditorGUIUtility.labelWidth = prevLabelWidth;
}
#endif // NEW_PREFERENCES_SETTINGS_PROVIDER
}
}
@@ -1,170 +0,0 @@
/******************************************************************************
* 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 UnityEditor;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
using Icons = SpineEditorUtilities.Icons;
public class SpriteAtlasImportWindow : EditorWindow {
const bool IsUtilityWindow = false;
[MenuItem("Window/Spine/SpriteAtlas Import", false, 5000)]
public static void Init (MenuCommand command) {
var window = EditorWindow.GetWindow<SpriteAtlasImportWindow>(IsUtilityWindow);
window.minSize = new Vector2(284f, 256f);
window.maxSize = new Vector2(500f, 256f);
window.titleContent = new GUIContent("Spine SpriteAtlas Import", Icons.spine);
window.Show();
}
public UnityEngine.U2D.SpriteAtlas spriteAtlasAsset;
public TextAsset skeletonDataFile;
public SpineSpriteAtlasAsset spineSpriteAtlasAsset;
SerializedObject so;
void OnEnable () {
if (!SpineSpriteAtlasAsset.AnySpriteAtlasNeedsRegionsLoaded())
return;
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
EditorApplication.update += SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
void OnDisable () {
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
void OnGUI () {
so = so ?? new SerializedObject(this);
EditorGUIUtility.wideMode = true;
EditorGUILayout.LabelField("Spine SpriteAtlas Import", EditorStyles.boldLabel);
using (new SpineInspectorUtility.BoxScope()) {
EditorGUI.BeginChangeCheck();
var spriteAtlasAssetProperty = so.FindProperty("spriteAtlasAsset");
EditorGUILayout.PropertyField(spriteAtlasAssetProperty, new GUIContent("SpriteAtlas", EditorGUIUtility.IconContent("SpriteAtlas Icon").image));
if (EditorGUI.EndChangeCheck()) {
so.ApplyModifiedProperties();
if (spriteAtlasAsset != null) {
if (AssetUtility.SpriteAtlasSettingsNeedAdjustment(spriteAtlasAsset)) {
AssetUtility.AdjustSpriteAtlasSettings(spriteAtlasAsset);
}
GenerateAssetsFromSpriteAtlas(spriteAtlasAsset);
}
}
var spineSpriteAtlasAssetProperty = so.FindProperty("spineSpriteAtlasAsset");
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spineSpriteAtlasAssetProperty, new GUIContent("SpineSpriteAtlasAsset", EditorGUIUtility.IconContent("ScriptableObject Icon").image));
if (spineSpriteAtlasAssetProperty.objectReferenceValue == null) {
spineSpriteAtlasAssetProperty.objectReferenceValue = spineSpriteAtlasAsset = FindSpineSpriteAtlasAsset(spriteAtlasAsset);
}
if (EditorGUI.EndChangeCheck()) {
so.ApplyModifiedProperties();
}
EditorGUILayout.Space();
using (new EditorGUI.DisabledScope(spineSpriteAtlasAsset == null)) {
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Load regions by entering Play mode"))) {
GenerateAssetsFromSpriteAtlas(spriteAtlasAsset);
SpineSpriteAtlasAsset.UpdateByStartingEditorPlayMode();
}
}
using (new SpineInspectorUtility.BoxScope()) {
if (spriteAtlasAsset == null) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please assign SpriteAtlas file.", Icons.warning), GUILayout.Height(46));
}
else if (spineSpriteAtlasAsset == null || spineSpriteAtlasAsset.RegionsNeedLoading) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please hit 'Load regions ..' to load\nregion info. Play mode is started\nand stopped automatically.", Icons.warning), GUILayout.Height(54));
}
else {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("SpriteAtlas imported\nsuccessfully.", Icons.spine), GUILayout.Height(46));
}
}
}
bool isAtlasComplete = (spineSpriteAtlasAsset != null && !spineSpriteAtlasAsset.RegionsNeedLoading);
bool canImportSkeleton = (spriteAtlasAsset != null && skeletonDataFile != null);
using (new SpineInspectorUtility.BoxScope()) {
using (new EditorGUI.DisabledScope(!isAtlasComplete)) {
var skeletonDataAssetProperty = so.FindProperty("skeletonDataFile");
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(skeletonDataAssetProperty, SpineInspectorUtility.TempContent("Skeleton json/skel file", Icons.spine));
if (EditorGUI.EndChangeCheck()) {
so.ApplyModifiedProperties();
}
EditorGUILayout.Space();
}
using (new EditorGUI.DisabledScope(!canImportSkeleton)) {
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Import Skeleton"))) {
//AssetUtility.IngestSpriteAtlas(spriteAtlasAsset, null);
string skeletonPath = AssetDatabase.GetAssetPath(skeletonDataFile);
string[] skeletons = new string[] { skeletonPath };
AssetUtility.ImportSpineContent(skeletons, null);
}
}
}
}
void GenerateAssetsFromSpriteAtlas (UnityEngine.U2D.SpriteAtlas spriteAtlasAsset) {
AssetUtility.IngestSpriteAtlas(spriteAtlasAsset, null);
string texturePath;
if (AssetUtility.GeneratePngFromSpriteAtlas(spriteAtlasAsset, out texturePath)) {
Debug.Log(string.Format("Generated SpriteAtlas texture '{0}'", texturePath), spriteAtlasAsset);
}
}
SpineSpriteAtlasAsset FindSpineSpriteAtlasAsset (UnityEngine.U2D.SpriteAtlas spriteAtlasAsset) {
string path = AssetDatabase.GetAssetPath(spriteAtlasAsset).Replace(".spriteatlas", AssetUtility.SpriteAtlasSuffix + ".asset");
if (System.IO.File.Exists(path)) {
return AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(path);
}
return null;
}
SkeletonDataAsset FindSkeletonDataAsset (TextAsset skeletonDataFile) {
string path = AssetDatabase.GetAssetPath(skeletonDataFile);
path = path.Replace(".json", AssetUtility.SkeletonDataSuffix + ".asset");
path = path.Replace(".skel.bytes", AssetUtility.SkeletonDataSuffix + ".asset");
if (System.IO.File.Exists(path)) {
return AssetDatabase.LoadAssetAtPath<SkeletonDataAsset>(path);
}
return null;
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a5b99b091defeef439a0cb8c99fd8a51
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: eb646ac6e394e534b80d5cac61478488
guid: 6351693f94cbf774182d4b3f2a756a43
folderAsset: yes
timeCreated: 1563305058
timeCreated: 1527569401
licenseType: Free
DefaultImporter:
userData:
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: b6badf2758b1ea44e8c5ec62ef338e22
guid: b7f013ad20f0af34e913e21b44466777
folderAsset: yes
timeCreated: 1563305058
timeCreated: 1455492480
licenseType: Free
DefaultImporter:
userData:
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
@@ -33,7 +33,6 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
@@ -56,7 +55,7 @@ namespace Spine.Unity.Editor {
}
}
void InitializeEditor () {
void OnEnable () {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
slotName = serializedObject.FindProperty("slotName");
isTrigger = serializedObject.FindProperty("isTrigger");
@@ -65,17 +64,12 @@ namespace Spine.Unity.Editor {
}
public override void OnInspectorGUI () {
#if !NEW_PREFAB_SYSTEM
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#else
bool isInspectingPrefab = false;
#endif
// Note: when calling InitializeEditor() in OnEnable, it throws exception
// "SerializedObjectNotCreatableException: Object at index 0 is null".
InitializeEditor();
// Try to auto-assign SkeletonRenderer field.
if (skeletonRenderer.objectReferenceValue == null) {
var foundSkeletonRenderer = follower.GetComponentInParent<SkeletonRenderer>();
@@ -86,7 +80,6 @@ namespace Spine.Unity.Editor {
skeletonRenderer.objectReferenceValue = foundSkeletonRenderer;
serializedObject.ApplyModifiedProperties();
InitializeEditor();
}
var skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
@@ -94,7 +87,7 @@ namespace Spine.Unity.Editor {
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollower to a separate child GameObject of the Spine GameObject.", MessageType.Warning);
if (GUILayout.Button(new GUIContent("Move BoundingBoxFollower to new GameObject", Icons.boundingBox), GUILayout.Height(30f))) {
if (GUILayout.Button(new GUIContent("Move BoundingBoxFollower to new GameObject", Icons.boundingBox), GUILayout.Height(50f))) {
AddBoundingBoxFollowerChild(skeletonRendererValue, follower);
DestroyImmediate(follower);
return;
@@ -108,7 +101,6 @@ namespace Spine.Unity.Editor {
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
#if !NEW_PREFAB_SYSTEM
if (!isInspectingPrefab)
rebuildRequired = true;
@@ -126,7 +118,6 @@ namespace Spine.Unity.Editor {
if (clearStateChanged || triggerChanged) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
if (triggerChanged)
foreach (var col in follower.colliderTable.Values)
col.isTrigger = isTrigger.boolValue;
@@ -161,8 +152,6 @@ namespace Spine.Unity.Editor {
}
if (follower.Slot == null)
follower.Initialize(false);
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
if (!hasBoneFollower) {
bool buttonDisabled = follower.Slot == null;
@@ -199,21 +188,11 @@ namespace Spine.Unity.Editor {
var go = AddBoundingBoxFollowerChild((SkeletonRenderer)command.context);
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollower");
}
[MenuItem("CONTEXT/SkeletonRenderer/Add all BoundingBoxFollower GameObjects")]
static void AddAllBoundingBoxFollowerChildren (MenuCommand command) {
var objects = AddAllBoundingBoxFollowerChildren((SkeletonRenderer)command.context);
foreach (var go in objects)
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollower");
}
#endregion
public static GameObject AddBoundingBoxFollowerChild (SkeletonRenderer skeletonRenderer,
BoundingBoxFollower original = null, string name = "BoundingBoxFollower",
string slotName = null) {
var go = EditorInstantiation.NewGameObject(name, true);
go.transform.SetParent(skeletonRenderer.transform, false);
static GameObject AddBoundingBoxFollowerChild (SkeletonRenderer sr, BoundingBoxFollower original = null) {
var go = SpineEditorUtilities.EditorInstantiation.NewGameObject("BoundingBoxFollower");
go.transform.SetParent(sr.transform, false);
var newFollower = go.AddComponent<BoundingBoxFollower>();
if (original != null) {
@@ -221,40 +200,16 @@ namespace Spine.Unity.Editor {
newFollower.isTrigger = original.isTrigger;
newFollower.clearStateOnDisable = original.clearStateOnDisable;
}
if (slotName != null)
newFollower.slotName = slotName;
newFollower.skeletonRenderer = skeletonRenderer;
newFollower.skeletonRenderer = sr;
newFollower.Initialize();
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
return go;
}
public static List<GameObject> AddAllBoundingBoxFollowerChildren (
SkeletonRenderer skeletonRenderer, BoundingBoxFollower original = null) {
List<GameObject> createdGameObjects = new List<GameObject>();
foreach (var skin in skeletonRenderer.Skeleton.Data.Skins) {
var attachments = skin.Attachments;
foreach (var entry in attachments) {
var boundingBoxAttachment = entry.Value as BoundingBoxAttachment;
if (boundingBoxAttachment == null)
continue;
int slotIndex = entry.Key.SlotIndex;
var slot = skeletonRenderer.Skeleton.Slots.Items[slotIndex];
string slotName = slot.Data.Name;
GameObject go = AddBoundingBoxFollowerChild(skeletonRenderer,
original, boundingBoxAttachment.Name, slotName);
var boneFollower = go.AddComponent<BoneFollower>();
boneFollower.skeletonRenderer = skeletonRenderer;
boneFollower.SetBone(slot.Data.BoneData.Name);
createdGameObjects.Add(go);
}
}
return createdGameObjects;
}
}
}
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 33c080d1c093a2c45b6c72c17a557067
guid: ffde24e0e567a61418f76218f8cffb4c
folderAsset: yes
timeCreated: 1563304704
timeCreated: 1527569418
licenseType: Free
DefaultImporter:
userData:
@@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 52627c17e6dd4bf4dad4bdfc490ce823
guid: 99abd7478ddde384cbf86f2ecd396900
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,16 +15,16 @@
* 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.
* 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.
*****************************************************************************/
#define SPINE_OPTIONAL_MATERIALOVERRIDE
@@ -37,7 +37,7 @@ using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Spine.Unity.Examples;
using Spine.Unity.Modules;
namespace Spine.Unity.Editor {
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 0134640f881c8d24d812a6f9af9d0761
guid: a5ca7a6f2b7e25646ad2f5776178bf78
folderAsset: yes
timeCreated: 1563304704
timeCreated: 1527569438
licenseType: Free
DefaultImporter:
userData:
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 7220dc1e8d545e849a2eb63e8633349b
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,37 @@
/******************************************************************************
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
using UnityEngine;
using UnityEditor;
namespace Spine.Unity.Modules {
public class SkeletonRagdoll2DInspector {}
}
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: efbbf90926e217c40831926fce374905
timeCreated: 1573666328
guid: b6dd0b99faf3aeb4d803eb9989cb369c
timeCreated: 1431741936
licenseType: Free
MonoImporter:
serializedVersion: 2
@@ -0,0 +1,46 @@
/******************************************************************************
* 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
using UnityEngine;
using UnityEditor;
namespace Spine.Unity.Modules {
public class SkeletonRagdollInspector : UnityEditor.Editor {
[CustomPropertyDrawer(typeof(SkeletonRagdoll.LayerFieldAttribute))]
public class LayerFieldPropertyDrawer : PropertyDrawer {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
property.intValue = EditorGUI.LayerField(position, label, property.intValue);
}
}
}
}
@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 49377c72c37e2c149b106c260a241f3c
timeCreated: 1563311043
guid: c95a670c56447c644a0f062e4cdd448e
timeCreated: 1431740230
licenseType: Free
MonoImporter:
serializedVersion: 2
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 615182d5e489bf3478299e5bbf15dc23
guid: f9ef69c370f1b0f4db091a85df7f2c96
folderAsset: yes
timeCreated: 1573830740
timeCreated: 1527569612
licenseType: Free
DefaultImporter:
userData:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7bebbafa671002646b3a7267b32a0d60
folderAsset: yes
timeCreated: 1479419399
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
* 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
@@ -15,36 +15,27 @@
* 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.
* 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 UnityEditor;
using Spine.Unity;
using SpineInspectorUtility = Spine.Unity.Editor.SpineInspectorUtility;
public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
public class SpineSpriteShaderGUI : ShaderGUI {
static readonly string kShaderVertexLit = "Spine/Sprite/Vertex Lit";
static readonly string kShaderPixelLit = "Spine/Sprite/Pixel Lit";
static readonly string kShaderUnlit = "Spine/Sprite/Unlit";
static readonly string kShaderVertexLitOutline = "Spine/Outline/Sprite/Vertex Lit";
static readonly string kShaderPixelLitOutline = "Spine/Outline/Sprite/Pixel Lit";
static readonly string kShaderUnlitOutline = "Spine/Outline/Sprite/Unlit";
static readonly string kShaderLitLW = "Lightweight Render Pipeline/Spine/Sprite";
static readonly string kShaderLitURP = "Universal Render Pipeline/Spine/Sprite";
static readonly string kShaderLitURP2D = "Universal Render Pipeline/2D/Spine/Sprite";
static readonly int kSolidQueue = 2000;
static readonly int kAlphaTestQueue = 2450;
static readonly int kTransparentQueue = 3000;
@@ -63,9 +54,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
VertexLit,
PixelLit,
Unlit,
LitLightweight,
LitUniversal,
LitUniversal2D
};
private enum eCulling {
@@ -78,22 +66,12 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
MeshNormals = -1,
FixedNormalsViewSpace = 0,
FixedNormalsModelSpace = 1,
FixedNormalsWorldSpace = 2
};
private enum eDiffuseRampMode {
NoRampSpecified = -1,
FullRangeHard = 0,
FullRangeSoft = 1,
OldHard = 2,
OldSoft = 3,
DefaultRampMode = OldHard
};
MaterialEditor _materialEditor;
MaterialProperty _mainTexture = null;
MaterialProperty _color = null;
MaterialProperty _maskTexture = null;
MaterialProperty _pixelSnap = null;
@@ -130,7 +108,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
MaterialProperty _smoothnessScale = null;
static GUIContent _albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
static GUIContent _maskText = new GUIContent("Light Mask", "Light mask texture (secondary Sprite texture)");
static GUIContent _altAlbedoText = new GUIContent("Secondary Albedo", "When a secondary albedo texture is set the albedo will be a blended mix of the two textures based on the blend value.");
static GUIContent _metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
static GUIContent _smoothnessText = new GUIContent("Smoothness", "Smoothness value");
@@ -143,19 +120,15 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
static GUIContent _depthText = new GUIContent("Write to Depth", "Write to Depth Buffer by clipping alpha.");
static GUIContent _depthAlphaCutoffText = new GUIContent("Depth Alpha Cutoff", "Threshold for depth write alpha cutoff");
static GUIContent _shadowAlphaCutoffText = new GUIContent("Shadow Alpha Cutoff", "Threshold for shadow alpha cutoff");
static GUIContent _receiveShadowsText = new GUIContent("Receive Shadows", "When enabled, other GameObjects can cast shadows onto this GameObject. 'Write to Depth' has to be enabled in Lightweight RP.");
static GUIContent _fixedNormalText = new GUIContent("Fixed Normals", "If this is ticked instead of requiring mesh normals a Fixed Normal will be used instead (it's quicker and can result in better looking lighting effects on 2d objects).");
static GUIContent _fixedNormalDirectionText = new GUIContent("Fixed Normal Direction", "Should normally be (0,0,1) if in view-space or (0,0,-1) if in model-space.");
static GUIContent _adjustBackfaceTangentText = new GUIContent("Adjust Back-face Tangents", "Tick only if you are going to rotate the sprite to face away from the camera, the tangents will be flipped when this is the case to make lighting correct.");
static GUIContent _sphericalHarmonicsText = new GUIContent("Light Probes & Ambient", "Enable to use spherical harmonics to aplpy ambient light and/or light probes. In vertex-lit mode this will be approximated from scenes ambient trilight settings.");
static GUIContent _sphericalHarmonicsText = new GUIContent("Spherical Harmonics", "Enable to use spherical harmonics to calculate ambient light / light probes. In vertex-lit mode this will be approximated from scenes ambient trilight settings.");
static GUIContent _lightingModeText = new GUIContent("Lighting Mode", "Lighting Mode");
static GUIContent[] _lightingModeOptions = {
new GUIContent("Vertex Lit"),
new GUIContent("Pixel Lit"),
new GUIContent("Unlit"),
new GUIContent("Lit Lightweight"),
new GUIContent("Lit Universal"),
new GUIContent("Lit Universal2D")
new GUIContent("Unlit")
};
static GUIContent _blendModeText = new GUIContent("Blend Mode", "Blend Mode");
static GUIContent[] _blendModeOptions = {
@@ -167,13 +140,13 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
new GUIContent("Multiply"),
new GUIContent("Multiply x2")
};
static GUIContent _rendererQueueText = new GUIContent("Render Queue Offset");
static GUIContent _rendererQueueText = new GUIContent("Renderer Queue");
static GUIContent _cullingModeText = new GUIContent("Culling Mode");
static GUIContent[] _cullingModeOptions = { new GUIContent("Off"), new GUIContent("Front"), new GUIContent("Back") };
static GUIContent _pixelSnapText = new GUIContent("Pixel Snap");
//static GUIContent _customRenderTypetagsText = new GUIContent("Use Custom RenderType tags");
static GUIContent _fixedNormalSpaceText = new GUIContent("Fixed Normal Space");
static GUIContent[] _fixedNormalSpaceOptions = { new GUIContent("View-Space"), new GUIContent("Model-Space"), new GUIContent("World-Space") };
static GUIContent[] _fixedNormalSpaceOptions = { new GUIContent("View-Space"), new GUIContent("Model-Space") };
static GUIContent _rimLightingToggleText = new GUIContent("Rim Lighting", "Enable Rim Lighting.");
static GUIContent _rimColorText = new GUIContent("Rim Color");
static GUIContent _rimPowerText = new GUIContent("Rim Power");
@@ -187,7 +160,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
static GUIContent _meshRequiresTangentsText = new GUIContent("Note: Material requires a mesh with tangents.");
static GUIContent _meshRequiresNormalsText = new GUIContent("Note: Material requires a mesh with normals.");
static GUIContent _meshRequiresNormalsAndTangentsText = new GUIContent("Note: Material requires a mesh with Normals and Tangents.");
static GUIContent[] _fixedDiffuseRampModeOptions = { new GUIContent("Hard"), new GUIContent("Soft"), new GUIContent("Old Hard"), new GUIContent("Old Soft") };
const string _primaryMapsText = "Main Maps";
const string _depthLabelText = "Depth";
@@ -206,11 +178,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
base.AssignNewShaderToMaterial(material, oldShader, newShader);
//If not originally a sprite shader set default keywords
if (oldShader.name != kShaderVertexLit && oldShader.name != kShaderPixelLit && oldShader.name != kShaderUnlit &&
oldShader.name != kShaderVertexLitOutline && oldShader.name != kShaderPixelLitOutline && oldShader.name != kShaderUnlitOutline &&
oldShader.name != kShaderLitLW &&
oldShader.name != kShaderLitURP &&
oldShader.name != kShaderLitURP2D) {
if (oldShader.name != kShaderVertexLit && oldShader.name != kShaderPixelLit && oldShader.name != kShaderUnlit) {
SetDefaultSpriteKeywords(material, newShader);
}
@@ -221,16 +189,13 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
#region Virtual Interface
protected override void FindProperties (MaterialProperty[] props) {
base.FindProperties(props);
protected virtual void FindProperties (MaterialProperty[] props) {
_mainTexture = FindProperty("_MainTex", props);
_maskTexture = FindProperty("_MaskTex", props, false);
_color = FindProperty("_Color", props);
_pixelSnap = FindProperty("PixelSnap", props);
_writeToDepth = FindProperty("_ZWrite", props, false);
_writeToDepth = FindProperty("_ZWrite", props);
_depthAlphaCutoff = FindProperty("_Cutoff", props);
_shadowAlphaCutoff = FindProperty("_ShadowAlphaCutoff", props);
_renderQueue = FindProperty("_RenderQueue", props);
@@ -322,16 +287,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
dataChanged |= RenderRimLightingProperties();
}
{
EditorGUILayout.Space();
RenderStencilProperties();
}
{
EditorGUILayout.Space();
RenderOutlineProperties();
}
if (dataChanged) {
MaterialChanged(_materialEditor);
}
@@ -369,18 +324,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
if (material.shader.name != kShaderUnlit)
_materialEditor.SetShader(Shader.Find(kShaderUnlit), false);
break;
case eLightMode.LitLightweight:
if (material.shader.name != kShaderLitLW)
_materialEditor.SetShader(Shader.Find(kShaderLitLW), false);
break;
case eLightMode.LitUniversal:
if (material.shader.name != kShaderLitURP)
_materialEditor.SetShader(Shader.Find(kShaderLitURP), false);
break;
case eLightMode.LitUniversal2D:
if (material.shader.name != kShaderLitURP2D)
_materialEditor.SetShader(Shader.Find(kShaderLitURP2D), false);
break;
}
}
@@ -408,20 +351,15 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
dataChanged = true;
}
if (QualitySettings.activeColorSpace == ColorSpace.Linear &&
!EditorGUI.showMixedValue && blendMode == eBlendMode.PreMultipliedAlpha) {
EditorGUILayout.HelpBox(MaterialChecks.kPMANotSupportedLinearMessage, MessageType.Error, true);
}
}
EditorGUI.BeginDisabledGroup(true);
_materialEditor.RenderQueueField();
EditorGUI.EndDisabledGroup();
// GUILayout.Label(Styles.advancedText, EditorStyles.boldLabel);
// m_MaterialEditor.RenderQueueField();
// m_MaterialEditor.EnableInstancingField();
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = _renderQueue.hasMixedValue;
int renderQueue = EditorGUILayout.IntField(_rendererQueueText, (int)_renderQueue.floatValue);
int renderQueue = EditorGUILayout.IntSlider(_rendererQueueText, (int)_renderQueue.floatValue, 0, 49);
if (EditorGUI.EndChangeCheck()) {
SetInt("_RenderQueue", renderQueue);
dataChanged = true;
@@ -455,10 +393,8 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
if (_bumpMap != null)
_materialEditor.TexturePropertySingleLine(_normalMapText, _bumpMap, _bumpMap.textureValue != null ? _bumpScale : null);
if (_maskTexture != null)
_materialEditor.TexturePropertySingleLine(_maskText, _maskTexture);
dataChanged |= RenderDiffuseRampProperties();
if (_diffuseRamp != null)
_materialEditor.TexturePropertySingleLine(_diffuseRampText, _diffuseRamp);
dataChanged |= EditorGUI.EndChangeCheck();
@@ -485,23 +421,18 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
EditorGUI.BeginChangeCheck();
bool showDepthAlphaCutoff = true;
// e.g. Pixel Lit shader always has ZWrite enabled
if (_writeToDepth != null) {
bool mixedValue = _writeToDepth.hasMixedValue;
EditorGUI.showMixedValue = mixedValue;
bool writeTodepth = EditorGUILayout.Toggle(_depthText, _writeToDepth.floatValue != 0.0f);
bool mixedValue = _writeToDepth.hasMixedValue;
EditorGUI.showMixedValue = mixedValue;
bool writeTodepth = EditorGUILayout.Toggle(_depthText, _writeToDepth.floatValue != 0.0f);
if (EditorGUI.EndChangeCheck()) {
SetInt("_ZWrite", writeTodepth ? 1 : 0);
_depthAlphaCutoff.floatValue = writeTodepth ? 0.5f : 0.0f;
mixedValue = false;
dataChanged = true;
}
showDepthAlphaCutoff = writeTodepth && !mixedValue && GetMaterialBlendMode((Material)_materialEditor.target) != eBlendMode.Opaque;
if (EditorGUI.EndChangeCheck()) {
SetInt("_ZWrite", writeTodepth ? 1 : 0);
_depthAlphaCutoff.floatValue = writeTodepth ? 0.5f : 0.0f;
mixedValue = false;
dataChanged = true;
}
if (showDepthAlphaCutoff) {
if (writeTodepth && !mixedValue && GetMaterialBlendMode((Material)_materialEditor.target) != eBlendMode.Opaque) {
EditorGUI.BeginChangeCheck();
_materialEditor.RangeProperty(_depthAlphaCutoff, _depthAlphaCutoffText.text);
dataChanged |= EditorGUI.EndChangeCheck();
@@ -528,7 +459,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
break;
default:
{
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderType);
}
break;
@@ -622,90 +553,13 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
return dataChanged;
}
protected virtual bool RenderDiffuseRampProperties () {
bool dataChanged = false;
eDiffuseRampMode rampMode = GetMaterialDiffuseRampMode((Material)_materialEditor.target);
bool mixedRampMode = false;
foreach (Material material in _materialEditor.targets) {
if (rampMode != GetMaterialDiffuseRampMode(material)) {
mixedRampMode = true;
break;
}
}
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = mixedRampMode;
EditorGUILayout.BeginHorizontal();
if (_diffuseRamp != null)
_materialEditor.TexturePropertySingleLine(_diffuseRampText, _diffuseRamp);
if (EditorGUI.EndChangeCheck()) {
if (rampMode == eDiffuseRampMode.NoRampSpecified)
rampMode = eDiffuseRampMode.DefaultRampMode;
SetDiffuseRampMode(_materialEditor, rampMode);
mixedRampMode = false;
dataChanged = true;
}
if (_diffuseRamp != null && _diffuseRamp.textureValue != null) {
//Show drop down for ramp mode
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = mixedRampMode;
rampMode = (eDiffuseRampMode)EditorGUILayout.Popup((int)rampMode, _fixedDiffuseRampModeOptions);
if (EditorGUI.EndChangeCheck()) {
SetDiffuseRampMode(_materialEditor, rampMode);
mixedRampMode = false;
dataChanged = true;
}
}
EditorGUILayout.EndHorizontal();
EditorGUI.showMixedValue = false;
return dataChanged;
}
protected virtual bool RenderShadowsProperties () {
bool dataChanged = false;
EditorGUI.BeginChangeCheck();
_materialEditor.RangeProperty(_shadowAlphaCutoff, _shadowAlphaCutoffText.text);
dataChanged = EditorGUI.EndChangeCheck();
bool areMixedShaders = false;
bool hasReceiveShadowsParameter = IsLWRPShader(_materialEditor, out areMixedShaders) ||
IsURP3DShader(_materialEditor, out areMixedShaders);
if (hasReceiveShadowsParameter) {
EditorGUI.BeginChangeCheck();
bool mixedValue;
bool enableReceive = !IsKeywordEnabled(_materialEditor, "_RECEIVE_SHADOWS_OFF", out mixedValue);
EditorGUI.showMixedValue = mixedValue;
enableReceive = EditorGUILayout.Toggle(_receiveShadowsText, enableReceive);
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck()) {
SetKeyword(_materialEditor, "_RECEIVE_SHADOWS_OFF", !enableReceive);
dataChanged = true;
}
}
return dataChanged;
return EditorGUI.EndChangeCheck();
}
protected virtual bool RenderSphericalHarmonicsProperties () {
bool areMixedShaders = false;
bool isLWRPShader = IsLWRPShader(_materialEditor, out areMixedShaders);
bool isURP3DShader = IsURP3DShader(_materialEditor, out areMixedShaders);
bool isURP2DShader = IsURP2DShader(_materialEditor, out areMixedShaders);
bool hasSHParameter = !(isLWRPShader || isURP3DShader || isURP2DShader);
if (!hasSHParameter)
return false;
EditorGUI.BeginChangeCheck();
bool mixedValue;
bool enabled = IsKeywordEnabled(_materialEditor, "_SPHERICAL_HARMONICS", out mixedValue);
@@ -722,13 +576,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
}
protected virtual bool RenderFogProperties () {
bool areMixedShaders = false;
bool isURP2DShader = IsURP2DShader(_materialEditor, out areMixedShaders);
if (isURP2DShader && !areMixedShaders)
return false;
EditorGUI.BeginChangeCheck();
bool mixedValue;
bool fog = IsKeywordEnabled(_materialEditor, "_FOG", out mixedValue);
@@ -896,7 +743,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
SetKeyword(material, "_EMISSION", false);
//Start with preMultiply alpha by default
SetBlendMode(material, eBlendMode.PreMultipliedAlpha);
SetDiffuseRampMode(material, eDiffuseRampMode.DefaultRampMode);
//Start with mesh normals by default
SetNormalsMode(material, eNormalsMode.MeshNormals, false);
if (_fixedNormal != null)
@@ -909,15 +755,14 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
//Start with Culling disabled
material.SetInt("_Cull", (int)eCulling.Off);
//Start with Z writing disabled
if (material.HasProperty("_ZWrite"))
material.SetInt("_ZWrite", 0);
material.SetInt("_ZWrite", 0);
}
//Z write is on then
static void SetRenderType (Material material, string renderType, bool useCustomRenderQueue) {
//Want a check box to say if should use Sprite render queue (for custom writing depth and normals)
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
if (useCustomRenderQueue) {
//If sprite has fixed normals then assign custom render type so we can write its correct normal with soft edges
@@ -951,7 +796,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
eBlendMode blendMode = GetMaterialBlendMode(material);
SetBlendMode(material, blendMode);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
bool clipAlpha = zWrite && blendMode != eBlendMode.Opaque && material.GetFloat("_Cutoff") > 0.0f;
SetKeyword(material, "_ALPHA_CLIP", clipAlpha);
@@ -983,33 +828,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
m.DisableKeyword(keyword);
}
static bool IsLWRPShader (MaterialEditor editor, out bool mixedValue) {
return IsShaderType(kShaderLitLW, editor, out mixedValue);
}
static bool IsURP3DShader (MaterialEditor editor, out bool mixedValue) {
return IsShaderType(kShaderLitURP, editor, out mixedValue);
}
static bool IsURP2DShader (MaterialEditor editor, out bool mixedValue) {
return IsShaderType(kShaderLitURP2D, editor, out mixedValue);
}
static bool IsShaderType (string shaderType, MaterialEditor editor, out bool mixedValue) {
mixedValue = false;
bool isAnyTargetTypeShader = false;
foreach (Material material in editor.targets) {
if (material.shader.name == shaderType) {
isAnyTargetTypeShader = true;
}
else if (isAnyTargetTypeShader) {
mixedValue = true;
}
}
return isAnyTargetTypeShader;
}
static bool IsKeywordEnabled (MaterialEditor editor, string keyword, out bool mixedValue) {
bool keywordEnabled = ((Material)editor.target).IsKeywordEnabled(keyword);
mixedValue = false;
@@ -1025,24 +843,11 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
}
static eLightMode GetMaterialLightMode (Material material) {
if (material.shader.name == kShaderPixelLit ||
material.shader.name == kShaderPixelLitOutline) {
if (material.shader.name == kShaderPixelLit) {
return eLightMode.PixelLit;
}
else if (material.shader.name == kShaderUnlit ||
material.shader.name == kShaderUnlitOutline) {
} else if (material.shader.name == kShaderUnlit) {
return eLightMode.Unlit;
}
else if (material.shader.name == kShaderLitLW) {
return eLightMode.LitLightweight;
}
else if (material.shader.name == kShaderLitURP) {
return eLightMode.LitUniversal;
}
else if (material.shader.name == kShaderLitURP2D) {
return eLightMode.LitUniversal2D;
}
else { // if (material.shader.name == kShaderVertexLit || kShaderVertexLitOutline)
} else {
return eLightMode.VertexLit;
}
}
@@ -1088,7 +893,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.One);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderQueue);
renderQueue = zWrite ? kAlphaTestQueue : kTransparentQueue;
}
@@ -1097,7 +902,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcColor);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderQueue);
renderQueue = zWrite ? kAlphaTestQueue : kTransparentQueue;
}
@@ -1106,7 +911,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.SrcColor);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderQueue);
renderQueue = zWrite ? kAlphaTestQueue : kTransparentQueue;
}
@@ -1115,7 +920,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.DstColor);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.SrcColor);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderQueue);
renderQueue = zWrite ? kAlphaTestQueue : kTransparentQueue;
}
@@ -1124,7 +929,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
bool zWrite = HasZWriteEnabled(material);
bool zWrite = material.GetFloat("_ZWrite") > 0.0f;
SetRenderType(material, zWrite ? "TransparentCutout" : "Transparent", useCustomRenderQueue);
renderQueue = zWrite ? kAlphaTestQueue : kTransparentQueue;
}
@@ -1138,16 +943,15 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
static eNormalsMode GetMaterialNormalsMode (Material material) {
if (material.IsKeywordEnabled("_FIXED_NORMALS_VIEWSPACE") || material.IsKeywordEnabled("_FIXED_NORMALS_VIEWSPACE_BACKFACE"))
return eNormalsMode.FixedNormalsViewSpace;
if (material.IsKeywordEnabled("_FIXED_NORMALS_WORLDSPACE"))
return eNormalsMode.FixedNormalsWorldSpace;
if (material.IsKeywordEnabled("_FIXED_NORMALS_MODELSPACE") || material.IsKeywordEnabled("_FIXED_NORMALS_MODELSPACE_BACKFACE"))
return eNormalsMode.FixedNormalsModelSpace;
return eNormalsMode.MeshNormals;
}
static void SetNormalsMode (MaterialEditor materialEditor, eNormalsMode normalsMode, bool allowBackFaceRendering) {
SetNormalsMode((Material)materialEditor.target, normalsMode, allowBackFaceRendering);
foreach (Material material in materialEditor.targets) {
SetNormalsMode(material, normalsMode, allowBackFaceRendering);
}
@@ -1156,7 +960,6 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
static void SetNormalsMode (Material material, eNormalsMode normalsMode, bool allowBackFaceRendering) {
SetKeyword(material, "_FIXED_NORMALS_VIEWSPACE", normalsMode == eNormalsMode.FixedNormalsViewSpace && !allowBackFaceRendering);
SetKeyword(material, "_FIXED_NORMALS_VIEWSPACE_BACKFACE", normalsMode == eNormalsMode.FixedNormalsViewSpace && allowBackFaceRendering);
SetKeyword(material, "_FIXED_NORMALS_WORLDSPACE", normalsMode == eNormalsMode.FixedNormalsWorldSpace);
SetKeyword(material, "_FIXED_NORMALS_MODELSPACE", normalsMode == eNormalsMode.FixedNormalsModelSpace && !allowBackFaceRendering);
SetKeyword(material, "_FIXED_NORMALS_MODELSPACE_BACKFACE", normalsMode == eNormalsMode.FixedNormalsModelSpace && allowBackFaceRendering);
}
@@ -1165,37 +968,5 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
return material.IsKeywordEnabled("_FIXED_NORMALS_VIEWSPACE_BACKFACE") || material.IsKeywordEnabled("_FIXED_NORMALS_MODELSPACE_BACKFACE");
}
static eDiffuseRampMode GetMaterialDiffuseRampMode (Material material) {
if (material.IsKeywordEnabled("_FULLRANGE_HARD_RAMP"))
return eDiffuseRampMode.FullRangeHard;
if (material.IsKeywordEnabled("_FULLRANGE_SOFT_RAMP"))
return eDiffuseRampMode.FullRangeSoft;
if (material.IsKeywordEnabled("_OLD_HARD_RAMP"))
return eDiffuseRampMode.OldHard;
if (material.IsKeywordEnabled("_OLD_SOFT_RAMP"))
return eDiffuseRampMode.OldSoft;
return eDiffuseRampMode.NoRampSpecified;
}
static void SetDiffuseRampMode (MaterialEditor materialEditor, eDiffuseRampMode rampMode) {
foreach (Material material in materialEditor.targets) {
SetDiffuseRampMode(material, rampMode);
}
}
static void SetDiffuseRampMode (Material material, eDiffuseRampMode rampMode) {
SetKeyword(material, "_FULLRANGE_HARD_RAMP", rampMode == eDiffuseRampMode.FullRangeHard);
SetKeyword(material, "_FULLRANGE_SOFT_RAMP", rampMode == eDiffuseRampMode.FullRangeSoft);
SetKeyword(material, "_OLD_HARD_RAMP", rampMode == eDiffuseRampMode.OldHard);
SetKeyword(material, "_OLD_SOFT_RAMP", rampMode == eDiffuseRampMode.OldSoft);
}
static bool HasZWriteEnabled (Material material) {
if (material.HasProperty("_ZWrite")) {
return material.GetFloat("_ZWrite") > 0.0f;
}
else return true; // Pixel Lit shader always has _ZWrite enabled.
}
#endregion
}
@@ -1,7 +1,7 @@
fileFormatVersion: 2
guid: 6e8ed065898e65f4d9303492725fb912
guid: 7a4120eda5e72634b8ea086a00778669
folderAsset: yes
timeCreated: 1573829873
timeCreated: 1527569450
licenseType: Free
DefaultImporter:
userData:

Some files were not shown because too many files have changed in this diff Show More