Merge branch 'master' into 3.6-beta

This commit is contained in:
NathanSweet 2016-12-14 19:12:16 +01:00
commit cdaaf295b2
53 changed files with 845 additions and 331 deletions

19
.npmignore Normal file
View File

@ -0,0 +1,19 @@
CMakeLists.txt
examples
spine-as3
spine-c
spine-cocos2d-objc
spine-cocos2dx
spine-corona
spine-csharp
spine-js
spine-libgdx
spine-love
spine-lua
spine-monogame
spine-sfml
spine-starling
spine-threejs
spine-tk2d
spine-unity
spine-xna

29
package.json Normal file
View File

@ -0,0 +1,29 @@
{
"name": "spine-runtimes",
"version": "3.5.35",
"description": "2D skeletal animation runtimes for Spine.",
"main": "spine-ts/build/spine-all.js",
"directories": {
"example": "examples"
},
"files": [
"spine-ts"
],
"repository": {
"type": "git",
"url": "git@github.com:EsotericSoftware/spine-runtimes.git"
},
"keywords": [
"spine",
"runtimes",
"2d",
"skeletal",
"animation"
],
"author": "Esoteric Software",
"license": "SEE LICENSE IN LICENSE",
"bugs": {
"url": "https://github.com/EsotericSoftware/spine-runtimes/issues"
},
"homepage": "https://github.com/EsotericSoftware/spine-runtimes#readme"
}

View File

@ -172,6 +172,7 @@ public class AnimationState {
}
}
queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -217,7 +218,8 @@ public class AnimationState {
}
}
queueEvents(from, animationTime);
if (entry.mixDuration > 0) queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
@ -317,8 +319,7 @@ public class AnimationState {
event = events[i];
if (event.time < animationStart) continue; // Discard events outside animation start/end.
queue.event(entry, events[i]);
}
events.length = 0;
}
}
public function clearTracks ():void {

View File

@ -83,7 +83,7 @@ public dynamic class MeshAttachment extends VertexAttachment {
}
}
public function applyFFD (sourceAttachment:Attachment) : Boolean {
override public function applyDeform (sourceAttachment:VertexAttachment) : Boolean {
return this == sourceAttachment || (inheritDeform && _parentMesh == sourceAttachment);
}

View File

@ -351,6 +351,7 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
}
}
_spAnimationState_queueEvents(self, current, animationTime);
internal->eventsCount = 0;
current->nextAnimationLast = animationTime;
current->nextTrackLast = current->trackTime;
}
@ -414,7 +415,8 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e
}
}
_spAnimationState_queueEvents(self, from, animationTime);
if (entry->mixDuration > 0) _spAnimationState_queueEvents(self, from, animationTime);
internal->eventsCount = 0;
from->nextAnimationLast = animationTime;
from->nextTrackLast = from->trackTime;
@ -528,7 +530,6 @@ void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry,
if (event->time < animationStart) continue; /* Discard events outside animation start/end. */
_spEventQueue_event(internal->queue, entry, event);
}
internal->eventsCount = 0;
}
void spAnimationState_clearTracks (spAnimationState* self) {

View File

@ -582,6 +582,7 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
kv_trim(spTimeline*, timelines);
animation = spAnimation_create(name, 0);
FREE(animation->timelines);
animation->duration = duration;
animation->timelinesCount = kv_size(timelines);
animation->timelines = kv_array(timelines);

View File

@ -186,6 +186,7 @@ namespace Spine {
}
}
QueueEvents(current, animationTime);
events.Clear(false);
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -234,7 +235,8 @@ namespace Spine {
}
}
QueueEvents(from, animationTime);
if (entry.mixDuration > 0 ) QueueEvents(from, animationTime);
events.Clear(false);
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
@ -333,8 +335,7 @@ namespace Spine {
Event e = eventsItems[i];
if (e.time < animationStart) continue; // Discard events outside animation start/end.
queue.Event(entry, eventsItems[i]);
}
events.Clear(false);
}
}
/// <summary>

View File

@ -799,7 +799,7 @@ public class Animation {
if (time >= frames[frames.length - 1]) // Time is after last frame.
frameIndex = frames.length - 1;
else
frameIndex = binarySearch(frames, time, 1) - 1;
frameIndex = binarySearch(frames, time) - 1;
String attachmentName = attachmentNames[frameIndex];
slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));

View File

@ -827,7 +827,10 @@ public class AnimationState {
this.timeScale = timeScale;
}
/** The listener for events generated by this track entry, or null. */
/** The listener for events generated by this track entry, or null.
* <p>
* A track entry returned from {@link AnimationState#setAnimation(int, Animation, boolean)} is already the current animation
* for the track, so the track entry listener {@link AnimationStateListener#start(TrackEntry)} will not be called. */
public AnimationStateListener getListener () {
return listener;
}

View File

