Merge branch '3.6' into 3.7-beta

This commit is contained in:
badlogic 2017-12-15 09:48:07 +01:00
commit ee7d9d27eb
13 changed files with 400 additions and 384 deletions

View File

@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: cbe5d97ed1d75964cab2e2882a52a200
folderAsset: yes
timeCreated: 1455489536
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -73,7 +73,7 @@ namespace Spine.Unity {
bool skeletonTransformIsParent; bool skeletonTransformIsParent;
/// <summary> /// <summary>
/// Sets the target bone by its bone name. Returns false if no bone was found.</summary> /// Sets the target bone by its bone name. Returns false if no bone was found. To set the bone by reference, use BoneFollower.bone directly.</summary>
public bool SetBone (string name) { public bool SetBone (string name) {
bone = skeletonRenderer.skeleton.FindBone(name); bone = skeletonRenderer.skeleton.FindBone(name);
if (bone == null) { if (bone == null) {

View File

@ -1,366 +1,366 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes Software License v2.5 * Spine Runtimes Software License v2.5
* *
* Copyright (c) 2013-2016, Esoteric Software * Copyright (c) 2013-2016, Esoteric Software
* All rights reserved. * All rights reserved.
* *
* You are granted a perpetual, non-exclusive, non-sublicensable, and * You are granted a perpetual, non-exclusive, non-sublicensable, and
* non-transferable license to use, install, execute, and perform the Spine * non-transferable license to use, install, execute, and perform the Spine
* Runtimes software and derivative works solely for personal or internal * Runtimes software and derivative works solely for personal or internal
* use. Without the written permission of Esoteric Software (see Section 2 of * use. Without the written permission of Esoteric Software (see Section 2 of
* the Spine Software License Agreement), you may not (a) modify, translate, * the Spine Software License Agreement), you may not (a) modify, translate,
* adapt, or develop new applications using the Spine Runtimes or otherwise * adapt, or develop new applications using the Spine Runtimes or otherwise
* create derivative works or improvements of the Spine Runtimes or (b) remove, * create derivative works or improvements of the Spine Runtimes or (b) remove,
* delete, alter, or obscure any trademarks or any copyright, trademark, patent, * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
* or other intellectual property or proprietary rights notices on or in the * or other intellectual property or proprietary rights notices on or in the
* Software, including any copy thereof. Redistributions in binary or source * Software, including any copy thereof. Redistributions in binary or source
* form must include this license and terms. * form must include this license and terms.
* *
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
//#define BAKE_ALL_BUTTON //#define BAKE_ALL_BUTTON
//#define REGION_BAKING_MESH //#define REGION_BAKING_MESH
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using Spine; using Spine;
namespace Spine.Unity.Editor { namespace Spine.Unity.Editor {
using Event = UnityEngine.Event; using Event = UnityEngine.Event;
[CustomEditor(typeof(AtlasAsset)), CanEditMultipleObjects] [CustomEditor(typeof(AtlasAsset)), CanEditMultipleObjects]
public class AtlasAssetInspector : UnityEditor.Editor { public class AtlasAssetInspector : UnityEditor.Editor {
SerializedProperty atlasFile, materials; SerializedProperty atlasFile, materials;
AtlasAsset atlasAsset; AtlasAsset atlasAsset;
GUIContent spriteSlicesLabel; GUIContent spriteSlicesLabel;
GUIContent SpriteSlicesLabel { GUIContent SpriteSlicesLabel {
get { get {
if (spriteSlicesLabel == null) { if (spriteSlicesLabel == null) {
spriteSlicesLabel = new GUIContent( spriteSlicesLabel = new GUIContent(
"Apply Regions as Texture Sprite Slices", "Apply Regions as Texture Sprite Slices",
SpineEditorUtilities.Icons.unity, SpineEditorUtilities.Icons.unity,
"Adds Sprite slices to atlas texture(s). " + "Adds Sprite slices to atlas texture(s). " +
"Updates existing slices if ones with matching names exist. \n\n" + "Updates existing slices if ones with matching names exist. \n\n" +
"If your atlas was exported with Premultiply Alpha, " + "If your atlas was exported with Premultiply Alpha, " +
"your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default."); "your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default.");
} }
return spriteSlicesLabel; return spriteSlicesLabel;
} }
} }
static List<AtlasRegion> GetRegions (Atlas atlas) { static List<AtlasRegion> GetRegions (Atlas atlas) {
FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic);
return (List<AtlasRegion>)regionsField.GetValue(atlas); return (List<AtlasRegion>)regionsField.GetValue(atlas);
} }
void OnEnable () { void OnEnable () {
SpineEditorUtilities.ConfirmInitialization(); SpineEditorUtilities.ConfirmInitialization();
atlasFile = serializedObject.FindProperty("atlasFile"); atlasFile = serializedObject.FindProperty("atlasFile");
materials = serializedObject.FindProperty("materials"); materials = serializedObject.FindProperty("materials");
materials.isExpanded = true; materials.isExpanded = true;
atlasAsset = (AtlasAsset)target; atlasAsset = (AtlasAsset)target;
#if REGION_BAKING_MESH #if REGION_BAKING_MESH
UpdateBakedList(); UpdateBakedList();
#endif #endif
} }
#if REGION_BAKING_MESH #if REGION_BAKING_MESH
private List<bool> baked; private List<bool> baked;
private List<GameObject> bakedObjects; private List<GameObject> bakedObjects;
void UpdateBakedList () { void UpdateBakedList () {
AtlasAsset asset = (AtlasAsset)target; AtlasAsset asset = (AtlasAsset)target;
baked = new List<bool>(); baked = new List<bool>();
bakedObjects = new List<GameObject>(); bakedObjects = new List<GameObject>();
if (atlasFile.objectReferenceValue != null) { if (atlasFile.objectReferenceValue != null) {
List<AtlasRegion> regions = this.Regions; List<AtlasRegion> regions = this.Regions;
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
AtlasRegion region = regions[i]; AtlasRegion region = regions[i];
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/");
GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject));
baked.Add(prefab != null); baked.Add(prefab != null);
bakedObjects.Add(prefab); bakedObjects.Add(prefab);
} }
} }
} }
#endif #endif
override public void OnInspectorGUI () { override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) { if (serializedObject.isEditingMultipleObjects) {
DrawDefaultInspector(); DrawDefaultInspector();
return; return;
} }
serializedObject.Update(); serializedObject.Update();
atlasAsset = atlasAsset ?? (AtlasAsset)target; atlasAsset = atlasAsset ?? (AtlasAsset)target;
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true); EditorGUILayout.PropertyField(materials, true);
if (EditorGUI.EndChangeCheck()) { if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
atlasAsset.Clear(); atlasAsset.Clear();
atlasAsset.GetAtlas(); atlasAsset.GetAtlas();
} }
if (materials.arraySize == 0) { if (materials.arraySize == 0) {
EditorGUILayout.HelpBox("No materials", MessageType.Error); EditorGUILayout.HelpBox("No materials", MessageType.Error);
return; return;
} }
for (int i = 0; i < materials.arraySize; i++) { for (int i = 0; i < materials.arraySize; i++) {
SerializedProperty prop = materials.GetArrayElementAtIndex(i); SerializedProperty prop = materials.GetArrayElementAtIndex(i);
Material mat = (Material)prop.objectReferenceValue; var material = (Material)prop.objectReferenceValue;
if (mat == null) { if (material == null) {
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error); EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
return; return;
} }
} }
EditorGUILayout.Space(); EditorGUILayout.Space();
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS))) { if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS))) {
foreach (var m in atlasAsset.materials) { foreach (var m in atlasAsset.materials) {
var texture = m.mainTexture; var texture = m.mainTexture;
texture.mipMapBias = SpineEditorUtilities.DEFAULT_MIPMAPBIAS; texture.mipMapBias = SpineEditorUtilities.DEFAULT_MIPMAPBIAS;
} }
Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS); Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS);
} }
EditorGUILayout.Space(); EditorGUILayout.Space();
if (atlasFile.objectReferenceValue != null) { if (atlasFile.objectReferenceValue != null) {
if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) { if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) {
var atlas = atlasAsset.GetAtlas(); var atlas = atlasAsset.GetAtlas();
foreach (var m in atlasAsset.materials) foreach (var m in atlasAsset.materials)
UpdateSpriteSlices(m.mainTexture, atlas); UpdateSpriteSlices(m.mainTexture, atlas);
} }
} }
EditorGUILayout.Space(); EditorGUILayout.Space();
#if REGION_BAKING_MESH #if REGION_BAKING_MESH
if (atlasFile.objectReferenceValue != null) { if (atlasFile.objectReferenceValue != null) {
Atlas atlas = asset.GetAtlas(); Atlas atlas = asset.GetAtlas();
FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas); List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon)); EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon));
EditorGUI.indentLevel++; EditorGUI.indentLevel++;
AtlasPage lastPage = null; AtlasPage lastPage = null;
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
if (lastPage != regions[i].page) { if (lastPage != regions[i].page) {
if (lastPage != null) { if (lastPage != null) {
EditorGUILayout.Separator(); EditorGUILayout.Separator();
EditorGUILayout.Separator(); EditorGUILayout.Separator();
} }
lastPage = regions[i].page; lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject); Material mat = ((Material)lastPage.rendererObject);
if (mat != null) { if (mat != null) {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
{ {
EditorGUI.BeginDisabledGroup(true); EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup();
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} else { } else {
EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning));
} }
} }
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
{ {
//EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]); //EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]);
bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]); bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]);
if(baked[i]){ if(baked[i]){
EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250)); EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250));
} }
if (result && !baked[i]) { if (result && !baked[i]) {
//bake //bake
baked[i] = true; baked[i] = true;
bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]);
EditorGUIUtility.PingObject(bakedObjects[i]); EditorGUIUtility.PingObject(bakedObjects[i]);
} else if (!result && baked[i]) { } else if (!result && baked[i]) {
//unbake //unbake
bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel"); bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel");
switch (unbakeResult) { switch (unbakeResult) {
case true: case true:
//delete //delete
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/");
AssetDatabase.DeleteAsset(bakedPrefabPath); AssetDatabase.DeleteAsset(bakedPrefabPath);
baked[i] = false; baked[i] = false;
break; break;
case false: case false:
//do nothing //do nothing
break; break;
} }
} }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
EditorGUI.indentLevel--; EditorGUI.indentLevel--;
#if BAKE_ALL_BUTTON #if BAKE_ALL_BUTTON
// Check state // Check state
bool allBaked = true; bool allBaked = true;
bool allUnbaked = true; bool allUnbaked = true;
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
allBaked &= baked[i]; allBaked &= baked[i];
allUnbaked &= !baked[i]; allUnbaked &= !baked[i];
} }
if (!allBaked && GUILayout.Button("Bake All")) { if (!allBaked && GUILayout.Button("Bake All")) {
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
if (!baked[i]) { if (!baked[i]) {
baked[i] = true; baked[i] = true;
bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]);
} }
} }
} else if (!allUnbaked && GUILayout.Button("Unbake All")) { } else if (!allUnbaked && GUILayout.Button("Unbake All")) {
bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel"); bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel");
switch (unbakeResult) { switch (unbakeResult) {
case true: case true:
//delete //delete
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
if (baked[i]) { if (baked[i]) {
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/");
AssetDatabase.DeleteAsset(bakedPrefabPath); AssetDatabase.DeleteAsset(bakedPrefabPath);
baked[i] = false; baked[i] = false;
} }
} }
break; break;
case false: case false:
//do nothing //do nothing
break; break;
} }
} }
#endif #endif
} }
#else #else
if (atlasFile.objectReferenceValue != null) { if (atlasFile.objectReferenceValue != null) {
EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel);
int baseIndent = EditorGUI.indentLevel; int baseIndent = EditorGUI.indentLevel;
var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas());
AtlasPage lastPage = null; AtlasPage lastPage = null;
for (int i = 0; i < regions.Count; i++) { for (int i = 0; i < regions.Count; i++) {
if (lastPage != regions[i].page) { if (lastPage != regions[i].page) {
if (lastPage != null) { if (lastPage != null) {
EditorGUILayout.Separator(); EditorGUILayout.Separator();
EditorGUILayout.Separator(); EditorGUILayout.Separator();
} }
lastPage = regions[i].page; lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject); Material mat = ((Material)lastPage.rendererObject);
if (mat != null) { if (mat != null) {
EditorGUI.indentLevel = baseIndent; EditorGUI.indentLevel = baseIndent;
using (new GUILayout.HorizontalScope()) using (new GUILayout.HorizontalScope())
using (new EditorGUI.DisabledGroupScope(true)) using (new EditorGUI.DisabledGroupScope(true))
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.indentLevel = baseIndent + 1; EditorGUI.indentLevel = baseIndent + 1;
} else { } else {
EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning); EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning);
} }
} }
EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image));
} }
EditorGUI.indentLevel = baseIndent; EditorGUI.indentLevel = baseIndent;
} }
#endif #endif
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current))
atlasAsset.Clear(); atlasAsset.Clear();
} }
static public void UpdateSpriteSlices (Texture texture, Atlas atlas) { static public void UpdateSpriteSlices (Texture texture, Atlas atlas) {
string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID());
var t = (TextureImporter)TextureImporter.GetAtPath(texturePath); var t = (TextureImporter)TextureImporter.GetAtPath(texturePath);
t.spriteImportMode = SpriteImportMode.Multiple; t.spriteImportMode = SpriteImportMode.Multiple;
var spriteSheet = t.spritesheet; var spriteSheet = t.spritesheet;
var sprites = new List<SpriteMetaData>(spriteSheet); var sprites = new List<SpriteMetaData>(spriteSheet);
var regions = AtlasAssetInspector.GetRegions(atlas); var regions = AtlasAssetInspector.GetRegions(atlas);
char[] FilenameDelimiter = {'.'}; char[] FilenameDelimiter = {'.'};
int updatedCount = 0; int updatedCount = 0;
int addedCount = 0; int addedCount = 0;
foreach (var r in regions) { foreach (var r in regions) {
string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0]; string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0];
string textureName = texture.name; string textureName = texture.name;
bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal); bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal);
// if (pageMatch) { // if (pageMatch) {
// int pw = r.page.width; // int pw = r.page.width;
// int ph = r.page.height; // int ph = r.page.height;
// bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize; // bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize;
// if (mismatchSize) // if (mismatchSize)
// Debug.LogWarningFormat("Size mismatch found.\nExpected atlas size is {0}x{1}. Texture Import Max Size of texture '{2}'({4}x{5}) is currently set to {3}.", pw, ph, texture.name, t.maxTextureSize, texture.width, texture.height); // Debug.LogWarningFormat("Size mismatch found.\nExpected atlas size is {0}x{1}. Texture Import Max Size of texture '{2}'({4}x{5}) is currently set to {3}.", pw, ph, texture.name, t.maxTextureSize, texture.width, texture.height);
// } // }
int spriteIndex = pageMatch ? sprites.FindIndex( int spriteIndex = pageMatch ? sprites.FindIndex(
(s) => string.Equals(s.name, r.name, StringComparison.Ordinal) (s) => string.Equals(s.name, r.name, StringComparison.Ordinal)
) : -1; ) : -1;
bool spriteNameMatchExists = spriteIndex >= 0; bool spriteNameMatchExists = spriteIndex >= 0;
if (pageMatch) { if (pageMatch) {
Rect spriteRect = new Rect(); Rect spriteRect = new Rect();
if (r.rotate) { if (r.rotate) {
spriteRect.width = r.height; spriteRect.width = r.height;
spriteRect.height = r.width; spriteRect.height = r.width;
} else { } else {
spriteRect.width = r.width; spriteRect.width = r.width;
spriteRect.height = r.height; spriteRect.height = r.height;
} }
spriteRect.x = r.x; spriteRect.x = r.x;
spriteRect.y = r.page.height - spriteRect.height - r.y; spriteRect.y = r.page.height - spriteRect.height - r.y;
if (spriteNameMatchExists) { if (spriteNameMatchExists) {
var s = sprites[spriteIndex]; var s = sprites[spriteIndex];
s.rect = spriteRect; s.rect = spriteRect;
sprites[spriteIndex] = s; sprites[spriteIndex] = s;
updatedCount++; updatedCount++;
} else { } else {
sprites.Add(new SpriteMetaData { sprites.Add(new SpriteMetaData {
name = r.name, name = r.name,
pivot = new Vector2(0.5f, 0.5f), pivot = new Vector2(0.5f, 0.5f),
rect = spriteRect rect = spriteRect
}); });
addedCount++; addedCount++;
} }
} }
} }
t.spritesheet = sprites.ToArray(); t.spritesheet = sprites.ToArray();
EditorUtility.SetDirty(t); EditorUtility.SetDirty(t);
AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate);
EditorGUIUtility.PingObject(texture); EditorGUIUtility.PingObject(texture);
Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name)); Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name));
} }
} }
} }

