Merge branch '3.6' into 3.7-beta

This commit is contained in:
badlogic 2017-10-30 10:11:26 +01:00
commit 581d67f490
63 changed files with 2034 additions and 1535 deletions

View File

@ -85,6 +85,7 @@
* Added support for two color tinting. All base materials, e.g. SpineUnlitNormalMaterial, now do proper two color tinting. No material parameters have changed.
* Updated to Unreal Engine 4.16.1. Note that 4.16 has a regression which will make it impossible to compile plain .c files!
* spine-c is now exposed from the plugin shared library on Windows via __declspec.
* Updated to Unreal Engine 4.18
## C#
* **Breaking changes**

View File

@ -33,6 +33,7 @@ package spine {
public class PathConstraint implements Constraint {
private static const NONE : int = -1, BEFORE : int = -2, AFTER : int = -3;
private static const epsilon : Number = 0.00001;
internal var _data : PathConstraintData;
internal var _bones : Vector.<Bone>;
public var target : Slot;
@ -88,11 +89,15 @@ package spine {
for (var i : int = 0, n : int = spacesCount - 1; i < n;) {
var bone : Bone = bones[i];
var setupLength : Number = bone.data.length;
if (setupLength == 0) setupLength = 0.000000001;
var x : Number = setupLength * bone.a, y : Number = setupLength * bone.c;
var length : Number = Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
spaces[++i] = 0;
} else {
var x : Number = setupLength * bone.a, y : Number = setupLength * bone.c;
var length : Number = Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (i = 1; i < spacesCount; i++)

View File

@ -207,9 +207,10 @@ package spine.animation {
if (from.mixingFrom != null) applyMixingFrom(from, skeleton, currentPose);
var mix : Number = 0;
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
mix = 1;
else {
currentPose = MixPose.setup;
} else {
mix = to.mixTime / to.mixDuration;
if (mix > 1) mix = 1;
}

View File

@ -253,10 +253,10 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
bone->rotation = bone->data->rotation;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
r = bone->data->rotation - bone->rotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
bone->rotation += r * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -333,9 +333,9 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
bone->y = bone->data->y;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
bone->x += (bone->data->x - bone->x) * alpha;
bone->y += (bone->data->y - bone->y) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -405,9 +405,9 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
bone->scaleY = bone->data->scaleY;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
bone->scaleX += (bone->data->scaleX - bone->scaleX) * alpha;
bone->scaleY += (bone->data->scaleY - bone->scaleY) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -492,9 +492,9 @@ void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
bone->shearY = bone->data->shearY;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
bone->shearX += (bone->data->shearX - bone->shearX) * alpha;
bone->shearY += (bone->data->shearY - bone->shearY) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -561,11 +561,11 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
spColor_setFromColor(&slot->color, &slot->data->color);
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
color = &slot->color;
setup = &slot->data->color;
spColor_addFloats(color, (setup->r - color->r) * alpha, (setup->g - color->g) * alpha, (setup->b - color->b) * alpha,
(setup->a - color->a) * alpha);
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -651,7 +651,6 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
spColor_setFromColor(slot->darkColor, slot->data->darkColor);
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
light = &slot->color;
dark = slot->darkColor;
setupLight = &slot->data->color;
@ -659,6 +658,7 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
spColor_addFloats(light, (setupLight->r - light->r) * alpha, (setupLight->g - light->g) * alpha, (setupLight->b - light->b) * alpha,
(setupLight->a - light->a) * alpha);
spColor_addFloats(dark, (setupDark->r - dark->r) * alpha, (setupDark->g - dark->g) * alpha, (setupDark->b - dark->b) * alpha, 0);
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -863,7 +863,6 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
slot->attachmentVerticesCount = 0;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
if (alpha == 1) {
slot->attachmentVerticesCount = 0;
return;
@ -880,6 +879,7 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
vertices[i] *= alpha;
}
}
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -1164,9 +1164,9 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
constraint->bendDirection = constraint->data->bendDirection;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
constraint->mix += (constraint->data->mix - constraint->mix) * alpha;
constraint->bendDirection = constraint->data->bendDirection;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -1250,11 +1250,11 @@ void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleto
constraint->shearMix = data->shearMix;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
constraint->rotateMix += (data->rotateMix - constraint->rotateMix) * alpha;
constraint->translateMix += (data->translateMix - constraint->translateMix) * alpha;
constraint->scaleMix += (data->scaleMix - constraint->scaleMix) * alpha;
constraint->shearMix += (data->shearMix - constraint->shearMix) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
return;
@ -1341,8 +1341,8 @@ void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkele
constraint->position = constraint->data->position;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
constraint->position += (constraint->data->position - constraint->position) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -1406,8 +1406,8 @@ void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkelet
constraint->spacing = constraint->data->spacing;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
constraint->spacing += (constraint->data->spacing - constraint->spacing) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}
@ -1476,9 +1476,9 @@ void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton*
constraint->translateMix = constraint->data->translateMix;
return;
case SP_MIX_POSE_CURRENT:
case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
constraint->rotateMix += (constraint->data->rotateMix - constraint->rotateMix) * alpha;
constraint->translateMix += (constraint->data->translateMix - constraint->translateMix) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */
}
return;
}

View File

@ -419,9 +419,10 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
spTrackEntry* from = to->mixingFrom;
if (from->mixingFrom) _spAnimationState_applyMixingFrom(self, from, skeleton, currentPose);
if (to->mixDuration == 0) /* Single frame mix to undo mixingFrom changes. */
if (to->mixDuration == 0) { /* Single frame mix to undo mixingFrom changes. */
mix = 1;
else {
currentPose = SP_MIX_POSE_SETUP;
} else {
mix = to->mixTime / to->mixDuration;
if (mix > 1) mix = 1;
}

View File

@ -35,6 +35,7 @@
#define PATHCONSTRAINT_NONE -1
#define PATHCONSTRAINT_BEFORE -2
#define PATHCONSTRAINT_AFTER -3
#define EPSILON 0.00001f
spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const spSkeleton* skeleton) {
int i;
@ -113,13 +114,17 @@ void spPathConstraint_apply (spPathConstraint* self) {
lengths = self->lengths;
}
for (i = 0, n = spacesCount - 1; i < n;) {
spBone* bone = bones[i];
spBone *bone = bones[i];
setupLength = bone->data->length;
if (setupLength == 0) setupLength = 0.000000001f;
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
if (setupLength < EPSILON) {
if (scale) lengths[i] = 0;
spaces[++i] = 0;
} else {
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (i = 1; i < spacesCount; i++) {

View File

@ -220,9 +220,10 @@ namespace Spine {
if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton, currentPose);
float mix;
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
mix = 1;
else {
currentPose = MixPose.Setup;
} else {
mix = to.mixTime / to.mixDuration;
if (mix > 1) mix = 1;
}
@ -258,13 +259,17 @@ namespace Spine {
break;
case Dip:
pose = MixPose.Setup;
alpha = alphaDip;
alpha = mix == 1 ? 0 : alphaDip;
break;
default:
pose = MixPose.Setup;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
alpha *= Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
if (mix == 1) {
alpha = 0;
} else {
alpha = alphaDip;
var dipMix = timelineDipMix[i];
alpha *= Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
}
break;
}
from.totalAlpha += alpha;

View File

@ -1,4 +1,4 @@
//
//
// System.Collections.Generic.List
//
// Authors:
@ -90,7 +90,18 @@ namespace Spine {
}
public ExposedList<T> Resize (int newSize) {
if (newSize > Items.Length) Array.Resize(ref Items, newSize);
int itemsLength = Items.Length;
var oldItems = Items;
if (newSize > itemsLength) {
Array.Resize(ref Items, newSize);
// var newItems = new T[newSize];
// Array.Copy(oldItems, newItems, Count);
// Items = newItems;
} else if (newSize < itemsLength) {
// Allow nulling of T reference type to allow GC.
for (int i = newSize; i < itemsLength; i++)
oldItems[i] = default(T);
}
Count = newSize;
return this;
}

View File

@ -33,6 +33,7 @@ using System;
namespace Spine {
public class PathConstraint : IConstraint {
const int NONE = -1, BEFORE = -2, AFTER = -3;
const float Epsilon = 0.00001f;
internal PathConstraintData data;
internal ExposedList<Bone> bones;
@ -93,11 +94,15 @@ namespace Spine {
for (int i = 0, n = spacesCount - 1; i < n;) {
Bone bone = bonesItems[i];
float setupLength = bone.data.length;
if (setupLength == 0) setupLength = 0.000000001f;
float x = setupLength * bone.a, y = setupLength * bone.c;
float length = (float)Math.Sqrt(x * x + y * y);
if (scale) lengths.Items[i] = length;
spaces.Items[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
if (setupLength < PathConstraint.Epsilon) {
if (scale) lengths.Items[i] = 0;
spaces.Items[++i] = 0;
} else {
float x = setupLength * bone.a, y = setupLength * bone.c;
float length = (float)Math.Sqrt(x * x + y * y);
if (scale) lengths.Items[i] = length;
spaces.Items[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (int i = 1; i < spacesCount; i++)
@ -122,7 +127,7 @@ namespace Spine {
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
float length = lengths.Items[i];
if (length != 0) {
if (length >= PathConstraint.Epsilon) {
float s = ((float)Math.Sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
bone.a *= s;
bone.c *= s;
@ -134,7 +139,7 @@ namespace Spine {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin;
if (tangents)
r = positions[p - 1];
else if (spaces.Items[i + 1] == 0)
else if (spaces.Items[i + 1] < PathConstraint.Epsilon)
r = positions[p + 2];
else
r = MathUtils.Atan2(dy, dx);
@ -230,7 +235,7 @@ namespace Spine {
path.ComputeWorldVertices(target, curve * 6 + 2, 8, world, 0);
}
AddCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], output, o,
tangents || (i > 0 && space == 0));
tangents || (i > 0 && space < PathConstraint.Epsilon));
}
return output;
}
@ -378,7 +383,7 @@ namespace Spine {
}
break;
}
AddCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, output, o, tangents || (i > 0 && space == 0));
AddCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, output, o, tangents || (i > 0 && space < PathConstraint.Epsilon));
}
return output;
}
@ -399,13 +404,14 @@ namespace Spine {
static void AddCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
float[] output, int o, bool tangents) {
if (p == 0 || float.IsNaN(p)) p = 0.0001f;
if (p < PathConstraint.Epsilon || float.IsNaN(p)) p = PathConstraint.Epsilon;
float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
output[o] = x;
output[o + 1] = y;
if (tangents) output[o + 2] = (float)Math.Atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
if (tangents)
output[o + 2] = (float)Math.Atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
}
}
}

View File

@ -47,7 +47,7 @@ namespace Spine {
public ExposedList<int> ClippedTriangles { get { return clippedTriangles; } }
public ExposedList<float> ClippedUVs { get { return clippedUVs; } }
public bool IsClipping () { return clipAttachment != null; }
public bool IsClipping { get { return clipAttachment != null; } }
public int ClipStart (Slot slot, ClippingAttachment clip) {
if (clipAttachment != null) return 0;
@ -89,7 +89,7 @@ namespace Spine {
clippedVertices.Clear();
clippedUVs.Clear();
clippedTriangles.Clear();
//outer: // libgdx
//outer:
for (int i = 0; i < trianglesLength; i += 3) {
int vertexOffset = triangles[i] << 1;
float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
@ -258,7 +258,7 @@ namespace Spine {
return clipped;
}
public static void MakeClockwise (ExposedList<float> polygon) {
static void MakeClockwise (ExposedList<float> polygon) {
float[] vertices = polygon.Items;
int verticeslength = polygon.Count;

View File

@ -31,7 +31,7 @@
using System;
namespace Spine {
public class Triangulator {
internal class Triangulator {
private readonly ExposedList<ExposedList<float>> convexPolygons = new ExposedList<ExposedList<float>>();
private readonly ExposedList<ExposedList<int>> convexPolygonsIndices = new ExposedList<ExposedList<int>>();

View File

@ -51,7 +51,31 @@ import com.esotericsoftware.spine.Animation.Timeline;
* See <a href='http://esotericsoftware.com/spine-applying-animations/'>Applying Animations</a> in the Spine Runtimes Guide. */
public class AnimationState {
static private final Animation emptyAnimation = new Animation("<empty>", new Array(0), 0);
static private final int SUBSEQUENT = 0, FIRST = 1, DIP = 2, DIP_MIX = 3;
/** 1) A previously applied timeline has set this property.<br>
* Result: Mix from the current pose to the timeline pose. */
static private final int SUBSEQUENT = 0;
/** 1) This is the first timeline to set this property.<br>
* 2) The next track entry applied after this one does not have a timeline to set this property.<br>
* Result: Mix from the setup pose to the timeline pose. */
static private final int FIRST = 1;
/** 1) This is the first timeline to set this property.<br>
* 2) The next track entry to be applied does have a timeline to set this property.<br>
* 3) The next track entry after that one does not have a timeline to set this property.<br>
* Result: Mix from the setup pose to the timeline pose, but avoid the "dipping" problem by not using the mix percentage. This
* means the timeline pose won't mix out toward the setup pose. A subsequent timeline will set this property using a mix. */
static private final int DIP = 2;
/** 1) This is the first timeline to set this property.<br>
* 2) The next track entry to be applied does have a timeline to set this property.<br>
* 3) The next track entry after that one does have a timeline to set this property.<br>
* 4) timelineDipMix stores the first subsequent track entry that does not have a timeline to set this property.<br>
* Result: This is the same as DIP except the mix percentage from the timelineDipMix track entry is used. This handles when
* more than 2 track entries in a row have a timeline which sets the same property.<br>
* Eg, A -> B -> C -> D where A, B, and C have a timeline to set the same property, but D does not. When A is applied, A's mix
* percentage is not used to avoid dipping, however a later track entry (D, the first entry without a timeline which sets the
* property) is actually mixing out A (which affects B and C). Without using D's mix percentage, A would be applied fully until
* mixed out, causing snapping. */
static private final int DIP_MIX = 3;
private AnimationStateData data;
final Array<TrackEntry> tracks = new Array();
@ -220,9 +244,10 @@ public class AnimationState {
if (from.mixingFrom != null) applyMixingFrom(from, skeleton, currentPose);
float mix;
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
mix = 1;
else {
currentPose = MixPose.setup;
} else {
mix = to.mixTime / to.mixDuration;
if (mix > 1) mix = 1;
}
@ -261,10 +286,8 @@ public class AnimationState {
break;
default:
pose = MixPose.setup;
alpha = alphaDip;
TrackEntry dipMix = (TrackEntry)timelineDipMix[i];
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
alpha = alphaDip * Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
}
from.totalAlpha += alpha;
if (timeline instanceof RotateTimeline)
@ -517,12 +540,19 @@ public class AnimationState {
}
/** Sets an empty animation for a track, discarding any queued animations, and sets the track entry's
* {@link TrackEntry#getMixDuration()}.
* {@link TrackEntry#getMixDuration()}. An empty animation has no timelines and serves as a placeholder for mixing in or out.
* <p>
* Mixing out is done by setting an empty animation. A mix duration of 0 still mixes out over one frame.
* Mixing out is done by setting an empty animation with a mix duration using either {@link #setEmptyAnimation(int, float)},
* {@link #setEmptyAnimations(float)}, or {@link #addEmptyAnimation(int, float, float)}. Mixing to an empty animation causes
* the previous animation to be applied less and less over the mix duration. Properties keyed in the previous animation
* transition to the value from lower tracks or to the setup pose value if no lower tracks key the property. A mix duration of
* 0 still mixes out over one frame.
* <p>
* To mix in, first set an empty animation and add an animation using {@link #addAnimation(int, Animation, boolean, float)},
* then set the {@link TrackEntry#setMixDuration(float)} on the returned track entry. */
* Mixing in is done by first setting an empty animation, then adding an animation using
* {@link #addAnimation(int, Animation, boolean, float)} and on the returned track entry, set the
* {@link TrackEntry#setMixDuration(float)}. Mixing from an empty animation causes the new animation to be applied more and
* more over the mix duration. Properties keyed in the new animation transition from the value from lower tracks or from the
* setup pose value if no lower tracks key the property to the value keyed in the new animation. */
public TrackEntry setEmptyAnimation (int trackIndex, float mixDuration) {
TrackEntry entry = setAnimation(trackIndex, emptyAnimation, false);
entry.mixDuration = mixDuration;
@ -533,6 +563,8 @@ public class AnimationState {
/** Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's
* {@link TrackEntry#getMixDuration()}. If the track is empty, it is equivalent to calling
* {@link #setEmptyAnimation(int, float)}.
* <p>
* See {@link #setEmptyAnimation(int, float)}.
* @param delay Seconds to begin this animation after the start of the previous animation. May be <= 0 to use the animation
* duration of the previous track minus any mix duration plus <code>delay</code>.
* @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
@ -810,8 +842,8 @@ public class AnimationState {
* is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the
* properties keyed by the animation are set to the setup pose and the track is cleared.
* <p>
* It may be desired to use {@link AnimationState#addEmptyAnimation(int, float, float)} to mix the properties back to the
* setup pose over time, rather than have it happen instantly. */
* It may be desired to use {@link AnimationState#addEmptyAnimation(int, float, float)} rather than have the animation
* abruptly cease being applied. */
public float getTrackEnd () {
return trackEnd;
}

View File

@ -30,7 +30,6 @@
package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
@ -46,6 +45,7 @@ import com.esotericsoftware.spine.utils.SpineUtils;
* See <a href="http://esotericsoftware.com/spine-path-constraints">Path constraints</a> in the Spine User Guide. */
public class PathConstraint implements Constraint {
static private final int NONE = -1, BEFORE = -2, AFTER = -3;
static private final float epsilon = 0.00001f;
final PathConstraintData data;
final Array<Bone> bones;
@ -113,11 +113,15 @@ public class PathConstraint implements Constraint {
for (int i = 0, n = spacesCount - 1; i < n;) {
Bone bone = (Bone)bones[i];
float setupLength = bone.data.length;
if (setupLength == 0) setupLength = 0.000000001f;
float x = setupLength * bone.a, y = setupLength * bone.c;
float length = (float)Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
spaces[++i] = 0;
} else {
float x = setupLength * bone.a, y = setupLength * bone.c;
float length = (float)Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (int i = 1; i < spacesCount; i++)
@ -142,7 +146,7 @@ public class PathConstraint implements Constraint {
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
float length = lengths[i];
if (length != 0) {
if (length >= epsilon) {
float s = ((float)Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
bone.a *= s;
bone.c *= s;
@ -154,7 +158,7 @@ public class PathConstraint implements Constraint {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin;
if (tangents)
r = positions[p - 1];
else if (spaces[i + 1] == 0)
else if (spaces[i + 1] < epsilon)
r = positions[p + 2];
else
r = (float)Math.atan2(dy, dx);
@ -247,7 +251,7 @@ public class PathConstraint implements Constraint {
path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2);
}
addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o,
tangents || (i > 0 && space == 0));
tangents || (i > 0 && space < epsilon));
}
return out;
}
@ -395,7 +399,7 @@ public class PathConstraint implements Constraint {
}
break;
}
addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0));
addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space < epsilon));
}
return out;
}
@ -416,13 +420,14 @@ public class PathConstraint implements Constraint {
private void addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
float[] out, int o, boolean tangents) {
if (p == 0 || Float.isNaN(p)) p = 0.0001f;
if (p < epsilon || Float.isNaN(p)) p = epsilon;
float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
out[o] = x;
out[o + 1] = y;
if (tangents) out[o + 2] = (float)Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
if (tangents)
out[o + 2] = (float)Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
}
public int getOrder () {

View File

@ -57,6 +57,7 @@ import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData.Page;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
@ -96,6 +97,7 @@ public class SkeletonViewer extends ApplicationAdapter {
OrthographicCamera camera;
TwoColorPolygonBatch batch;
TextureAtlas atlas;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
SkeletonData skeletonData;
@ -155,7 +157,20 @@ public class SkeletonViewer extends ApplicationAdapter {
}
}
TextureAtlasData data = !atlasFile.exists() ? null : new TextureAtlasData(atlasFile, atlasFile.parent(), false);
TextureAtlas atlas = new TextureAtlas(data) {
if (data != null) {
boolean linear = true;
for (int i = 0, n = data.getPages().size; i < n; i++) {
Page page = data.getPages().get(i);
if (page.minFilter != TextureFilter.Linear || page.magFilter != TextureFilter.Linear) {
linear = false;
break;
}
}
ui.linearCheckbox.setChecked(linear);
}
atlas = new TextureAtlas(data) {
public AtlasRegion findRegion (String name) {
AtlasRegion region = super.findRegion(name);
if (region == null) {
@ -416,6 +431,8 @@ public class SkeletonViewer extends ApplicationAdapter {
CheckBox premultipliedCheckbox = new CheckBox("Premultiplied", skin);
CheckBox linearCheckbox = new CheckBox("Linear", skin);
TextButton bonesSetupPoseButton = new TextButton("Bones", skin);
TextButton slotsSetupPoseButton = new TextButton("Slots", skin);
TextButton setupPoseButton = new TextButton("Both", skin);
@ -458,6 +475,8 @@ public class SkeletonViewer extends ApplicationAdapter {
premultipliedCheckbox.setChecked(true);
linearCheckbox.setChecked(true);
loopCheckbox.setChecked(true);
scaleSlider.setValue(1);
@ -519,7 +538,13 @@ public class SkeletonViewer extends ApplicationAdapter {
root.add();
root.add(table(debugMeshHullCheckbox, debugMeshTrianglesCheckbox)).row();
root.add("Atlas alpha:");
root.add(premultipliedCheckbox).row();
{
Table table = table();
table.add(premultipliedCheckbox);
table.add("Filtering:").growX().getActor().setAlignment(Align.right);
table.add(linearCheckbox);
root.add(table).fill().row();
}
root.add(new Image(skin.newDrawable("white", new Color(0x4e4e4eff)))).height(1).fillX().colspan(2).pad(-3, 0, 1, 0)
.row();
@ -739,6 +764,15 @@ public class SkeletonViewer extends ApplicationAdapter {
}
});
linearCheckbox.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
if (atlas == null) return;
TextureFilter filter = linearCheckbox.isChecked() ? TextureFilter.Linear : TextureFilter.Nearest;
for (Texture texture : atlas.getTextures())
texture.setFilter(filter, filter);
}
});
skinList.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
if (skeleton != null) {
@ -777,19 +811,19 @@ public class SkeletonViewer extends ApplicationAdapter {
public boolean touchDown (int screenX, int screenY, int pointer, int button) {
offsetX = screenX;
offsetY = Gdx.graphics.getHeight() - screenY;
offsetY = Gdx.graphics.getHeight() - 1 - screenY;
return false;
}
public boolean touchDragged (int screenX, int screenY, int pointer) {
float deltaX = screenX - offsetX;
float deltaY = Gdx.graphics.getHeight() - screenY - offsetY;
float deltaY = Gdx.graphics.getHeight() - 1 - screenY - offsetY;
camera.position.x -= deltaX * camera.zoom;
camera.position.y -= deltaY * camera.zoom;
offsetX = screenX;
offsetY = Gdx.graphics.getHeight() - screenY;
offsetY = Gdx.graphics.getHeight() - 1 - screenY;
return false;
}
@ -834,7 +868,7 @@ public class SkeletonViewer extends ApplicationAdapter {
}
Table table (Actor... actors) {
Table table = new Table();
Table table = new Table(skin);
table.defaults().space(6);
table.add(actors);
return table;

View File

@ -428,6 +428,7 @@ function AnimationState:applyMixingFrom (to, skeleton, currentPose)
local mix = 0
if to.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
mix = 1
currentPose = MixPose.setup
else
mix = to.mixTime / to.mixDuration
if mix > 1 then mix = 1 end

View File

@ -55,6 +55,7 @@ PathConstraint.__index = PathConstraint
PathConstraint.NONE = -1
PathConstraint.BEFORE = -2
PathConstraint.AFTER = -3
PathConstraint.epsilon = 0.00001
function PathConstraint.new (data, skeleton)
if not data then error("data cannot be nil", 2) end
@ -118,13 +119,22 @@ function PathConstraint:update ()
while i < n do
local bone = bones[i + 1];
local setupLength = bone.data.length
if setupLength == 0 then setupLength = 0.0000001 end
local x = setupLength * bone.a
local y = setupLength * bone.c
local length = math_sqrt(x * x + y * y)
if scale then lengths[i + 1] = length end
i = i + 1
if lengthSpacing then spaces[i + 1] = (setupLength + spacing) * length / setupLength else spaces[i + 1] = spacing * length / setupLength end
if setupLength < PathConstraint.epsilon then
if scale then lengths[i + 1] = 0 end
i = i + 1
spaces[i + 1] = 0
else
local x = setupLength * bone.a
local y = setupLength * bone.c
local length = math_sqrt(x * x + y * y)
if scale then lengths[i + 1] = length end
i = i + 1
if lengthSpacing then
spaces[i + 1] = (setupLength + spacing) * length / setupLength
else
spaces[i + 1] = spacing * length / setupLength
end
end
end
else
local i = 1

View File

@ -752,6 +752,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1715,8 +1715,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -3290,13 +3292,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3602,6 +3609,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -752,6 +752,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1715,8 +1715,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -3290,13 +3292,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3602,6 +3609,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -681,6 +681,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1266,8 +1266,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -2969,13 +2971,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3281,6 +3288,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -681,6 +681,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1266,8 +1266,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -2969,13 +2971,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3281,6 +3288,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -681,6 +681,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1266,8 +1266,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -2969,13 +2971,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3281,6 +3288,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -681,6 +681,7 @@ declare module spine {
static NONE: number;
static BEFORE: number;
static AFTER: number;
static epsilon: number;
data: PathConstraintData;
bones: Array<Bone>;
target: Slot;

View File

@ -1266,8 +1266,10 @@ var spine;
if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton, currentPose);
var mix = 0;
if (to.mixDuration == 0)
if (to.mixDuration == 0) {
mix = 1;
currentPose = spine.MixPose.setup;
}
else {
mix = to.mixTime / to.mixDuration;
if (mix > 1)
@ -2969,13 +2971,18 @@ var spine;
for (var i = 0, n = spacesCount - 1; i < n;) {
var bone = bones[i];
var setupLength = bone.data.length;
if (setupLength == 0)
setupLength = 0.0000001;
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale)
lengths[i] = 0;
spaces[++i] = 0;
}
else {
var x = setupLength * bone.a, y = setupLength * bone.c;
var length_1 = Math.sqrt(x * x + y * y);
if (scale)
lengths[i] = length_1;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength;
}
}
}
else {
@ -3281,6 +3288,7 @@ var spine;
PathConstraint.NONE = -1;
PathConstraint.BEFORE = -2;
PathConstraint.AFTER = -3;
PathConstraint.epsilon = 0.00001;
return PathConstraint;
}());
spine.PathConstraint = PathConstraint;

File diff suppressed because one or more lines are too long

View File

@ -191,9 +191,10 @@ module spine {
if (from.mixingFrom != null) this.applyMixingFrom(from, skeleton, currentPose);
let mix = 0;
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
mix = 1;
else {
currentPose = MixPose.setup;
} else {
mix = to.mixTime / to.mixDuration;
if (mix > 1) mix = 1;
}

View File

@ -31,6 +31,7 @@
module spine {
export class PathConstraint implements Constraint {
static NONE = -1; static BEFORE = -2; static AFTER = -3;
static epsilon = 0.00001;
data: PathConstraintData;
bones: Array<Bone>;
@ -81,11 +82,15 @@ module spine {
for (let i = 0, n = spacesCount - 1; i < n;) {
let bone = bones[i];
let setupLength = bone.data.length;
if (setupLength == 0) setupLength = 0.0000001;
let x = setupLength * bone.a, y = setupLength * bone.c;
let length = Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
if (setupLength < PathConstraint.epsilon) {
if (scale) lengths[i] = 0;
spaces[++i] = 0;
} else {
let x = setupLength * bone.a, y = setupLength * bone.c;
let length = Math.sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (let i = 1; i < spacesCount; i++)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-monokai",t.cssText=".ace-monokai .ace_gutter {background: #2F3129;color: #8F908A}.ace-monokai .ace_print-margin {width: 1px;background: #555651}.ace-monokai {background-color: #272822;color: #F8F8F2}.ace-monokai .ace_cursor {color: #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection {background: #49483E}.ace-monokai.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #272822;}.ace-monokai .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active-line {background: #202020}.ace-monokai .ace_gutter-active-line {background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected-word {border: 1px solid #49483E}.ace-monokai .ace_invisible {color: #52524d}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta.ace_tag,.ace-monokai .ace_storage {color: #F92672}.ace-monokai .ace_punctuation,.ace-monokai .ace_punctuation.ace_tag {color: #fff}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other {color: #AE81FF}.ace-monokai .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function {color: #66D9EF}.ace-monokai .ace_fold {background-color: #A6E22E;border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type {font-style: italic;color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable {color: #A6E22E}.ace-monokai .ace_variable.ace_parameter {font-style: italic;color: #FD971F}.ace-monokai .ace_string {color: #E6DB74}.ace-monokai .ace_comment {color: #75715E}.ace-monokai .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,96 @@
<html>
<script src="../../build/spine-webgl.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<style>
/* Dead Simple Grid (c) 2015 Vladimir Agafonkin */
.row .row { margin: 0 -1.5em; }
.col { padding: 0 1.5em; }
.row:after {
content: "";
clear: both;
display: table;
}
@media only screen { .col {
float: left;
width: 100%;
box-sizing: border-box;
}}
@media only screen and (min-width: 30em) {
.content { width: 50%; height: 100%; padding: 0 }
.sidebar { width: 50%; height: 100%; padding: 0 }
}
body {
margin: 0;
}
iframe {
width: 100%;
height: 100%;
border:none;
}
.panel {
width: 100%;
height: 50%;
}
.buttons {
position: absolute;
top: 5; left: 5;
}
</style>
<body>
<div class="buttons">
<button id="playButton">Run</button>
<button id="stopButton">Stop</button>
</div>
<div class="row">
<div class="col content">
<iframe id="iframe"></iframe>
</div>
<div class="col sidebar">
<div id="codeJs" class="panel"></div>
<div id="codeHtml" class="panel"></div>
</div>
</div>
</body>
<script id="initialJs" type="text/plain">
var canvas = document.getElementById("canvas");
var config = { alpha: false };
var context = new spine.webgl.ManagedWebGLRenderingContext(canvas, config);
var gl = context.gl;
function render() {
gl.clearColor(0.2, 0.2, 0.2, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
</script>
<script src="js/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
$(document).ready(function() {
var editorJs = ace.edit("codeJs");
editorJs.setTheme("ace/theme/monokai");
editorJs.getSession().setMode("ace/mode/javascript");
editorJs.setValue(document.getElementById("initialJs").innerHTML);
var editorHtml = ace.edit("codeHtml");
editorHtml.setTheme("ace/theme/monokai");
editorHtml.getSession().setMode("ace/mode/html");
editorHtml.setValue('<script src="../../build/spine-webgl.js"><\/script>\n<canvas id="canvas" style="width: 100%; height: 98vh;"></canvas>');
$("#playButton").click(function() {
var iframe = document.getElementById("iframe");
var source = "<html><body>" + editorHtml.getValue() + "<script>" + editorJs.getValue() + "<\/script></body></html>";
iframe.srcdoc = source;
});
});
</script>
</html>

View File

@ -25,7 +25,11 @@ void FRuntimeMeshComponentDetails::CustomizeDetails( IDetailLayoutBuilder& Detai
const FText ConvertToStaticMeshText = LOCTEXT("ConvertToStaticMesh", "Create StaticMesh");
// Cache set of selected things
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 18
SelectedObjectsList = DetailBuilder.GetDetailsView().GetSelectedObjects();
#else
SelectedObjectsList = DetailBuilder.GetDetailsView()->GetSelectedObjects();
#endif
RuntimeMeshCategory.AddCustomRow(ConvertToStaticMeshText, false)
.NameContent()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -4,7 +4,7 @@ MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
icon: {fileID: 2800000, guid: 3fc714a0dc1cf6b4b959e073fff2844e, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -726,6 +726,9 @@ namespace Spine.Unity.Editor {
}
void DoRenderPreview (bool drawHandles) {
if (this.PreviewUtilityCamera.activeTexture == null || this.PreviewUtilityCamera.targetTexture == null )
return;
GameObject go = this.m_previewInstance;
if (m_requireRefresh && go != null) {

View File

@ -4,7 +4,7 @@ MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
icon: {fileID: 2800000, guid: 68defdbc95b30a74a9ad396bfc9a2277, type: 3}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 3fc714a0dc1cf6b4b959e073fff2844e
timeCreated: 1508165143
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

View File

@ -375,12 +375,10 @@ namespace Spine.Unity.Editor {
ISkeletonComponent skeletonComponent = GetTargetSkeletonComponent(property);
var validSkins = new List<Skin>();
if (skeletonComponent != null && targetAttribute.currentSkinOnly) {
Skin currentSkin = null;
var skinProperty = property.FindPropertyRelative(targetAttribute.skinField);
var skinProperty = property.FindBaseOrSiblingProperty(targetAttribute.skinField);
if (skinProperty != null) currentSkin = skeletonComponent.Skeleton.Data.FindSkin(skinProperty.stringValue);
currentSkin = currentSkin ?? skeletonComponent.Skeleton.Skin;

View File

@ -230,9 +230,16 @@ namespace Spine.Unity.Editor {
EditorApplication.hierarchyWindowItemOnGUI += HierarchyDragAndDrop;
// Hierarchy Icons
#if UNITY_2017_2_OR_NEWER
EditorApplication.playModeStateChanged -= HierarchyIconsOnPlaymodeStateChanged;
EditorApplication.playModeStateChanged += HierarchyIconsOnPlaymodeStateChanged;
HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
EditorApplication.playmodeStateChanged -= HierarchyIconsOnPlaymodeStateChanged;
EditorApplication.playmodeStateChanged += HierarchyIconsOnPlaymodeStateChanged;
HierarchyIconsOnPlaymodeStateChanged();
#endif
initialized = true;
}
@ -255,7 +262,11 @@ namespace Spine.Unity.Editor {
showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons);
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons);
#if UNITY_2017_2_OR_NEWER
HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
HierarchyIconsOnPlaymodeStateChanged();
#endif
}
EditorGUILayout.Separator();
@ -496,7 +507,11 @@ namespace Spine.Unity.Editor {
#endregion
#region Hierarchy
#if UNITY_2017_2_OR_NEWER
static void HierarchyIconsOnPlaymodeStateChanged (PlayModeStateChange stateChange) {
#else
static void HierarchyIconsOnPlaymodeStateChanged () {
#endif
skeletonRendererTable.Clear();
skeletonUtilityBoneTable.Clear();
boundingBoxFollowerTable.Clear();

File diff suppressed because it is too large Load Diff

View File

@ -113,37 +113,37 @@ namespace Spine.Unity.Modules.AttachmentTools {
#region Runtime RegionAttachments
/// <summary>
/// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses a new AtlasPage with the Material provided./// </summary>
public static RegionAttachment ToRegionAttachment (this Sprite sprite, Material material) {
return sprite.ToRegionAttachment(material.ToSpineAtlasPage());
public static RegionAttachment ToRegionAttachment (this Sprite sprite, Material material, float rotation = 0f) {
return sprite.ToRegionAttachment(material.ToSpineAtlasPage(), rotation);
}
/// <summary>
/// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses the AtlasPage provided./// </summary>
public static RegionAttachment ToRegionAttachment (this Sprite sprite, AtlasPage page) {
public static RegionAttachment ToRegionAttachment (this Sprite sprite, AtlasPage page, float rotation = 0f) {
if (sprite == null) throw new System.ArgumentNullException("sprite");
if (page == null) throw new System.ArgumentNullException("page");
var region = sprite.ToAtlasRegion(page);
var unitsPerPixel = 1f / sprite.pixelsPerUnit;
return region.ToRegionAttachment(sprite.name, unitsPerPixel);
return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation);
}
/// <summary>
/// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton"</summary>
public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = SpriteAtlasRegionExtensions.SpineTextureFormat, bool mipmaps = SpriteAtlasRegionExtensions.UseMipMaps, Material materialPropertySource = null) {
public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) {
if (sprite == null) throw new System.ArgumentNullException("sprite");
if (shader == null) throw new System.ArgumentNullException("shader");
var region = sprite.ToAtlasRegionPMAClone(shader, textureFormat, mipmaps, materialPropertySource);
var unitsPerPixel = 1f / sprite.pixelsPerUnit;
return region.ToRegionAttachment(sprite.name, unitsPerPixel);
return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation);
}
public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Material materialPropertySource, TextureFormat textureFormat = SpriteAtlasRegionExtensions.SpineTextureFormat, bool mipmaps = SpriteAtlasRegionExtensions.UseMipMaps) {
return sprite.ToRegionAttachmentPMAClone(materialPropertySource.shader, textureFormat, mipmaps, materialPropertySource);
public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Material materialPropertySource, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, float rotation = 0f) {
return sprite.ToRegionAttachmentPMAClone(materialPropertySource.shader, textureFormat, mipmaps, materialPropertySource, rotation);
}
/// <summary>
/// Creates a new RegionAttachment from a given AtlasRegion.</summary>
public static RegionAttachment ToRegionAttachment (this AtlasRegion region, string attachmentName, float scale = 0.01f) {
public static RegionAttachment ToRegionAttachment (this AtlasRegion region, string attachmentName, float scale = 0.01f, float rotation = 0f) {
if (string.IsNullOrEmpty(attachmentName)) throw new System.ArgumentException("attachmentName can't be null or empty.", "attachmentName");
if (region == null) throw new System.ArgumentNullException("region");
@ -162,14 +162,13 @@ namespace Spine.Unity.Modules.AttachmentTools {
attachment.Path = region.name;
attachment.scaleX = 1;
attachment.scaleY = 1;
attachment.rotation = 0;
attachment.rotation = rotation;
attachment.r = 1;
attachment.g = 1;
attachment.b = 1;
attachment.a = 1;
// pass OriginalWidth and OriginalHeight because UpdateOffset uses it in its calculation.
attachment.width = attachment.regionOriginalWidth * scale;
attachment.height = attachment.regionOriginalHeight * scale;
@ -210,7 +209,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
#endregion
}
public static class SpriteAtlasRegionExtensions {
public static class AtlasUtilities {
internal const TextureFormat SpineTextureFormat = TextureFormat.RGBA32;
internal const float DefaultMipmapBias = -0.5f;
internal const bool UseMipMaps = false;
@ -395,16 +394,98 @@ namespace Spine.Unity.Modules.AttachmentTools {
#region Runtime Repacking
/// <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>
public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material m, out Texture2D t, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) {
return GetRepackedSkin(o, newName, materialPropertySource.shader, out m, out t, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource);
/// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments, but mapped to a new single texture using the same material.</summary>
/// <param name="sourceAttachments">The list of attachments to be repacked.</param>
/// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
///
/// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments") {
if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments");
if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments");
// Use these to detect and use shared regions.
var existingRegions = new Dictionary<AtlasRegion, int>();
var regionIndexes = new List<int>();
var texturesToPack = new List<Texture2D>();
var originalRegions = new List<AtlasRegion>();
outputAttachments.Clear();
outputAttachments.AddRange(sourceAttachments);
int newRegionIndex = 0;
for (int i = 0, n = sourceAttachments.Count; i < n; i++) {
var originalAttachment = sourceAttachments[i];
var newAttachment = originalAttachment.GetClone(true);
if (IsRenderable(newAttachment)) {
var region = newAttachment.GetAtlasRegion();
int existingIndex;
if (existingRegions.TryGetValue(region, out existingIndex)) {
regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
} else {
originalRegions.Add(region);
texturesToPack.Add(region.ToTexture()); // Add the texture to the PackTextures argument
existingRegions.Add(region, newRegionIndex); // Add the region to the dictionary of known regions
regionIndexes.Add(newRegionIndex); // Store the region index for the eventual new attachment.
newRegionIndex++;
}
outputAttachments[i] = newAttachment;
}
}
// Fill a new texture with the collected attachment textures.
var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
newTexture.anisoLevel = texturesToPack[0].anisoLevel;
newTexture.name = newAssetName;
var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
// Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
Shader shader = materialPropertySource == null ? Shader.Find("Spine/Skeleton") : materialPropertySource.shader;
var newMaterial = new Material(shader);
if (materialPropertySource != null) {
newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
}
newMaterial.name = newAssetName;
newMaterial.mainTexture = newTexture;
var page = newMaterial.ToSpineAtlasPage();
page.name = newAssetName;
var repackedRegions = new List<AtlasRegion>();
for (int i = 0, n = originalRegions.Count; i < n; i++) {
var oldRegion = originalRegions[i];
var newRegion = UVRectToAtlasRegion(rects[i], oldRegion.name, page, oldRegion.offsetX, oldRegion.offsetY, oldRegion.rotate);
repackedRegions.Add(newRegion);
}
// Map the cloned attachments to the repacked atlas.
for (int i = 0, n = outputAttachments.Count; i < n; i++) {
var a = outputAttachments[i];
a.SetRegion(repackedRegions[regionIndexes[i]]);
}
// Clean up.
foreach (var ttp in texturesToPack)
UnityEngine.Object.Destroy(ttp);
outputTexture = newTexture;
outputMaterial = newMaterial;
}
/// <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>
public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material m, out Texture2D t, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null) {
public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) {
return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource);
}
/// <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>
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) {
var skinAttachments = o.Attachments;
var newSkin = new Skin(newName);
@ -441,7 +522,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
// Fill a new texture with the collected attachment textures.
var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
newTexture.mipMapBias = SpriteAtlasRegionExtensions.DefaultMipmapBias;
newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
newTexture.anisoLevel = texturesToPack[0].anisoLevel;
newTexture.name = newName;
var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
@ -471,12 +552,12 @@ namespace Spine.Unity.Modules.AttachmentTools {
a.SetRegion(repackedRegions[regionIndexes[i]]);
}
// // Clean up
// foreach (var ttp in texturesToPack)
// UnityEngine.Object.Destroy(ttp);
// Clean up.
foreach (var ttp in texturesToPack)
UnityEngine.Object.Destroy(ttp);
t = newTexture;
m = newMaterial;
outputTexture = newTexture;
outputMaterial = newMaterial;
return newSkin;
}
@ -679,7 +760,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
}
}
public static class SkinExtensions {
public static class SkinUtilities {
#region Skeleton Skin Extensions
/// <summary>

View File

@ -344,8 +344,8 @@ VertexOutput vert(VertexInput input)
output.pos = calculateLocalPos(input.vertex);
output.color = calculateVertexColor(input.color);
output.texcoord = float3(calculateTextureCoord(input.texcoord), 0);
float3 viewPos = mul(UNITY_MATRIX_MV, input.vertex);
float3 viewPos = UnityObjectViewPos(input.vertex); //float3 viewPos = mul(UNITY_MATRIX_MV, input.vertex);
#if defined(FIXED_NORMALS_BACKFACE_RENDERING) || defined(_RIM_LIGHTING)
float4 powWorld = calculateWorldPos(input.vertex);
#endif

View File

@ -110,9 +110,9 @@ Shader "Spine/SkeletonGraphic Tint Black (Premultiply Alpha)"
clip (texColor.a - 0.001);
#endif
return (texColor * IN.color) + float4(((1-texColor.rgb) * (_Black.rgb + float3(IN.uv1.r, IN.uv1.g, IN.uv2.r)) * texColor.a*_Color.a*i.vertexColor.a), 0);
return (texColor * IN.color) + float4(((1-texColor.rgb) * (_Black.rgb + float3(IN.uv1.r, IN.uv1.g, IN.uv2.r)) * texColor.a * _Color.a * IN.color.a), 0);
}
ENDCG
}
}
}
}

View File

@ -91,7 +91,7 @@ Shader "Spine/SkeletonGraphic (Premultiply Alpha)"
OUT.vertex.xy += (_ScreenParams.zw-1.0) * float2(-1,1);
#endif
OUT.color = IN.color * _Color;
OUT.color = IN.color * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
return OUT;
}
@ -112,4 +112,4 @@ Shader "Spine/SkeletonGraphic (Premultiply Alpha)"
ENDCG
}
}
}
}

View File

@ -176,7 +176,7 @@ namespace Spine {
darkColor.A = premultipliedAlpha ? (byte)255 : (byte)0;
// clip
if (clipper.IsClipping()) {
if (clipper.IsClipping) {
clipper.ClipTriangles(vertices, verticesCount << 1, indices, indicesCount, uvs);
vertices = clipper.ClippedVertices.Items;
verticesCount = clipper.ClippedVertices.Count >> 1;