@ -158,6 +158,7 @@ public class Skeleton {
public void updateCache () {
Array<Updatable> updateCache = this.updateCache;
updateCache.clear();
updateCacheReset.clear();
Array<Bone> bones = this.bones;
for (int i = 0, n = bones.size; i < n; i++)

View File

@ -554,7 +554,7 @@ function Animation.ColorTimeline.new (frameCount)
slot.color:set(r, g, b, a)
else
local color = slot.color
if setupPose then color.setFrom(slot.data.color) end
if setupPose then color:setFrom(slot.data.color) end
color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha)
end
end

View File

@ -38,6 +38,7 @@ local math_abs = math.abs
local math_signum = utils.signum
local math_floor = math.floor
local math_ceil = math.ceil
local math_mod = utils.mod
local function zlen(array)
return #array + 1
@ -327,6 +328,7 @@ function AnimationState:apply (skeleton)
end
end
self:queueEvents(current, animationTime)
self.events = {};
current.nextAnimationLast = animationTime
current.nextTrackLast = current.trackTime
end
@ -374,7 +376,8 @@ function AnimationState:applyMixingFrom (entry, skeleton)
end
end
self:queueEvents(from, animationTime)
if (entry.mixDuration > 0) then self:queueEvents(from, animationTime) end
self.events = {};
from.nextAnimationLast = animationTime
from.nextTrackLast = from.trackTime
@ -440,7 +443,7 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, se
if math_abs(lastTotal) > 180 then lastTotal = lastTotal + 360 * math_signum(lastTotal) end
dir = current
end
total = diff + lastTotal - math_ceil(lastTotal / 360 - 0.5) * 360 -- FIXME used to be %360, store loops as part of lastTotal.
total = diff + lastTotal - math_mod(lastTotal, 360) -- FIXME used to be %360, store loops as part of lastTotal.
if dir ~= current then total = total + 360 * math_signum(lastTotal) end
timelinesRotation[i] = total
end
@ -488,7 +491,6 @@ function AnimationState:queueEvents (entry, animationTime)
end
i = i + 1
end
self.events = {}
end
function AnimationState:clearTracks ()
@ -741,7 +743,7 @@ function AnimationState:setTimelinesFirst (entry)
end
end
function AnimationState:checkTimlinesFirst (entry)
function AnimationState:checkTimelinesFirst (entry)
if entry.mixingFrom then self:checkTimelinesFirst(entry.mixingFrom) end
self:checkTimelinesUsage(entry, entry.timelinesFirst)
end

View File

@ -138,4 +138,14 @@ function utils.signum (value)
end
end
-- Implements Java float modulo
function utils.mod(a, b)
if b < 0 then b = -b end
if a < 0 then
return -(-a % b)
else
return a % b
end
end
return utils

View File

@ -42,7 +42,7 @@ public class Main extends Sprite {
var example:Class;
example = SpineboyExample;
// example = GoblinsExample;
// example = RaptorExample;
example = RaptorExample;
// example = TankExample;
// example = VineExample;
// example = StretchymanExample;

View File

@ -1398,6 +1398,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1441,7 +1442,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1529,7 +1532,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -1398,6 +1398,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1441,7 +1442,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1529,7 +1532,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -1051,6 +1051,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1094,7 +1095,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1182,7 +1185,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -1051,6 +1051,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1094,7 +1095,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1182,7 +1185,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -1051,6 +1051,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1094,7 +1095,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1182,7 +1185,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -1051,6 +1051,7 @@ var spine;
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -1094,7 +1095,9 @@ var spine;
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true);
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0)
this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
return mix;
@ -1182,7 +1185,6 @@ var spine;
continue;
this.queue.event(entry, events[i]);
}
this.events.length = 0;
};
AnimationState.prototype.clearTracks = function () {
this.queue.drainDisabled = true;

File diff suppressed because one or more lines are too long

View File

@ -157,6 +157,7 @@ module spine {
}
}
this.queueEvents(current, animationTime);
events.length = 0;
current.nextAnimationLast = animationTime;
current.nextTrackLast = current.trackTime;
}
@ -202,7 +203,8 @@ module spine {
}
}
this.queueEvents(from, animationTime);
if (entry.mixDuration > 0) this.queueEvents(from, animationTime);
this.events.length = 0;
from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime;
@ -302,7 +304,6 @@ module spine {
if (event.time < animationStart) continue; // Discard events outside animation start/end.
this.queue.event(entry, events[i]);
}
this.events.length = 0;
}
clearTracks () {

View File

@ -288,47 +288,56 @@ namespace Spine.Unity.Editor {
var sprites = new List<SpriteMetaData>(spriteSheet);
var regions = AtlasAssetInspector.GetRegions(atlas);
int textureHeight = texture.height;
char[] FilenameDelimiter = {'.'};
int updatedCount = 0;
int addedCount = 0;
foreach (var r in regions) {
int width, height;
if (r.rotate) {
width = r.height;
height = r.width;
} else {
width = r.width;
height = r.height;
}
int x = r.x;
int y = textureHeight - height - r.y;
string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0];
string textureName = texture.name;
bool pageMatch = string.Equals(pageName, textureName,StringComparison.Ordinal);
bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal);
// if (pageMatch) {
// int pw = r.page.width;
// int ph = r.page.height;
// bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize;
// 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);
// }
int spriteIndex = pageMatch ? sprites.FindIndex(
(s) => string.Equals(s.name, r.name, StringComparison.Ordinal)
) : -1;
bool matchFound = spriteIndex >= 0;
bool spriteNameMatchExists = spriteIndex >= 0;
if (matchFound) {
var s = sprites[spriteIndex];
s.rect = new Rect(x, y, width, height);
sprites[spriteIndex] = s;
updatedCount++;
} else {
if (pageMatch) {
if (pageMatch) {
Rect spriteRect = new Rect();
if (r.rotate) {
spriteRect.width = r.height;
spriteRect.height = r.width;
} else {
spriteRect.width = r.width;
spriteRect.height = r.height;
}
spriteRect.x = r.x;
spriteRect.y = r.page.height - spriteRect.height - r.y;
if (spriteNameMatchExists) {
var s = sprites[spriteIndex];
s.rect = spriteRect;
sprites[spriteIndex] = s;
updatedCount++;
} else {
sprites.Add(new SpriteMetaData {
name = r.name,
pivot = new Vector2(0.5f, 0.5f),
rect = new Rect(x, y, width, height)
rect = spriteRect
});
addedCount++;
}
}
}
t.spritesheet = sprites.ToArray();

View File

@ -41,6 +41,7 @@ using Spine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonDataAsset))]
public class SkeletonDataAssetInspector : UnityEditor.Editor {
@ -135,7 +136,7 @@ namespace Spine.Unity.Editor {
serializedObject.Update();
EditorGUILayout.LabelField(new GUIContent(target.name + " (SkeletonDataAsset)", SpineEditorUtilities.Icons.spine), EditorStyles.whiteLargeLabel);
EditorGUILayout.LabelField(new GUIContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel);
if (m_skeletonData != null) {
EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel);
}
@ -154,12 +155,12 @@ namespace Spine.Unity.Editor {
// }
}
EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, SpineEditorUtilities.Icons.spine));
EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, Icons.spine));
EditorGUILayout.PropertyField(scale);
}
// if (m_skeletonData != null) {
// if (SpineInspectorUtility.CenteredButton(new GUIContent("Instantiate", SpineEditorUtilities.Icons.spine, "Creates a new Spine GameObject in the active scene using this Skeleton Data.\nYou can also instantiate by dragging the SkeletonData asset from Project view into Scene View.")))
// if (SpineInspectorUtility.CenteredButton(new GUIContent("Instantiate", Icons.spine, "Creates a new Spine GameObject in the active scene using this Skeleton Data.\nYou can also instantiate by dragging the SkeletonData asset from Project view into Scene View.")))
// SpineEditorUtilities.ShowInstantiateContextMenu(this.m_skeletonDataAsset, Vector3.zero);
// }
@ -212,7 +213,7 @@ namespace Spine.Unity.Editor {
#if !SPINE_TK2D
// Reimport Button
using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) {
if (GUILayout.Button(new GUIContent("Attempt Reimport", SpineEditorUtilities.Icons.warning))) {
if (GUILayout.Button(new GUIContent("Attempt Reimport", Icons.warning))) {
DoReimport();
return;
}
@ -223,7 +224,7 @@ namespace Spine.Unity.Editor {
// List warnings.
foreach (var line in warnings)
EditorGUILayout.LabelField(new GUIContent(line, SpineEditorUtilities.Icons.warning));
EditorGUILayout.LabelField(new GUIContent(line, Icons.warning));
}
if (!Application.isPlaying)
@ -233,10 +234,10 @@ namespace Spine.Unity.Editor {
void DrawUnityTools () {
#if SPINE_SKELETON_ANIMATOR
using (new SpineInspectorUtility.BoxScope()) {
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, new GUIContent("SkeletonAnimator", SpineEditorUtilities.Icons.unityIcon));
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, new GUIContent("SkeletonAnimator", Icons.unityIcon));
if (isMecanimExpanded) {
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(controller, new GUIContent("Controller", SpineEditorUtilities.Icons.controllerIcon));
EditorGUILayout.PropertyField(controller, new GUIContent("Controller", Icons.controllerIcon));
if (controller.objectReferenceValue == null) {
// Generate Mecanim Controller Button
@ -264,7 +265,7 @@ namespace Spine.Unity.Editor {
#if SPINE_BAKING
bool pre = isBakingExpanded;
isBakingExpanded = EditorGUILayout.Foldout(isBakingExpanded, new GUIContent("Baking", SpineEditorUtilities.Icons.unityIcon));
isBakingExpanded = EditorGUILayout.Foldout(isBakingExpanded, new GUIContent("Baking", Icons.unityIcon));
if (pre != isBakingExpanded)
EditorPrefs.SetBool(ShowBakingPrefsKey, isBakingExpanded);
@ -298,7 +299,7 @@ namespace Spine.Unity.Editor {
// Bake Skin buttons.
using (new GUILayout.HorizontalScope()) {
if (GUILayout.Button(new GUIContent("Bake All Skins", SpineEditorUtilities.Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(150)))
if (GUILayout.Button(new GUIContent("Bake All Skins", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(150)))
SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, m_skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions);
if (m_skeletonAnimation != null && m_skeletonAnimation.skeleton != null) {
@ -312,10 +313,10 @@ namespace Spine.Unity.Editor {
skinName = m_skeletonAnimation.skeleton.Skin.Name;
using (new GUILayout.VerticalScope()) {
if (GUILayout.Button(new GUIContent("Bake \"" + skinName + "\"", SpineEditorUtilities.Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250)))
if (GUILayout.Button(new GUIContent("Bake \"" + skinName + "\"", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250)))
SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new ExposedList<Skin>(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions);
using (new GUILayout.HorizontalScope()) {
GUILayout.Label(new GUIContent("Skins", SpineEditorUtilities.Icons.skinsRoot), GUILayout.Width(50));
GUILayout.Label(new GUIContent("Skins", Icons.skinsRoot), GUILayout.Width(50));
if (GUILayout.Button(skinName, EditorStyles.popup, GUILayout.Width(196))) {
DrawSkinDropdown();
}
@ -391,12 +392,12 @@ namespace Spine.Unity.Editor {
}
void DrawAnimationList () {
showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), SpineEditorUtilities.Icons.animationRoot));
showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), Icons.animationRoot));
if (!showAnimationList)
return;
if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
if (GUILayout.Button(new GUIContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
StopAnimation();
m_skeletonAnimation.skeleton.SetToSetupPose();
m_requireRefresh = true;
@ -422,13 +423,13 @@ namespace Spine.Unity.Editor {
} else {
GUILayout.Label("-", GUILayout.Width(24));
}
EditorGUILayout.LabelField(new GUIContent(animation.Name, SpineEditorUtilities.Icons.animation), new GUIContent(animation.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(animation.Duration * 30)) + ")").PadLeft(12, ' ')));
EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), new GUIContent(animation.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(animation.Duration * 30)) + ")").PadLeft(12, ' ')));
}
}
}
void DrawSlotList () {
showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", SpineEditorUtilities.Icons.slotRoot));
showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", Icons.slotRoot));
if (!showSlotList) return;
if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null) return;
@ -440,10 +441,11 @@ namespace Spine.Unity.Editor {
var defaultSkinAttachmentNames = new List<string>();
var defaultSkin = m_skeletonData.Skins.Items[0];
Skin skin = m_skeletonAnimation.skeleton.Skin ?? defaultSkin;
var slotsItems = m_skeletonAnimation.skeleton.Slots.Items;
for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) {
Slot slot = m_skeletonAnimation.skeleton.Slots.Items[i];
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot));
Slot slot = slotsItems[i];
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot));
if (showAttachments) {
EditorGUI.indentLevel++;
@ -470,15 +472,15 @@ namespace Spine.Unity.Editor {
var type = attachment.GetType();
if (type == typeof(RegionAttachment))
icon = SpineEditorUtilities.Icons.image;
icon = Icons.image;
else if (type == typeof(MeshAttachment))
icon = SpineEditorUtilities.Icons.mesh;
icon = Icons.mesh;
else if (type == typeof(BoundingBoxAttachment))
icon = SpineEditorUtilities.Icons.boundingBox;
icon = Icons.boundingBox;
else if (type == typeof(PathAttachment))
icon = SpineEditorUtilities.Icons.boundingBox;
icon = Icons.boundingBox;
else
icon = SpineEditorUtilities.Icons.warning;
icon = Icons.warning;
//JOHN: left todo: Icon for paths. Generic icon for unidentified attachments.
// MITCH: left todo: Waterboard Nate
@ -491,9 +493,9 @@ namespace Spine.Unity.Editor {
if (!defaultSkinAttachmentNames.Contains(attachmentName)) {
Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect();
skinPlaceHolderIconRect.width = SpineEditorUtilities.Icons.skinPlaceholder.width;
skinPlaceHolderIconRect.height = SpineEditorUtilities.Icons.skinPlaceholder.height;
GUI.DrawTexture(skinPlaceHolderIconRect, SpineEditorUtilities.Icons.skinPlaceholder);
skinPlaceHolderIconRect.width = Icons.skinPlaceholder.width;
skinPlaceHolderIconRect.height = Icons.skinPlaceholder.height;
GUI.DrawTexture(skinPlaceHolderIconRect, Icons.skinPlaceholder);
}
if (toggled != initialState) {
@ -698,7 +700,7 @@ namespace Spine.Unity.Editor {
GameObject go = this.m_previewInstance;
Bounds bounds = go.GetComponent<Renderer>().bounds;
m_orthoGoal = bounds.size.y;
m_posGoal = bounds.center + new Vector3(0, 0, -10);
m_posGoal = bounds.center + new Vector3(0, 0, -10f);
}
void AdjustCameraGoals () {
@ -752,11 +754,8 @@ namespace Spine.Unity.Editor {
if (drawHandles) {
Handles.SetCamera(m_previewUtility.m_Camera);
foreach (var slot in m_skeletonAnimation.skeleton.Slots) {
var boundingBoxAttachment = slot.Attachment as BoundingBoxAttachment;
if (boundingBoxAttachment != null)
SpineEditorUtilities.DrawBoundingBox(slot, boundingBoxAttachment);
}
SpineHandles.DrawBoundingBoxes(m_skeletonAnimation.transform, m_skeletonAnimation.skeleton);
if (showAttachments) SpineHandles.DrawPaths(m_skeletonAnimation.transform, m_skeletonAnimation.skeleton);
}
go.GetComponent<Renderer>().enabled = false;
@ -772,9 +771,10 @@ namespace Spine.Unity.Editor {
Repaint();
} else if (m_requireRefresh) {
Repaint();
} else {
}
//else {
//only needed if using smooth menus
}
//}
if (needToSerialize) {
needToSerialize = false;
@ -794,7 +794,7 @@ namespace Spine.Unity.Editor {
popRect.x += 4;
popRect.height = 24;
popRect.width = 40;
EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", SpineEditorUtilities.Icons.skinsRoot));
EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", Icons.skinsRoot));
popRect.y += 11;
popRect.width = 150;
@ -837,11 +837,11 @@ namespace Spine.Unity.Editor {
for (int i = 0; i < m_animEvents.Count; i++) {
float fr = m_animEventFrames[i];
var evRect = new Rect(barRect);
evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (SpineEditorUtilities.Icons.userEvent.width / 2), barRect.x, float.MaxValue);
evRect.width = SpineEditorUtilities.Icons.userEvent.width;
evRect.height = SpineEditorUtilities.Icons.userEvent.height;
evRect.y += SpineEditorUtilities.Icons.userEvent.height;
GUI.DrawTexture(evRect, SpineEditorUtilities.Icons.userEvent);
evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (Icons.userEvent.width / 2), barRect.x, float.MaxValue);
evRect.width = Icons.userEvent.width;
evRect.height = Icons.userEvent.height;
evRect.y += Icons.userEvent.height;
GUI.DrawTexture(evRect, Icons.userEvent);
Event ev = Event.current;
if (ev.type == EventType.Repaint) {

View File

@ -55,7 +55,10 @@ namespace Spine.Unity {
public bool followBoneRotation = true;
[Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")]
public bool followSkeletonFlip = false;
public bool followSkeletonFlip = true;
[Tooltip("Follows the target bone's local scale. BoneFollower cannot inherit world/skewed scale because of UnityEngine.Transform property limitations.")]
public bool followLocalScale = false;
[UnityEngine.Serialization.FormerlySerializedAs("resetOnAwake")]
public bool initializeOnAwake = true;
@ -101,7 +104,6 @@ namespace Spine.Unity {
if (bone == null) {
if (string.IsNullOrEmpty(boneName)) return;
bone = skeletonRenderer.skeleton.FindBone(boneName);
if (bone == null) {
Debug.LogError("Bone not found: " + boneName, this);
@ -114,7 +116,6 @@ namespace Spine.Unity {
// Recommended setup: Use local transform properties if Spine GameObject is the immediate parent
thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z);
if (followBoneRotation) thisTransform.localRotation = Quaternion.Euler(0f, 0f, bone.WorldRotationX);
} else {
// For special cases: Use transform world properties if transform relationship is complicated
Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f));
@ -126,11 +127,10 @@ namespace Spine.Unity {
thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + bone.WorldRotationX);
}
}
if (followSkeletonFlip) {
float flipScaleY = bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f;
thisTransform.localScale = new Vector3(1f, flipScaleY, 1f);
}
Vector3 localScale = followLocalScale ? new Vector3(bone.scaleX, bone.scaleY, 1f) : Vector3.one;
if (followSkeletonFlip) localScale.y *= bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f;
thisTransform.localScale = localScale;
}
}

View File

@ -34,7 +34,7 @@ using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(BoneFollower))]
public class BoneFollowerInspector : UnityEditor.Editor {
SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation, followSkeletonFlip;
SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation, followLocalScale, followSkeletonFlip;
BoneFollower targetBoneFollower;
bool needsReset;
@ -43,6 +43,7 @@ namespace Spine.Unity.Editor {
boneName = serializedObject.FindProperty("boneName");
followBoneRotation = serializedObject.FindProperty("followBoneRotation");
followZPosition = serializedObject.FindProperty("followZPosition");
followLocalScale = serializedObject.FindProperty("followLocalScale");
followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip");
targetBoneFollower = (BoneFollower)target;
@ -50,6 +51,51 @@ namespace Spine.Unity.Editor {
targetBoneFollower.SkeletonRenderer.Initialize(false);
}
public void OnSceneGUI () {
if (targetBoneFollower == null) return;
var skeletonRendererComponent = targetBoneFollower.skeletonRenderer;
if (skeletonRendererComponent == null) return;
var transform = skeletonRendererComponent.transform;
var skeleton = skeletonRendererComponent.skeleton;
if (string.IsNullOrEmpty(targetBoneFollower.boneName)) {
SpineHandles.DrawBones(transform, skeleton);
SpineHandles.DrawBoneNames(transform, skeleton);
Handles.Label(targetBoneFollower.transform.position, "No bone selected", EditorStyles.helpBox);
} else {
var targetBone = targetBoneFollower.bone;
if (targetBone == null) return;
SpineHandles.DrawBoneWireframe(transform, targetBone, SpineHandles.TransformContraintColor);
Handles.Label(targetBone.GetWorldPosition(transform), targetBone.Data.Name, SpineHandles.BoneNameStyle);
}
}
#region Context Menu Item
[MenuItem ("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
var skeletonRenderer = cmd.context as SkeletonRenderer;
var go = new GameObject("BoneFollower");
var t = go.transform;
t.SetParent(skeletonRenderer.transform);
t.localPosition = Vector3.zero;
var f = go.AddComponent<BoneFollower>();
f.skeletonRenderer = skeletonRenderer;
EditorGUIUtility.PingObject(t);
Undo.RegisterCreatedObjectUndo(go, "Add BoneFollower");
}
// Validate
[MenuItem ("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject", true)]
static bool ValidateAddBoneFollowerGameObject (MenuCommand cmd) {
var skeletonRenderer = cmd.context as SkeletonRenderer;
return skeletonRenderer.valid;
}
#endregion
override public void OnInspectorGUI () {
if (needsReset) {
targetBoneFollower.Initialize();
@ -87,6 +133,7 @@ namespace Spine.Unity.Editor {
}
EditorGUILayout.PropertyField(followBoneRotation);
EditorGUILayout.PropertyField(followZPosition);
EditorGUILayout.PropertyField(followLocalScale);
EditorGUILayout.PropertyField(followSkeletonFlip);
} else {
var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer;

View File

@ -41,6 +41,8 @@ namespace Spine.Unity.Editor {
[CanEditMultipleObjects]
public class SkeletonRendererInspector : UnityEditor.Editor {
protected static bool advancedFoldout;
protected static bool showBoneNames, showPaths, showShapes, showConstraints = true;
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors, clearStateOnDisable;
protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
protected bool isInspectingPrefab;
@ -226,18 +228,21 @@ namespace Spine.Unity.Editor {
// More Render Options...
using (new SpineInspectorUtility.BoxScope()) {
EditorGUI.BeginChangeCheck();
if (advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced")) {
using (new SpineInspectorUtility.IndentScope()) {
SeparatorsField(separatorSlotNames);
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
// Optimization options
EditorGUILayout.PropertyField(meshes, MeshesLabel);
EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
EditorGUILayout.Space();
}
SeparatorsField(separatorSlotNames);
EditorGUILayout.Space();
// Render options
const float MinZSpacing = -0.1f;
const float MaxZSpacing = 0f;
@ -245,18 +250,28 @@ namespace Spine.Unity.Editor {
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.LabelField("Vertex Data", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel);
EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
// Optional fields. May be disabled in SkeletonRenderer.
if (normals != null) EditorGUILayout.PropertyField(normals, NormalsLabel);
if (tangents != null) EditorGUILayout.PropertyField(tangents, TangentsLabel);
if (frontFacing != null) EditorGUILayout.PropertyField(frontFacing);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor Preview", EditorStyles.boldLabel);
showBoneNames = EditorGUILayout.Toggle("Show Bone Names", showBoneNames);
showPaths = EditorGUILayout.Toggle("Show Paths", showPaths);
showShapes = EditorGUILayout.Toggle("Show Shapes", showShapes);
showConstraints = EditorGUILayout.Toggle("Show Constraints", showConstraints);
}
EditorGUILayout.Space();
}
}
if (EditorGUI.EndChangeCheck())
SceneView.RepaintAll();
}
}
@ -290,6 +305,20 @@ namespace Spine.Unity.Editor {
}
}
public void OnSceneGUI () {
var skeletonRenderer = (SkeletonRenderer)target;
var skeleton = skeletonRenderer.skeleton;
var transform = skeletonRenderer.transform;
if (skeleton == null) return;
if (showPaths) SpineHandles.DrawPaths(transform, skeleton);
SpineHandles.DrawBones(transform, skeleton);
if (showConstraints) SpineHandles.DrawConstraints(transform, skeleton);
if (showBoneNames) SpineHandles.DrawBoneNames(transform, skeleton);
if (showShapes) SpineHandles.DrawBoundingBoxes(transform, skeleton);
}
public void DrawSkeletonUtilityButton (bool multi) {
if (multi) {
// Support multi-edit SkeletonUtility button.

View File

@ -76,37 +76,6 @@ namespace Spine.Unity.Editor {
public static Texture2D unityIcon;
public static Texture2D controllerIcon;
internal static Mesh _boneMesh;
public static Mesh BoneMesh {
get {
if (_boneMesh == null) {
_boneMesh = new Mesh();
_boneMesh.vertices = new [] {
new Vector3(0, 0, 0),
new Vector3(-0.1f, 0.1f, 0),
new Vector3(0, 1, 0),
new Vector3(0.1f, 0.1f, 0)
};
_boneMesh.uv = new Vector2[4];
_boneMesh.triangles = new [] { 0, 1, 2, 2, 3, 0 };
_boneMesh.RecalculateBounds();
_boneMesh.RecalculateNormals();
}
return _boneMesh;
}
}
internal static Material _boneMaterial;
public static Material BoneMaterial {
get {
if (_boneMaterial == null) {
_boneMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
_boneMaterial.SetColor("_Color", new Color(0.4f, 0.4f, 0.4f, 0.25f));
}
return _boneMaterial;
}
}
public static void Initialize () {
skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png");
nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-null.png");
@ -133,7 +102,6 @@ namespace Spine.Unity.Editor {
subMeshRenderer = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-subMeshRenderer.png");
unityIcon = EditorGUIUtility.FindTexture("SceneAsset Icon");
controllerIcon = EditorGUIUtility.FindTexture("AnimatorController Icon");
}
}
@ -173,6 +141,9 @@ namespace Spine.Unity.Editor {
const string SHOW_HIERARCHY_ICONS_KEY = "SPINE_SHOW_HIERARCHY_ICONS";
public static bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS;
public const float DEFAULT_SCENE_ICONS_SCALE = 1f;
public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
#region Initialization
static SpineEditorUtilities () {
Initialize();
@ -184,6 +155,8 @@ namespace Spine.Unity.Editor {
defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, DEFAULT_DEFAULT_SCALE);
defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, DEFAULT_DEFAULT_SHADER);
showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, DEFAULT_SHOW_HIERARCHY_ICONS);
SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
preferencesLoaded = true;
}
SceneView.onSceneGUIDelegate -= OnSceneGUI;
@ -222,21 +195,20 @@ namespace Spine.Unity.Editor {
[PreferenceItem("Spine")]
static void PreferencesGUI () {
if (!preferencesLoaded) {
preferencesLoaded = true;
defaultMix = EditorPrefs.GetFloat(DEFAULT_MIX_KEY, DEFAULT_DEFAULT_MIX);
defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, DEFAULT_DEFAULT_SCALE);
defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, DEFAULT_DEFAULT_SHADER);
showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, DEFAULT_SHOW_HIERARCHY_ICONS);
SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
preferencesLoaded = true;
}
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);
HierarchyWindowChanged();
}
HierarchyWindowChanged();
}
EditorGUILayout.Separator();
@ -252,6 +224,7 @@ namespace Spine.Unity.Editor {
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetFloat(DEFAULT_SCALE_KEY, defaultScale);
EditorGUI.BeginChangeCheck();
#if UNITY_5_3_OR_NEWER
defaultShader = EditorGUILayout.DelayedTextField(new GUIContent("Default shader", "Default shader for materials auto-generated on import."), defaultShader);
@ -260,17 +233,27 @@ namespace Spine.Unity.Editor {
#endif
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetString(DEFAULT_SHADER_KEY, defaultShader);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor", EditorStyles.boldLabel);
EditorGUI.BeginChangeCheck();
SpineHandles.handleScale = EditorGUILayout.Slider("Editor Bone Scale", SpineHandles.handleScale, 0.01f, 2f);
SpineHandles.handleScale = Mathf.Max(0.01f, SpineHandles.handleScale);
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, SpineHandles.handleScale);
SceneView.RepaintAll();
}
GUILayout.Space(20);
EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("TK2D");
if (GUILayout.Button("Enable", GUILayout.Width(64)))
EnableTK2D();
if (GUILayout.Button("Disable", GUILayout.Width(64)))
DisableTK2D();
GUILayout.EndHorizontal();
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("TK2D");
if (GUILayout.Button("Enable", GUILayout.Width(64)))
EnableTK2D();
if (GUILayout.Button("Disable", GUILayout.Width(64)))
DisableTK2D();
}
}
#endregion
@ -548,7 +531,7 @@ namespace Spine.Unity.Editor {
bool abortSkeletonImport = false;
foreach (string sp in skeletonPaths) {
if (!reimport && CheckForValidSkeletonData(sp)) {
ClearExistingSkeletonData(sp);
ReloadSkeletonData(sp);
continue;
}
@ -613,7 +596,7 @@ namespace Spine.Unity.Editor {
// Any post processing of images
}
static void ClearExistingSkeletonData (string skeletonJSONPath) {
static void ReloadSkeletonData (string skeletonJSONPath) {
string dir = Path.GetDirectoryName(skeletonJSONPath);
TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset));
DirectoryInfo dirInfo = new DirectoryInfo(dir);
@ -628,6 +611,7 @@ namespace Spine.Unity.Editor {
if (Selection.activeObject == skeletonDataAsset)
Selection.activeObject = null;
Debug.LogFormat("Changes to '{0}' detected. Clearing SkeletonDataAsset: {1}", skeletonJSONPath, localPath);
skeletonDataAsset.Clear();
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset));
@ -660,9 +644,8 @@ namespace Spine.Unity.Editor {
// if (currentHash == null || lastHash != currentHash)
// Do any upkeep on synchronized assets
if (currentHash != null) {
if (currentHash != null)
EditorPrefs.SetString(guid + "_hash", currentHash);
}
}
}
}
@ -1248,18 +1231,18 @@ namespace Spine.Unity.Editor {
SkeletonAnimation newSkeletonAnimation = go.GetComponent<SkeletonAnimation>();
newSkeletonAnimation.skeletonDataAsset = skeletonDataAsset;
{
bool requiresNormals = false;
foreach (AtlasAsset atlasAsset in skeletonDataAsset.atlasAssets) {
foreach (Material m in atlasAsset.materials) {
if (m.shader.name.Contains("Lit")) {
requiresNormals = true;
break;
}
}
}
newSkeletonAnimation.calculateNormals = requiresNormals;
}
// {
// bool requiresNormals = false;
// foreach (AtlasAsset atlasAsset in skeletonDataAsset.atlasAssets) {
// foreach (Material m in atlasAsset.materials) {
// if (m.shader.name.Contains("Lit")) {
// requiresNormals = true;
// break;
// }
// }
// }
// newSkeletonAnimation.calculateNormals = requiresNormals;
// }
try {
newSkeletonAnimation.Initialize(false);
@ -1404,24 +1387,190 @@ namespace Spine.Unity.Editor {
}
#endregion
#region Handles
static public void DrawBone (Matrix4x4 transformMatrix) {
SpineEditorUtilities.Icons.BoneMaterial.SetPass(0);
Graphics.DrawMeshNow(SpineEditorUtilities.Icons.BoneMesh, transformMatrix);
public static string GetPathSafeRegionName (AtlasRegion region) {
return region.name.Replace("/", "_");
}
}
public static class SpineHandles {
internal static float handleScale = 1f;
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); } }
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;
public static Material BoneMaterial {
get {
if (_boneMaterial == null) {
_boneMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
_boneMaterial.SetColor("_Color", SpineHandles.BoneColor);
}
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);
_boneNameStyle.alignment = TextAnchor.MiddleCenter;
_boneNameStyle.stretchWidth = true;
_boneNameStyle.padding = new RectOffset(0, 0, 0, 0);
_boneNameStyle.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;
}
}
public static void DrawBoneNames (Transform transform, Skeleton skeleton) {
GUIStyle style = BoneNameStyle;
foreach (Bone b in skeleton.Bones) {
var pos = new Vector3(b.WorldX, b.WorldY, 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 boneScale = 1.8f; // Draw the root bone largest;
DrawCrosshairs2D(skeleton.Bones.Items[0].GetWorldPosition(transform), 0.08f);
foreach (Bone b in skeleton.Bones) {
DrawBone(transform, b, boneScale);
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) {
Handles.color = color;
var pos = new Vector3(b.WorldX, b.WorldY, 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 *= (SpineHandles.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my, my);
Handles.DrawPolyLine(GetBoneWireBuffer(transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)));
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward);
} else {
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward);
}
}
public static void DrawBone (Transform transform, Bone b, float boneScale) {
var pos = new Vector3(b.WorldX, b.WorldY, 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 *= (SpineHandles.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my, my);
SpineHandles.BoneMaterial.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);
}
}
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;
static public void DrawPath (Slot s, PathAttachment p, Transform t) {
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 = new Color(254f/255f, 127f/255f, 0); // Path orange
Handles.color = SpineHandles.PathColor;
Matrix4x4 m = t.localToWorldMatrix;
const int step = 6;
@ -1445,38 +1594,37 @@ namespace Spine.Unity.Editor {
}
const float endCapSize = 0.05f;
var q = Quaternion.identity;
Handles.DotCap(0, m.MultiplyPoint(new Vector3(pv[2], pv[3])), q, endCapSize);
// if (!p.Closed) Handles.DotCap(0, m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3])), q, endCapSize);
Vector3 firstPoint = m.MultiplyPoint(new Vector3(pv[2], pv[3]));
Handles.DotCap(0, firstPoint, Quaternion.identity, endCapSize * HandleUtility.GetHandleSize(firstPoint));
// if (!p.Closed) Handles.DotCap(0, m.MultiplyPoint(new Vector3(pv[n - 4], pv[n - 3])), q, endCapSize);
if (includeName) Handles.Label(firstPoint + new Vector3(0,0.1f), p.Name, PathNameStyle);
Handles.color = ocolor;
}
static public 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);
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);
}
}
static public void DrawBoundingBox (Slot slot, BoundingBoxAttachment box) {
public static void DrawBoundingBox (Slot slot, BoundingBoxAttachment box, Transform t) {
if (box.Vertices.Length <= 0) return; // Handle cases where user creates a BoundingBoxAttachment but doesn't actually define it.
var worldVerts = new float[box.Vertices.Length];
box.ComputeWorldVertices(slot, worldVerts);
Handles.color = Color.green;
Vector3 lastVert = Vector3.back;
Vector3 vert = Vector3.back;
Vector3 firstVert = new Vector3(worldVerts[0], worldVerts[1], -1);
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);
@ -1486,10 +1634,154 @@ namespace Spine.Unity.Editor {
Handles.DrawLine(lastVert, firstVert);
}
#endregion
public static string GetPathSafeRegionName (AtlasRegion region) {
return region.name.Replace("/", "_");
public static void DrawConstraints (Transform transform, Skeleton skeleton) {
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);
if (tc.TranslateMix > 0) {
if (tc.TranslateMix != 1f) {
Handles.color = handleColor;
foreach (var b in tc.Bones) {
pos = b.GetWorldPosition(transform);
Handles.DrawDottedLine(targetPos, pos, Thickness);
}
}
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f);
Handles.color = handleColor;
SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform);
}
}
// IK Constraints
handleColor = SpineHandles.IkColor;
foreach (var ikc in skeleton.IkConstraints) {
Bone targetBone = ikc.Target;
targetPos = targetBone.GetWorldPosition(transform);
var bones = ikc.Bones;
active = ikc.Mix > 0;
if (active) {
pos = bones.Items[0].GetWorldPosition(transform);
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;
m.m13 = targetBone.WorldY;
SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m);
break;
}
case 2: {
Bone childBone = bones.Items[1];
Vector3 child = childBone.GetWorldPosition(transform);
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;
m.m13 = targetBone.WorldY;
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), handleColor, normal, 1f);
}
}
static void DrawCrosshairs2D (Vector3 position, float scale) {
scale *= SpineHandles.handleScale;
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) {
scale *= SpineHandles.handleScale;
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 *= SpineHandles.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 (Matrix4x4 m) {
var s = SpineHandles.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 *= SpineHandles.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 * SpineHandles.handleScale);
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);
}
}