View File

@ -37,10 +37,16 @@ namespace Spine.Unity {
event UpdateBonesDelegate UpdateWorld; event UpdateBonesDelegate UpdateWorld;
event UpdateBonesDelegate UpdateComplete; event UpdateBonesDelegate UpdateComplete;
void LateUpdate (); //void LateUpdate ();
Skeleton Skeleton { get; } Skeleton Skeleton { get; }
} }
/// <summary>Holds a reference to a SkeletonDataAsset.</summary>
public interface ISkeletonDataAssetComponent {
/// <summary>Gets the SkeletonDataAsset of the Spine Component.</summary>
SkeletonDataAsset SkeletonDataAsset { get; }
}
/// <summary>A Spine-Unity Component that manages a Spine.Skeleton instance, instantiated from a SkeletonDataAsset.</summary> /// <summary>A Spine-Unity Component that manages a Spine.Skeleton instance, instantiated from a SkeletonDataAsset.</summary>
public interface ISkeletonComponent { public interface ISkeletonComponent {
/// <summary>Gets the SkeletonDataAsset of the Spine Component.</summary> /// <summary>Gets the SkeletonDataAsset of the Spine Component.</summary>

View File

@ -501,6 +501,7 @@ namespace Spine.Unity {
Color c = default(Color); Color c = default(Color);
// Identify and prepare values.
var region = attachment as RegionAttachment; var region = attachment as RegionAttachment;
if (region != null) { if (region != null) {
region.ComputeWorldVertices(slot.bone, workingVerts, 0); region.ComputeWorldVertices(slot.bone, workingVerts, 0);
@ -531,6 +532,9 @@ namespace Spine.Unity {
continue; continue;
} }
} }
// If not any renderable attachment.
clipper.ClipEnd(slot);
continue; continue;
} }
} }
@ -557,6 +561,7 @@ namespace Spine.Unity {
uvs = clipper.clippedUVs.Items; uvs = clipper.clippedUVs.Items;
} }
// Actually add slot/attachment data into buffers.
if (attachmentVertexCount != 0 && attachmentIndexCount != 0) { if (attachmentVertexCount != 0 && attachmentIndexCount != 0) {
if (tintBlack) if (tintBlack)
AddAttachmentTintBlack(slot.r2, slot.g2, slot.b2, attachmentVertexCount); AddAttachmentTintBlack(slot.r2, slot.g2, slot.b2, attachmentVertexCount);
@ -633,6 +638,7 @@ namespace Spine.Unity {
submeshItems[oldTriangleCount + i] = attachmentTriangleIndices[i] + ovc; submeshItems[oldTriangleCount + i] = attachmentTriangleIndices[i] + ovc;
} }
} }
clipper.ClipEnd(slot); clipper.ClipEnd(slot);
} }
clipper.ClipEnd(); clipper.ClipEnd();
@ -1155,7 +1161,7 @@ namespace Spine.Unity {
doubleBufferedMesh = new DoubleBuffered<SmartMesh>(); doubleBufferedMesh = new DoubleBuffered<SmartMesh>();
} }
public Material[] GetUpdatedShaderdMaterialsArray () { public Material[] GetUpdatedSharedMaterialsArray () {
if (submeshMaterials.Count == sharedMaterials.Length) if (submeshMaterials.Count == sharedMaterials.Length)
submeshMaterials.CopyTo(sharedMaterials); submeshMaterials.CopyTo(sharedMaterials);
else else

View File

@ -486,6 +486,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary> /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
/// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks> /// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) { public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) {
if (o == null) throw new System.NullReferenceException("Skin was null");
var skinAttachments = o.Attachments; var skinAttachments = o.Attachments;
var newSkin = new Skin(newName); var newSkin = new Skin(newName);

View File

@ -35,7 +35,7 @@ using Spine;
namespace Spine.Unity { namespace Spine.Unity {
[ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] [ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent]
[AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")]
public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation { public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, ISkeletonDataAssetComponent {
#region Inspector #region Inspector
public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset skeletonDataAsset;

View File

@ -112,9 +112,9 @@ namespace Spine.Unity.Modules {
meshGenerator.FillVertexData(mesh); meshGenerator.FillVertexData(mesh);
if (updateTriangles) { if (updateTriangles) {
meshGenerator.FillTriangles(mesh); meshGenerator.FillTriangles(mesh);
meshRenderer.sharedMaterials = buffers.GetUpdatedShaderdMaterialsArray(); meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
} else if (buffers.MaterialsChangedInLastUpdate()) { } else if (buffers.MaterialsChangedInLastUpdate()) {
meshRenderer.sharedMaterials = buffers.GetUpdatedShaderdMaterialsArray(); meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
} }
} }

View File

@ -126,11 +126,16 @@ namespace Spine.Unity {
} }
#endregion #endregion
/// <summary>
/// Clears the previously generated mesh, resets the skeleton's pose, and clears all previously active animations.</summary>
public override void ClearState () { public override void ClearState () {
base.ClearState(); base.ClearState();
if (state != null) state.ClearTracks(); if (state != null) state.ClearTracks();
} }
/// <summary>
/// Initialize this component. Attempts to load the SkeletonData and creates the internal Spine objects and buffers.</summary>
/// <param name="overwrite">If set to <c>true</c>, force overwrite an already initialized object.</param>
public override void Initialize (bool overwrite) { public override void Initialize (bool overwrite) {
if (valid && !overwrite) if (valid && !overwrite)
return; return;

View File

@ -38,7 +38,7 @@ namespace Spine.Unity {
/// <summary>Renders a skeleton.</summary> /// <summary>Renders a skeleton.</summary>
[ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent]
[HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")] [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")]
public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent { public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, ISkeletonDataAssetComponent {
public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer);
public event SkeletonRendererDelegate OnRebuild; public event SkeletonRendererDelegate OnRebuild;
@ -163,12 +163,17 @@ namespace Spine.Unity {
valid = false; valid = false;
} }
/// <summary>
/// Clears the previously generated mesh and resets the skeleton's pose.</summary>
public virtual void ClearState () { public virtual void ClearState () {
meshFilter.sharedMesh = null; meshFilter.sharedMesh = null;
currentInstructions.Clear(); currentInstructions.Clear();
if (skeleton != null) skeleton.SetToSetupPose(); if (skeleton != null) skeleton.SetToSetupPose();
} }
/// <summary>
/// Initialize this component. Attempts to load the SkeletonData and creates the internal Skeleton object and buffers.</summary>
/// <param name="overwrite">If set to <c>true</c>, it will overwrite internal objects if they were already generated. Otherwise, the initialized component will ignore subsequent calls to initialize.</param>
public virtual void Initialize (bool overwrite) { public virtual void Initialize (bool overwrite) {
if (valid && !overwrite) if (valid && !overwrite)
return; return;
@ -219,6 +224,8 @@ namespace Spine.Unity {
OnRebuild(this); OnRebuild(this);
} }
/// <summary>
/// Generates a new UnityEngine.Mesh from the internal Skeleton.</summary>
public virtual void LateUpdate () { public virtual void LateUpdate () {
if (!valid) return; if (!valid) return;
@ -305,9 +312,9 @@ namespace Spine.Unity {
rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions); rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions);
if (updateTriangles) { // Check if the triangles should also be updated. if (updateTriangles) { // Check if the triangles should also be updated.
meshGenerator.FillTriangles(currentMesh); meshGenerator.FillTriangles(currentMesh);
meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedShaderdMaterialsArray(); meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
} else if (rendererBuffers.MaterialsChangedInLastUpdate()) { } else if (rendererBuffers.MaterialsChangedInLastUpdate()) {
meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedShaderdMaterialsArray(); meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
} }