mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Merge branch '3.8' into 4.0-beta
This commit is contained in:
commit
33e2aea7ff
@ -360,6 +360,8 @@
|
|||||||
* Added support for **multiple atlas textures at `SkeletonGraphic`**. You can enable this feature by enabling the parameter `Multiple CanvasRenders` in the `Advanced` section of the `SkeletonGraphic` Inspector. This automatically creates the required number of child `CanvasRenderer` GameObjects for each required draw call (submesh).
|
* Added support for **multiple atlas textures at `SkeletonGraphic`**. You can enable this feature by enabling the parameter `Multiple CanvasRenders` in the `Advanced` section of the `SkeletonGraphic` Inspector. This automatically creates the required number of child `CanvasRenderer` GameObjects for each required draw call (submesh).
|
||||||
* Added support for **Render Separator Slots** at `SkeletonGraphic`. Render separation can be enabled directly in the `Advanced` section of the `SkeletonGraphic` Inspector, it does not require any additional components (like `SkeletonRenderSeparator` or `SkeletonPartsRenderer` for `SkeletonRenderer` components). When enabled, additional separator GameObjects will be created automatically for each separation part, and `CanvasRenderer` GameObjects re-parented to them accordingly. The separator GameObjects can be moved around and re-parented in the hierarchy according to your requirements to achieve the desired draw order within your `Canvas`. A usage example can be found in the updated `Spine Examples/Other Examples/SkeletonRenderSeparator` scene.
|
* Added support for **Render Separator Slots** at `SkeletonGraphic`. Render separation can be enabled directly in the `Advanced` section of the `SkeletonGraphic` Inspector, it does not require any additional components (like `SkeletonRenderSeparator` or `SkeletonPartsRenderer` for `SkeletonRenderer` components). When enabled, additional separator GameObjects will be created automatically for each separation part, and `CanvasRenderer` GameObjects re-parented to them accordingly. The separator GameObjects can be moved around and re-parented in the hierarchy according to your requirements to achieve the desired draw order within your `Canvas`. A usage example can be found in the updated `Spine Examples/Other Examples/SkeletonRenderSeparator` scene.
|
||||||
* Added `SkeletonGraphicCustomMaterials` component, providing functionality to override materials and textures of a `SkeletonGraphic`, similar to `SkeletonRendererCustomMaterials`. Note: overriding materials or textures per slot is not provided due to structural limitations.
|
* Added `SkeletonGraphicCustomMaterials` component, providing functionality to override materials and textures of a `SkeletonGraphic`, similar to `SkeletonRendererCustomMaterials`. Note: overriding materials or textures per slot is not provided due to structural limitations.
|
||||||
|
* Added **Root Motion support** for `SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic` via new components `SkeletonRootMotion` and `SkeletonMecanimRootMotion`. The `SkeletonAnimation` and `SkeletonGraphic` component Inspector now provides a line `Root Motion` with `Add Component` and `Remove Component` buttons to add/remove the new `SkeletonRootMotion` component to your GameObject. The `SkeletonMecanim` Inspector detects whether root motion is enabled at the `Animator` component and adds a `SkeletonMecanimRootMotion` component automatically.
|
||||||
|
* `SkeletonMecanim` now provides an additional `Custom MixMode` parameter under `Mecanim Translator`. It is enabled by default in version 3.8 to maintain current behaviour, using the set `Mix Mode` for each Mecanim layer. When disabled, `SkeletonMecanim` will use the recommended `MixMode` according to the layer blend mode. Additional information can be found in the [Mecanim Translator section](http://esotericsoftware.com/spine-unity#Parameters-for-animation-blending-control) on the spine-unity documentation pages.
|
||||||
|
|
||||||
* **Changes of default values**
|
* **Changes of default values**
|
||||||
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
|
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
|
||||||
|
|||||||
@ -48,6 +48,7 @@ namespace spine {
|
|||||||
bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect);
|
bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect);
|
||||||
Color4B ColorToColor4B(const Color& color);
|
Color4B ColorToColor4B(const Color& color);
|
||||||
bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex);
|
bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex);
|
||||||
|
bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C Variable length array
|
// C Variable length array
|
||||||
@ -301,18 +302,7 @@ namespace spine {
|
|||||||
for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) {
|
for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) {
|
||||||
Slot* slot = _skeleton->getDrawOrder()[i];;
|
Slot* slot = _skeleton->getDrawOrder()[i];;
|
||||||
|
|
||||||
if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) {
|
if (nothingToDraw(*slot, _startSlotIndex, _endSlotIndex)) {
|
||||||
_clipper->clipEnd(*slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!slot->getAttachment()) {
|
|
||||||
_clipper->clipEnd(*slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Early exit if slot is invisible
|
|
||||||
if (slot->getColor().a == 0 || !slot->getBone().isActive()) {
|
|
||||||
_clipper->clipEnd(*slot);
|
_clipper->clipEnd(*slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -324,12 +314,6 @@ namespace spine {
|
|||||||
RegionAttachment* attachment = static_cast<RegionAttachment*>(slot->getAttachment());
|
RegionAttachment* attachment = static_cast<RegionAttachment*>(slot->getAttachment());
|
||||||
attachmentVertices = static_cast<AttachmentVertices*>(attachment->getRendererObject());
|
attachmentVertices = static_cast<AttachmentVertices*>(attachment->getRendererObject());
|
||||||
|
|
||||||
// Early exit if attachment is invisible
|
|
||||||
if (attachment->getColor().a == 0) {
|
|
||||||
_clipper->clipEnd(*slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float* dstTriangleVertices = nullptr;
|
float* dstTriangleVertices = nullptr;
|
||||||
int dstStride = 0; // in floats
|
int dstStride = 0; // in floats
|
||||||
if (hasSingleTint) {
|
if (hasSingleTint) {
|
||||||
@ -556,7 +540,7 @@ namespace spine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
#if COCOS2D_VERSION < 0x00040000
|
#if COCOS2D_VERSION < 0x00040000
|
||||||
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
|
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
|
||||||
#else
|
#else
|
||||||
@ -641,7 +625,7 @@ namespace spine {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DrawNode* drawNode = DrawNode::create();
|
DrawNode* drawNode = DrawNode::create();
|
||||||
drawNode->setGlobalZOrder(getGlobalZOrder());
|
drawNode->setGlobalZOrder(getGlobalZOrder());
|
||||||
|
|
||||||
// Draw bounding rectangle
|
// Draw bounding rectangle
|
||||||
if (_debugBoundingRect) {
|
if (_debugBoundingRect) {
|
||||||
@ -935,21 +919,32 @@ namespace spine {
|
|||||||
return startSlotIndex > index || endSlotIndex < index;
|
return startSlotIndex > index || endSlotIndex < index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nothingToDraw(Slot& slot, int startSlotIndex, int endSlotIndex) {
|
||||||
|
Attachment *attachment = slot.getAttachment();
|
||||||
|
if (!attachment ||
|
||||||
|
slotIsOutRange(slot, startSlotIndex, endSlotIndex) ||
|
||||||
|
!slot.getBone().isActive() ||
|
||||||
|
slot.getColor().a == 0)
|
||||||
|
return true;
|
||||||
|
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||||
|
if (static_cast<RegionAttachment*>(attachment)->getColor().a == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
||||||
|
if (static_cast<MeshAttachment*>(attachment)->getColor().a == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
|
int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
|
||||||
int coordCount = 0;
|
int coordCount = 0;
|
||||||
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
|
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
|
||||||
Slot& slot = *skeleton.getSlots()[i];
|
Slot& slot = *skeleton.getSlots()[i];
|
||||||
|
if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Attachment* const attachment = slot.getAttachment();
|
Attachment* const attachment = slot.getAttachment();
|
||||||
if (!attachment) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Early exit if slot is invisible
|
|
||||||
if (slot.getColor().a == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||||
coordCount += 8;
|
coordCount += 8;
|
||||||
}
|
}
|
||||||
@ -969,16 +964,10 @@ namespace spine {
|
|||||||
#endif
|
#endif
|
||||||
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
|
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
|
||||||
/*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw
|
/*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw
|
||||||
|
if (nothingToDraw(slot, startSlotIndex, endSlotIndex)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Attachment* const attachment = slot.getAttachment();
|
Attachment* const attachment = slot.getAttachment();
|
||||||
if (!attachment) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (slot.getColor().a == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||||
RegionAttachment* const regionAttachment = static_cast<RegionAttachment*>(attachment);
|
RegionAttachment* const regionAttachment = static_cast<RegionAttachment*>(attachment);
|
||||||
assert(dstPtr + 8 <= dstEnd);
|
assert(dstPtr + 8 <= dstEnd);
|
||||||
@ -1010,7 +999,7 @@ namespace spine {
|
|||||||
|
|
||||||
BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha) {
|
BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha) {
|
||||||
BlendFunc blendFunc;
|
BlendFunc blendFunc;
|
||||||
|
|
||||||
#if COCOS2D_VERSION < 0x00040000
|
#if COCOS2D_VERSION < 0x00040000
|
||||||
switch (blendMode) {
|
switch (blendMode) {
|
||||||
case BlendMode_Additive:
|
case BlendMode_Additive:
|
||||||
@ -1056,15 +1045,15 @@ namespace spine {
|
|||||||
bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) {
|
bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) {
|
||||||
if (Camera::getVisitingCamera() == nullptr)
|
if (Camera::getVisitingCamera() == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto director = Director::getInstance();
|
auto director = Director::getInstance();
|
||||||
auto scene = director->getRunningScene();
|
auto scene = director->getRunningScene();
|
||||||
|
|
||||||
if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera()))
|
if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize());
|
Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize());
|
||||||
|
|
||||||
// transform center point to screen space
|
// transform center point to screen space
|
||||||
float hSizeX = rect.size.width/2;
|
float hSizeX = rect.size.width/2;
|
||||||
float hSizeY = rect.size.height/2;
|
float hSizeY = rect.size.height/2;
|
||||||
@ -1075,7 +1064,7 @@ namespace spine {
|
|||||||
// convert content size to world coordinates
|
// convert content size to world coordinates
|
||||||
float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4]));
|
float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4]));
|
||||||
float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5]));
|
float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5]));
|
||||||
|
|
||||||
// enlarge visible rect half size in screen coord
|
// enlarge visible rect half size in screen coord
|
||||||
visibleRect.origin.x -= wshw;
|
visibleRect.origin.x -= wshw;
|
||||||
visibleRect.origin.y -= wshh;
|
visibleRect.origin.y -= wshh;
|
||||||
|
|||||||
@ -1031,9 +1031,9 @@ void AnimationState::computeHold(TrackEntry *entry) {
|
|||||||
} else {
|
} else {
|
||||||
for (TrackEntry *next = to->_mixingTo; next != NULL; next = next->_mixingTo) {
|
for (TrackEntry *next = to->_mixingTo; next != NULL; next = next->_mixingTo) {
|
||||||
if (next->_animation->hasTimeline(id)) continue;
|
if (next->_animation->hasTimeline(id)) continue;
|
||||||
if (entry->_mixDuration > 0) {
|
if (next->_mixDuration > 0) {
|
||||||
timelineMode[i] = HoldMix;
|
timelineMode[i] = HoldMix;
|
||||||
timelineHoldMix[i] = entry;
|
timelineHoldMix[i] = next;
|
||||||
i++;
|
i++;
|
||||||
goto continue_outer; // continue outer;
|
goto continue_outer; // continue outer;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,9 +43,13 @@ namespace Spine {
|
|||||||
public Animation (string name, ExposedList<Timeline> timelines, float duration) {
|
public Animation (string name, ExposedList<Timeline> timelines, float duration) {
|
||||||
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
||||||
if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null.");
|
if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null.");
|
||||||
this.timelineIds = new HashSet<int>();
|
// Note: avoiding reallocations by adding all hash set entries at
|
||||||
foreach (Timeline timeline in timelines)
|
// once (EnsureCapacity() is only available in newer .Net versions).
|
||||||
timelineIds.Add(timeline.PropertyId);
|
int[] propertyIDs = new int[timelines.Count];
|
||||||
|
for (int i = 0; i < timelines.Count; ++i) {
|
||||||
|
propertyIDs[i] = timelines.Items[i].PropertyId;
|
||||||
|
}
|
||||||
|
this.timelineIds = new HashSet<int>(propertyIDs);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.timelines = timelines;
|
this.timelines = timelines;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
|
|||||||
@ -85,6 +85,25 @@ namespace Spine {
|
|||||||
|
|
||||||
public delegate void TrackEntryEventDelegate (TrackEntry trackEntry, Event e);
|
public delegate void TrackEntryEventDelegate (TrackEntry trackEntry, Event e);
|
||||||
public event TrackEntryEventDelegate Event;
|
public event TrackEntryEventDelegate Event;
|
||||||
|
|
||||||
|
public void AssignEventSubscribersFrom (AnimationState src) {
|
||||||
|
Event = src.Event;
|
||||||
|
Start = src.Start;
|
||||||
|
Interrupt = src.Interrupt;
|
||||||
|
End = src.End;
|
||||||
|
Dispose = src.Dispose;
|
||||||
|
Complete = src.Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEventSubscribersFrom (AnimationState src) {
|
||||||
|
Event += src.Event;
|
||||||
|
Start += src.Start;
|
||||||
|
Interrupt += src.Interrupt;
|
||||||
|
End += src.End;
|
||||||
|
Dispose += src.Dispose;
|
||||||
|
Complete += src.Complete;
|
||||||
|
}
|
||||||
|
|
||||||
// end of difference
|
// end of difference
|
||||||
private readonly EventQueue queue; // Initialized by constructor.
|
private readonly EventQueue queue; // Initialized by constructor.
|
||||||
private readonly HashSet<int> propertyIDs = new HashSet<int>();
|
private readonly HashSet<int> propertyIDs = new HashSet<int>();
|
||||||
|
|||||||
@ -883,6 +883,7 @@ namespace Spine {
|
|||||||
|
|
||||||
internal class SkeletonInput {
|
internal class SkeletonInput {
|
||||||
private byte[] chars = new byte[32];
|
private byte[] chars = new byte[32];
|
||||||
|
private byte[] bytesBigEndian = new byte[4];
|
||||||
internal ExposedList<String> strings;
|
internal ExposedList<String> strings;
|
||||||
Stream input;
|
Stream input;
|
||||||
|
|
||||||
@ -905,15 +906,20 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float ReadFloat () {
|
public float ReadFloat () {
|
||||||
chars[3] = (byte)input.ReadByte();
|
input.Read(bytesBigEndian, 0, 4);
|
||||||
chars[2] = (byte)input.ReadByte();
|
chars[3] = bytesBigEndian[0];
|
||||||
chars[1] = (byte)input.ReadByte();
|
chars[2] = bytesBigEndian[1];
|
||||||
chars[0] = (byte)input.ReadByte();
|
chars[1] = bytesBigEndian[2];
|
||||||
|
chars[0] = bytesBigEndian[3];
|
||||||
return BitConverter.ToSingle(chars, 0);
|
return BitConverter.ToSingle(chars, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadInt () {
|
public int ReadInt () {
|
||||||
return (input.ReadByte() << 24) + (input.ReadByte() << 16) + (input.ReadByte() << 8) + input.ReadByte();
|
input.Read(bytesBigEndian, 0, 4);
|
||||||
|
return (bytesBigEndian[0] << 24)
|
||||||
|
+ (bytesBigEndian[1] << 16)
|
||||||
|
+ (bytesBigEndian[2] << 8)
|
||||||
|
+ bytesBigEndian[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadInt (bool optimizePositive) {
|
public int ReadInt (bool optimizePositive) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ $(function () {
|
|||||||
alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo);
|
alert("Error: " + message + "\n" + "URL:" + url + "\nLine: " + lineNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
spineDemos.init();
|
spineDemos.init();
|
||||||
spineDemos.assetManager = new spine.SharedAssetManager("assets/");
|
spineDemos.assetManager = new spine.SharedAssetManager("assets/");
|
||||||
|
|
||||||
|
|||||||
157
spine-ts/webgl/example/barebones.html
Normal file
157
spine-ts/webgl/example/barebones.html
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<html>
|
||||||
|
<script src="../../build/spine-webgl.js"></script>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; }
|
||||||
|
body, html { height: 100% }
|
||||||
|
canvas { position: absolute; width: 100% ;height: 100%; }
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var canvas;
|
||||||
|
var gl;
|
||||||
|
var shader;
|
||||||
|
var batcher;
|
||||||
|
var mvp = new spine.webgl.Matrix4();
|
||||||
|
var assetManager;
|
||||||
|
var skeletonRenderer;
|
||||||
|
|
||||||
|
var lastFrameTime;
|
||||||
|
var spineboy;
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
// Setup canvas and WebGL context. We pass alpha: false to canvas.getContext() so we don't use premultiplied alpha when
|
||||||
|
// loading textures. That is handled separately by PolygonBatcher.
|
||||||
|
canvas = document.getElementById("canvas");
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
var config = { alpha: false };
|
||||||
|
gl = canvas.getContext("webgl", config) || canvas.getContext("experimental-webgl", config);
|
||||||
|
if (!gl) {
|
||||||
|
alert('WebGL is unavailable.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a simple shader, mesh, model-view-projection matrix, SkeletonRenderer, and AssetManager.
|
||||||
|
shader = spine.webgl.Shader.newTwoColoredTextured(gl);
|
||||||
|
batcher = new spine.webgl.PolygonBatcher(gl);
|
||||||
|
mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
|
||||||
|
skeletonRenderer = new spine.webgl.SkeletonRenderer(gl);
|
||||||
|
assetManager = new spine.webgl.AssetManager(gl);
|
||||||
|
|
||||||
|
// Tell AssetManager to load the resources for each skeleton, including the exported .skel file, the .atlas file and the .png
|
||||||
|
// file for the atlas. We then wait until all resources are loaded in the load() method.
|
||||||
|
assetManager.loadBinary("assets/spineboy-pro.skel");
|
||||||
|
assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
|
||||||
|
requestAnimationFrame(load);
|
||||||
|
}
|
||||||
|
|
||||||
|
function load () {
|
||||||
|
// Wait until the AssetManager has loaded all resources, then load the skeletons.
|
||||||
|
if (assetManager.isLoadingComplete()) {
|
||||||
|
spineboy = loadSpineboy("run", true);
|
||||||
|
lastFrameTime = Date.now() / 1000;
|
||||||
|
requestAnimationFrame(render); // Loading is done, call render every frame.
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(load);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSpineboy (initialAnimation, premultipliedAlpha) {
|
||||||
|
// Load the texture atlas from the AssetManager.
|
||||||
|
var atlas = assetManager.get("assets/spineboy-pma.atlas");
|
||||||
|
|
||||||
|
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||||
|
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
|
// Create a SkeletonBinary instance for parsing the .skel file.
|
||||||
|
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
|
||||||
|
|
||||||
|
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||||
|
skeletonBinary.scale = 1;
|
||||||
|
var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/spineboy-pro.skel"));
|
||||||
|
var skeleton = new spine.Skeleton(skeletonData);
|
||||||
|
var bounds = calculateSetupPoseBounds(skeleton);
|
||||||
|
|
||||||
|
// Create an AnimationState, and set the initial animation in looping mode.
|
||||||
|
var animationStateData = new spine.AnimationStateData(skeleton.data);
|
||||||
|
var animationState = new spine.AnimationState(animationStateData);
|
||||||
|
animationState.setAnimation(0, initialAnimation, true);
|
||||||
|
|
||||||
|
// Pack everything up and return to caller.
|
||||||
|
return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha };
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateSetupPoseBounds (skeleton) {
|
||||||
|
skeleton.setToSetupPose();
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
var offset = new spine.Vector2();
|
||||||
|
var size = new spine.Vector2();
|
||||||
|
skeleton.getBounds(offset, size, []);
|
||||||
|
return { offset: offset, size: size };
|
||||||
|
}
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
var now = Date.now() / 1000;
|
||||||
|
var delta = now - lastFrameTime;
|
||||||
|
lastFrameTime = now;
|
||||||
|
|
||||||
|
// Update the MVP matrix to adjust for canvas size changes
|
||||||
|
resize();
|
||||||
|
|
||||||
|
gl.clearColor(0.3, 0.3, 0.3, 1);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Apply the animation state based on the delta time.
|
||||||
|
var skeleton = spineboy.skeleton;
|
||||||
|
var state = spineboy.state;
|
||||||
|
var premultipliedAlpha = spineboy.premultipliedAlpha;
|
||||||
|
state.update(delta);
|
||||||
|
state.apply(skeleton);
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
// Bind the shader and set the texture and model-view-projection matrix.
|
||||||
|
shader.bind();
|
||||||
|
shader.setUniformi(spine.webgl.Shader.SAMPLER, 0);
|
||||||
|
shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, mvp.values);
|
||||||
|
|
||||||
|
// Start the batch and tell the SkeletonRenderer to render the active skeleton.
|
||||||
|
batcher.begin(shader);
|
||||||
|
skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||||
|
skeletonRenderer.draw(batcher, skeleton);
|
||||||
|
batcher.end();
|
||||||
|
|
||||||
|
shader.unbind();
|
||||||
|
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize () {
|
||||||
|
var w = canvas.clientWidth;
|
||||||
|
var h = canvas.clientHeight;
|
||||||
|
if (canvas.width != w || canvas.height != h) {
|
||||||
|
canvas.width = w;
|
||||||
|
canvas.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculations to center the skeleton in the canvas.
|
||||||
|
var bounds = spineboy.bounds;
|
||||||
|
var centerX = bounds.offset.x + bounds.size.x / 2;
|
||||||
|
var centerY = bounds.offset.y + bounds.size.y / 2;
|
||||||
|
var scaleX = bounds.size.x / canvas.width;
|
||||||
|
var scaleY = bounds.size.y / canvas.height;
|
||||||
|
var scale = Math.max(scaleX, scaleY) * 1.2;
|
||||||
|
if (scale < 1) scale = 1;
|
||||||
|
var width = canvas.width * scale;
|
||||||
|
var height = canvas.height * scale;
|
||||||
|
|
||||||
|
mvp.ortho2d(centerX - width / 2, centerY - height / 2, width, height);
|
||||||
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -2,9 +2,9 @@
|
|||||||
<script src="../../build/spine-webgl.js"></script>
|
<script src="../../build/spine-webgl.js"></script>
|
||||||
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; }
|
* { margin: 0; padding: 0; }
|
||||||
body, html { height: 100% }
|
body, html { height: 100% }
|
||||||
canvas { position: absolute; width: 100% ;height: 100%; }
|
canvas { position: absolute; width: 100% ;height: 100%; }
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
@ -15,21 +15,22 @@
|
|||||||
<span>Skin:</span><select id="skinList"></select>
|
<span>Skin:</span><select id="skinList"></select>
|
||||||
<span>Vertex Effect:</span><select id="effectList"></select>
|
<span>Vertex Effect:</span><select id="effectList"></select>
|
||||||
<span>Debug:</span><input type="checkbox" id="debug">
|
<span>Debug:</span><input type="checkbox" id="debug">
|
||||||
<div>
|
</div>
|
||||||
</center>
|
</center>
|
||||||
</body>
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
var lastFrameTime = Date.now() / 1000;
|
|
||||||
var canvas;
|
var canvas;
|
||||||
|
var gl;
|
||||||
var shader;
|
var shader;
|
||||||
var batcher;
|
var batcher;
|
||||||
var gl;
|
|
||||||
var mvp = new spine.webgl.Matrix4();
|
var mvp = new spine.webgl.Matrix4();
|
||||||
var assetManager;
|
|
||||||
var skeletonRenderer;
|
var skeletonRenderer;
|
||||||
|
var assetManager;
|
||||||
|
|
||||||
var debugRenderer;
|
var debugRenderer;
|
||||||
var shapes;
|
var shapes;
|
||||||
|
|
||||||
|
var lastFrameTime;
|
||||||
var skeletons = {};
|
var skeletons = {};
|
||||||
var activeSkeleton = "spineboy";
|
var activeSkeleton = "spineboy";
|
||||||
var swirlEffect = new spine.SwirlEffect(0);
|
var swirlEffect = new spine.SwirlEffect(0);
|
||||||
@ -49,11 +50,14 @@ function init () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a simple shader, mesh, model-view-projection matrix and SkeletonRenderer.
|
// Create a simple shader, mesh, model-view-projection matrix, SkeletonRenderer, and AssetManager.
|
||||||
shader = spine.webgl.Shader.newTwoColoredTextured(gl);
|
shader = spine.webgl.Shader.newTwoColoredTextured(gl);
|
||||||
batcher = new spine.webgl.PolygonBatcher(gl);
|
batcher = new spine.webgl.PolygonBatcher(gl);
|
||||||
mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
|
mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1);
|
||||||
skeletonRenderer = new spine.webgl.SkeletonRenderer(gl);
|
skeletonRenderer = new spine.webgl.SkeletonRenderer(gl);
|
||||||
|
assetManager = new spine.webgl.AssetManager(gl);
|
||||||
|
|
||||||
|
// Create a debug renderer and the ShapeRenderer it needs to render lines.
|
||||||
debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl);
|
debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl);
|
||||||
debugRenderer.drawRegionAttachments = true;
|
debugRenderer.drawRegionAttachments = true;
|
||||||
debugRenderer.drawBoundingBoxes = true;
|
debugRenderer.drawBoundingBoxes = true;
|
||||||
@ -62,9 +66,8 @@ function init () {
|
|||||||
debugRenderer.drawPaths = true;
|
debugRenderer.drawPaths = true;
|
||||||
debugShader = spine.webgl.Shader.newColored(gl);
|
debugShader = spine.webgl.Shader.newColored(gl);
|
||||||
shapes = new spine.webgl.ShapeRenderer(gl);
|
shapes = new spine.webgl.ShapeRenderer(gl);
|
||||||
assetManager = new spine.webgl.AssetManager(gl);
|
|
||||||
|
|
||||||
// Tell AssetManager to load the resources for each model, including the exported .skel file, the .atlas file and the .png
|
// Tell AssetManager to load the resources for each skeleton, including the exported .skel file, the .atlas file and the .png
|
||||||
// file for the atlas. We then wait until all resources are loaded in the load() method.
|
// file for the atlas. We then wait until all resources are loaded in the load() method.
|
||||||
assetManager.loadBinary("assets/spineboy-pro.skel");
|
assetManager.loadBinary("assets/spineboy-pro.skel");
|
||||||
assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
|
assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
|
||||||
@ -94,7 +97,8 @@ function load () {
|
|||||||
skeletons["stretchyman"] = loadSkeleton("stretchyman-pro", "sneak", true);
|
skeletons["stretchyman"] = loadSkeleton("stretchyman-pro", "sneak", true);
|
||||||
skeletons["coin"] = loadSkeleton("coin-pro", "animation", true);
|
skeletons["coin"] = loadSkeleton("coin-pro", "animation", true);
|
||||||
setupUI();
|
setupUI();
|
||||||
requestAnimationFrame(render);
|
lastFrameTime = Date.now() / 1000;
|
||||||
|
requestAnimationFrame(render); // Loading is done, call render every frame.
|
||||||
} else {
|
} else {
|
||||||
requestAnimationFrame(load);
|
requestAnimationFrame(load);
|
||||||
}
|
}
|
||||||
@ -104,22 +108,23 @@ function loadSkeleton (name, initialAnimation, premultipliedAlpha, skin) {
|
|||||||
if (skin === undefined) skin = "default";
|
if (skin === undefined) skin = "default";
|
||||||
|
|
||||||
// Load the texture atlas using name.atlas from the AssetManager.
|
// Load the texture atlas using name.atlas from the AssetManager.
|
||||||
atlas = assetManager.get("assets/" + name.replace("-ess", "").replace("-pro", "") + (premultipliedAlpha ? "-pma": "") + ".atlas");
|
var atlas = assetManager.get("assets/" + name.replace("-ess", "").replace("-pro", "") + (premultipliedAlpha ? "-pma": "") + ".atlas");
|
||||||
|
|
||||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||||
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
// Create a SkeletonBinary instance for parsing the .skel file.
|
// Create a SkeletonBinary instance for parsing the .skel file.
|
||||||
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
|
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
|
||||||
|
|
||||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||||
|
skeletonBinary.scale = 1;
|
||||||
var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/" + name + ".skel"));
|
var skeletonData = skeletonBinary.readSkeletonData(assetManager.get("assets/" + name + ".skel"));
|
||||||
var skeleton = new spine.Skeleton(skeletonData);
|
var skeleton = new spine.Skeleton(skeletonData);
|
||||||
skeleton.setSkinByName(skin);
|
skeleton.setSkinByName(skin);
|
||||||
var bounds = calculateBounds(skeleton);
|
var bounds = calculateSetupPoseBounds(skeleton);
|
||||||
|
|
||||||
// Create an AnimationState, and set the initial animation in looping mode.
|
// Create an AnimationState, and set the initial animation in looping mode.
|
||||||
animationStateData = new spine.AnimationStateData(skeleton.data);
|
var animationStateData = new spine.AnimationStateData(skeleton.data);
|
||||||
var animationState = new spine.AnimationState(animationStateData);
|
var animationState = new spine.AnimationState(animationStateData);
|
||||||
if (name == "spineboy") {
|
if (name == "spineboy") {
|
||||||
animationStateData.setMix("walk", "jump", 0.4)
|
animationStateData.setMix("walk", "jump", 0.4)
|
||||||
@ -155,7 +160,7 @@ function loadSkeleton (name, initialAnimation, premultipliedAlpha, skin) {
|
|||||||
return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha };
|
return { skeleton: skeleton, state: animationState, bounds: bounds, premultipliedAlpha: premultipliedAlpha };
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateBounds(skeleton) {
|
function calculateSetupPoseBounds(skeleton) {
|
||||||
skeleton.setToSetupPose();
|
skeleton.setToSetupPose();
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
var offset = new spine.Vector2();
|
var offset = new spine.Vector2();
|
||||||
@ -236,7 +241,6 @@ function setupUI () {
|
|||||||
function render () {
|
function render () {
|
||||||
var now = Date.now() / 1000;
|
var now = Date.now() / 1000;
|
||||||
var delta = now - lastFrameTime;
|
var delta = now - lastFrameTime;
|
||||||
delta = 0.016;
|
|
||||||
lastFrameTime = now;
|
lastFrameTime = now;
|
||||||
|
|
||||||
// Update the MVP matrix to adjust for canvas size changes
|
// Update the MVP matrix to adjust for canvas size changes
|
||||||
@ -246,8 +250,8 @@ function render () {
|
|||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// Apply the animation state based on the delta time.
|
// Apply the animation state based on the delta time.
|
||||||
var state = skeletons[activeSkeleton].state;
|
|
||||||
var skeleton = skeletons[activeSkeleton].skeleton;
|
var skeleton = skeletons[activeSkeleton].skeleton;
|
||||||
|
var state = skeletons[activeSkeleton].state;
|
||||||
var bounds = skeletons[activeSkeleton].bounds;
|
var bounds = skeletons[activeSkeleton].bounds;
|
||||||
var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha;
|
var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha;
|
||||||
state.update(delta);
|
state.update(delta);
|
||||||
@ -269,10 +273,9 @@ function render () {
|
|||||||
swirlTime += delta;
|
swirlTime += delta;
|
||||||
var percent = swirlTime % 2;
|
var percent = swirlTime % 2;
|
||||||
if (percent > 1) percent = 1 - (percent -1 );
|
if (percent > 1) percent = 1 - (percent -1 );
|
||||||
// swirlEffect.angle = -60 + 120 * (perecent < 0.5 ? Math.pow(percent * 2, 2) / 2 : Math.pow((percent - 1) * 2, 2) / -2 + 1);
|
swirlEffect.angle = 120 * percent - 60;
|
||||||
swirlEffect.angle = 360 * percent;
|
swirlEffect.centerX = bounds.offset.x + bounds.size.x / 2;
|
||||||
swirlEffect.centerX = 200; //bounds.offset.x + bounds.size.x / 2
|
swirlEffect.centerY = bounds.offset.y + bounds.size.y / 2;
|
||||||
swirlEffect.centerY = 200; //bounds.offset.y + bounds.size.y / 2
|
|
||||||
swirlEffect.radius = Math.sqrt(bounds.size.x * bounds.size.x + bounds.size.y * bounds.size.y);
|
swirlEffect.radius = Math.sqrt(bounds.size.x * bounds.size.x + bounds.size.y * bounds.size.y);
|
||||||
skeletonRenderer.vertexEffect = swirlEffect;
|
skeletonRenderer.vertexEffect = swirlEffect;
|
||||||
} else if (effect == "Jitter") {
|
} else if (effect == "Jitter") {
|
||||||
@ -285,7 +288,7 @@ function render () {
|
|||||||
|
|
||||||
shader.unbind();
|
shader.unbind();
|
||||||
|
|
||||||
// draw debug information
|
// Draw debug information.
|
||||||
var debug = $('#debug').is(':checked');
|
var debug = $('#debug').is(':checked');
|
||||||
if (debug) {
|
if (debug) {
|
||||||
debugShader.bind();
|
debugShader.bind();
|
||||||
@ -303,13 +306,13 @@ function render () {
|
|||||||
function resize () {
|
function resize () {
|
||||||
var w = canvas.clientWidth;
|
var w = canvas.clientWidth;
|
||||||
var h = canvas.clientHeight;
|
var h = canvas.clientHeight;
|
||||||
var bounds = skeletons[activeSkeleton].bounds;
|
|
||||||
if (canvas.width != w || canvas.height != h) {
|
if (canvas.width != w || canvas.height != h) {
|
||||||
canvas.width = w;
|
canvas.width = w;
|
||||||
canvas.height = h;
|
canvas.height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// magic
|
// Calculations to center the skeleton in the canvas.
|
||||||
|
var bounds = skeletons[activeSkeleton].bounds;
|
||||||
var centerX = bounds.offset.x + bounds.size.x / 2;
|
var centerX = bounds.offset.x + bounds.size.x / 2;
|
||||||
var centerY = bounds.offset.y + bounds.size.y / 2;
|
var centerY = bounds.offset.y + bounds.size.y / 2;
|
||||||
var scaleX = bounds.size.x / canvas.width;
|
var scaleX = bounds.size.x / canvas.width;
|
||||||
@ -323,9 +326,8 @@ function resize () {
|
|||||||
gl.viewport(0, 0, canvas.width, canvas.height);
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
(function() {
|
init();
|
||||||
init();
|
|
||||||
})();
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -55,7 +55,7 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnEnable () {
|
void InitializeEditor () {
|
||||||
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
|
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
|
||||||
slotName = serializedObject.FindProperty("slotName");
|
slotName = serializedObject.FindProperty("slotName");
|
||||||
isTrigger = serializedObject.FindProperty("isTrigger");
|
isTrigger = serializedObject.FindProperty("isTrigger");
|
||||||
@ -64,12 +64,17 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInspectorGUI () {
|
public override void OnInspectorGUI () {
|
||||||
|
|
||||||
#if !NEW_PREFAB_SYSTEM
|
#if !NEW_PREFAB_SYSTEM
|
||||||
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
||||||
#else
|
#else
|
||||||
bool isInspectingPrefab = false;
|
bool isInspectingPrefab = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Note: when calling InitializeEditor() in OnEnable, it throws exception
|
||||||
|
// "SerializedObjectNotCreatableException: Object at index 0 is null".
|
||||||
|
InitializeEditor();
|
||||||
|
|
||||||
// Try to auto-assign SkeletonRenderer field.
|
// Try to auto-assign SkeletonRenderer field.
|
||||||
if (skeletonRenderer.objectReferenceValue == null) {
|
if (skeletonRenderer.objectReferenceValue == null) {
|
||||||
var foundSkeletonRenderer = follower.GetComponentInParent<SkeletonRenderer>();
|
var foundSkeletonRenderer = follower.GetComponentInParent<SkeletonRenderer>();
|
||||||
@ -80,6 +85,7 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
skeletonRenderer.objectReferenceValue = foundSkeletonRenderer;
|
skeletonRenderer.objectReferenceValue = foundSkeletonRenderer;
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
InitializeEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
var skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
|
var skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
|
||||||
@ -101,6 +107,7 @@ namespace Spine.Unity.Editor {
|
|||||||
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
|
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
|
||||||
if (EditorGUI.EndChangeCheck()) {
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
InitializeEditor();
|
||||||
#if !NEW_PREFAB_SYSTEM
|
#if !NEW_PREFAB_SYSTEM
|
||||||
if (!isInspectingPrefab)
|
if (!isInspectingPrefab)
|
||||||
rebuildRequired = true;
|
rebuildRequired = true;
|
||||||
@ -118,6 +125,7 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
if (clearStateChanged || triggerChanged) {
|
if (clearStateChanged || triggerChanged) {
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
InitializeEditor();
|
||||||
if (triggerChanged)
|
if (triggerChanged)
|
||||||
foreach (var col in follower.colliderTable.Values)
|
foreach (var col in follower.colliderTable.Values)
|
||||||
col.isTrigger = isTrigger.boolValue;
|
col.isTrigger = isTrigger.boolValue;
|
||||||
@ -152,6 +160,8 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (follower.Slot == null)
|
||||||
|
follower.Initialize(false);
|
||||||
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
|
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
|
||||||
if (!hasBoneFollower) {
|
if (!hasBoneFollower) {
|
||||||
bool buttonDisabled = follower.Slot == null;
|
bool buttonDisabled = follower.Slot == null;
|
||||||
|
|||||||
@ -72,7 +72,9 @@ namespace Spine.Unity.Editor {
|
|||||||
var component = o as SkeletonAnimation;
|
var component = o as SkeletonAnimation;
|
||||||
component.timeScale = Mathf.Max(component.timeScale, 0);
|
component.timeScale = Mathf.Max(component.timeScale, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
|
SkeletonRootMotionParameter();
|
||||||
|
|
||||||
if (!isInspectingPrefab) {
|
if (!isInspectingPrefab) {
|
||||||
if (requireRepaint) {
|
if (requireRepaint) {
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using Spine;
|
|
||||||
|
|
||||||
namespace Spine.Unity.Editor {
|
namespace Spine.Unity.Editor {
|
||||||
using Icons = SpineEditorUtilities.Icons;
|
using Icons = SpineEditorUtilities.Icons;
|
||||||
@ -44,6 +43,11 @@ namespace Spine.Unity.Editor {
|
|||||||
public class SkeletonGraphicInspector : UnityEditor.Editor {
|
public class SkeletonGraphicInspector : UnityEditor.Editor {
|
||||||
|
|
||||||
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
|
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
|
||||||
|
const string ReloadButtonString = "Reload";
|
||||||
|
protected GUIContent SkeletonDataAssetLabel;
|
||||||
|
static GUILayoutOption reloadButtonWidth;
|
||||||
|
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
|
||||||
|
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
|
||||||
|
|
||||||
SerializedProperty material, color;
|
SerializedProperty material, color;
|
||||||
SerializedProperty skeletonDataAsset, initialSkinName;
|
SerializedProperty skeletonDataAsset, initialSkinName;
|
||||||
@ -56,6 +60,7 @@ namespace Spine.Unity.Editor {
|
|||||||
SkeletonGraphic thisSkeletonGraphic;
|
SkeletonGraphic thisSkeletonGraphic;
|
||||||
protected bool isInspectingPrefab;
|
protected bool isInspectingPrefab;
|
||||||
protected bool slotsReapplyRequired = false;
|
protected bool slotsReapplyRequired = false;
|
||||||
|
protected bool forceReloadQueued = false;
|
||||||
|
|
||||||
protected bool TargetIsValid {
|
protected bool TargetIsValid {
|
||||||
get {
|
get {
|
||||||
@ -80,6 +85,10 @@ namespace Spine.Unity.Editor {
|
|||||||
#else
|
#else
|
||||||
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
||||||
#endif
|
#endif
|
||||||
|
SpineEditorUtilities.ConfirmInitialization();
|
||||||
|
|
||||||
|
// Labels
|
||||||
|
SkeletonDataAssetLabel = new GUIContent("SkeletonData Asset", Icons.spine);
|
||||||
|
|
||||||
var so = this.serializedObject;
|
var so = this.serializedObject;
|
||||||
thisSkeletonGraphic = target as SkeletonGraphic;
|
thisSkeletonGraphic = target as SkeletonGraphic;
|
||||||
@ -115,10 +124,34 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInspectorGUI () {
|
public override void OnInspectorGUI () {
|
||||||
|
|
||||||
|
if (UnityEngine.Event.current.type == EventType.Layout) {
|
||||||
|
if (forceReloadQueued) {
|
||||||
|
forceReloadQueued = false;
|
||||||
|
foreach (var c in targets) {
|
||||||
|
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonGraphic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach (var c in targets) {
|
||||||
|
var component = c as SkeletonGraphic;
|
||||||
|
if (!component.IsValid) {
|
||||||
|
SpineEditorUtilities.ReinitializeComponent(component);
|
||||||
|
if (!component.IsValid) continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool wasChanged = false;
|
bool wasChanged = false;
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) {
|
||||||
|
SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel);
|
||||||
|
if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth))
|
||||||
|
forceReloadQueued = true;
|
||||||
|
}
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(material);
|
EditorGUILayout.PropertyField(material);
|
||||||
EditorGUILayout.PropertyField(color);
|
EditorGUILayout.PropertyField(color);
|
||||||
|
|
||||||
@ -201,6 +234,8 @@ namespace Spine.Unity.Editor {
|
|||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
EditorGUILayout.PropertyField(freeze);
|
EditorGUILayout.PropertyField(freeze);
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
|
SkeletonRendererInspector.SkeletonRootMotionParameter(targets);
|
||||||
|
EditorGUILayout.Space();
|
||||||
EditorGUILayout.LabelField("UI", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("UI", EditorStyles.boldLabel);
|
||||||
EditorGUILayout.PropertyField(raycastTarget);
|
EditorGUILayout.PropertyField(raycastTarget);
|
||||||
|
|
||||||
|
|||||||
@ -30,21 +30,125 @@
|
|||||||
// Contributed by: Mitch Thompson
|
// Contributed by: Mitch Thompson
|
||||||
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Spine.Unity.Editor {
|
namespace Spine.Unity.Editor {
|
||||||
[CustomEditor(typeof(SkeletonMecanim))]
|
[CustomEditor(typeof(SkeletonMecanim))]
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
public class SkeletonMecanimInspector : SkeletonRendererInspector {
|
public class SkeletonMecanimInspector : SkeletonRendererInspector {
|
||||||
protected SerializedProperty mecanimTranslator;
|
public static bool mecanimSettingsFoldout;
|
||||||
|
|
||||||
|
protected SerializedProperty autoReset;
|
||||||
|
protected SerializedProperty useCustomMixMode;
|
||||||
|
protected SerializedProperty layerMixModes;
|
||||||
|
protected SerializedProperty layerBlendModes;
|
||||||
|
|
||||||
protected override void OnEnable () {
|
protected override void OnEnable () {
|
||||||
base.OnEnable();
|
base.OnEnable();
|
||||||
mecanimTranslator = serializedObject.FindProperty("translator");
|
SerializedProperty mecanimTranslator = serializedObject.FindProperty("translator");
|
||||||
|
autoReset = mecanimTranslator.FindPropertyRelative("autoReset");
|
||||||
|
useCustomMixMode = mecanimTranslator.FindPropertyRelative("useCustomMixMode");
|
||||||
|
layerMixModes = mecanimTranslator.FindPropertyRelative("layerMixModes");
|
||||||
|
layerBlendModes = mecanimTranslator.FindPropertyRelative("layerBlendModes");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DrawInspectorGUI (bool multi) {
|
protected override void DrawInspectorGUI (bool multi) {
|
||||||
|
|
||||||
|
AddRootMotionComponentIfEnabled();
|
||||||
|
|
||||||
base.DrawInspectorGUI(multi);
|
base.DrawInspectorGUI(multi);
|
||||||
EditorGUILayout.PropertyField(mecanimTranslator, true);
|
|
||||||
|
using (new SpineInspectorUtility.BoxScope()) {
|
||||||
|
mecanimSettingsFoldout = EditorGUILayout.Foldout(mecanimSettingsFoldout, "Mecanim Translator");
|
||||||
|
if (mecanimSettingsFoldout) {
|
||||||
|
EditorGUILayout.PropertyField(autoReset, new GUIContent("Auto Reset",
|
||||||
|
"When set to true, the skeleton state is mixed out to setup-" +
|
||||||
|
"pose when an animation finishes, according to the " +
|
||||||
|
"animation's keyed items."));
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(useCustomMixMode, new GUIContent("Custom MixMode",
|
||||||
|
"When disabled, the recommended MixMode is used according to the layer blend mode. Enable to specify a custom MixMode for each Mecanim layer."));
|
||||||
|
|
||||||
|
if (useCustomMixMode.hasMultipleDifferentValues || useCustomMixMode.boolValue == true) {
|
||||||
|
DrawLayerSettings();
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddRootMotionComponentIfEnabled () {
|
||||||
|
foreach (var t in targets) {
|
||||||
|
var component = t as Component;
|
||||||
|
var animator = component.GetComponent<Animator>();
|
||||||
|
if (animator != null && animator.applyRootMotion) {
|
||||||
|
if (component.GetComponent<SkeletonMecanimRootMotion>() == null) {
|
||||||
|
component.gameObject.AddComponent<SkeletonMecanimRootMotion>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DrawLayerSettings () {
|
||||||
|
string[] layerNames = GetLayerNames();
|
||||||
|
float widthLayerColumn = 140;
|
||||||
|
float widthMixColumn = 84;
|
||||||
|
|
||||||
|
using (new GUILayout.HorizontalScope()) {
|
||||||
|
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
|
||||||
|
rect.width = widthLayerColumn;
|
||||||
|
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mecanim Layer"), EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
var savedIndent = EditorGUI.indentLevel;
|
||||||
|
EditorGUI.indentLevel = 0;
|
||||||
|
|
||||||
|
rect.position += new Vector2(rect.width, 0);
|
||||||
|
rect.width = widthMixColumn;
|
||||||
|
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mix Mode"), EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
EditorGUI.indentLevel = savedIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (new SpineInspectorUtility.IndentScope()) {
|
||||||
|
int layerCount = layerMixModes.arraySize;
|
||||||
|
for (int i = 0; i < layerCount; ++i) {
|
||||||
|
using (new GUILayout.HorizontalScope()) {
|
||||||
|
string layerName = i < layerNames.Length ? layerNames[i] : ("Layer " + i);
|
||||||
|
|
||||||
|
var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
|
||||||
|
rect.width = widthLayerColumn;
|
||||||
|
EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent(layerName));
|
||||||
|
|
||||||
|
var savedIndent = EditorGUI.indentLevel;
|
||||||
|
EditorGUI.indentLevel = 0;
|
||||||
|
|
||||||
|
var mixMode = layerMixModes.GetArrayElementAtIndex(i);
|
||||||
|
var blendMode = layerBlendModes.GetArrayElementAtIndex(i);
|
||||||
|
rect.position += new Vector2(rect.width, 0);
|
||||||
|
rect.width = widthMixColumn;
|
||||||
|
EditorGUI.PropertyField(rect, mixMode, GUIContent.none);
|
||||||
|
|
||||||
|
EditorGUI.indentLevel = savedIndent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string[] GetLayerNames () {
|
||||||
|
int maxLayerCount = 0;
|
||||||
|
int maxIndex = 0;
|
||||||
|
for (int i = 0; i < targets.Length; ++i) {
|
||||||
|
var skeletonMecanim = ((SkeletonMecanim)targets[i]);
|
||||||
|
int count = skeletonMecanim.Translator.MecanimLayerCount;
|
||||||
|
if (count > maxLayerCount) {
|
||||||
|
maxLayerCount = count;
|
||||||
|
maxIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxLayerCount == 0)
|
||||||
|
return new string[0];
|
||||||
|
var skeletonMecanimMaxLayers = ((SkeletonMecanim)targets[maxIndex]);
|
||||||
|
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,81 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Spine.Unity.Editor {
|
||||||
|
[CustomEditor(typeof(SkeletonMecanimRootMotion))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
public class SkeletonMecanimRootMotionInspector : SkeletonRootMotionBaseInspector {
|
||||||
|
protected SerializedProperty mecanimLayerFlags;
|
||||||
|
|
||||||
|
protected GUIContent mecanimLayersLabel;
|
||||||
|
|
||||||
|
protected override void OnEnable () {
|
||||||
|
base.OnEnable();
|
||||||
|
mecanimLayerFlags = serializedObject.FindProperty("mecanimLayerFlags");
|
||||||
|
|
||||||
|
mecanimLayersLabel = new UnityEngine.GUIContent("Mecanim Layers", "Mecanim layers to apply root motion at. Defaults to the first Mecanim layer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnInspectorGUI () {
|
||||||
|
|
||||||
|
base.MainPropertyFields();
|
||||||
|
MecanimLayerMaskPropertyField();
|
||||||
|
|
||||||
|
base.OptionalPropertyFields();
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string[] GetLayerNames () {
|
||||||
|
int maxLayerCount = 0;
|
||||||
|
int maxIndex = 0;
|
||||||
|
for (int i = 0; i < targets.Length; ++i) {
|
||||||
|
var skeletonMecanim = ((SkeletonMecanimRootMotion)targets[i]).SkeletonMecanim;
|
||||||
|
int count = skeletonMecanim.Translator.MecanimLayerCount;
|
||||||
|
if (count > maxLayerCount) {
|
||||||
|
maxLayerCount = count;
|
||||||
|
maxIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxLayerCount == 0)
|
||||||
|
return new string[0];
|
||||||
|
var skeletonMecanimMaxLayers = ((SkeletonMecanimRootMotion)targets[maxIndex]).SkeletonMecanim;
|
||||||
|
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void MecanimLayerMaskPropertyField () {
|
||||||
|
string[] layerNames = GetLayerNames();
|
||||||
|
if (layerNames.Length > 0)
|
||||||
|
mecanimLayerFlags.intValue = EditorGUILayout.MaskField(
|
||||||
|
mecanimLayersLabel, mecanimLayerFlags.intValue, layerNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4613924c50d66cf458f0db803776dd2f
|
||||||
|
timeCreated: 1593175106
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -82,7 +82,7 @@ namespace Spine.Unity.Editor {
|
|||||||
const string ReloadButtonString = "Reload";
|
const string ReloadButtonString = "Reload";
|
||||||
static GUILayoutOption reloadButtonWidth;
|
static GUILayoutOption reloadButtonWidth;
|
||||||
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
|
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
|
||||||
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButtonRight; } }
|
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
|
||||||
|
|
||||||
protected bool TargetIsValid {
|
protected bool TargetIsValid {
|
||||||
get {
|
get {
|
||||||
@ -106,7 +106,6 @@ namespace Spine.Unity.Editor {
|
|||||||
#else
|
#else
|
||||||
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SpineEditorUtilities.ConfirmInitialization();
|
SpineEditorUtilities.ConfirmInitialization();
|
||||||
|
|
||||||
// Labels
|
// Labels
|
||||||
@ -173,11 +172,8 @@ namespace Spine.Unity.Editor {
|
|||||||
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current) ||
|
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current) ||
|
||||||
AreAnyMaskMaterialsMissing()) {
|
AreAnyMaskMaterialsMissing()) {
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) {
|
||||||
if (multi) {
|
foreach (var o in targets)
|
||||||
foreach (var o in targets) EditorForceInitializeComponent((SkeletonRenderer)o);
|
SpineEditorUtilities.ReinitializeComponent((SkeletonRenderer)o);
|
||||||
} else {
|
|
||||||
EditorForceInitializeComponent((SkeletonRenderer)target);
|
|
||||||
}
|
|
||||||
SceneView.RepaintAll();
|
SceneView.RepaintAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,25 +184,16 @@ namespace Spine.Unity.Editor {
|
|||||||
if (Event.current.type == EventType.Layout) {
|
if (Event.current.type == EventType.Layout) {
|
||||||
if (forceReloadQueued) {
|
if (forceReloadQueued) {
|
||||||
forceReloadQueued = false;
|
forceReloadQueued = false;
|
||||||
if (multi) {
|
foreach (var c in targets) {
|
||||||
foreach (var c in targets)
|
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer);
|
||||||
EditorForceReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer);
|
|
||||||
} else {
|
|
||||||
EditorForceReloadSkeletonDataAssetAndComponent(target as SkeletonRenderer);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (multi) {
|
foreach (var c in targets) {
|
||||||
foreach (var c in targets) {
|
var component = c as SkeletonRenderer;
|
||||||
var component = c as SkeletonRenderer;
|
if (!component.valid) {
|
||||||
if (!component.valid) {
|
SpineEditorUtilities.ReinitializeComponent(component);
|
||||||
EditorForceInitializeComponent(component);
|
if (!component.valid) continue;
|
||||||
if (!component.valid) continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
var component = (SkeletonRenderer)target;
|
|
||||||
if (!component.valid)
|
|
||||||
EditorForceInitializeComponent(component);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,15 +228,8 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
#if NO_PREFAB_MESH
|
#if NO_PREFAB_MESH
|
||||||
if (isInspectingPrefab) {
|
if (isInspectingPrefab) {
|
||||||
if (multi) {
|
foreach (var c in targets) {
|
||||||
foreach (var c in targets) {
|
var component = (SkeletonRenderer)c;
|
||||||
var component = (SkeletonRenderer)c;
|
|
||||||
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
|
|
||||||
if (meshFilter != null && meshFilter.sharedMesh != null)
|
|
||||||
meshFilter.sharedMesh = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var component = (SkeletonRenderer)target;
|
|
||||||
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
|
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
|
||||||
if (meshFilter != null && meshFilter.sharedMesh != null)
|
if (meshFilter != null && meshFilter.sharedMesh != null)
|
||||||
meshFilter.sharedMesh = null;
|
meshFilter.sharedMesh = null;
|
||||||
@ -286,7 +266,7 @@ namespace Spine.Unity.Editor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SkeletonDataAssetIsValid(component.skeletonDataAsset)) {
|
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.skeletonDataAsset)) {
|
||||||
EditorGUILayout.HelpBox("Skeleton Data Asset error. Please check Skeleton Data Asset.", MessageType.Error);
|
EditorGUILayout.HelpBox("Skeleton Data Asset error. Please check Skeleton Data Asset.", MessageType.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -414,6 +394,48 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void SkeletonRootMotionParameter() {
|
||||||
|
SkeletonRootMotionParameter(targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SkeletonRootMotionParameter(Object[] targets) {
|
||||||
|
int rootMotionComponentCount = 0;
|
||||||
|
foreach (var t in targets) {
|
||||||
|
var component = t as Component;
|
||||||
|
if (component.GetComponent<SkeletonRootMotion>() != null) {
|
||||||
|
++rootMotionComponentCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool allHaveRootMotion = rootMotionComponentCount == targets.Length;
|
||||||
|
bool anyHaveRootMotion = rootMotionComponentCount > 0;
|
||||||
|
|
||||||
|
using (new GUILayout.HorizontalScope()) {
|
||||||
|
EditorGUILayout.PrefixLabel("Root Motion");
|
||||||
|
|
||||||
|
if (!allHaveRootMotion) {
|
||||||
|
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Component", Icons.constraintTransform), GUILayout.MaxWidth(130), GUILayout.Height(18))) {
|
||||||
|
foreach (var t in targets) {
|
||||||
|
var component = t as Component;
|
||||||
|
if (component.GetComponent<SkeletonRootMotion>() == null) {
|
||||||
|
component.gameObject.AddComponent<SkeletonRootMotion>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anyHaveRootMotion) {
|
||||||
|
if (GUILayout.Button(SpineInspectorUtility.TempContent("Remove Component", Icons.constraintTransform), GUILayout.MaxWidth(140), GUILayout.Height(18))) {
|
||||||
|
foreach (var t in targets) {
|
||||||
|
var component = t as Component;
|
||||||
|
var rootMotionComponent = component.GetComponent<SkeletonRootMotion>();
|
||||||
|
if (rootMotionComponent != null) {
|
||||||
|
DestroyImmediate(rootMotionComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
|
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
|
||||||
var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
|
var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
|
||||||
field.SetValue(skeletonRenderer, newSlotNames);
|
field.SetValue(skeletonRenderer, newSlotNames);
|
||||||
@ -535,38 +557,6 @@ namespace Spine.Unity.Editor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EditorForceReloadSkeletonDataAssetAndComponent (SkeletonRenderer component) {
|
|
||||||
if (component == null) return;
|
|
||||||
|
|
||||||
// Clear all and reload.
|
|
||||||
if (component.skeletonDataAsset != null) {
|
|
||||||
foreach (AtlasAssetBase aa in component.skeletonDataAsset.atlasAssets) {
|
|
||||||
if (aa != null) aa.Clear();
|
|
||||||
}
|
|
||||||
component.skeletonDataAsset.Clear();
|
|
||||||
}
|
|
||||||
component.skeletonDataAsset.GetSkeletonData(true);
|
|
||||||
|
|
||||||
// Reinitialize.
|
|
||||||
EditorForceInitializeComponent(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EditorForceInitializeComponent (SkeletonRenderer component) {
|
|
||||||
if (component == null) return;
|
|
||||||
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
|
||||||
component.Initialize(true);
|
|
||||||
|
|
||||||
#if BUILT_IN_SPRITE_MASK_COMPONENT
|
|
||||||
SpineMaskUtilities.EditorAssignSpriteMaskMaterials(component);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
component.LateUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) {
|
|
||||||
return asset != null && asset.GetSkeletonData(quiet: true) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AreAnyMaskMaterialsMissing() {
|
bool AreAnyMaskMaterialsMissing() {
|
||||||
#if BUILT_IN_SPRITE_MASK_COMPONENT
|
#if BUILT_IN_SPRITE_MASK_COMPONENT
|
||||||
foreach (var o in targets) {
|
foreach (var o in targets) {
|
||||||
@ -584,13 +574,13 @@ namespace Spine.Unity.Editor {
|
|||||||
static void EditorSetMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType)
|
static void EditorSetMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType)
|
||||||
{
|
{
|
||||||
if (component == null) return;
|
if (component == null) return;
|
||||||
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
||||||
SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType);
|
SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EditorDeleteMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) {
|
static void EditorDeleteMaskMaterials(SkeletonRenderer component, SpriteMaskInteraction maskType) {
|
||||||
if (component == null) return;
|
if (component == null) return;
|
||||||
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
||||||
SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType);
|
SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -0,0 +1,92 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Spine.Unity.Editor {
|
||||||
|
[CustomEditor(typeof(SkeletonRootMotionBase))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
public class SkeletonRootMotionBaseInspector : UnityEditor.Editor {
|
||||||
|
protected SerializedProperty rootMotionBoneName;
|
||||||
|
protected SerializedProperty transformPositionX;
|
||||||
|
protected SerializedProperty transformPositionY;
|
||||||
|
protected SerializedProperty rigidBody2D;
|
||||||
|
protected SerializedProperty rigidBody;
|
||||||
|
|
||||||
|
protected GUIContent rootMotionBoneNameLabel;
|
||||||
|
protected GUIContent transformPositionXLabel;
|
||||||
|
protected GUIContent transformPositionYLabel;
|
||||||
|
protected GUIContent rigidBody2DLabel;
|
||||||
|
protected GUIContent rigidBodyLabel;
|
||||||
|
|
||||||
|
protected virtual void OnEnable () {
|
||||||
|
|
||||||
|
rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName");
|
||||||
|
transformPositionX = serializedObject.FindProperty("transformPositionX");
|
||||||
|
transformPositionY = serializedObject.FindProperty("transformPositionY");
|
||||||
|
rigidBody2D = serializedObject.FindProperty("rigidBody2D");
|
||||||
|
rigidBody = serializedObject.FindProperty("rigidBody");
|
||||||
|
|
||||||
|
rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from.");
|
||||||
|
transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)");
|
||||||
|
transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone.");
|
||||||
|
rigidBody2DLabel = new UnityEngine.GUIContent("Rigidbody2D",
|
||||||
|
"Optional Rigidbody2D: Assign a Rigidbody2D here if you want " +
|
||||||
|
" to apply the root motion to the rigidbody instead of the Transform." +
|
||||||
|
"\n\n" +
|
||||||
|
"Note that animation and physics updates are not always in sync." +
|
||||||
|
"Some jitter may result at certain framerates.");
|
||||||
|
rigidBodyLabel = new UnityEngine.GUIContent("Rigidbody",
|
||||||
|
"Optional Rigidbody: Assign a Rigidbody here if you want " +
|
||||||
|
" to apply the root motion to the rigidbody instead of the Transform." +
|
||||||
|
"\n\n" +
|
||||||
|
"Note that animation and physics updates are not always in sync." +
|
||||||
|
"Some jitter may result at certain framerates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI () {
|
||||||
|
MainPropertyFields();
|
||||||
|
OptionalPropertyFields();
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void MainPropertyFields () {
|
||||||
|
EditorGUILayout.PropertyField(rootMotionBoneName, rootMotionBoneNameLabel);
|
||||||
|
EditorGUILayout.PropertyField(transformPositionX, transformPositionXLabel);
|
||||||
|
EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OptionalPropertyFields () {
|
||||||
|
//EditorGUILayout.LabelField("Optional", EditorStyles.boldLabel);
|
||||||
|
EditorGUILayout.PropertyField(rigidBody2D, rigidBody2DLabel);
|
||||||
|
EditorGUILayout.PropertyField(rigidBody, rigidBodyLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f2cba83baf6afdf44a996e40017c6325
|
||||||
|
timeCreated: 1593175106
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Spine.Unity.Editor {
|
||||||
|
[CustomEditor(typeof(SkeletonRootMotion))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
public class SkeletonRootMotionInspector : SkeletonRootMotionBaseInspector {
|
||||||
|
protected SerializedProperty animationTrackFlags;
|
||||||
|
protected GUIContent animationTrackFlagsLabel;
|
||||||
|
|
||||||
|
string[] TrackNames;
|
||||||
|
|
||||||
|
protected override void OnEnable () {
|
||||||
|
base.OnEnable();
|
||||||
|
|
||||||
|
animationTrackFlags = serializedObject.FindProperty("animationTrackFlags");
|
||||||
|
animationTrackFlagsLabel = new UnityEngine.GUIContent("Animation Tracks",
|
||||||
|
"Animation tracks to apply root motion at. Defaults to the first" +
|
||||||
|
" animation track (index 0).");
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnInspectorGUI () {
|
||||||
|
|
||||||
|
base.MainPropertyFields();
|
||||||
|
AnimationTracksPropertyField();
|
||||||
|
|
||||||
|
base.OptionalPropertyFields();
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AnimationTracksPropertyField () {
|
||||||
|
|
||||||
|
if (TrackNames == null) {
|
||||||
|
InitTrackNames();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
animationTrackFlags.intValue = EditorGUILayout.MaskField(
|
||||||
|
animationTrackFlagsLabel, animationTrackFlags.intValue, TrackNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void InitTrackNames () {
|
||||||
|
int numEntries = 32;
|
||||||
|
TrackNames = new string[numEntries];
|
||||||
|
for (int i = 0; i < numEntries; ++i) {
|
||||||
|
TrackNames[i] = string.Format("Track {0}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e4836100aed984c4a9af11d39c63cb6b
|
||||||
|
timeCreated: 1593183609
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -169,7 +169,7 @@ public class SpineSpriteShaderGUI : SpineShaderWithOutlineGUI {
|
|||||||
static GUIContent _rimPowerText = new GUIContent("Rim Power");
|
static GUIContent _rimPowerText = new GUIContent("Rim Power");
|
||||||
static GUIContent _specularToggleText = new GUIContent("Specular", "Enable Specular.");
|
static GUIContent _specularToggleText = new GUIContent("Specular", "Enable Specular.");
|
||||||
static GUIContent _colorAdjustmentToggleText = new GUIContent("Color Adjustment", "Enable material color adjustment.");
|
static GUIContent _colorAdjustmentToggleText = new GUIContent("Color Adjustment", "Enable material color adjustment.");
|
||||||
static GUIContent _colorAdjustmentColorText = new GUIContent("Overlay Color");
|
static GUIContent _colorAdjustmentColorText = new GUIContent("Overlay Color & Alpha");
|
||||||
static GUIContent _colorAdjustmentHueText = new GUIContent("Hue");
|
static GUIContent _colorAdjustmentHueText = new GUIContent("Hue");
|
||||||
static GUIContent _colorAdjustmentSaturationText = new GUIContent("Saturation");
|
static GUIContent _colorAdjustmentSaturationText = new GUIContent("Saturation");
|
||||||
static GUIContent _colorAdjustmentBrightnessText = new GUIContent("Brightness");
|
static GUIContent _colorAdjustmentBrightnessText = new GUIContent("Brightness");
|
||||||
|
|||||||
@ -46,6 +46,10 @@
|
|||||||
#define NEW_PREFERENCES_SETTINGS_PROVIDER
|
#define NEW_PREFERENCES_SETTINGS_PROVIDER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_2017_1_OR_NEWER
|
||||||
|
#define BUILT_IN_SPRITE_MASK_COMPONENT
|
||||||
|
#endif
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -189,6 +193,62 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ReloadSkeletonDataAssetAndComponent (SkeletonRenderer component) {
|
||||||
|
if (component == null) return;
|
||||||
|
ReloadSkeletonDataAsset(component.skeletonDataAsset);
|
||||||
|
ReinitializeComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReloadSkeletonDataAssetAndComponent (SkeletonGraphic component) {
|
||||||
|
if (component == null) return;
|
||||||
|
ReloadSkeletonDataAsset(component.skeletonDataAsset);
|
||||||
|
// Reinitialize.
|
||||||
|
ReinitializeComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReloadSkeletonDataAsset (SkeletonDataAsset skeletonDataAsset) {
|
||||||
|
if (skeletonDataAsset != null) {
|
||||||
|
foreach (AtlasAssetBase aa in skeletonDataAsset.atlasAssets) {
|
||||||
|
if (aa != null) aa.Clear();
|
||||||
|
}
|
||||||
|
skeletonDataAsset.Clear();
|
||||||
|
}
|
||||||
|
skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReinitializeComponent (SkeletonRenderer component) {
|
||||||
|
if (component == null) return;
|
||||||
|
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
||||||
|
|
||||||
|
var stateComponent = component as IAnimationStateComponent;
|
||||||
|
AnimationState oldAnimationState = null;
|
||||||
|
if (stateComponent != null) {
|
||||||
|
oldAnimationState = stateComponent.AnimationState;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.Initialize(true); // implicitly clears any subscribers
|
||||||
|
|
||||||
|
if (oldAnimationState != null) {
|
||||||
|
stateComponent.AnimationState.AssignEventSubscribersFrom(oldAnimationState);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BUILT_IN_SPRITE_MASK_COMPONENT
|
||||||
|
SpineMaskUtilities.EditorAssignSpriteMaskMaterials(component);
|
||||||
|
#endif
|
||||||
|
component.LateUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReinitializeComponent (SkeletonGraphic component) {
|
||||||
|
if (component == null) return;
|
||||||
|
if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
|
||||||
|
component.Initialize(true);
|
||||||
|
component.LateUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) {
|
||||||
|
return asset != null && asset.GetSkeletonData(quiet: true) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IssueWarningsForUnrecommendedTextureSettings(string texturePath)
|
public static bool IssueWarningsForUnrecommendedTextureSettings(string texturePath)
|
||||||
{
|
{
|
||||||
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
||||||
|
|||||||
@ -27,6 +27,10 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
|
||||||
|
#define NEW_PREFAB_SYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
@ -81,7 +85,18 @@ namespace Spine.Unity.Examples {
|
|||||||
|
|
||||||
// Restore mesh part for undo logic after undo of "Add Parts Renderer".
|
// Restore mesh part for undo logic after undo of "Add Parts Renderer".
|
||||||
// Triggers regeneration and assignment of the mesh filter's mesh.
|
// Triggers regeneration and assignment of the mesh filter's mesh.
|
||||||
if (component.GetComponent<MeshFilter>() && component.GetComponent<MeshFilter>().sharedMesh == null) {
|
|
||||||
|
bool isMeshFilterAlwaysNull = false;
|
||||||
|
#if UNITY_EDITOR && NEW_PREFAB_SYSTEM
|
||||||
|
// Don't store mesh or material at the prefab, otherwise it will permanently reload
|
||||||
|
var prefabType = UnityEditor.PrefabUtility.GetPrefabAssetType(component);
|
||||||
|
if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(component) &&
|
||||||
|
(prefabType == UnityEditor.PrefabAssetType.Regular || prefabType == UnityEditor.PrefabAssetType.Variant)) {
|
||||||
|
isMeshFilterAlwaysNull = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!isMeshFilterAlwaysNull && component.GetComponent<MeshFilter>() && component.GetComponent<MeshFilter>().sharedMesh == null) {
|
||||||
component.OnDisable();
|
component.OnDisable();
|
||||||
component.OnEnable();
|
component.OnEnable();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,12 @@ namespace Spine.Unity {
|
|||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DisposeColliders();
|
slot = null;
|
||||||
|
currentAttachment = null;
|
||||||
|
currentAttachmentName = null;
|
||||||
|
currentCollider = null;
|
||||||
|
colliderTable.Clear();
|
||||||
|
nameTable.Clear();
|
||||||
|
|
||||||
var skeleton = skeletonRenderer.skeleton;
|
var skeleton = skeletonRenderer.skeleton;
|
||||||
slot = skeleton.FindSlot(slotName);
|
slot = skeleton.FindSlot(slotName);
|
||||||
@ -118,13 +123,16 @@ namespace Spine.Unity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int requiredCollidersCount = 0;
|
||||||
|
var colliders = GetComponents<PolygonCollider2D>();
|
||||||
if (this.gameObject.activeInHierarchy) {
|
if (this.gameObject.activeInHierarchy) {
|
||||||
foreach (var skin in skeleton.Data.Skins)
|
foreach (var skin in skeleton.Data.Skins)
|
||||||
AddSkin(skin, slotIndex);
|
AddCollidersForSkin(skin, slotIndex, colliders, ref requiredCollidersCount);
|
||||||
|
|
||||||
if (skeleton.skin != null)
|
if (skeleton.skin != null)
|
||||||
AddSkin(skeleton.skin, slotIndex);
|
AddCollidersForSkin(skeleton.skin, slotIndex, colliders, ref requiredCollidersCount);
|
||||||
}
|
}
|
||||||
|
DisposeExcessCollidersAfter(requiredCollidersCount);
|
||||||
|
|
||||||
if (BoundingBoxFollower.DebugMessages) {
|
if (BoundingBoxFollower.DebugMessages) {
|
||||||
bool valid = colliderTable.Count != 0;
|
bool valid = colliderTable.Count != 0;
|
||||||
@ -137,7 +145,7 @@ namespace Spine.Unity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSkin (Skin skin, int slotIndex) {
|
void AddCollidersForSkin (Skin skin, int slotIndex, PolygonCollider2D[] previousColliders, ref int collidersCount) {
|
||||||
if (skin == null) return;
|
if (skin == null) return;
|
||||||
var skinEntries = new List<Skin.SkinEntry>();
|
var skinEntries = new List<Skin.SkinEntry>();
|
||||||
skin.GetAttachments(slotIndex, skinEntries);
|
skin.GetAttachments(slotIndex, skinEntries);
|
||||||
@ -151,8 +159,11 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
if (boundingBoxAttachment != null) {
|
if (boundingBoxAttachment != null) {
|
||||||
if (!colliderTable.ContainsKey(boundingBoxAttachment)) {
|
if (!colliderTable.ContainsKey(boundingBoxAttachment)) {
|
||||||
var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, slot, gameObject, isTrigger);
|
var bbCollider = collidersCount < previousColliders.Length ?
|
||||||
|
previousColliders[collidersCount] : gameObject.AddComponent<PolygonCollider2D>();
|
||||||
|
++collidersCount;
|
||||||
|
SkeletonUtility.SetColliderPointsLocal(bbCollider, slot, boundingBoxAttachment);
|
||||||
|
bbCollider.isTrigger = isTrigger;
|
||||||
bbCollider.enabled = false;
|
bbCollider.enabled = false;
|
||||||
bbCollider.hideFlags = HideFlags.NotEditable;
|
bbCollider.hideFlags = HideFlags.NotEditable;
|
||||||
bbCollider.isTrigger = IsTrigger;
|
bbCollider.isTrigger = IsTrigger;
|
||||||
@ -178,33 +189,21 @@ namespace Spine.Unity {
|
|||||||
currentCollider = null;
|
currentCollider = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisposeColliders () {
|
void DisposeExcessCollidersAfter (int requiredCount) {
|
||||||
var colliders = GetComponents<PolygonCollider2D>();
|
var colliders = GetComponents<PolygonCollider2D>();
|
||||||
if (colliders.Length == 0) return;
|
if (colliders.Length == 0) return;
|
||||||
|
|
||||||
if (Application.isEditor) {
|
for (int i = requiredCount; i < colliders.Length; ++i) {
|
||||||
if (Application.isPlaying) {
|
var collider = colliders[i];
|
||||||
foreach (var c in colliders) {
|
if (collider != null) {
|
||||||
if (c != null)
|
#if UNITY_EDITOR
|
||||||
Destroy(c);
|
if (Application.isEditor && !Application.isPlaying)
|
||||||
}
|
DestroyImmediate(collider);
|
||||||
} else {
|
else
|
||||||
foreach (var c in colliders)
|
#endif
|
||||||
if (c != null)
|
Destroy(collider);
|
||||||
DestroyImmediate(c);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
foreach (PolygonCollider2D c in colliders)
|
|
||||||
if (c != null)
|
|
||||||
Destroy(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = null;
|
|
||||||
currentAttachment = null;
|
|
||||||
currentAttachmentName = null;
|
|
||||||
currentCollider = null;
|
|
||||||
colliderTable.Clear();
|
|
||||||
nameTable.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LateUpdate () {
|
void LateUpdate () {
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2b957aa69dae9f948bacdeec549d28ea
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1593173800
|
||||||
|
licenseType: Pro
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Spine.Unity.AnimationTools;
|
||||||
|
|
||||||
|
namespace Spine.Unity {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add this component to a SkeletonMecanim GameObject
|
||||||
|
/// to turn motion of a selected root bone into Transform or RigidBody motion.
|
||||||
|
/// Local bone translation movement is used as motion.
|
||||||
|
/// All top-level bones of the skeleton are moved to compensate the root
|
||||||
|
/// motion bone location, keeping the distance relationship between bones intact.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Only compatible with <c>SkeletonMecanim</c>.
|
||||||
|
/// For <c>SkeletonAnimation</c> or <c>SkeletonGraphic</c> please use
|
||||||
|
/// <see cref="SkeletonRootMotion">SkeletonRootMotion</see> instead.
|
||||||
|
/// </remarks>
|
||||||
|
public class SkeletonMecanimRootMotion : SkeletonRootMotionBase {
|
||||||
|
#region Inspector
|
||||||
|
const int DefaultMecanimLayerFlags = -1;
|
||||||
|
public int mecanimLayerFlags = DefaultMecanimLayerFlags;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected Vector2 movementDelta;
|
||||||
|
|
||||||
|
SkeletonMecanim skeletonMecanim;
|
||||||
|
public SkeletonMecanim SkeletonMecanim {
|
||||||
|
get {
|
||||||
|
return skeletonMecanim ? skeletonMecanim : skeletonMecanim = GetComponent<SkeletonMecanim>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Reset () {
|
||||||
|
base.Reset();
|
||||||
|
mecanimLayerFlags = DefaultMecanimLayerFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Start () {
|
||||||
|
base.Start();
|
||||||
|
skeletonMecanim = GetComponent<SkeletonMecanim>();
|
||||||
|
if (skeletonMecanim) {
|
||||||
|
skeletonMecanim.Translator.OnClipApplied -= OnClipApplied;
|
||||||
|
skeletonMecanim.Translator.OnClipApplied += OnClipApplied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnClipApplied(Spine.Animation clip, int layerIndex, float weight,
|
||||||
|
float time, float lastTime, bool playsBackward) {
|
||||||
|
|
||||||
|
if (((mecanimLayerFlags & 1<<layerIndex) == 0) || weight == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var timeline = clip.FindTranslateTimelineForBone(rootMotionBoneIndex);
|
||||||
|
if (timeline != null) {
|
||||||
|
if (!playsBackward)
|
||||||
|
movementDelta += weight * GetTimelineMovementDelta(lastTime, time, timeline, clip);
|
||||||
|
else
|
||||||
|
movementDelta -= weight * GetTimelineMovementDelta(time, lastTime, timeline, clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Vector2 CalculateAnimationsMovementDelta () {
|
||||||
|
// Note: movement delta is not gather after animation but
|
||||||
|
// in OnClipApplied after every applied animation.
|
||||||
|
Vector2 result = movementDelta;
|
||||||
|
movementDelta = Vector2.zero;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 95813afe390494344a6ce2cbc8bfb7d1
|
||||||
|
timeCreated: 1592849332
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Spine.Unity.AnimationTools;
|
||||||
|
|
||||||
|
namespace Spine.Unity {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add this component to a SkeletonAnimation or SkeletonGraphic GameObject
|
||||||
|
/// to turn motion of a selected root bone into Transform or RigidBody motion.
|
||||||
|
/// Local bone translation movement is used as motion.
|
||||||
|
/// All top-level bones of the skeleton are moved to compensate the root
|
||||||
|
/// motion bone location, keeping the distance relationship between bones intact.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Only compatible with SkeletonAnimation (or other components that implement
|
||||||
|
/// ISkeletonComponent, ISkeletonAnimation and IAnimationStateComponent).
|
||||||
|
/// For <c>SkeletonMecanim</c> please use
|
||||||
|
/// <see cref="SkeletonMecanimRootMotion">SkeletonMecanimRootMotion</see> instead.
|
||||||
|
/// </remarks>
|
||||||
|
public class SkeletonRootMotion : SkeletonRootMotionBase {
|
||||||
|
#region Inspector
|
||||||
|
const int DefaultAnimationTrackFlags = -1;
|
||||||
|
public int animationTrackFlags = DefaultAnimationTrackFlags;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
AnimationState animationState;
|
||||||
|
Canvas canvas;
|
||||||
|
|
||||||
|
protected override float AdditionalScale {
|
||||||
|
get {
|
||||||
|
return canvas ? canvas.referencePixelsPerUnit: 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Reset () {
|
||||||
|
base.Reset();
|
||||||
|
animationTrackFlags = DefaultAnimationTrackFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Start () {
|
||||||
|
base.Start();
|
||||||
|
var animstateComponent = skeletonComponent as IAnimationStateComponent;
|
||||||
|
this.animationState = (animstateComponent != null) ? animstateComponent.AnimationState : null;
|
||||||
|
|
||||||
|
if (this.GetComponent<CanvasRenderer>() != null) {
|
||||||
|
canvas = this.GetComponentInParent<Canvas>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Vector2 CalculateAnimationsMovementDelta () {
|
||||||
|
Vector2 localDelta = Vector2.zero;
|
||||||
|
int trackCount = animationState.Tracks.Count;
|
||||||
|
|
||||||
|
for (int trackIndex = 0; trackIndex < trackCount; ++trackIndex) {
|
||||||
|
// note: animationTrackFlags != -1 below covers trackIndex >= 32,
|
||||||
|
// with -1 corresponding to entry "everything" of the dropdown list.
|
||||||
|
if (animationTrackFlags != -1 && (animationTrackFlags & 1 << trackIndex) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TrackEntry track = animationState.GetCurrent(trackIndex);
|
||||||
|
TrackEntry next = null;
|
||||||
|
while (track != null) {
|
||||||
|
var animation = track.Animation;
|
||||||
|
var timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex);
|
||||||
|
if (timeline != null) {
|
||||||
|
var currentDelta = GetTrackMovementDelta(track, timeline, animation, next);
|
||||||
|
localDelta += currentDelta;
|
||||||
|
}
|
||||||
|
// Traverse mixingFrom chain.
|
||||||
|
next = track;
|
||||||
|
track = track.mixingFrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return localDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 GetTrackMovementDelta (TrackEntry track, TranslateTimeline timeline,
|
||||||
|
Animation animation, TrackEntry next) {
|
||||||
|
|
||||||
|
float start = track.animationLast;
|
||||||
|
float end = track.AnimationTime;
|
||||||
|
Vector2 currentDelta = GetTimelineMovementDelta(start, end, timeline, animation);
|
||||||
|
|
||||||
|
ApplyMixAlphaToDelta(ref currentDelta, next, track);
|
||||||
|
return currentDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyMixAlphaToDelta (ref Vector2 currentDelta, TrackEntry next, TrackEntry track) {
|
||||||
|
// Apply mix alpha to the delta position (based on AnimationState.cs).
|
||||||
|
float mix;
|
||||||
|
if (next != null) {
|
||||||
|
if (next.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
|
||||||
|
mix = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mix = next.mixTime / next.mixDuration;
|
||||||
|
if (mix > 1) mix = 1;
|
||||||
|
}
|
||||||
|
float mixAndAlpha = track.alpha * next.interruptAlpha * (1 - mix);
|
||||||
|
currentDelta *= mixAndAlpha;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (track.mixDuration == 0) {
|
||||||
|
mix = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mix = track.alpha * (track.mixTime / track.mixDuration);
|
||||||
|
if (mix > 1) mix = 1;
|
||||||
|
}
|
||||||
|
currentDelta *= mix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f21c9538588898a45a3da22bf4779ab3
|
||||||
|
timeCreated: 1591121072
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,184 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Spine.Unity.AnimationTools;
|
||||||
|
|
||||||
|
namespace Spine.Unity {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for skeleton root motion components.
|
||||||
|
/// </summary>
|
||||||
|
abstract public class SkeletonRootMotionBase : MonoBehaviour {
|
||||||
|
#region Inspector
|
||||||
|
|
||||||
|
[SpineBone]
|
||||||
|
[SerializeField]
|
||||||
|
protected string rootMotionBoneName = "root";
|
||||||
|
public bool transformPositionX = true;
|
||||||
|
public bool transformPositionY = true;
|
||||||
|
|
||||||
|
[Header("Optional")]
|
||||||
|
public Rigidbody2D rigidBody2D;
|
||||||
|
public Rigidbody rigidBody;
|
||||||
|
|
||||||
|
public bool UsesRigidbody {
|
||||||
|
get { return rigidBody != null || rigidBody2D != null; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected ISkeletonComponent skeletonComponent;
|
||||||
|
protected Bone rootMotionBone;
|
||||||
|
protected int rootMotionBoneIndex;
|
||||||
|
protected List<Bone> topLevelBones = new List<Bone>();
|
||||||
|
protected Vector2 rigidbodyDisplacement;
|
||||||
|
|
||||||
|
protected virtual void Reset () {
|
||||||
|
FindRigidbodyComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Start () {
|
||||||
|
skeletonComponent = GetComponent<ISkeletonComponent>();
|
||||||
|
GatherTopLevelBones();
|
||||||
|
SetRootMotionBone(rootMotionBoneName);
|
||||||
|
|
||||||
|
var skeletonAnimation = skeletonComponent as ISkeletonAnimation;
|
||||||
|
if (skeletonAnimation != null)
|
||||||
|
skeletonAnimation.UpdateLocal += HandleUpdateLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected Vector2 CalculateAnimationsMovementDelta ();
|
||||||
|
|
||||||
|
protected virtual float AdditionalScale { get { return 1.0f; } }
|
||||||
|
|
||||||
|
protected Vector2 GetTimelineMovementDelta (float startTime, float endTime,
|
||||||
|
TranslateTimeline timeline, Animation animation) {
|
||||||
|
|
||||||
|
Vector2 currentDelta;
|
||||||
|
if (startTime > endTime) // Looped
|
||||||
|
currentDelta = (timeline.Evaluate(animation.duration) - timeline.Evaluate(startTime))
|
||||||
|
+ (timeline.Evaluate(endTime) - timeline.Evaluate(0));
|
||||||
|
else if (startTime != endTime) // Non-looped
|
||||||
|
currentDelta = timeline.Evaluate(endTime) - timeline.Evaluate(startTime);
|
||||||
|
else
|
||||||
|
currentDelta = Vector2.zero;
|
||||||
|
return currentDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatherTopLevelBones () {
|
||||||
|
topLevelBones.Clear();
|
||||||
|
var skeleton = skeletonComponent.Skeleton;
|
||||||
|
foreach (var bone in skeleton.Bones) {
|
||||||
|
if (bone.Parent == null)
|
||||||
|
topLevelBones.Add(bone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetRootMotionBone (string name) {
|
||||||
|
var skeleton = skeletonComponent.Skeleton;
|
||||||
|
int index = skeleton.FindBoneIndex(name);
|
||||||
|
if (index >= 0) {
|
||||||
|
this.rootMotionBoneIndex = index;
|
||||||
|
this.rootMotionBone = skeleton.bones.Items[index];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Debug.Log("Bone named \"" + name + "\" could not be found.");
|
||||||
|
this.rootMotionBoneIndex = 0;
|
||||||
|
this.rootMotionBone = skeleton.RootBone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleUpdateLocal (ISkeletonAnimation animatedSkeletonComponent) {
|
||||||
|
if (!this.isActiveAndEnabled)
|
||||||
|
return; // Root motion is only applied when component is enabled.
|
||||||
|
|
||||||
|
var movementDelta = CalculateAnimationsMovementDelta();
|
||||||
|
AdjustMovementDeltaToConfiguration(ref movementDelta, animatedSkeletonComponent.Skeleton);
|
||||||
|
ApplyRootMotion(movementDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdjustMovementDeltaToConfiguration (ref Vector2 localDelta, Skeleton skeleton) {
|
||||||
|
if (skeleton.ScaleX < 0) localDelta.x = -localDelta.x;
|
||||||
|
if (skeleton.ScaleY < 0) localDelta.y = -localDelta.y;
|
||||||
|
if (!transformPositionX) localDelta.x = 0f;
|
||||||
|
if (!transformPositionY) localDelta.y = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyRootMotion (Vector2 localDelta) {
|
||||||
|
localDelta *= AdditionalScale;
|
||||||
|
// Apply root motion to Transform or RigidBody;
|
||||||
|
if (UsesRigidbody) {
|
||||||
|
rigidbodyDisplacement += (Vector2)transform.TransformVector(localDelta);
|
||||||
|
// Accumulated displacement is applied on the next Physics update (FixedUpdate)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
transform.position += transform.TransformVector(localDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move top level bones in opposite direction of the root motion bone
|
||||||
|
foreach (var topLevelBone in topLevelBones) {
|
||||||
|
if (transformPositionX) topLevelBone.x -= rootMotionBone.x;
|
||||||
|
if (transformPositionY) topLevelBone.y -= rootMotionBone.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void FixedUpdate () {
|
||||||
|
if (!this.isActiveAndEnabled)
|
||||||
|
return; // Root motion is only applied when component is enabled.
|
||||||
|
|
||||||
|
if(rigidBody2D != null) {
|
||||||
|
rigidBody2D.MovePosition(new Vector2(transform.position.x, transform.position.y)
|
||||||
|
+ rigidbodyDisplacement);
|
||||||
|
}
|
||||||
|
if (rigidBody != null) {
|
||||||
|
rigidBody.MovePosition(transform.position
|
||||||
|
+ new Vector3(rigidbodyDisplacement.x, rigidbodyDisplacement.y, 0));
|
||||||
|
}
|
||||||
|
rigidbodyDisplacement = Vector2.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDisable () {
|
||||||
|
rigidbodyDisplacement = Vector2.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void FindRigidbodyComponent () {
|
||||||
|
rigidBody2D = this.GetComponent<Rigidbody2D>();
|
||||||
|
if (!rigidBody2D)
|
||||||
|
rigidBody = this.GetComponent<Rigidbody>();
|
||||||
|
|
||||||
|
if (!rigidBody2D && !rigidBody) {
|
||||||
|
rigidBody2D = this.GetComponentInParent<Rigidbody2D>();
|
||||||
|
if (!rigidBody2D)
|
||||||
|
rigidBody = this.GetComponentInParent<Rigidbody>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fc23a4f220b20024ab0592719f92587d
|
||||||
|
timeCreated: 1592849332
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -210,6 +210,13 @@ namespace Spine.Unity {
|
|||||||
if (allowMultipleCanvasRenderers) canvasRenderer.Clear();
|
if (allowMultipleCanvasRenderers) canvasRenderer.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnDisable () {
|
||||||
|
base.OnDisable();
|
||||||
|
foreach (var canvasRenderer in canvasRenderers) {
|
||||||
|
canvasRenderer.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Update () {
|
public virtual void Update () {
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) {
|
||||||
@ -426,7 +433,7 @@ namespace Spine.Unity {
|
|||||||
ScaleY = this.initialFlipY ? -1 : 1
|
ScaleY = this.initialFlipY ? -1 : 1
|
||||||
};
|
};
|
||||||
|
|
||||||
meshBuffers = new DoubleBuffered<MeshRendererBuffers.SmartMesh>();
|
InitMeshBuffers();
|
||||||
baseTexture = skeletonDataAsset.atlasAssets[0].PrimaryMaterial.mainTexture;
|
baseTexture = skeletonDataAsset.atlasAssets[0].PrimaryMaterial.mainTexture;
|
||||||
canvasRenderer.SetTexture(this.mainTexture); // Needed for overwriting initializations.
|
canvasRenderer.SetTexture(this.mainTexture); // Needed for overwriting initializations.
|
||||||
|
|
||||||
@ -478,6 +485,16 @@ namespace Spine.Unity {
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
protected void InitMeshBuffers () {
|
||||||
|
if (meshBuffers != null) {
|
||||||
|
meshBuffers.GetNext().Clear();
|
||||||
|
meshBuffers.GetNext().Clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
meshBuffers = new DoubleBuffered<MeshRendererBuffers.SmartMesh>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void UpdateMeshSingleCanvasRenderer () {
|
protected void UpdateMeshSingleCanvasRenderer () {
|
||||||
if (canvasRenderers.Count > 0)
|
if (canvasRenderers.Count > 0)
|
||||||
DisableUnusedCanvasRenderers(usedCount : 0);
|
DisableUnusedCanvasRenderers(usedCount : 0);
|
||||||
|
|||||||
@ -125,10 +125,17 @@ namespace Spine.Unity {
|
|||||||
public class MecanimTranslator {
|
public class MecanimTranslator {
|
||||||
#region Inspector
|
#region Inspector
|
||||||
public bool autoReset = true;
|
public bool autoReset = true;
|
||||||
|
public bool useCustomMixMode = true;
|
||||||
public MixMode[] layerMixModes = new MixMode[0];
|
public MixMode[] layerMixModes = new MixMode[0];
|
||||||
public MixBlend[] layerBlendModes = new MixBlend[0];
|
public MixBlend[] layerBlendModes = new MixBlend[0];
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public delegate void OnClipAppliedDelegate (Spine.Animation clip, int layerIndex, float weight,
|
||||||
|
float time, float lastTime, bool playsBackward);
|
||||||
|
protected event OnClipAppliedDelegate _OnClipApplied;
|
||||||
|
|
||||||
|
public event OnClipAppliedDelegate OnClipApplied { add { _OnClipApplied += value; } remove { _OnClipApplied -= value; } }
|
||||||
|
|
||||||
public enum MixMode { AlwaysMix, MixNext, Hard }
|
public enum MixMode { AlwaysMix, MixNext, Hard }
|
||||||
|
|
||||||
readonly Dictionary<int, Spine.Animation> animationTable = new Dictionary<int, Spine.Animation>(IntEqualityComparer.Instance);
|
readonly Dictionary<int, Spine.Animation> animationTable = new Dictionary<int, Spine.Animation>(IntEqualityComparer.Instance);
|
||||||
@ -157,6 +164,26 @@ namespace Spine.Unity {
|
|||||||
Animator animator;
|
Animator animator;
|
||||||
public Animator Animator { get { return this.animator; } }
|
public Animator Animator { get { return this.animator; } }
|
||||||
|
|
||||||
|
public int MecanimLayerCount {
|
||||||
|
get {
|
||||||
|
if (!animator)
|
||||||
|
return 0;
|
||||||
|
return animator.layerCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] MecanimLayerNames {
|
||||||
|
get {
|
||||||
|
if (!animator)
|
||||||
|
return new string[0];
|
||||||
|
string[] layerNames = new string[animator.layerCount];
|
||||||
|
for (int i = 0; i < animator.layerCount; ++i) {
|
||||||
|
layerNames[i] = animator.GetLayerName(i);
|
||||||
|
}
|
||||||
|
return layerNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialize(Animator animator, SkeletonDataAsset skeletonDataAsset) {
|
public void Initialize(Animator animator, SkeletonDataAsset skeletonDataAsset) {
|
||||||
this.animator = animator;
|
this.animator = animator;
|
||||||
|
|
||||||
@ -171,24 +198,87 @@ namespace Spine.Unity {
|
|||||||
ClearClipInfosForLayers();
|
ClearClipInfosForLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply (Skeleton skeleton) {
|
private bool ApplyAnimation (Skeleton skeleton, AnimatorClipInfo info, AnimatorStateInfo stateInfo,
|
||||||
if (layerMixModes.Length < animator.layerCount) {
|
int layerIndex, float layerWeight, MixBlend layerBlendMode, bool useClipWeight1 = false) {
|
||||||
System.Array.Resize<MixMode>(ref layerMixModes, animator.layerCount);
|
float weight = info.weight * layerWeight;
|
||||||
layerMixModes[animator.layerCount-1] = MixMode.MixNext;
|
if (weight == 0)
|
||||||
}
|
return false;
|
||||||
|
|
||||||
|
var clip = GetAnimation(info.clip);
|
||||||
|
if (clip == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var time = AnimationTime(stateInfo.normalizedTime, info.clip.length,
|
||||||
|
info.clip.isLooping, stateInfo.speed < 0);
|
||||||
|
weight = useClipWeight1 ? layerWeight : weight;
|
||||||
|
clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
|
||||||
|
weight, layerBlendMode, MixDirection.In);
|
||||||
|
if (_OnClipApplied != null)
|
||||||
|
OnClipAppliedCallback(clip, stateInfo, layerIndex, time, info.clip.isLooping, weight);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ApplyInterruptionAnimation (Skeleton skeleton,
|
||||||
|
bool interpolateWeightTo1, AnimatorClipInfo info, AnimatorStateInfo stateInfo,
|
||||||
|
int layerIndex, float layerWeight, MixBlend layerBlendMode, float interruptingClipTimeAddition,
|
||||||
|
bool useClipWeight1 = false) {
|
||||||
|
|
||||||
|
float clipWeight = interpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
|
||||||
|
float weight = clipWeight * layerWeight;
|
||||||
|
if (weight == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var clip = GetAnimation(info.clip);
|
||||||
|
if (clip == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var time = AnimationTime(stateInfo.normalizedTime + interruptingClipTimeAddition,
|
||||||
|
info.clip.length, stateInfo.speed < 0);
|
||||||
|
weight = useClipWeight1 ? layerWeight : weight;
|
||||||
|
clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
|
||||||
|
weight, layerBlendMode, MixDirection.In);
|
||||||
|
if (_OnClipApplied != null) {
|
||||||
|
OnClipAppliedCallback(clip, stateInfo, layerIndex, time, info.clip.isLooping, weight);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClipAppliedCallback (Spine.Animation clip, AnimatorStateInfo stateInfo,
|
||||||
|
int layerIndex, float time, bool isLooping, float weight) {
|
||||||
|
|
||||||
|
float clipDuration = clip.duration == 0 ? 1 : clip.duration;
|
||||||
|
float speedFactor = stateInfo.speedMultiplier * stateInfo.speed;
|
||||||
|
float lastTime = time - (Time.deltaTime * speedFactor);
|
||||||
|
if (isLooping && clip.duration != 0) {
|
||||||
|
time %= clip.duration;
|
||||||
|
lastTime %= clip.duration;
|
||||||
|
}
|
||||||
|
_OnClipApplied(clip, layerIndex, weight, time, lastTime, speedFactor < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply (Skeleton skeleton) {
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) {
|
||||||
GetLayerBlendModes();
|
GetLayerBlendModes();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (layerMixModes.Length < animator.layerCount) {
|
||||||
|
int oldSize = layerMixModes.Length;
|
||||||
|
System.Array.Resize<MixMode>(ref layerMixModes, animator.layerCount);
|
||||||
|
for (int layer = oldSize; layer < animator.layerCount; ++layer) {
|
||||||
|
bool isAdditiveLayer = false;
|
||||||
|
if (layer < layerBlendModes.Length)
|
||||||
|
isAdditiveLayer = layerBlendModes[layer] == MixBlend.Add;
|
||||||
|
layerMixModes[layer] = isAdditiveLayer ? MixMode.MixNext : MixMode.AlwaysMix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InitClipInfosForLayers();
|
InitClipInfosForLayers();
|
||||||
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
|
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
|
||||||
GetStateUpdatesFromAnimator(layer);
|
GetStateUpdatesFromAnimator(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//skeleton.Update(Time.deltaTime); // Doesn't actually do anything, currently. (Spine 3.6).
|
|
||||||
|
|
||||||
// Clear Previous
|
// Clear Previous
|
||||||
if (autoReset) {
|
if (autoReset) {
|
||||||
var previousAnimations = this.previousAnimations;
|
var previousAnimations = this.previousAnimations;
|
||||||
@ -257,56 +347,41 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
int clipInfoCount, nextClipInfoCount, interruptingClipInfoCount;
|
int clipInfoCount, nextClipInfoCount, interruptingClipInfoCount;
|
||||||
IList<AnimatorClipInfo> clipInfo, nextClipInfo, interruptingClipInfo;
|
IList<AnimatorClipInfo> clipInfo, nextClipInfo, interruptingClipInfo;
|
||||||
bool shallInterpolateWeightTo1;
|
bool interpolateWeightTo1;
|
||||||
GetAnimatorClipInfos(layer, out isInterruptionActive, out clipInfoCount, out nextClipInfoCount, out interruptingClipInfoCount,
|
GetAnimatorClipInfos(layer, out isInterruptionActive, out clipInfoCount, out nextClipInfoCount, out interruptingClipInfoCount,
|
||||||
out clipInfo, out nextClipInfo, out interruptingClipInfo, out shallInterpolateWeightTo1);
|
out clipInfo, out nextClipInfo, out interruptingClipInfo, out interpolateWeightTo1);
|
||||||
|
|
||||||
MixMode mode = layerMixModes[layer];
|
|
||||||
MixBlend layerBlendMode = (layer < layerBlendModes.Length) ? layerBlendModes[layer] : MixBlend.Replace;
|
MixBlend layerBlendMode = (layer < layerBlendModes.Length) ? layerBlendModes[layer] : MixBlend.Replace;
|
||||||
|
MixMode mode = GetMixMode(layer, layerBlendMode);
|
||||||
if (mode == MixMode.AlwaysMix) {
|
if (mode == MixMode.AlwaysMix) {
|
||||||
// Always use Mix instead of Applying the first non-zero weighted clip.
|
// Always use Mix instead of Applying the first non-zero weighted clip.
|
||||||
for (int c = 0; c < clipInfoCount; c++) {
|
for (int c = 0; c < clipInfoCount; c++) {
|
||||||
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode);
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
if (hasNext) {
|
if (hasNext) {
|
||||||
for (int c = 0; c < nextClipInfoCount; c++) {
|
for (int c = 0; c < nextClipInfoCount; c++) {
|
||||||
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode);
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isInterruptionActive) {
|
if (isInterruptionActive) {
|
||||||
for (int c = 0; c < interruptingClipInfoCount; c++)
|
for (int c = 0; c < interruptingClipInfoCount; c++)
|
||||||
{
|
{
|
||||||
var info = interruptingClipInfo[c];
|
ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
|
||||||
float clipWeight = shallInterpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
|
interruptingClipInfo[c], interruptingStateInfo,
|
||||||
float weight = clipWeight * layerWeight; if (weight == 0) continue;
|
layer, layerWeight, layerBlendMode, interruptingClipTimeAddition);
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0),
|
|
||||||
info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // case MixNext || Hard
|
} else { // case MixNext || Hard
|
||||||
// Apply first non-zero weighted clip
|
// Apply first non-zero weighted clip
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for (; c < clipInfoCount; c++) {
|
for (; c < clipInfoCount; c++) {
|
||||||
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
if (!ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode, useClipWeight1:true))
|
||||||
var clip = GetAnimation(info.clip);
|
continue;
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
|
|
||||||
++c; break;
|
++c; break;
|
||||||
}
|
}
|
||||||
// Mix the rest
|
// Mix the rest
|
||||||
for (; c < clipInfoCount; c++) {
|
for (; c < clipInfoCount; c++) {
|
||||||
var info = clipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode);
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(stateInfo.normalizedTime, info.clip.length, info.clip.isLooping, stateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c = 0;
|
c = 0;
|
||||||
@ -314,19 +389,15 @@ namespace Spine.Unity {
|
|||||||
// Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
|
// Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
|
||||||
if (mode == MixMode.Hard) {
|
if (mode == MixMode.Hard) {
|
||||||
for (; c < nextClipInfoCount; c++) {
|
for (; c < nextClipInfoCount; c++) {
|
||||||
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
if (!ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode, useClipWeight1:true))
|
||||||
var clip = GetAnimation(info.clip);
|
continue;
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
|
|
||||||
++c; break;
|
++c; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Mix the rest
|
// Mix the rest
|
||||||
for (; c < nextClipInfoCount; c++) {
|
for (; c < nextClipInfoCount; c++) {
|
||||||
var info = nextClipInfo[c]; float weight = info.weight * layerWeight; if (weight == 0) continue;
|
if (!ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode))
|
||||||
var clip = GetAnimation(info.clip);
|
continue;
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(nextStateInfo.normalizedTime, info.clip.length, nextStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,23 +406,19 @@ namespace Spine.Unity {
|
|||||||
// Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
|
// Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
|
||||||
if (mode == MixMode.Hard) {
|
if (mode == MixMode.Hard) {
|
||||||
for (; c < interruptingClipInfoCount; c++) {
|
for (; c < interruptingClipInfoCount; c++) {
|
||||||
var info = interruptingClipInfo[c];
|
if (ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
|
||||||
float clipWeight = shallInterpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
|
interruptingClipInfo[c], interruptingStateInfo,
|
||||||
float weight = clipWeight * layerWeight; if (weight == 0) continue;
|
layer, layerWeight, layerBlendMode, interruptingClipTimeAddition, useClipWeight1:true)) {
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
++c; break;
|
||||||
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), info.clip.isLooping, null, 1f, layerBlendMode, MixDirection.In);
|
}
|
||||||
++c; break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Mix the rest
|
// Mix the rest
|
||||||
for (; c < interruptingClipInfoCount; c++) {
|
for (; c < interruptingClipInfoCount; c++) {
|
||||||
var info = interruptingClipInfo[c];
|
ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
|
||||||
float clipWeight = shallInterpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
|
interruptingClipInfo[c], interruptingStateInfo,
|
||||||
float weight = clipWeight * layerWeight; if (weight == 0) continue;
|
layer, layerWeight, layerBlendMode, interruptingClipTimeAddition);
|
||||||
var clip = GetAnimation(info.clip);
|
|
||||||
if (clip != null)
|
|
||||||
clip.Apply(skeleton, 0, AnimationTime(interruptingStateInfo.normalizedTime + interruptingClipTimeAddition, info.clip.length, interruptingStateInfo.speed < 0), info.clip.isLooping, null, weight, layerBlendMode, MixDirection.In);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,9 +426,7 @@ namespace Spine.Unity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static float AnimationTime (float normalizedTime, float clipLength, bool loop, bool reversed) {
|
static float AnimationTime (float normalizedTime, float clipLength, bool loop, bool reversed) {
|
||||||
if (reversed)
|
float time = AnimationTime(normalizedTime, clipLength, reversed);
|
||||||
normalizedTime = (1 - normalizedTime + (int)normalizedTime) + (int)normalizedTime;
|
|
||||||
float time = normalizedTime * clipLength;
|
|
||||||
if (loop) return time;
|
if (loop) return time;
|
||||||
const float EndSnapEpsilon = 1f / 30f; // Workaround for end-duration keys not being applied.
|
const float EndSnapEpsilon = 1f / 30f; // Workaround for end-duration keys not being applied.
|
||||||
return (clipLength - time < EndSnapEpsilon) ? clipLength : time; // return a time snapped to clipLength;
|
return (clipLength - time < EndSnapEpsilon) ? clipLength : time; // return a time snapped to clipLength;
|
||||||
@ -398,7 +463,24 @@ namespace Spine.Unity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
private MixMode GetMixMode (int layer, MixBlend layerBlendMode) {
|
||||||
|
if (useCustomMixMode) {
|
||||||
|
MixMode mode = layerMixModes[layer];
|
||||||
|
// Note: at additive blending it makes no sense to use constant weight 1 at a fadeout anim add1 as
|
||||||
|
// with override layers, so we use AlwaysMix instead to use the proper weights.
|
||||||
|
// AlwaysMix leads to the expected result = lower_layer + lerp(add1, add2, transition_weight).
|
||||||
|
if (layerBlendMode == MixBlend.Add && mode == MixMode.MixNext) {
|
||||||
|
mode = MixMode.AlwaysMix;
|
||||||
|
layerMixModes[layer] = mode;
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return layerBlendMode == MixBlend.Add ? MixMode.AlwaysMix : MixMode.MixNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
void GetLayerBlendModes() {
|
void GetLayerBlendModes() {
|
||||||
if (layerBlendModes.Length < animator.layerCount) {
|
if (layerBlendModes.Length < animator.layerCount) {
|
||||||
System.Array.Resize<MixBlend>(ref layerBlendModes, animator.layerCount);
|
System.Array.Resize<MixBlend>(ref layerBlendModes, animator.layerCount);
|
||||||
|
|||||||
@ -191,8 +191,10 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
skeletonRenderer.LateUpdate();
|
skeletonRenderer.LateUpdate();
|
||||||
|
|
||||||
foreach (var s in partsRenderers)
|
foreach (var partsRenderer in partsRenderers) {
|
||||||
s.ClearMesh();
|
if (partsRenderer != null)
|
||||||
|
partsRenderer.ClearMesh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialPropertyBlock copiedBlock;
|
MaterialPropertyBlock copiedBlock;
|
||||||
@ -221,6 +223,8 @@ namespace Spine.Unity {
|
|||||||
int rendererIndex = 0;
|
int rendererIndex = 0;
|
||||||
var currentRenderer = partsRenderers[rendererIndex];
|
var currentRenderer = partsRenderers[rendererIndex];
|
||||||
for (int si = 0, start = 0; si <= lastSubmeshInstruction; si++) {
|
for (int si = 0, start = 0; si <= lastSubmeshInstruction; si++) {
|
||||||
|
if (currentRenderer == null)
|
||||||
|
continue;
|
||||||
if (submeshInstructionsItems[si].forceSeparate || si == lastSubmeshInstruction) {
|
if (submeshInstructionsItems[si].forceSeparate || si == lastSubmeshInstruction) {
|
||||||
// Apply properties
|
// Apply properties
|
||||||
var meshGenerator = currentRenderer.MeshGenerator;
|
var meshGenerator = currentRenderer.MeshGenerator;
|
||||||
@ -245,7 +249,9 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
// Clear extra renderers if they exist.
|
// Clear extra renderers if they exist.
|
||||||
for (; rendererIndex < rendererCount; rendererIndex++) {
|
for (; rendererIndex < rendererCount; rendererIndex++) {
|
||||||
partsRenderers[rendererIndex].ClearMesh();
|
currentRenderer = partsRenderers[rendererIndex];
|
||||||
|
if (currentRenderer != null)
|
||||||
|
partsRenderers[rendererIndex].ClearMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -529,7 +529,7 @@ namespace Spine.Unity {
|
|||||||
separatorSlots.Add(slot);
|
separatorSlots.Add(slot);
|
||||||
}
|
}
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
else
|
else if (!string.IsNullOrEmpty(separatorSlotNames[i]))
|
||||||
{
|
{
|
||||||
Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonDataAsset.skeletonJSON.name);
|
Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonDataAsset.skeletonJSON.name);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -503,7 +503,10 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
for (int slotIndex = instruction.startSlot; slotIndex < instruction.endSlot; slotIndex++) {
|
for (int slotIndex = instruction.startSlot; slotIndex < instruction.endSlot; slotIndex++) {
|
||||||
var slot = drawOrderItems[slotIndex];
|
var slot = drawOrderItems[slotIndex];
|
||||||
if (!slot.bone.active) continue;
|
if (!slot.bone.active) {
|
||||||
|
clipper.ClipEnd(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var attachment = slot.attachment;
|
var attachment = slot.attachment;
|
||||||
float z = zSpacing * slotIndex;
|
float z = zSpacing * slotIndex;
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,6 @@ Shader "Spine/Outline/Sprite/Pixel Lit"
|
|||||||
_BumpMap ("Normal Map", 2D) = "bump" {}
|
_BumpMap ("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
@ -8,8 +8,6 @@ Shader "Spine/Outline/Sprite/Unlit"
|
|||||||
_Color ("Color", Color) = (1,1,1,1)
|
_Color ("Color", Color) = (1,1,1,1)
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_ZWrite ("Depth Write", Float) = 0.0
|
_ZWrite ("Depth Write", Float) = 0.0
|
||||||
_Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.0
|
_Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.0
|
||||||
|
|||||||
@ -11,8 +11,6 @@ Shader "Spine/Outline/Sprite/Vertex Lit"
|
|||||||
_BumpMap ("Normal Map", 2D) = "bump" {}
|
_BumpMap ("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
// Upgrade NOTE: upgraded instancing buffer 'PerDrawSprite' to new syntax.
|
// Upgrade NOTE: upgraded instancing buffer 'PerDrawSprite' to new syntax.
|
||||||
|
|
||||||
// Upgrade NOTE: upgraded instancing buffer 'PerDrawSprite' to new syntax.
|
|
||||||
|
|
||||||
#ifndef SHADER_SHARED_INCLUDED
|
#ifndef SHADER_SHARED_INCLUDED
|
||||||
#define SHADER_SHARED_INCLUDED
|
#define SHADER_SHARED_INCLUDED
|
||||||
|
|
||||||
@ -13,28 +11,6 @@
|
|||||||
#include "UnityCG.cginc"
|
#include "UnityCG.cginc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UNITY_INSTANCING_ENABLED
|
|
||||||
|
|
||||||
UNITY_INSTANCING_BUFFER_START(PerDrawSprite)
|
|
||||||
// SpriteRenderer.Color while Non-Batched/Instanced.
|
|
||||||
fixed4 unity_SpriteRendererColorArray[UNITY_INSTANCED_ARRAY_SIZE];
|
|
||||||
// this could be smaller but that's how bit each entry is regardless of type
|
|
||||||
float4 unity_SpriteFlipArray[UNITY_INSTANCED_ARRAY_SIZE];
|
|
||||||
UNITY_INSTANCING_BUFFER_END(PerDrawSprite)
|
|
||||||
|
|
||||||
#define _RendererColor unity_SpriteRendererColorArray[unity_InstanceID]
|
|
||||||
#define _Flip unity_SpriteFlipArray[unity_InstanceID]
|
|
||||||
|
|
||||||
#endif // instancing
|
|
||||||
|
|
||||||
CBUFFER_START(UnityPerDrawSprite)
|
|
||||||
#ifndef UNITY_INSTANCING_ENABLED
|
|
||||||
fixed4 _RendererColor;
|
|
||||||
float4 _Flip;
|
|
||||||
#endif
|
|
||||||
float _EnableExternalAlpha;
|
|
||||||
CBUFFER_END
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// Space functions
|
// Space functions
|
||||||
//
|
//
|
||||||
@ -376,11 +352,6 @@ inline fixed4 applyFog(fixed4 pixel, float fogCoordOrFactorAtLWRP)
|
|||||||
|
|
||||||
uniform sampler2D _MainTex;
|
uniform sampler2D _MainTex;
|
||||||
|
|
||||||
#if ETC1_EXTERNAL_ALPHA
|
|
||||||
//External alpha texture for ETC1 compression
|
|
||||||
uniform sampler2D _AlphaTex;
|
|
||||||
#endif //ETC1_EXTERNAL_ALPHA
|
|
||||||
|
|
||||||
#if _TEXTURE_BLEND
|
#if _TEXTURE_BLEND
|
||||||
uniform sampler2D _BlendTex;
|
uniform sampler2D _BlendTex;
|
||||||
uniform float _BlendAmount;
|
uniform float _BlendAmount;
|
||||||
@ -401,11 +372,6 @@ inline fixed4 calculateTexturePixel(float2 texcoord)
|
|||||||
pixel = tex2D(_MainTex, texcoord);
|
pixel = tex2D(_MainTex, texcoord);
|
||||||
#endif // !_TEXTURE_BLEND
|
#endif // !_TEXTURE_BLEND
|
||||||
|
|
||||||
#if ETC1_EXTERNAL_ALPHA
|
|
||||||
fixed4 alpha = tex2D (_AlphaTex, texcoord);
|
|
||||||
pixel.a = lerp (pixel.a, alpha.r, _EnableExternalAlpha);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_COLOR_ADJUST)
|
#if defined(_COLOR_ADJUST)
|
||||||
pixel = adjustColor(pixel);
|
pixel = adjustColor(pixel);
|
||||||
#endif // _COLOR_ADJUST
|
#endif // _COLOR_ADJUST
|
||||||
|
|||||||
@ -9,8 +9,6 @@ Shader "Spine/Sprite/Pixel Lit"
|
|||||||
_BumpMap ("Normal Map", 2D) = "bump" {}
|
_BumpMap ("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
@ -6,8 +6,6 @@ Shader "Spine/Sprite/Unlit"
|
|||||||
_Color ("Color", Color) = (1,1,1,1)
|
_Color ("Color", Color) = (1,1,1,1)
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_ZWrite ("Depth Write", Float) = 0.0
|
_ZWrite ("Depth Write", Float) = 0.0
|
||||||
_Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.0
|
_Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.0
|
||||||
|
|||||||
@ -9,8 +9,6 @@ Shader "Spine/Sprite/Vertex Lit"
|
|||||||
_BumpMap ("Normal Map", 2D) = "bump" {}
|
_BumpMap ("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
@ -27,10 +27,16 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
#define CONFIGURABLE_ENTER_PLAY_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
|
||||||
namespace Spine.Unity.AttachmentTools {
|
namespace Spine.Unity.AttachmentTools {
|
||||||
|
|
||||||
public static class AtlasUtilities {
|
public static class AtlasUtilities {
|
||||||
@ -41,6 +47,14 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
|
|
||||||
const int NonrenderingRegion = -1;
|
const int NonrenderingRegion = -1;
|
||||||
|
|
||||||
|
#if CONFIGURABLE_ENTER_PLAY_MODE
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
static void Init () {
|
||||||
|
// handle disabled domain reload
|
||||||
|
AtlasUtilities.ClearCache();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) {
|
public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) {
|
||||||
return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource);
|
return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -442,7 +442,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SkeletonExtensions {
|
public static class SpineSkeletonExtensions {
|
||||||
public static bool IsWeighted (this VertexAttachment va) {
|
public static bool IsWeighted (this VertexAttachment va) {
|
||||||
return va.bones != null && va.bones.Length > 0;
|
return va.bones != null && va.bones.Length > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,91 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace Spine.Unity.AnimationTools {
|
||||||
|
public static class TimelineExtensions {
|
||||||
|
|
||||||
|
/// <summary>Evaluates the resulting value of a TranslateTimeline at a given time.
|
||||||
|
/// SkeletonData can be accessed from Skeleton.Data or from SkeletonDataAsset.GetSkeletonData.
|
||||||
|
/// If no SkeletonData is given, values are computed relative to setup pose instead of local-absolute.</summary>
|
||||||
|
public static Vector2 Evaluate (this TranslateTimeline timeline, float time, SkeletonData skeletonData = null) {
|
||||||
|
const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1;
|
||||||
|
const int X = 1, Y = 2;
|
||||||
|
|
||||||
|
var frames = timeline.frames;
|
||||||
|
if (time < frames[0]) return Vector2.zero;
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
if (time >= frames[frames.Length - TranslateTimeline.ENTRIES]) { // Time is after last frame.
|
||||||
|
x = frames[frames.Length + PREV_X];
|
||||||
|
y = frames[frames.Length + PREV_Y];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Interpolate between the previous frame and the current frame.
|
||||||
|
int frame = Animation.BinarySearch(frames, time, TranslateTimeline.ENTRIES);
|
||||||
|
x = frames[frame + PREV_X];
|
||||||
|
y = frames[frame + PREV_Y];
|
||||||
|
float frameTime = frames[frame];
|
||||||
|
float percent = timeline.GetCurvePercent(frame / TranslateTimeline.ENTRIES - 1,
|
||||||
|
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||||
|
|
||||||
|
x += (frames[frame + X] - x) * percent;
|
||||||
|
y += (frames[frame + Y] - y) * percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 xy = new Vector2(x, y);
|
||||||
|
if (skeletonData == null) {
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var boneData = skeletonData.bones.Items[timeline.boneIndex];
|
||||||
|
return xy + new Vector2(boneData.x, boneData.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the translate timeline for a given boneIndex.
|
||||||
|
/// You can get the boneIndex using SkeletonData.FindBoneIndex.
|
||||||
|
/// The root bone is always boneIndex 0.
|
||||||
|
/// This will return null if a TranslateTimeline is not found.</summary>
|
||||||
|
public static TranslateTimeline FindTranslateTimelineForBone (this Animation a, int boneIndex) {
|
||||||
|
foreach (var timeline in a.timelines) {
|
||||||
|
if (timeline.GetType().IsSubclassOf(typeof(TranslateTimeline)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var translateTimeline = timeline as TranslateTimeline;
|
||||||
|
if (translateTimeline != null && translateTimeline.boneIndex == boneIndex)
|
||||||
|
return translateTimeline;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 07807fefbff25484ba41b1d16911fb0e
|
||||||
|
timeCreated: 1591974498
|
||||||
|
licenseType: Pro
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -9,8 +9,6 @@ Shader "Lightweight Render Pipeline/Spine/Sprite"
|
|||||||
_BumpMap("Normal Map", 2D) = "bump" {}
|
_BumpMap("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
@ -119,6 +119,7 @@
|
|||||||
Tags { "LightMode" = "NormalsRendering"}
|
Tags { "LightMode" = "NormalsRendering"}
|
||||||
|
|
||||||
Blend SrcAlpha OneMinusSrcAlpha
|
Blend SrcAlpha OneMinusSrcAlpha
|
||||||
|
ZWrite Off
|
||||||
|
|
||||||
HLSLPROGRAM
|
HLSLPROGRAM
|
||||||
#pragma prefer_hlslcc gles
|
#pragma prefer_hlslcc gles
|
||||||
|
|||||||
@ -10,8 +10,6 @@ Shader "Universal Render Pipeline/2D/Spine/Sprite"
|
|||||||
_BumpMap("Normal Map", 2D) = "bump" {}
|
_BumpMap("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
@ -116,6 +114,7 @@ Shader "Universal Render Pipeline/2D/Spine/Sprite"
|
|||||||
|
|
||||||
Blend SrcAlpha OneMinusSrcAlpha
|
Blend SrcAlpha OneMinusSrcAlpha
|
||||||
Cull[_Cull]
|
Cull[_Cull]
|
||||||
|
ZWrite[_ZWrite]
|
||||||
|
|
||||||
HLSLPROGRAM
|
HLSLPROGRAM
|
||||||
#pragma prefer_hlslcc gles
|
#pragma prefer_hlslcc gles
|
||||||
|
|||||||
@ -9,8 +9,6 @@ Shader "Universal Render Pipeline/Spine/Sprite"
|
|||||||
_BumpMap("Normal Map", 2D) = "bump" {}
|
_BumpMap("Normal Map", 2D) = "bump" {}
|
||||||
|
|
||||||
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
|
||||||
[PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
|
|
||||||
[PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
|
|
||||||
|
|
||||||
_EmissionColor("Color", Color) = (0,0,0,0)
|
_EmissionColor("Color", Color) = (0,0,0,0)
|
||||||
_EmissionMap("Emission", 2D) = "white" {}
|
_EmissionMap("Emission", 2D) = "white" {}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user