View File

@ -45,11 +45,37 @@ namespace Spine.Unity.Modules {
[SpineSlot] public string slot;
#endregion
#if UNITY_EDITOR
void OnValidate () {
var skeletonComponent = GetComponent<ISkeletonComponent>();
var skeletonRenderer = skeletonComponent as SkeletonRenderer;
bool apma;
if (skeletonRenderer != null) {
apma = skeletonRenderer.pmaVertexColors;
} else {
var skeletonGraphic = skeletonComponent as SkeletonGraphic;
apma = skeletonGraphic != null && skeletonGraphic.SpineMeshGenerator.PremultiplyVertexColors;
}
if (apma) {
try {
sprite.texture.GetPixel(0, 0);
} catch (UnityException e) {
Debug.LogFormat("Texture of {0} ({1}) is not read/write enabled. SpriteAttacher requires this in order to work with a SkeletonRenderer that renders premultiplied alpha. Please check the texture settings.", sprite.name, sprite.texture.name);
UnityEditor.EditorGUIUtility.PingObject(sprite.texture);
throw e;
}
}
}
#endif
RegionAttachment attachment;
bool applyPMA;
Dictionary<Texture, AtlasPage> atlasPageCache = new Dictionary<Texture, AtlasPage>();
AtlasPage GetPageFor (Texture texture, Shader shader) {
static Dictionary<Texture, AtlasPage> atlasPageCache;
static AtlasPage GetPageFor (Texture texture, Shader shader) {
if (atlasPageCache == null) atlasPageCache = new Dictionary<Texture, AtlasPage>();
AtlasPage atlasPage;
atlasPageCache.TryGetValue(texture, out atlasPage);
if (atlasPage == null) {
@ -76,7 +102,7 @@ namespace Spine.Unity.Modules {
}
Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader);
attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(GetPageFor(sprite.texture, attachmentShader));
attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader));
skeletonComponent.Skeleton.FindSlot(slot).Attachment = attachment;
}
}

View File

@ -175,11 +175,12 @@ namespace Spine.Unity.Editor {
#region Menus
[MenuItem("CONTEXT/SkeletonRenderer/Add BoundingBoxFollower GameObject")]
static void AddBoundingBoxFollowerChild (MenuCommand command) {
AddBoundingBoxFollowerChild((SkeletonRenderer)command.context);
var go = AddBoundingBoxFollowerChild((SkeletonRenderer)command.context);
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollower");
}
#endregion
static void AddBoundingBoxFollowerChild (SkeletonRenderer sr, BoundingBoxFollower original = null) {
static GameObject AddBoundingBoxFollowerChild (SkeletonRenderer sr, BoundingBoxFollower original = null) {
var go = new GameObject("BoundingBoxFollower");
go.transform.SetParent(sr.transform, false);
var newFollower = go.AddComponent<BoundingBoxFollower>();
@ -196,6 +197,7 @@ namespace Spine.Unity.Editor {
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
return go;
}
}

View File

@ -90,26 +90,6 @@ inline half3 calculateNormalFromBumpMap(float2 texUV, half3 tangentWorld, half3
#endif // _NORMALMAP
#if defined(_DIFFUSE_RAMP)
////////////////////////////////////////
// Diffuse ramp functions
//
uniform sampler2D _DiffuseRamp;
inline fixed3 calculateDiffuseRamp(float ramp)
{
return tex2D(_DiffuseRamp, float2(ramp, ramp)).rgb;
}
inline fixed3 calculateRampedDiffuse(fixed3 lightColor, float attenuation, float angleDot)
{
float ramp = clamp(((angleDot * 0.5) + 0.5) * attenuation, 0.0, 1.0);
return lightColor * calculateDiffuseRamp(ramp);
}
#endif // _DIFFUSE_RAMP
////////////////////////////////////////
// Blending functions
//

View File

@ -39,11 +39,9 @@ inline half3 calculateSpriteWorldNormal(VertexInput vertex)
//Rotate fixed normal by inverse camera matrix to convert the fixed normal into world space
float3x3 invView = transpose((float3x3)UNITY_MATRIX_VP);
float3 normal = _FixedNormal.xyz;
#if UNITY_REVERSED_Z
normal.z = -normal.z;
#endif
return normalize(mul(invView, normal));
#endif // !MESH_NORMALS
}
@ -84,6 +82,36 @@ inline half3 calculateSpriteWorldBinormal(half3 normalWorld, half3 tangentWorld,
#endif // _NORMALMAP
#if defined(_DIFFUSE_RAMP)
////////////////////////////////////////
// Diffuse ramp functions
//
//Disable for softer, more traditional diffuse ramping
#define HARD_DIFFUSE_RAMP
uniform sampler2D _DiffuseRamp;
inline fixed3 calculateDiffuseRamp(float ramp)
{
return tex2D(_DiffuseRamp, float2(ramp, ramp)).rgb;
}
inline fixed3 calculateRampedDiffuse(fixed3 lightColor, float attenuation, float angleDot)
{
float d = angleDot * 0.5 + 0.5;
#if defined(HARD_DIFFUSE_RAMP)
half3 ramp = calculateDiffuseRamp(d * attenuation * 2);
return lightColor * ramp;
#else
half3 ramp = calculateDiffuseRamp(d);
return lightColor * ramp * (attenuation * 2);
#endif
}
#endif // _DIFFUSE_RAMP
////////////////////////////////////////
// Rim Lighting functions
//

View File

@ -55,10 +55,10 @@ inline fixed3 calculateLightDiffuse(VertexOutput input, float3 normalWorld)
float3 lightWorldDirection = normalize(_WorldSpaceLightPos0.xyz - input.posWorld.xyz * _WorldSpaceLightPos0.w);
float attenuation = LIGHT_ATTENUATION(input);
float angleDot = dotClamped(normalWorld, lightWorldDirection);
float angleDot = max(0, dot(normalWorld, lightWorldDirection));
#if defined(_DIFFUSE_RAMP)
fixed3 lightDiffuse = calculateRampedDiffuse(_LightColor0.rgb, sqrt(attenuation), angleDot);
fixed3 lightDiffuse = calculateRampedDiffuse(_LightColor0.rgb, attenuation, angleDot);
#else
fixed3 lightDiffuse = _LightColor0.rgb * (attenuation * angleDot);
#endif // _DIFFUSE_RAMP
@ -147,7 +147,7 @@ fixed4 fragBase(VertexOutput input) : SV_Target
fixed3 diffuse = calculateLightDiffuse(input, normalWorld);
//Combine along with vertex lighting for the base lighting pass
fixed3 lighting = saturate(ambient + diffuse + input.vertexLighting);
fixed3 lighting = ambient + diffuse + input.vertexLighting;
APPLY_EMISSION(lighting, input.texcoord)

View File

@ -126,7 +126,7 @@ struct VertexLightInfo
fixed3 lightColor;
#if defined(_DIFFUSE_RAMP)
float attenuationSqrt;
float attenuation;
#endif // _DIFFUSE_RAMP
};
@ -134,7 +134,7 @@ inline VertexLightInfo getVertexLightAttenuatedInfo(int index, float3 viewPos)
{
VertexLightInfo lightInfo;
//For directional lights _WorldSpaceLightPos0.w is set to zero
//For directional lights unity_LightPosition.w is set to zero
lightInfo.lightDirection = unity_LightPosition[index].xyz - viewPos.xyz * unity_LightPosition[index].w;
float lengthSq = dot(lightInfo.lightDirection, lightInfo.lightDirection);
@ -157,7 +157,7 @@ inline VertexLightInfo getVertexLightAttenuatedInfo(int index, float3 viewPos)
//If using a diffuse ramp texture then need to pass through the lights attenuation, otherwise premultiply the light color with it
#if defined(_DIFFUSE_RAMP)
lightInfo.lightColor = unity_LightColor[index].rgb;
lightInfo.attenuationSqrt = sqrt(attenuation);
lightInfo.attenuation = attenuation;
#else
lightInfo.lightColor = unity_LightColor[index].rgb * attenuation;
#endif // _DIFFUSE_RAMP
@ -205,25 +205,23 @@ fixed3 calculateAmbientLight(half3 normalWorld)
}
////////////////////////////////////////
// Light Packing Functions (this stuff gets messy!)
// Light Packing Functions
//
#if defined(_DIFFUSE_RAMP)
inline fixed3 calculateLightDiffuse(fixed3 lightColor, half3 normal, half3 lightDirection, float attenuation)
inline fixed3 calculateLightDiffuse(fixed3 lightColor, half3 viewNormal, half3 lightViewDir, float attenuation)
{
float angleDot = max(0, dot(normal, lightDirection));
fixed3 diffuse = calculateRampedDiffuse(lightColor, attenuation, angleDot);
return diffuse;
float angleDot = max(0, dot(viewNormal, lightViewDir));
return calculateRampedDiffuse(lightColor, attenuation, angleDot);
}
#else
inline fixed3 calculateLightDiffuse(fixed3 attenuatedLightColor, half3 normal, half3 lightDirection)
inline fixed3 calculateLightDiffuse(fixed3 attenuatedLightColor, half3 viewNormal, half3 lightViewDir)
{
float angleDot = max(0, dot(normal, lightDirection));
fixed3 diffuse = attenuatedLightColor * angleDot;
return diffuse;
float angleDot = max(0, dot(viewNormal, lightViewDir));
return attenuatedLightColor * angleDot;
}
#endif // _NORMALMAP
@ -231,16 +229,6 @@ inline fixed3 calculateLightDiffuse(fixed3 attenuatedLightColor, half3 normal, h
#if defined(PER_PIXEL_LIGHTING)
inline VertexLightInfo getVertexLightAttenuatedInfoWorldSpace(int index, float3 viewPos)
{
VertexLightInfo lightInfo = getVertexLightAttenuatedInfo(index, viewPos);
//Convert light direction from view space to world space
lightInfo.lightDirection = normalize(mul((float3x3)UNITY_MATRIX_V, lightInfo.lightDirection));
return lightInfo;
}
#define VERTEX_LIGHT_0_DIR VertexLightInfo0.xyz
#define VERTEX_LIGHT_0_R VertexLightInfo4.x
#define VERTEX_LIGHT_0_G VertexLightInfo4.y
@ -277,24 +265,24 @@ inline VertexLightInfo getVertexLightAttenuatedInfoWorldSpace(int index, float3
#define PACK_VERTEX_LIGHT_DIFFUSE(index, output, lightInfo) \
{ \
output.LIGHT_DIFFUSE_ATTEN_##index = lightInfo.attenuationSqrt; \
output.LIGHT_DIFFUSE_ATTEN_##index = lightInfo.attenuation; \
}
#define ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, vertexLightColor, normalDirection, vertexLightDir) \
#define ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, lightColor, viewNormal, lightViewDir) \
{ \
diffuse += calculateLightDiffuse(vertexLightColor, normalDirection, vertexLightDir, input.LIGHT_DIFFUSE_ATTEN_##index); \
diffuse += calculateLightDiffuse(lightColor, viewNormal, lightViewDir, input.LIGHT_DIFFUSE_ATTEN_##index); \
}
#else
#define PACK_VERTEX_LIGHT_DIFFUSE(index, output, lightInfo)
#define ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, vertexLightColor, normalDirection, vertexLightDir) \
#define ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, lightColor, viewNormal, lightViewDir) \
{ \
diffuse += calculateLightDiffuse(vertexLightColor, normalDirection, vertexLightDir); \
diffuse += calculateLightDiffuse(lightColor, viewNormal, lightViewDir); \
}
#endif
#define PACK_VERTEX_LIGHT(index, output, viewPos) \
{ \
VertexLightInfo lightInfo = getVertexLightAttenuatedInfoWorldSpace(index, viewPos); \
VertexLightInfo lightInfo = getVertexLightAttenuatedInfo(index, viewPos); \
output.VERTEX_LIGHT_##index##_DIR = lightInfo.lightDirection; \
output.VERTEX_LIGHT_##index##_R = lightInfo.lightColor.r; \
output.VERTEX_LIGHT_##index##_G = lightInfo.lightColor.g; \
@ -302,11 +290,11 @@ inline VertexLightInfo getVertexLightAttenuatedInfoWorldSpace(int index, float3
PACK_VERTEX_LIGHT_DIFFUSE(index, output, lightInfo); \
}
#define ADD_VERTEX_LIGHT(index, input, normalDirection, diffuse) \
#define ADD_VERTEX_LIGHT(index, input, viewNormal, diffuse) \
{ \
half3 vertexLightDir = input.VERTEX_LIGHT_##index##_DIR; \
fixed3 vertexLightColor = fixed3(input.VERTEX_LIGHT_##index##_R, input.VERTEX_LIGHT_##index##_G, input.VERTEX_LIGHT_##index##_B); \
ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, vertexLightColor, normalDirection, vertexLightDir) \
half3 lightViewDir = input.VERTEX_LIGHT_##index##_DIR; \
fixed3 lightColor = fixed3(input.VERTEX_LIGHT_##index##_R, input.VERTEX_LIGHT_##index##_G, input.VERTEX_LIGHT_##index##_B); \
ADD_VERTEX_LIGHT_DIFFUSE(index, diffuse, input, lightColor, viewNormal, lightViewDir) \
}
#else //!PER_PIXEL_LIGHTING
@ -318,8 +306,8 @@ inline VertexLightInfo getVertexLightAttenuatedInfoWorldSpace(int index, float3
inline fixed3 calculateLightDiffuse(int index, float3 viewPos, half3 viewNormal)
{
VertexLightInfo lightInfo = getVertexLightAttenuatedInfo(index, viewPos);
float diff = max (0, dot (viewNormal, lightInfo.lightDirection));
return lightInfo.lightColor * diff;
float angleDot = max(0, dot(viewNormal, lightInfo.lightDirection));
return lightInfo.lightColor * angleDot;
}
#endif // !PER_PIXEL_LIGHTING
@ -405,10 +393,11 @@ fixed4 frag(VertexOutput input) : SV_Target
fixed3 diffuse = fixed3(0,0,0);
//Add each vertex light to diffuse
ADD_VERTEX_LIGHT(0, input, normalWorld, diffuse)
ADD_VERTEX_LIGHT(1, input, normalWorld, diffuse)
ADD_VERTEX_LIGHT(2, input, normalWorld, diffuse)
ADD_VERTEX_LIGHT(3, input, normalWorld, diffuse)
half3 normalView = normalize(mul((float3x3)UNITY_MATRIX_V, normalWorld));
ADD_VERTEX_LIGHT(0, input, normalView, diffuse)
ADD_VERTEX_LIGHT(1, input, normalView, diffuse)
ADD_VERTEX_LIGHT(2, input, normalView, diffuse)
ADD_VERTEX_LIGHT(3, input, normalView, diffuse)
fixed3 lighting = ambient + diffuse;

View File

@ -27,7 +27,7 @@ Shader "Spine/Sprite/Pixel Lit"
_BlendTex ("Blend Texture", 2D) = "white" {}
_BlendAmount ("Blend", Range(0,1)) = 0.0
[HideInInspector] _SrcBlend ("__src", Float) = 1.0
[HideInInspector] _DstBlend ("__dst", Float) = 0.0
[HideInInspector] _RenderQueue ("__queue", Float) = 0.0
@ -36,7 +36,7 @@ Shader "Spine/Sprite/Pixel Lit"
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Sprite" }
Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" }
LOD 200
Pass
@ -64,7 +64,7 @@ Shader "Spine/Sprite/Pixel Lit"
#pragma shader_feature _FOG
#pragma multi_compile_fwdbase
#pragma fragmentoption ARB_precision_hint_fastest
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_fog
#pragma vertex vert

View File

@ -16,7 +16,7 @@ Shader "Spine/Sprite/Unlit"
_BlendTex ("Blend Texture", 2D) = "white" {}
_BlendAmount ("Blend", Range(0,1)) = 0.0
[HideInInspector] _SrcBlend ("__src", Float) = 1.0
[HideInInspector] _DstBlend ("__dst", Float) = 0.0
[HideInInspector] _RenderQueue ("__queue", Float) = 0.0
@ -25,7 +25,7 @@ Shader "Spine/Sprite/Unlit"
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Sprite" }
Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" }
LOD 100
Pass

View File

@ -27,7 +27,7 @@ Shader "Spine/Sprite/Vertex Lit"
_BlendTex ("Blend Texture", 2D) = "white" {}
_BlendAmount ("Blend", Range(0,1)) = 0.0
[HideInInspector] _SrcBlend ("__src", Float) = 1.0
[HideInInspector] _DstBlend ("__dst", Float) = 0.0
[HideInInspector] _RenderQueue ("__queue", Float) = 0.0
@ -36,7 +36,7 @@ Shader "Spine/Sprite/Vertex Lit"
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Sprite" }
Tags { "Queue"="Transparent" "RenderType"="Sprite" "AlphaDepth"="False" }
LOD 150
Pass

View File

@ -266,7 +266,9 @@ namespace Spine.Unity.Modules {
[MenuItem ("CONTEXT/SkeletonRenderer/Add Skeleton Render Separator")]
static void AddRenderSeparatorComponent (MenuCommand cmd) {
var skeletonRenderer = cmd.context as SkeletonRenderer;
skeletonRenderer.gameObject.AddComponent<SkeletonRenderSeparator>();
var newComponent = skeletonRenderer.gameObject.AddComponent<SkeletonRenderSeparator>();
Undo.RegisterCreatedObjectUndo(newComponent, "Add SkeletonRenderSeparator");
}
// Validate

View File

@ -18,7 +18,7 @@ Category {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_particles
// #pragma multi_compile_particles
#include "UnityCG.cginc"
@ -35,21 +35,20 @@ Category {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
#ifdef SOFTPARTICLES_ON
float4 projPos : TEXCOORD1;
#endif
// #ifdef SOFTPARTICLES_ON
// float4 projPos : TEXCOORD1;
// #endif
};
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f vert (appdata_t v) {
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
#ifdef SOFTPARTICLES_ON
o.projPos = ComputeScreenPos (o.vertex);
COMPUTE_EYEDEPTH(o.projPos.z);
#endif
// #ifdef SOFTPARTICLES_ON
// o.projPos = ComputeScreenPos (o.vertex);
// COMPUTE_EYEDEPTH(o.projPos.z);
// #endif
o.color = v.color;
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
@ -57,9 +56,8 @@ Category {
sampler2D_float _CameraDepthTexture;
fixed4 frag (v2f i) : SV_Target
{
return 2.0f * i.color * _Color * tex2D(_MainTex, i.texcoord);
fixed4 frag (v2f i) : SV_Target {
return i.color * _Color * tex2D(_MainTex, i.texcoord);
}
ENDCG
}

View File

@ -39,6 +39,7 @@ namespace Spine.Unity {
public enum MixMode { AlwaysMix, MixNext, SpineStyle }
public MixMode[] layerMixModes = new MixMode[0];
public bool autoReset = false;
#region Bone Callbacks (ISkeletonAnimation)
protected event UpdateBonesDelegate _UpdateLocal;
@ -88,6 +89,39 @@ namespace Spine.Unity {
//skeleton.Update(Time.deltaTime); // Doesn't actually do anything, currently. (Spine 3.5).
// Clear Previous
if (autoReset)
{
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
float layerWeight = animator.GetLayerWeight(layer);
if (layerWeight <= 0) continue;
AnimatorStateInfo nextStateInfo = animator.GetNextAnimatorStateInfo(layer);
#if UNITY_5
bool hasNext = nextStateInfo.fullPathHash != 0;
AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(layer);
AnimatorClipInfo[] nextClipInfo = animator.GetNextAnimatorClipInfo(layer);
#else
bool hasNext = nextStateInfo.nameHash != 0;
var clipInfo = animator.GetCurrentAnimationClipState(i);
var nextClipInfo = animator.GetNextAnimationClipState(i);
#endif
for (int c = 0; c < clipInfo.Length; c++) {
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
animationTable[NameHashCode(info.clip)].SetKeyedItemsToSetupPose(skeleton);
}
if (hasNext) {
for (int c = 0; c < nextClipInfo.Length; c++) {
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
animationTable[NameHashCode(info.clip)].SetKeyedItemsToSetupPose(skeleton);
}
}
}
}
// Apply
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
float layerWeight = (layer == 0) ? 1 : animator.GetLayerWeight(layer);

View File

@ -118,6 +118,12 @@ namespace Spine.Unity {
return new Vector2(bone.worldX, bone.worldY);
}
public static Vector2 GetSkeletonSpacePosition (this Bone bone, Vector2 boneLocal) {
Vector2 o;
bone.LocalToWorld(boneLocal.x, boneLocal.y, out o.x, out o.y);
return o;
}
public static Vector3 GetWorldPosition (this Bone bone, UnityEngine.Transform parentTransform) {
return parentTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY));
}
@ -142,15 +148,23 @@ namespace Spine.Unity {
#region Attachments
public static Material GetMaterial (this Attachment a) {
object rendererObject = null;
var regionAttachment = a as RegionAttachment;
if (regionAttachment != null)
return (Material)((AtlasRegion)regionAttachment.RendererObject).page.rendererObject;
rendererObject = regionAttachment.RendererObject;
var meshAttachment = a as MeshAttachment;
if (meshAttachment != null)
return (Material)((AtlasRegion)meshAttachment.RendererObject).page.rendererObject;
rendererObject = meshAttachment.RendererObject;
return null;
if (rendererObject == null)
return null;
#if SPINE_TK2D
return (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
#else
return (Material)((AtlasRegion)rendererObject).page.rendererObject;
#endif
}
/// <summary>Fills a Vector2 buffer with local vertices.</summary>

View File

@ -233,7 +233,6 @@ namespace Spine.Unity.Editor {
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) {

View File

@ -46,7 +46,8 @@ namespace Spine.Unity.Editor {
SkeletonUtility skeletonUtility;
Skeleton skeleton;
SkeletonRenderer skeletonRenderer;
Transform transform;
Skin activeSkin;
bool isPrefab;
Dictionary<Slot, List<Attachment>> attachmentTable = new Dictionary<Slot, List<Attachment>>();
@ -54,14 +55,12 @@ namespace Spine.Unity.Editor {
GUIContent SpawnHierarchyButtonLabel = new GUIContent("Spawn Hierarchy", Icons.skeleton);
GUIContent SlotsRootLabel = new GUIContent("Slots", Icons.slotRoot);
static AnimBool showSlots = new AnimBool(false);
static bool showPaths = true;
static bool debugSkeleton = false;
void OnEnable () {
skeletonUtility = (SkeletonUtility)target;
skeletonRenderer = skeletonUtility.GetComponent<SkeletonRenderer>();
skeleton = skeletonRenderer.skeleton;
transform = skeletonRenderer.transform;
skeleton = skeletonRenderer.Skeleton;
if (skeleton == null) {
skeletonRenderer.Initialize(false);
@ -74,33 +73,12 @@ namespace Spine.Unity.Editor {
UpdateAttachments();
isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab;
}
void OnSceneGUI () {
if (skeleton == null) {
OnEnable();
return;
}
var m = transform.localToWorldMatrix;
foreach (Bone b in skeleton.Bones) {
Vector3 pos = new Vector3(b.WorldX, b.WorldY, 0);
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX - 90f);
Vector3 scale = Vector3.one * b.Data.Length * b.WorldScaleX;
const float mx = 2f;
scale.x = Mathf.Clamp(scale.x, -mx, mx);
SpineEditorUtilities.DrawBone(m * Matrix4x4.TRS(pos, rot, scale));
}
if (showPaths) {
foreach (Slot s in skeleton.DrawOrder) {
var p = s.Attachment as PathAttachment;
if (p != null) SpineEditorUtilities.DrawPath(s, p, transform);
}
}
}
public override void OnInspectorGUI () {
bool requireRepaint = false;
if (skeletonRenderer.skeleton != skeleton || activeSkin != skeleton.Skin) {
UpdateAttachments();
}
if (isPrefab) {
GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning));
@ -123,10 +101,6 @@ namespace Spine.Unity.Editor {
debugSkeleton = EditorGUILayout.Foldout(debugSkeleton, "Debug Skeleton");
if (debugSkeleton) {
EditorGUI.BeginChangeCheck();
showPaths = EditorGUILayout.Toggle("Show Paths", showPaths);
requireRepaint |= EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
skeleton.FlipX = EditorGUILayout.ToggleLeft("skeleton.FlipX", skeleton.FlipX);
skeleton.FlipY = EditorGUILayout.ToggleLeft("skeleton.FlipY", skeleton.FlipY);
@ -183,13 +157,20 @@ namespace Spine.Unity.Editor {
}
void UpdateAttachments () {
attachmentTable = new Dictionary<Slot, List<Attachment>>();
Skin skin = skeleton.Skin ?? skeletonRenderer.skeletonDataAsset.GetSkeletonData(true).DefaultSkin;
skeleton = skeletonRenderer.skeleton;
Skin defaultSkin = skeleton.Data.DefaultSkin;
Skin skin = skeleton.Skin ?? defaultSkin;
bool notDefaultSkin = skin != defaultSkin;
attachmentTable.Clear();
for (int i = skeleton.Slots.Count - 1; i >= 0; i--) {
var attachments = new List<Attachment>();
skin.FindAttachmentsForSlot(i, attachments);
attachmentTable.Add(skeleton.Slots.Items[i], attachments);
skin.FindAttachmentsForSlot(i, attachments); // Add skin attachments.
if (notDefaultSkin) defaultSkin.FindAttachmentsForSlot(i, attachments); // Add default skin attachments.
}
activeSkin = skeleton.Skin;
}
// void SpawnHierarchyButton (string label, string tooltip, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca, params GUILayoutOption[] options) {

View File

@ -224,7 +224,7 @@ namespace Spine.Unity {
var utilityBones = this.utilityBones;
for (int i = 0, n = utilityBones.Count; i < n; i++) {
var b = utilityBones[i];
if (b.bone == null) return;
if (b.bone == null) continue;
hasTransformBones |= (b.mode == SkeletonUtilityBone.Mode.Override);
hasUtilityConstraints |= constraintTargets.Contains(b.bone);
}

View File

@ -117,8 +117,11 @@ namespace Spine.Unity {
float skeletonFlipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f;
if (mode == Mode.Follow) {
if (!bone.appliedValid)
bone.UpdateAppliedTransform();
if (position)
cachedTransform.localPosition = new Vector3(bone.x, bone.y, 0);
cachedTransform.localPosition = new Vector3(bone.ax, bone.ay, 0);
if (rotation) {
if (bone.data.transformMode.InheritsRotation()) {
@ -130,7 +133,7 @@ namespace Spine.Unity {
}
if (scale) {
cachedTransform.localScale = new Vector3(bone.scaleX, bone.scaleY, 1f);
cachedTransform.localScale = new Vector3(bone.ascaleX, bone.ascaleY, 1f);
incompatibleTransformMode = BoneTransformModeIncompatible(bone);
}
} else if (mode == Mode.Override) {