Merge branch '3.8' into 4.0-beta

This commit is contained in:
badlogic 2020-10-23 11:26:34 +02:00
commit ee3f088e6c
102 changed files with 14725 additions and 423 deletions

View File

@ -365,6 +365,14 @@
* Added **SkeletonGraphic Timeline support**. Added supprot for multi-track Timeline preview in the Editor outside of play mode (multi-track scrubbing). See the [Timeline-Extension-UPM-Package](http://esotericsoftware.com/spine-unity#Timeline-Extension-UPM-Package) section of the spine-unity documentation for more information. * Added **SkeletonGraphic Timeline support**. Added supprot for multi-track Timeline preview in the Editor outside of play mode (multi-track scrubbing). See the [Timeline-Extension-UPM-Package](http://esotericsoftware.com/spine-unity#Timeline-Extension-UPM-Package) section of the spine-unity documentation for more information.
* Added support for double-sided lighting at all `SkeletonLit` shaders (including URP and LWRP packages). * Added support for double-sided lighting at all `SkeletonLit` shaders (including URP and LWRP packages).
* Added frustum culling update mode parameters `Update When Invisible` (Inspector parameter) and `UpdateMode` (available via code) to all Skeleton components. This provides a simple way to disable certain updates when the `Renderer` is no longer visible (outside all cameras, culled in frustum culling). The new `UpdateMode` property allows disabling updates at a finer granularity level than disabling the whole component. Available modes are: `Nothing`, `OnlyAnimationStatus`, `EverythingExceptMesh` and `FullUpdate`. * Added frustum culling update mode parameters `Update When Invisible` (Inspector parameter) and `UpdateMode` (available via code) to all Skeleton components. This provides a simple way to disable certain updates when the `Renderer` is no longer visible (outside all cameras, culled in frustum culling). The new `UpdateMode` property allows disabling updates at a finer granularity level than disabling the whole component. Available modes are: `Nothing`, `OnlyAnimationStatus`, `EverythingExceptMesh` and `FullUpdate`.
* Added a new `Spine/Outline/OutlineOnly-ZWrite` shader to provide correct outline-only rendering. Note: the shader requires two render passes and is therefore not compatible with URP. The `Spine Examples/Other Examples/Outline Shaders` example scene has been updated to demonstrate the new shader.
* Added `OnMeshAndMaterialsUpdated` callback event to `SkeletonRenderSeparator` and `SkeletonPartsRenderer`. It is issued at the end of `LateUpdate`, before rendering.
* Added `Root Motion Scale X/Y` parameters to `SkeletonRootMotionBase` subclasses (`SkeletonRootMotion` and `SkeletonMecanimRootMotion`). Also providing `AdjustRootMotionToDistance()` and other methods to allow for easy delta compensation. Delta compensation can be used to e.g. stretch a jump to a given distance. Root motion can be adjusted at the start of an animation or every frame via `skeletonRootMotion.AdjustRootMotionToDistance(targetPosition - transform.position, trackIndex);`.
* Now providing a `Canvas Group Tint Black` parameter at the `SkeletonGraphic` Inspector in the `Advanced` section. When using the `Spine/SkeletonGraphic Tint Black` shader you can enable this parameter to receive proper blending results when using `Additive` blend mode under a `CanvasGroup`. Be sure to also have the parameter `CanvasGroup Compatible` enabled at the shader. Note that the normal `Spine/SkeletonGraphic` does not support `Additive` blend mode at a `CanvasGroup`, as it requires additional shader channels to work.
* Added `Mix and Match Skins` example scene to demonstrate how the 3.8 Skin API and combining skins can be used for a wardrobe and equipment use case.
* Spine Timeline Extensions: Added `Hold Previous` parameter at `SpineAnimationStateClip`.
* Added more warning messages at incompatible SkeletonRenderer/SkeletonGraphic Component vs Material settings. They appear both as an info box in the Inspector as well as upon initialization in the Console log window. The Inspector box warnings can be disabled via `Edit - Preferences - Spine`.
* Now providing `BeforeApply` update callbacks at all skeleton animation components (`SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`).
* **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`.

View File

@ -433,7 +433,7 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
#if COCOS2D_VERSION < 0x00040000 #if COCOS2D_VERSION < 0x00040000
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
#else #else
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, triangles, transform, transformFlags);
#endif #endif
const float* verts = _clipper->getClippedVertices().buffer(); const float* verts = _clipper->getClippedVertices().buffer();
@ -465,7 +465,7 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
#if COCOS2D_VERSION < 0x00040000 #if COCOS2D_VERSION < 0x00040000
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags); cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
#else #else
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags); cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, triangles, transform, transformFlags);
#endif #endif
if (_effect) { if (_effect) {
@ -504,7 +504,7 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
#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
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags);
#endif #endif
const float* verts = _clipper->getClippedVertices().buffer(); const float* verts = _clipper->getClippedVertices().buffer();
@ -539,7 +539,7 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
#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
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags); TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _programState, blendFunc, trianglesTwoColor, transform, transformFlags);
#endif #endif
if (_effect) { if (_effect) {

View File

@ -60,22 +60,8 @@ void SkeletonBatch::destroyInstance () {
SkeletonBatch::SkeletonBatch () { SkeletonBatch::SkeletonBatch () {
auto program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR); auto program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR);
_programState = std::make_shared<backend::ProgramState>(program); _programState = new backend::ProgramState(program); // new default program state
updateProgramStateLayout(_programState);
auto vertexLayout = _programState->getVertexLayout();
auto locPosition = _programState->getAttributeLocation("a_position");
auto locTexcoord = _programState->getAttributeLocation("a_texCoord");
auto locColor = _programState->getAttributeLocation("a_color");
vertexLayout->setAttribute("a_position", locPosition, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false);
vertexLayout->setAttribute("a_color", locColor, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
vertexLayout->setAttribute("a_texCoord", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false);
vertexLayout->setLayout(sizeof(_vertices[0]));
_locMVP = _programState->getUniformLocation("u_MVPMatrix");
_locTexture = _programState->getUniformLocation("u_texture");
for (unsigned int i = 0; i < INITIAL_SIZE; i++) { for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(createNewTrianglesCommand()); _commandsPool.push_back(createNewTrianglesCommand());
} }
@ -95,6 +81,25 @@ SkeletonBatch::~SkeletonBatch () {
delete _commandsPool[i]; delete _commandsPool[i];
_commandsPool[i] = nullptr; _commandsPool[i] = nullptr;
} }
CC_SAFE_RELEASE(_programState);
}
void SkeletonBatch::updateProgramStateLayout(cocos2d::backend::ProgramState* programState)
{
auto vertexLayout = programState->getVertexLayout();
auto locPosition = programState->getAttributeLocation("a_position");
auto locTexcoord = programState->getAttributeLocation("a_texCoord");
auto locColor = programState->getAttributeLocation("a_color");
vertexLayout->setAttribute("a_position", locPosition, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false);
vertexLayout->setAttribute("a_color", locColor, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
vertexLayout->setAttribute("a_texCoord", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false);
vertexLayout->setLayout(sizeof(_vertices[0]));
_locMVP = programState->getUniformLocation("u_MVPMatrix");
_locTexture = programState->getUniformLocation("u_texture");
} }
void SkeletonBatch::update (float delta) { void SkeletonBatch::update (float delta) {
@ -148,15 +153,27 @@ void SkeletonBatch::deallocateIndices(uint32_t numIndices) {
} }
cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, backend::ProgramState* programState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
TrianglesCommand* command = nextFreeCommand(); TrianglesCommand* command = nextFreeCommand();
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto programState = command->getPipelineDescriptor().programState; if (programState == nullptr)
CCASSERT(programState, "programState should not be null"); programState = _programState;
programState->setUniform(_locMVP, projectionMat.m, sizeof(projectionMat.m)); CCASSERT(programState, "programState should not be null");
programState->setTexture(_locTexture, 0, texture->getBackendTexture());
auto& pipelinePS = command->getPipelineDescriptor().programState;
if (pipelinePS != programState)
{
CC_SAFE_RELEASE(pipelinePS);
pipelinePS = programState;
CC_SAFE_RETAIN(pipelinePS);
updateProgramStateLayout(pipelinePS);
}
pipelinePS->setUniform(_locMVP, projectionMat.m, sizeof(projectionMat.m));
pipelinePS->setTexture(_locTexture, 0, texture->getBackendTexture());
command->init(globalOrder, texture, blendType, triangles, mv, flags); command->init(globalOrder, texture, blendType, triangles, mv, flags);
renderer->addCommand(command); renderer->addCommand(command);
@ -177,12 +194,6 @@ cocos2d::TrianglesCommand* SkeletonBatch::nextFreeCommand() {
} }
} }
auto* command = _commandsPool[_nextFreeCommand++]; auto* command = _commandsPool[_nextFreeCommand++];
auto& pipelineDescriptor = command->getPipelineDescriptor();
if (pipelineDescriptor.programState == nullptr)
{
CCASSERT(_programState, "programState should not be null");
pipelineDescriptor.programState = _programState->clone();
}
return command; return command;
} }

View File

@ -35,6 +35,7 @@
#include <spine/spine.h> #include <spine/spine.h>
#include <vector> #include <vector>
#include "renderer/backend/ProgramState.h"
namespace spine { namespace spine {
@ -50,8 +51,10 @@ namespace spine {
void deallocateVertices(uint32_t numVertices); void deallocateVertices(uint32_t numVertices);
unsigned short* allocateIndices(uint32_t numIndices); unsigned short* allocateIndices(uint32_t numIndices);
void deallocateIndices(uint32_t numVertices); void deallocateIndices(uint32_t numVertices);
cocos2d::TrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); cocos2d::TrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
void updateProgramStateLayout(cocos2d::backend::ProgramState* programState);
protected: protected:
SkeletonBatch (); SkeletonBatch ();
virtual ~SkeletonBatch (); virtual ~SkeletonBatch ();
@ -61,7 +64,9 @@ namespace spine {
cocos2d::TrianglesCommand* nextFreeCommand (); cocos2d::TrianglesCommand* nextFreeCommand ();
cocos2d::TrianglesCommand* createNewTrianglesCommand(); cocos2d::TrianglesCommand* createNewTrianglesCommand();
std::shared_ptr<cocos2d::backend::ProgramState> _programState = nullptr;
// the default program state for batch draw
cocos2d::backend::ProgramState* _programState = nullptr;
cocos2d::backend::UniformLocation _locMVP; cocos2d::backend::UniformLocation _locMVP;
cocos2d::backend::UniformLocation _locTexture; cocos2d::backend::UniformLocation _locTexture;

View File

@ -99,16 +99,7 @@ namespace {
backend::UniformLocation __locPMatrix; backend::UniformLocation __locPMatrix;
backend::UniformLocation __locTexture; backend::UniformLocation __locTexture;
void initTwoColorProgramState() static void updateProgramStateLayout(backend::ProgramState* programState) {
{
if (__twoColorProgramState)
{
return;
}
auto program = backend::Device::getInstance()->newProgram(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
auto* programState = new backend::ProgramState(program);
program->autorelease();
__locPMatrix = programState->getUniformLocation("u_PMatrix"); __locPMatrix = programState->getUniformLocation("u_PMatrix");
__locTexture = programState->getUniformLocation("u_texture"); __locTexture = programState->getUniformLocation("u_texture");
@ -124,6 +115,19 @@ namespace {
layout->setAttribute("a_color2", locColor2, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color2), true); layout->setAttribute("a_color2", locColor2, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color2), true);
layout->setAttribute("a_texCoords", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false); layout->setAttribute("a_texCoords", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false);
layout->setLayout(sizeof(spine::V3F_C4B_C4B_T2F)); layout->setLayout(sizeof(spine::V3F_C4B_C4B_T2F));
}
static void initTwoColorProgramState()
{
if (__twoColorProgramState)
{
return;
}
auto program = backend::Device::getInstance()->newProgram(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
auto* programState = new backend::ProgramState(program);
program->release();
updateProgramStateLayout(programState);
__twoColorProgramState = std::shared_ptr<backend::ProgramState>(programState); __twoColorProgramState = std::shared_ptr<backend::ProgramState>(programState);
} }
@ -136,9 +140,9 @@ TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _texture(n
_type = RenderCommand::Type::CUSTOM_COMMAND; _type = RenderCommand::Type::CUSTOM_COMMAND;
} }
void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *texture, BlendFunc blendType, const TwoColorTriangles& triangles, const Mat4& mv, uint32_t flags) { void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *texture, cocos2d::backend::ProgramState* programState, BlendFunc blendType, const TwoColorTriangles& triangles, const Mat4& mv, uint32_t flags) {
updateCommandPipelineDescriptor(); updateCommandPipelineDescriptor(programState);
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto finalMatrix = projectionMat * mv; auto finalMatrix = projectionMat * mv;
@ -177,18 +181,39 @@ void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *textu
void TwoColorTrianglesCommand::updateCommandPipelineDescriptor() void TwoColorTrianglesCommand::updateCommandPipelineDescriptor(cocos2d::backend::ProgramState* programState)
{ {
// OPTIMIZE ME: all commands belong a same Node should share a same programState like SkeletonBatch
if (!__twoColorProgramState) if (!__twoColorProgramState)
{ {
initTwoColorProgramState(); initTwoColorProgramState();
} }
CC_SAFE_RELEASE_NULL(_programState); bool needsUpdateStateLayout = false;
_programState = __twoColorProgramState->clone(); auto& pipelinePS = _pipelineDescriptor.programState;
if (programState != nullptr)
{
if (_programState != programState) {
CC_SAFE_RELEASE(_programState);
_programState = programState; // Because the programState belong to Node, so no need to clone
CC_SAFE_RETAIN(_programState);
needsUpdateStateLayout = true;
}
}
else {
needsUpdateStateLayout = _programState != nullptr && _programState->getProgram() != __twoColorProgramState->getProgram();
CC_SAFE_RELEASE(_programState);
_programState = __twoColorProgramState->clone();
}
CCASSERT(_programState, "programState should not be null");
pipelinePS = _programState;
if (needsUpdateStateLayout)
updateProgramStateLayout(pipelinePS);
_locPMatrix = __locPMatrix; _locPMatrix = __locPMatrix;
_locTexture = __locTexture; _locTexture = __locTexture;
_pipelineDescriptor.programState = _programState;
} }
TwoColorTrianglesCommand::~TwoColorTrianglesCommand() TwoColorTrianglesCommand::~TwoColorTrianglesCommand()
@ -330,9 +355,9 @@ void SkeletonTwoColorBatch::deallocateIndices(uint32_t numIndices) {
_indices.setSize(_indices.size() - numIndices, 0); _indices.setSize(_indices.size() - numIndices, 0);
} }
TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) { TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
TwoColorTrianglesCommand* command = nextFreeCommand(); TwoColorTrianglesCommand* command = nextFreeCommand();
command->init(globalOrder, texture, blendType, triangles, mv, flags); command->init(globalOrder, texture, programState, blendType, triangles, mv, flags);
command->updateVertexAndIndexBuffer(renderer, triangles.verts, triangles.vertCount, triangles.indices, triangles.indexCount); command->updateVertexAndIndexBuffer(renderer, triangles.verts, triangles.vertCount, triangles.indices, triangles.indexCount);
renderer->addCommand(command); renderer->addCommand(command);
return command; return command;

View File

@ -35,6 +35,7 @@
#include <spine/spine.h> #include <spine/spine.h>
#include <vector> #include <vector>
#include "renderer/backend/ProgramState.h"
namespace spine { namespace spine {
struct V3F_C4B_C4B_T2F { struct V3F_C4B_C4B_T2F {
@ -57,9 +58,9 @@ namespace spine {
~TwoColorTrianglesCommand(); ~TwoColorTrianglesCommand();
void init(float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); void init(float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
void updateCommandPipelineDescriptor(); void updateCommandPipelineDescriptor(cocos2d::backend::ProgramState* programState);
inline cocos2d::backend::TextureBackend* getTexture() const { return _texture; } inline cocos2d::backend::TextureBackend* getTexture() const { return _texture; }
@ -118,7 +119,7 @@ namespace spine {
unsigned short* allocateIndices(uint32_t numIndices); unsigned short* allocateIndices(uint32_t numIndices);
void deallocateIndices(uint32_t numIndices); void deallocateIndices(uint32_t numIndices);
TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::backend::ProgramState* programState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
void batch(cocos2d::Renderer* renderer, TwoColorTrianglesCommand* command); void batch(cocos2d::Renderer* renderer, TwoColorTrianglesCommand* command);

View File

@ -48,27 +48,27 @@ public:
/// The name of the event, which is unique within the skeleton. /// The name of the event, which is unique within the skeleton.
const String &getName() const; const String &getName() const;
int getIntValue(); int getIntValue() const;
void setIntValue(int inValue); void setIntValue(int inValue);
float getFloatValue(); float getFloatValue() const;
void setFloatValue(float inValue); void setFloatValue(float inValue);
const String &getStringValue(); const String &getStringValue() const;
void setStringValue(const String &inValue); void setStringValue(const String &inValue);
const String &getAudioPath(); const String &getAudioPath() const;
void setAudioPath(const String &inValue); void setAudioPath(const String &inValue);
float getVolume(); float getVolume() const;
void setVolume(float inValue); void setVolume(float inValue);
float getBalance(); float getBalance() const;
void setBalance(float inValue); void setBalance(float inValue);

View File

@ -51,7 +51,7 @@ const spine::String &spine::EventData::getName() const {
return _name; return _name;
} }
int spine::EventData::getIntValue() { int spine::EventData::getIntValue() const {
return _intValue; return _intValue;
} }
@ -59,7 +59,7 @@ void spine::EventData::setIntValue(int inValue) {
_intValue = inValue; _intValue = inValue;
} }
float spine::EventData::getFloatValue() { float spine::EventData::getFloatValue() const {
return _floatValue; return _floatValue;
} }
@ -67,7 +67,7 @@ void spine::EventData::setFloatValue(float inValue) {
_floatValue = inValue; _floatValue = inValue;
} }
const spine::String &spine::EventData::getStringValue() { const spine::String &spine::EventData::getStringValue() const {
return _stringValue; return _stringValue;
} }
@ -75,7 +75,7 @@ void spine::EventData::setStringValue(const spine::String &inValue) {
this->_stringValue = inValue; this->_stringValue = inValue;
} }
const spine::String &spine::EventData::getAudioPath() { const spine::String &spine::EventData::getAudioPath() const {
return _audioPath; return _audioPath;
} }
@ -84,7 +84,7 @@ void spine::EventData::setAudioPath(const spine::String &inValue) {
} }
float spine::EventData::getVolume() { float spine::EventData::getVolume() const {
return _volume; return _volume;
} }
@ -92,7 +92,7 @@ void spine::EventData::setVolume(float inValue) {
_volume = inValue; _volume = inValue;
} }
float spine::EventData::getBalance() { float spine::EventData::getBalance() const {
return _balance; return _balance;
} }

View File

@ -983,6 +983,14 @@ function AnimationState:getCurrent (trackIndex)
return self.tracks[trackIndex] return self.tracks[trackIndex]
end end
function AnimationState:getLast (trackIndex)
local lastEntry = self.tracks[trackIndex]
while lastEntry.next do
lastEntry = lastEntry.next
end
return lastEntry
end
function AnimationState:clearListeners () function AnimationState:clearListeners ()
self.onStart = nil self.onStart = nil
self.onInterrupt = nil self.onInterrupt = nil

View File

@ -610,8 +610,9 @@ void test (SkeletonData* skeletonData, Atlas* atlas) {
} }
} }
DebugExtension dbgExtension(SpineExtension::getInstance());
int main () { int main () {
DebugExtension dbgExtension(SpineExtension::getInstance());
SpineExtension::setInstance(&dbgExtension); SpineExtension::setInstance(&dbgExtension);
testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f); testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;
@ -1400,7 +1400,7 @@ declare module spine.webgl {
private boundUnit; private boundUnit;
private useMipMaps; private useMipMaps;
static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean; static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement, useMipMaps?: boolean); constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps?: boolean);
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear; static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
@ -1786,7 +1786,7 @@ declare module spine.webgl {
canvas: HTMLCanvasElement | OffscreenCanvas; canvas: HTMLCanvasElement | OffscreenCanvas;
gl: WebGLRenderingContext; gl: WebGLRenderingContext;
private restorables; private restorables;
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, contextConfig?: any); constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
addRestorable(restorable: Restorable): void; addRestorable(restorable: Restorable): void;
removeRestorable(restorable: Restorable): void; removeRestorable(restorable: Restorable): void;
} }

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }
@ -11000,7 +11032,7 @@ var spine;
var _this = this; var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; } if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array(); this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) { if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas_1 = canvasOrContext; var canvas_1 = canvasOrContext;
this.gl = (canvas_1.getContext("webgl2", contextConfig) || canvas_1.getContext("webgl", contextConfig)); this.gl = (canvas_1.getContext("webgl2", contextConfig) || canvas_1.getContext("webgl", contextConfig));
this.canvas = canvas_1; this.canvas = canvas_1;

File diff suppressed because one or more lines are too long

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;
@ -1369,7 +1369,7 @@ declare module spine.webgl {
private boundUnit; private boundUnit;
private useMipMaps; private useMipMaps;
static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean; static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement, useMipMaps?: boolean); constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps?: boolean);
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear; static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
@ -1755,7 +1755,7 @@ declare module spine.webgl {
canvas: HTMLCanvasElement | OffscreenCanvas; canvas: HTMLCanvasElement | OffscreenCanvas;
gl: WebGLRenderingContext; gl: WebGLRenderingContext;
private restorables; private restorables;
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, contextConfig?: any); constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
addRestorable(restorable: Restorable): void; addRestorable(restorable: Restorable): void;
removeRestorable(restorable: Restorable): void; removeRestorable(restorable: Restorable): void;
} }

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }
@ -10732,7 +10764,7 @@ var spine;
var _this = this; var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; } if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array(); this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) { if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas = canvasOrContext; var canvas = canvasOrContext;
this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig)); this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
this.canvas = canvas; this.canvas = canvas;

File diff suppressed because one or more lines are too long

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -636,7 +636,7 @@ declare module spine {
private queueAsset; private queueAsset;
loadText(clientId: string, path: string): void; loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void; loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void; loadTexture(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): void;
get(clientId: string, path: string): any; get(clientId: string, path: string): any;
private updateClientAssets; private updateClientAssets;
isLoadingComplete(clientId: string): boolean; isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
} }
declare module spine { declare module spine {
abstract class Texture { abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement); constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement; getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void; abstract dispose(): void;
@ -1369,7 +1369,7 @@ declare module spine.webgl {
private boundUnit; private boundUnit;
private useMipMaps; private useMipMaps;
static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean; static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement, useMipMaps?: boolean); constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps?: boolean);
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void; setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear; static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void; setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
@ -1755,7 +1755,7 @@ declare module spine.webgl {
canvas: HTMLCanvasElement | OffscreenCanvas; canvas: HTMLCanvasElement | OffscreenCanvas;
gl: WebGLRenderingContext; gl: WebGLRenderingContext;
private restorables; private restorables;
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, contextConfig?: any); constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
addRestorable(restorable: Restorable): void; addRestorable(restorable: Restorable): void;
removeRestorable(restorable: Restorable): void; removeRestorable(restorable: Restorable): void;
} }

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) { var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf || extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b); return extendStatics(d, b);
}; };
return function (d, b) { return function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) if (!this.queueAsset(clientId, textureLoader, path))
return; return;
var img = new Image(); var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = function (ev) { if (isWebWorker) {
_this.rawAssets[path] = img; var options = { mode: "cors" };
}; fetch(path, options).then(function (response) {
img.onerror = function (ev) { if (!response.ok) {
_this.errors[path] = "Couldn't load image " + path; _this.errors[path] = "Couldn't load image " + path;
}; }
img.src = path; return response.blob();
}).then(function (blob) {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
});
}).then(function (bitmap) {
_this.rawAssets[path] = bitmap;
});
}
else {
var img_1 = new Image();
img_1.crossOrigin = "anonymous";
img_1.onload = function (ev) {
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img_1.src = path;
}
}; };
SharedAssetManager.prototype.get = function (clientId, path) { SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path]; return clientAssets.assets[path];
}; };
SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { SharedAssetManager.prototype.updateClientAssets = function (clientAssets) {
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (var i = 0; i < clientAssets.toLoad.length; i++) { for (var i = 0; i < clientAssets.toLoad.length; i++) {
var path = clientAssets.toLoad[i]; var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path]; var asset = clientAssets.assets[path];
@ -3597,11 +3619,21 @@ var spine;
var rawAsset = this.rawAssets[path]; var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) if (rawAsset === null || rawAsset === undefined)
continue; continue;
if (rawAsset instanceof HTMLImageElement) { if (isWebWorker) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
else { else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }
@ -10732,7 +10764,7 @@ var spine;
var _this = this; var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; } if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array(); this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) { if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas = canvasOrContext; var canvas = canvasOrContext;
this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig)); this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
this.canvas = canvas; this.canvas = canvas;

File diff suppressed because one or more lines are too long

View File

@ -66,7 +66,7 @@ module spine.canvas {
if (attachment instanceof RegionAttachment) { if (attachment instanceof RegionAttachment) {
regionAttachment = <RegionAttachment>attachment; regionAttachment = <RegionAttachment>attachment;
region = <TextureAtlasRegion>regionAttachment.region; region = <TextureAtlasRegion>regionAttachment.region;
image = (<CanvasTexture>region.texture).getImage(); image = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else continue; } else continue;
let skeleton = slot.bone.skeleton; let skeleton = slot.bone.skeleton;
@ -131,13 +131,13 @@ module spine.canvas {
vertices = this.computeRegionVertices(slot, regionAttachment, false); vertices = this.computeRegionVertices(slot, regionAttachment, false);
triangles = SkeletonRenderer.QUAD_TRIANGLES; triangles = SkeletonRenderer.QUAD_TRIANGLES;
region = <TextureAtlasRegion>regionAttachment.region; region = <TextureAtlasRegion>regionAttachment.region;
texture = (<CanvasTexture>region.texture).getImage(); texture = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else if (attachment instanceof MeshAttachment) { } else if (attachment instanceof MeshAttachment) {
let mesh = <MeshAttachment>attachment; let mesh = <MeshAttachment>attachment;
vertices = this.computeMeshVertices(slot, mesh, false); vertices = this.computeMeshVertices(slot, mesh, false);
triangles = mesh.triangles; triangles = mesh.triangles;
texture = (<TextureAtlasRegion>mesh.region.renderObject).texture.getImage(); texture = (<TextureAtlasRegion>mesh.region.renderObject).texture.getImage() as HTMLImageElement;
} else continue; } else continue;
if (texture != null) { if (texture != null) {

View File

@ -32,7 +32,7 @@ module spine {
clientId: string; clientId: string;
toLoad = new Array<string>(); toLoad = new Array<string>();
assets: Map<any> = {}; assets: Map<any> = {};
textureLoader: (image: HTMLImageElement) => any; textureLoader: (image: HTMLImageElement | ImageBitmap) => any;
constructor(clientId: string) { constructor(clientId: string) {
this.clientId = clientId; this.clientId = clientId;
@ -56,7 +56,7 @@ module spine {
this.pathPrefix = pathPrefix; this.pathPrefix = pathPrefix;
} }
private queueAsset(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): boolean { private queueAsset(clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string): boolean {
let clientAssets = this.clientAssets[clientId]; let clientAssets = this.clientAssets[clientId];
if (clientAssets === null || clientAssets === undefined) { if (clientAssets === null || clientAssets === undefined) {
clientAssets = new Assets(clientId); clientAssets = new Assets(clientId);
@ -111,19 +111,40 @@ module spine {
request.send(); request.send();
} }
loadTexture (clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string) { loadTexture (clientId: string, textureLoader: (image: HTMLImageElement | ImageBitmap) => any, path: string) {
path = this.pathPrefix + path; path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path)) return; if (!this.queueAsset(clientId, textureLoader, path)) return;
let img = new Image(); let isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
img.crossOrigin = "anonymous"; let isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
img.onload = (ev) => {
this.rawAssets[path] = img; if (isWebWorker) {
// For webworker use fetch instead of Image()
const options = {mode: <RequestMode>"cors"};
fetch(path, options).then( (response) => {
if (!response.ok) {
this.errors[path] = "Couldn't load image " + path;
}
return response.blob();
}).then( (blob) => {
return createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none',
});
}).then( (bitmap) => {
this.rawAssets[path] = bitmap;
});
} else {
let img = new Image();
img.crossOrigin = "anonymous";
img.onload = (ev) => {
this.rawAssets[path] = img;
}
img.onerror = (ev) => {
this.errors[path] = `Couldn't load image ${path}`;
}
img.src = path;
} }
img.onerror = (ev) => {
this.errors[path] = `Couldn't load image ${path}`;
}
img.src = path;
} }
get (clientId: string, path: string) { get (clientId: string, path: string) {
@ -134,16 +155,29 @@ module spine {
} }
private updateClientAssets(clientAssets: Assets): void { private updateClientAssets(clientAssets: Assets): void {
let isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
let isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
for (let i = 0; i < clientAssets.toLoad.length; i++) { for (let i = 0; i < clientAssets.toLoad.length; i++) {
let path = clientAssets.toLoad[i]; let path = clientAssets.toLoad[i];
let asset = clientAssets.assets[path]; let asset = clientAssets.assets[path];
if (asset === null || asset === undefined) { if (asset === null || asset === undefined) {
let rawAsset = this.rawAssets[path]; let rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) continue; if (rawAsset === null || rawAsset === undefined) continue;
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(<HTMLImageElement>rawAsset); if (isWebWorker)
{
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(<ImageBitmap>rawAsset);
} else {
clientAssets.assets[path] = rawAsset;
}
} else { } else {
clientAssets.assets[path] = rawAsset; if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(<HTMLImageElement>rawAsset);
} else {
clientAssets.assets[path] = rawAsset;
}
} }
} }
} }

View File

@ -29,13 +29,13 @@
module spine { module spine {
export abstract class Texture { export abstract class Texture {
protected _image: HTMLImageElement; protected _image: HTMLImageElement | ImageBitmap;
constructor (image: HTMLImageElement) { constructor (image: HTMLImageElement | ImageBitmap) {
this._image = image; this._image = image;
} }
getImage (): HTMLImageElement { getImage (): HTMLImageElement | ImageBitmap {
return this._image; return this._image;
} }

View File

@ -30,7 +30,7 @@
module spine.webgl { module spine.webgl {
export class AssetManager extends spine.AssetManager { export class AssetManager extends spine.AssetManager {
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix: string = "") { constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix: string = "") {
super((image: HTMLImageElement) => { super((image: HTMLImageElement | ImageBitmap) => {
return new spine.webgl.GLTexture(context, image); return new spine.webgl.GLTexture(context, image);
}, pathPrefix); }, pathPrefix);
} }

View File

@ -36,7 +36,7 @@ module spine.webgl {
public static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL = false; public static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL = false;
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement, useMipMaps: boolean = false) { constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps: boolean = false) {
super(image); super(image);
this.context = context instanceof ManagedWebGLRenderingContext? context : new ManagedWebGLRenderingContext(context); this.context = context instanceof ManagedWebGLRenderingContext? context : new ManagedWebGLRenderingContext(context);
this.useMipMaps = useMipMaps; this.useMipMaps = useMipMaps;

View File

@ -33,8 +33,8 @@ module spine.webgl {
public gl: WebGLRenderingContext; public gl: WebGLRenderingContext;
private restorables = new Array<Restorable>(); private restorables = new Array<Restorable>();
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, contextConfig: any = { alpha: "true" }) { constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig: any = { alpha: "true" }) {
if (canvasOrContext instanceof HTMLCanvasElement) { if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
let canvas = canvasOrContext; let canvas = canvasOrContext;
this.gl = <WebGLRenderingContext> (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig)); this.gl = <WebGLRenderingContext> (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
this.canvas = canvas; this.canvas = canvas;

View File

@ -1093,6 +1093,84 @@ CanvasRenderer:
m_PrefabParentObject: {fileID: 0} m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1240492980} m_GameObject: {fileID: 1240492980}
--- !u!1 &1259836958
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1259836959}
- component: {fileID: 1259836961}
- component: {fileID: 1259836960}
m_Layer: 5
m_Name: Instructions (1)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1259836959
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1259836958}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1.0000044, y: 1.0000044, z: 1.0000044}
m_Children: []
m_Father: {fileID: 1442798444}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -394, y: 463}
m_SizeDelta: {x: 687, y: 32}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1259836960
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1259836958}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 28
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 0
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 1
m_VerticalOverflow: 1
m_LineSpacing: 1
m_Text: 'Please also have a look at the example scene
"Mix and Match Skins" which shows a similar
use case but uses the new Skin API.'
--- !u!222 &1259836961
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1259836958}
--- !u!1 &1315482508 --- !u!1 &1315482508
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1368,6 +1446,7 @@ RectTransform:
- {fileID: 906692069} - {fileID: 906692069}
- {fileID: 1315482509} - {fileID: 1315482509}
- {fileID: 748959554} - {fileID: 748959554}
- {fileID: 1259836959}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 2 m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -1678,6 +1757,8 @@ MonoBehaviour:
initialSkinName: base initialSkinName: base
initialFlipX: 0 initialFlipX: 0
initialFlipY: 0 initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: [] separatorSlotNames: []
zSpacing: 0 zSpacing: 0
useClipping: 1 useClipping: 1

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c1c5be7b33880734d9675fdca40ac5d0 guid: af3bca1819847fb46b46f8196526c285
folderAsset: yes timeCreated: 1480087951
licenseType: Free
DefaultImporter: DefaultImporter:
externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

View File

@ -173,7 +173,15 @@ MonoBehaviour:
startingLoop: 1 startingLoop: 1
timeScale: 1 timeScale: 1
freeze: 0 freeze: 0
updateMode: 3
updateWhenInvisible: 3
unscaledTime: 0 unscaledTime: 0
allowMultipleCanvasRenderers: 0
canvasRenderers: []
separatorSlotNames: []
enableSeparatorSlots: 0
separatorParts: []
updateSeparatorPartLocation: 1
meshGenerator: meshGenerator:
settings: settings:
useClipping: 1 useClipping: 1
@ -613,14 +621,236 @@ RectTransform:
- {fileID: 1290113543} - {fileID: 1290113543}
- {fileID: 1028287914} - {fileID: 1028287914}
- {fileID: 1758924602} - {fileID: 1758924602}
- {fileID: 1612003163}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 5 m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0} m_Pivot: {x: 0, y: 0}
--- !u!1 &988957974
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 988957981}
- component: {fileID: 988957980}
- component: {fileID: 988957979}
- component: {fileID: 988957978}
- component: {fileID: 988957977}
- component: {fileID: 988957976}
- component: {fileID: 988957975}
m_Layer: 0
m_Name: Spine GameObject (hero-pro) Z-Spacing
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!61 &988957975
BoxCollider2D:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0.43330622, y: 1.9115748}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 4.7975626, y: 5.72394}
m_EdgeRadius: 0
--- !u!114 &988957976
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -1862395651, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Delegates:
- eventID: 0
callback:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 988957977}
m_MethodName: set_enabled
m_Mode: 6
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 1
m_CallState: 2
- m_Target: {fileID: 988957978}
m_MethodName: set_AnimationName
m_Mode: 5
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument: attack
m_BoolArgument: 1
m_CallState: 2
m_TypeName: UnityEngine.EventSystems.EventTrigger+TriggerEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- eventID: 1
callback:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 988957977}
m_MethodName: set_enabled
m_Mode: 6
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
- m_Target: {fileID: 988957978}
m_MethodName: set_AnimationName
m_Mode: 5
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument: idle
m_BoolArgument: 0
m_CallState: 2
m_TypeName: UnityEngine.EventSystems.EventTrigger+TriggerEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
delegates: []
--- !u!114 &988957977
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 26947ae098a8447408d80c0c86e35b48, type: 3}
m_Name:
m_EditorClassIdentifier:
skeletonRenderer: {fileID: 988957978}
customSlotMaterials: []
customMaterialOverrides:
- overrideDisabled: 0
originalMaterial: {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2}
replacementMaterial: {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192,
type: 2}
--- !u!114 &988957978
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d247ba06193faa74d9335f5481b2b56c, type: 3}
m_Name:
m_EditorClassIdentifier:
skeletonDataAsset: {fileID: 11400000, guid: 2f899e95232e6144786de8fb99678a8d, type: 2}
initialSkinName: weapon/sword
initialFlipX: 0
initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: []
zSpacing: -0.0122
useClipping: 1
immutableTriangles: 0
pmaVertexColors: 1
clearStateOnDisable: 0
tintBlack: 0
singleSubmesh: 0
addNormals: 0
calculateTangents: 0
maskInteraction: 0
maskMaterials:
materialsMaskDisabled: []
materialsInsideMask: []
materialsOutsideMask: []
disableRenderingOnOverride: 1
_animationName: idle
loop: 1
timeScale: 0.4
--- !u!23 &988957979
MeshRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_Materials:
- {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!33 &988957980
MeshFilter:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_Mesh: {fileID: 0}
--- !u!4 &988957981
Transform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 988957974}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 2.1, y: -2.0300002, z: 0}
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1028287913 --- !u!1 &1028287913
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -762,13 +992,90 @@ MonoBehaviour:
m_HorizontalOverflow: 0 m_HorizontalOverflow: 0
m_VerticalOverflow: 0 m_VerticalOverflow: 0
m_LineSpacing: 1 m_LineSpacing: 1
m_Text: SkeletonAnimation m_Text: 'SkeletonAnimation
Outline Only'
--- !u!222 &1290113545 --- !u!222 &1290113545
CanvasRenderer: CanvasRenderer:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1290113542} m_GameObject: {fileID: 1290113542}
--- !u!1 &1612003162
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1612003163}
- component: {fileID: 1612003165}
- component: {fileID: 1612003164}
m_Layer: 5
m_Name: Description Text ZSpacing
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1612003163
RectTransform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1612003162}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.99999994, y: 0.99999994, z: 0.99999994}
m_Children: []
m_Father: {fileID: 953433494}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.40375003, y: 0.031118065}
m_AnchorMax: {x: 0.6937501, y: 0.1287785}
m_AnchoredPosition: {x: 1.8299999, y: 0.16599989}
m_SizeDelta: {x: 0.84000015, y: 0.33199978}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1612003164
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1612003162}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.9056604, g: 0.9056604, b: 0.9056604, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 12
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 0
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Add Z-Spacing at the SkeletonRenderer Component to receive outlines around
each attachment.
--- !u!222 &1612003165
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1612003162}
--- !u!1 &1628022514 --- !u!1 &1628022514
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1086,6 +1393,8 @@ MonoBehaviour:
initialSkinName: initialSkinName:
initialFlipX: 0 initialFlipX: 0
initialFlipY: 0 initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: [] separatorSlotNames: []
zSpacing: 0 zSpacing: 0
useClipping: 1 useClipping: 1
@ -1215,7 +1524,7 @@ GameObject:
- component: {fileID: 2051539995} - component: {fileID: 2051539995}
- component: {fileID: 2051539996} - component: {fileID: 2051539996}
m_Layer: 0 m_Layer: 0
m_Name: Spine GameObject (spineboy-pro) m_Name: Spine GameObject (hero-pro)
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -1227,7 +1536,7 @@ MonoBehaviour:
m_PrefabParentObject: {fileID: 0} m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2051539989} m_GameObject: {fileID: 2051539989}
m_Enabled: 0 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 26947ae098a8447408d80c0c86e35b48, type: 3} m_Script: {fileID: 11500000, guid: 26947ae098a8447408d80c0c86e35b48, type: 3}
m_Name: m_Name:
@ -1237,7 +1546,7 @@ MonoBehaviour:
customMaterialOverrides: customMaterialOverrides:
- overrideDisabled: 0 - overrideDisabled: 0
originalMaterial: {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2} originalMaterial: {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2}
replacementMaterial: {fileID: 2100000, guid: fd9012d511e32e04c84b87ea9276448d, replacementMaterial: {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192,
type: 2} type: 2}
--- !u!114 &2051539991 --- !u!114 &2051539991
MonoBehaviour: MonoBehaviour:
@ -1254,6 +1563,8 @@ MonoBehaviour:
initialSkinName: weapon/sword initialSkinName: weapon/sword
initialFlipX: 0 initialFlipX: 0
initialFlipY: 0 initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: [] separatorSlotNames: []
zSpacing: 0 zSpacing: 0
useClipping: 1 useClipping: 1
@ -1286,7 +1597,7 @@ MeshRenderer:
m_LightProbeUsage: 1 m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1 m_ReflectionProbeUsage: 1
m_Materials: m_Materials:
- {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2} - {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192, type: 2}
m_StaticBatchInfo: m_StaticBatchInfo:
firstSubMesh: 0 firstSubMesh: 0
subMeshCount: 0 subMeshCount: 0
@ -1319,8 +1630,8 @@ Transform:
m_PrefabInternal: {fileID: 0} m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2051539989} m_GameObject: {fileID: 2051539989}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.52, y: -2.0300002, z: 0} m_LocalPosition: {x: -1.1, y: -2.0300002, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 4 m_RootOrder: 4

View File

@ -70,7 +70,7 @@ namespace Spine.Unity.Examples {
} }
void Apply (SkeletonRenderer skeletonRenderer) { void Apply (SkeletonRenderer skeletonRenderer) {
StartCoroutine("Blink"); StartCoroutine(Blink());
} }
void Update () { void Update () {

View File

@ -0,0 +1,50 @@
/******************************************************************************
* 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 Spine.Unity;
using UnityEngine.UI;
namespace Spine.Unity.Examples {
public class MixAndMatchSkinsButtonExample : MonoBehaviour {
public SkeletonDataAsset skeletonDataAsset;
public MixAndMatchSkinsExample skinsSystem;
[SpineSkin(dataField:"skeletonDataAsset")] public string itemSkin;
public MixAndMatchSkinsExample.ItemType itemType;
void Start () {
var button = GetComponent<Button>();
button.onClick.AddListener(
delegate { skinsSystem.Equip(itemSkin, itemType); }
);
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c32a308f5ae4c534991805c82c575058
timeCreated: 1522744049
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,190 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity.AttachmentTools;
namespace Spine.Unity.Examples {
public class MixAndMatchSkinsExample : MonoBehaviour {
// character skins
[SpineSkin] public string baseSkin = "skin-base";
[SpineSkin] public string eyelidsSkin = "eyelids/girly";
// here we use arrays of strings to be able to cycle between them easily.
[SpineSkin] public string[] hairSkins = { "hair/brown", "hair/blue", "hair/pink", "hair/short-red", "hair/long-blue-with-scarf" };
public int activeHairIndex = 0;
[SpineSkin] public string[] eyesSkins = { "eyes/violet", "eyes/green", "eyes/yellow" };
public int activeEyesIndex = 0;
[SpineSkin] public string[] noseSkins = { "nose/short", "nose/long" };
public int activeNoseIndex = 0;
// equipment skins
public enum ItemType {
Cloth,
Pants,
Bag,
Hat
}
[SpineSkin] public string clothesSkin = "clothes/hoodie-orange";
[SpineSkin] public string pantsSkin = "legs/pants-jeans";
[SpineSkin] public string bagSkin = "";
[SpineSkin] public string hatSkin = "accessories/hat-red-yellow";
SkeletonAnimation skeletonAnimation;
// This "naked body" skin will likely change only once upon character creation,
// so we store this combined set of non-equipment Skins for later re-use.
Skin characterSkin;
// for repacking the skin to a new atlas texture
public Material runtimeMaterial;
public Texture2D runtimeAtlas;
void Awake () {
skeletonAnimation = this.GetComponent<SkeletonAnimation>();
}
void Start () {
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void NextHairSkin() {
activeHairIndex = (activeHairIndex + 1) % hairSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void PrevHairSkin () {
activeHairIndex = (activeHairIndex + hairSkins.Length - 1) % hairSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void NextEyesSkin () {
activeEyesIndex = (activeEyesIndex + 1) % eyesSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void PrevEyesSkin () {
activeEyesIndex = (activeEyesIndex + eyesSkins.Length - 1) % eyesSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void NextNoseSkin () {
activeNoseIndex = (activeNoseIndex + 1) % noseSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void PrevNoseSkin () {
activeNoseIndex = (activeNoseIndex + noseSkins.Length - 1) % noseSkins.Length;
UpdateCharacterSkin();
UpdateCombinedSkin();
}
public void Equip(string itemSkin, ItemType itemType) {
switch (itemType) {
case ItemType.Cloth:
clothesSkin = itemSkin;
break;
case ItemType.Pants:
pantsSkin = itemSkin;
break;
case ItemType.Bag:
bagSkin = itemSkin;
break;
case ItemType.Hat:
hatSkin = itemSkin;
break;
default:
break;
}
UpdateCombinedSkin();
}
public void OptimizeSkin () {
// Create a repacked skin.
var previousSkin = skeletonAnimation.Skeleton.Skin;
// Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
if (runtimeMaterial)
Destroy(runtimeMaterial);
if (runtimeAtlas)
Destroy(runtimeAtlas);
Skin repackedSkin = previousSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
previousSkin.Clear();
// Use the repacked skin.
skeletonAnimation.Skeleton.Skin = repackedSkin;
skeletonAnimation.Skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
// You can optionally clear the cache after multiple repack operations.
AtlasUtilities.ClearCache();
}
void UpdateCharacterSkin () {
var skeleton = skeletonAnimation.Skeleton;
var skeletonData = skeleton.Data;
characterSkin = new Skin("character-base");
// Note that the result Skin returned by calls to skeletonData.FindSkin()
// could be cached once in Start() instead of searching for the same skin
// every time. For demonstration purposes we keep it simple here.
characterSkin.AddSkin(skeletonData.FindSkin(baseSkin));
characterSkin.AddSkin(skeletonData.FindSkin(noseSkins[activeNoseIndex]));
characterSkin.AddSkin(skeletonData.FindSkin(eyelidsSkin));
characterSkin.AddSkin(skeletonData.FindSkin(eyesSkins[activeEyesIndex]));
characterSkin.AddSkin(skeletonData.FindSkin(hairSkins[activeHairIndex]));
}
void AddEquipmentSkinsTo (Skin combinedSkin) {
var skeleton = skeletonAnimation.Skeleton;
var skeletonData = skeleton.Data;
combinedSkin.AddSkin(skeletonData.FindSkin(clothesSkin));
combinedSkin.AddSkin(skeletonData.FindSkin(pantsSkin));
if (!string.IsNullOrEmpty(bagSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(bagSkin));
if (!string.IsNullOrEmpty(hatSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(hatSkin));
}
void UpdateCombinedSkin () {
var skeleton = skeletonAnimation.Skeleton;
var resultCombinedSkin = new Skin("character-combined");
resultCombinedSkin.AddSkin(characterSkin);
AddEquipmentSkinsTo(resultCombinedSkin);
skeleton.SetSkin(resultCombinedSkin);
skeleton.SetSlotsToSetupPose();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b5a66492fdefc494b8399943a0f9b250
timeCreated: 1601458489
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: hero-pro_MaterialOutlineOnly
m_Shader: {fileID: 4800000, guid: 177da18c3d2e0aa4cb39990ea011973c, type: 3}
m_ShaderKeywords: _USE8NEIGHBOURHOOD_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _MainTex:
m_Texture: {fileID: 2800000, guid: 25b07e861d1a62f4db687c871e4a3828, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _Cutoff: 0.9
- _FillPhase: 0
- _OutlineMipLevel: 0
- _OutlineReferenceTexWidth: 1024
- _OutlineSmoothness: 1
- _OutlineWidth: 3
- _StencilComp: 8
- _StencilRef: 1
- _StraightAlphaInput: 0
- _ThresholdEnd: 0.25
- _Use8Neighbourhood: 1
- _ZWriteOffset: 0.01
m_Colors:
- _FillColor: {r: 1, g: 1, b: 1, a: 1}
- _OutlineColor: {r: 0, g: 1, b: 0.97280097, a: 1}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: aadb1a26bea9b8d4381c38e65e64c192
timeCreated: 1524005968
licenseType: Free
NativeFormatImporter:
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9b5072c1342a08b429b2bbfa38e83bab
timeCreated: 1601458174
licenseType: Pro
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

View File

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

View File

@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a6b194f808b1af6499c93410e504af42, type: 3}
m_Name: mix-and-match-pma_Atlas
m_EditorClassIdentifier:
atlasFile: {fileID: 4900000, guid: 9b5072c1342a08b429b2bbfa38e83bab, type: 3}
materials:
- {fileID: 2100000, guid: f68af5332bca5ef49a0bb6a25be1a8e5, type: 2}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 071eeff112dbeca4e961d78214f41c38
timeCreated: 1601458175
licenseType: Pro
NativeFormatImporter:
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: mix-and-match-pma_Material
m_Shader: {fileID: 4800000, guid: 1e8a610c9e01c3648bac42585e5fc676, type: 3}
m_ShaderKeywords: _USE8NEIGHBOURHOOD_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _MainTex:
m_Texture: {fileID: 2800000, guid: a837e662e711d1a4ba0b4a9aeb141878, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _Cutoff: 0.1
- _OutlineMipLevel: 0
- _OutlineReferenceTexWidth: 1024
- _OutlineSmoothness: 1
- _OutlineWidth: 3
- _StencilComp: 8
- _StencilRef: 1
- _StraightAlphaInput: 0
- _ThresholdEnd: 0.25
- _Use8Neighbourhood: 1
m_Colors:
- _OutlineColor: {r: 1, g: 1, b: 0, a: 1}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: f68af5332bca5ef49a0bb6a25be1a8e5
timeCreated: 1601458174
licenseType: Pro
NativeFormatImporter:
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05c17836f4f4fe748b11ad96e9436421
timeCreated: 1601458174
licenseType: Pro
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f1b3b4b945939a54ea0b23d3396115fb, type: 3}
m_Name: mix-and-match-pro_SkeletonData
m_EditorClassIdentifier:
atlasAssets:
- {fileID: 11400000, guid: 071eeff112dbeca4e961d78214f41c38, type: 2}
scale: 0.01
skeletonJSON: {fileID: 4900000, guid: 05c17836f4f4fe748b11ad96e9436421, type: 3}
skeletonDataModifiers: []
fromAnimation: []
toAnimation: []
duration: []
defaultMix: 0.2
controller: {fileID: 0}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 91a60be3ea058c245b89efb440a49a58
timeCreated: 1601458175
licenseType: Pro
NativeFormatImporter:
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -108,7 +108,7 @@ namespace Spine.Unity.Editor {
} }
serializedObject.Update(); serializedObject.Update();
atlasAsset = atlasAsset ?? (SpineAtlasAsset)target; atlasAsset = (atlasAsset == null) ? (SpineAtlasAsset)target : atlasAsset;
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true); EditorGUILayout.PropertyField(materials, true);

View File

@ -71,7 +71,7 @@ namespace Spine.Unity.Editor {
} }
serializedObject.Update(); serializedObject.Update();
atlasAsset = atlasAsset ?? (SpineSpriteAtlasAsset)target; atlasAsset = (atlasAsset == null) ? (SpineSpriteAtlasAsset)target : atlasAsset;
if (atlasAsset.RegionsNeedLoading) { if (atlasAsset.RegionsNeedLoading) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) {

View File

@ -162,6 +162,12 @@ namespace Spine.Unity.Editor {
return; return;
} }
string errorMessage = null;
if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic(thisSkeletonGraphic, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
}
bool isSingleRendererOnly = (!allowMultipleCanvasRenderers.hasMultipleDifferentValues && allowMultipleCanvasRenderers.boolValue == false); bool isSingleRendererOnly = (!allowMultipleCanvasRenderers.hasMultipleDifferentValues && allowMultipleCanvasRenderers.boolValue == false);
bool isSeparationEnabledButNotMultipleRenderers = bool isSeparationEnabledButNotMultipleRenderers =
isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true); isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true);

View File

@ -289,7 +289,8 @@ namespace Spine.Unity.Editor {
return; return;
string errorMessage = null; string errorMessage = null;
if (MaterialChecks.IsMaterialSetupProblematic((SkeletonRenderer)this.target, ref errorMessage)) { if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic((SkeletonRenderer)this.target, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true); EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
} }

View File

@ -37,12 +37,16 @@ namespace Spine.Unity.Editor {
protected SerializedProperty rootMotionBoneName; protected SerializedProperty rootMotionBoneName;
protected SerializedProperty transformPositionX; protected SerializedProperty transformPositionX;
protected SerializedProperty transformPositionY; protected SerializedProperty transformPositionY;
protected SerializedProperty rootMotionScaleX;
protected SerializedProperty rootMotionScaleY;
protected SerializedProperty rigidBody2D; protected SerializedProperty rigidBody2D;
protected SerializedProperty rigidBody; protected SerializedProperty rigidBody;
protected GUIContent rootMotionBoneNameLabel; protected GUIContent rootMotionBoneNameLabel;
protected GUIContent transformPositionXLabel; protected GUIContent transformPositionXLabel;
protected GUIContent transformPositionYLabel; protected GUIContent transformPositionYLabel;
protected GUIContent rootMotionScaleXLabel;
protected GUIContent rootMotionScaleYLabel;
protected GUIContent rigidBody2DLabel; protected GUIContent rigidBody2DLabel;
protected GUIContent rigidBodyLabel; protected GUIContent rigidBodyLabel;
@ -51,12 +55,16 @@ namespace Spine.Unity.Editor {
rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName"); rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName");
transformPositionX = serializedObject.FindProperty("transformPositionX"); transformPositionX = serializedObject.FindProperty("transformPositionX");
transformPositionY = serializedObject.FindProperty("transformPositionY"); transformPositionY = serializedObject.FindProperty("transformPositionY");
rootMotionScaleX = serializedObject.FindProperty("rootMotionScaleX");
rootMotionScaleY = serializedObject.FindProperty("rootMotionScaleY");
rigidBody2D = serializedObject.FindProperty("rigidBody2D"); rigidBody2D = serializedObject.FindProperty("rigidBody2D");
rigidBody = serializedObject.FindProperty("rigidBody"); rigidBody = serializedObject.FindProperty("rigidBody");
rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from."); rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from.");
transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)"); transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)");
transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone."); transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone.");
rootMotionScaleXLabel = new UnityEngine.GUIContent("Root Motion Scale (X)", "Scale applied to the horizontal root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rootMotionScaleYLabel = new UnityEngine.GUIContent("Root Motion Scale (Y)", "Scale applied to the vertical root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rigidBody2DLabel = new UnityEngine.GUIContent("Rigidbody2D", rigidBody2DLabel = new UnityEngine.GUIContent("Rigidbody2D",
"Optional Rigidbody2D: Assign a Rigidbody2D here if you want " + "Optional Rigidbody2D: Assign a Rigidbody2D here if you want " +
" to apply the root motion to the rigidbody instead of the Transform." + " to apply the root motion to the rigidbody instead of the Transform." +
@ -81,6 +89,9 @@ namespace Spine.Unity.Editor {
EditorGUILayout.PropertyField(rootMotionBoneName, rootMotionBoneNameLabel); EditorGUILayout.PropertyField(rootMotionBoneName, rootMotionBoneNameLabel);
EditorGUILayout.PropertyField(transformPositionX, transformPositionXLabel); EditorGUILayout.PropertyField(transformPositionX, transformPositionXLabel);
EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel); EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel);
EditorGUILayout.PropertyField(rootMotionScaleX, rootMotionScaleXLabel);
EditorGUILayout.PropertyField(rootMotionScaleY, rootMotionScaleYLabel);
} }
protected virtual void OptionalPropertyFields () { protected virtual void OptionalPropertyFields () {

View File

@ -130,6 +130,9 @@ namespace Spine.Unity.Editor {
const string TEXTUREIMPORTER_WARNING_KEY = "SPINE_TEXTUREIMPORTER_WARNING"; const string TEXTUREIMPORTER_WARNING_KEY = "SPINE_TEXTUREIMPORTER_WARNING";
public static bool textureImporterWarning = SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING; public static bool textureImporterWarning = SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING;
const string COMPONENTMATERIAL_WARNING_KEY = "SPINE_COMPONENTMATERIAL_WARNING";
public static bool componentMaterialWarning = SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING;
public const float DEFAULT_MIPMAPBIAS = SpinePreferences.DEFAULT_MIPMAPBIAS; public const float DEFAULT_MIPMAPBIAS = SpinePreferences.DEFAULT_MIPMAPBIAS;
public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE"; public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
@ -162,6 +165,7 @@ namespace Spine.Unity.Editor {
mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME); mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING); atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING); textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
componentMaterialWarning = EditorPrefs.GetBool(COMPONENTMATERIAL_WARNING_KEY, SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING);
timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION); timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE); handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
preferencesLoaded = true; preferencesLoaded = true;
@ -180,6 +184,7 @@ namespace Spine.Unity.Editor {
newPreferences.mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME); newPreferences.mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
newPreferences.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING); newPreferences.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
newPreferences.textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING); newPreferences.textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
newPreferences.componentMaterialWarning = EditorPrefs.GetBool(COMPONENTMATERIAL_WARNING_KEY, SpinePreferences.DEFAULT_COMPONENTMATERIAL_WARNING);
newPreferences.timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION); newPreferences.timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
newPreferences.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE); newPreferences.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
} }
@ -196,6 +201,7 @@ namespace Spine.Unity.Editor {
EditorPrefs.SetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, preferences.mecanimEventIncludeFolderName); EditorPrefs.SetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, preferences.mecanimEventIncludeFolderName);
EditorPrefs.SetBool(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning); EditorPrefs.SetBool(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning);
EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning); EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning);
EditorPrefs.SetBool(COMPONENTMATERIAL_WARNING_KEY, preferences.componentMaterialWarning);
EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration); EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration);
EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, preferences.handleScale); EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, preferences.handleScale);
} }
@ -210,11 +216,11 @@ namespace Spine.Unity.Editor {
showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons); showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons);
if (EditorGUI.EndChangeCheck()) { if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons); EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons);
#if NEWPLAYMODECALLBACKS #if NEWPLAYMODECALLBACKS
HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else #else
HierarchyHandler.IconsOnPlaymodeStateChanged(); HierarchyHandler.IconsOnPlaymodeStateChanged();
#endif #endif
} }
BoolPrefsField(ref autoReloadSceneSkeletons, AUTO_RELOAD_SCENESKELETONS_KEY, new GUIContent("Auto-reload scene components", "Reloads Skeleton components in the scene whenever their SkeletonDataAsset is modified. This makes it so changes in the SkeletonDataAsset inspector are immediately reflected. This may be slow when your scenes have large numbers of SkeletonRenderers or SkeletonGraphic.")); BoolPrefsField(ref autoReloadSceneSkeletons, AUTO_RELOAD_SCENESKELETONS_KEY, new GUIContent("Auto-reload scene components", "Reloads Skeleton components in the scene whenever their SkeletonDataAsset is modified. This makes it so changes in the SkeletonDataAsset inspector are immediately reflected. This may be slow when your scenes have large numbers of SkeletonRenderers or SkeletonGraphic."));
@ -247,6 +253,7 @@ namespace Spine.Unity.Editor {
{ {
SpineEditorUtilities.BoolPrefsField(ref atlasTxtImportWarning, ATLASTXT_WARNING_KEY, new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found.")); SpineEditorUtilities.BoolPrefsField(ref atlasTxtImportWarning, ATLASTXT_WARNING_KEY, new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found."));
SpineEditorUtilities.BoolPrefsField(ref textureImporterWarning, TEXTUREIMPORTER_WARNING_KEY, new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts.")); SpineEditorUtilities.BoolPrefsField(ref textureImporterWarning, TEXTUREIMPORTER_WARNING_KEY, new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts."));
SpineEditorUtilities.BoolPrefsField(ref componentMaterialWarning, COMPONENTMATERIAL_WARNING_KEY, new GUIContent("Component & Material Warning", "Log a warning and recommendation whenever Component and Material settings are not compatible."));
} }
EditorGUILayout.Space(); EditorGUILayout.Space();
@ -278,11 +285,11 @@ namespace Spine.Unity.Editor {
} }
} }
#if SPINE_TK2D_DEFINE #if SPINE_TK2D_DEFINE
bool isTK2DDefineSet = true; bool isTK2DDefineSet = true;
#else #else
bool isTK2DDefineSet = false; bool isTK2DDefineSet = false;
#endif #endif
bool isTK2DAllowed = SpineTK2DEditorUtility.IsTK2DAllowed; bool isTK2DAllowed = SpineTK2DEditorUtility.IsTK2DAllowed;
if (SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) { if (SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) {
GUILayout.Space(20); GUILayout.Space(20);
@ -294,12 +301,12 @@ namespace Spine.Unity.Editor {
if (GUILayout.Button("Disable", GUILayout.Width(64))) if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineTK2DEditorUtility.DisableTK2D(); SpineTK2DEditorUtility.DisableTK2D();
} }
#if !SPINE_TK2D_DEFINE #if !SPINE_TK2D_DEFINE
if (!isTK2DAllowed) { if (!isTK2DAllowed) {
EditorGUILayout.LabelField("To allow TK2D support, please modify line 67 in", EditorStyles.boldLabel); EditorGUILayout.LabelField("To allow TK2D support, please modify line 67 in", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Spine/Editor/spine-unity/Editor/Util./BuildSettings.cs", EditorStyles.boldLabel); EditorGUILayout.LabelField("Spine/Editor/spine-unity/Editor/Util./BuildSettings.cs", EditorStyles.boldLabel);
} }
#endif #endif
} }
GUILayout.Space(20); GUILayout.Space(20);
@ -308,7 +315,7 @@ namespace Spine.Unity.Editor {
SpineEditorUtilities.BoolPrefsField(ref timelineUseBlendDuration, TIMELINE_USE_BLEND_DURATION_KEY, new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'.")); SpineEditorUtilities.BoolPrefsField(ref timelineUseBlendDuration, TIMELINE_USE_BLEND_DURATION_KEY, new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
} }
} }
#endif // !NEW_PREFERENCES_SETTINGS_PROVIDER #endif // !NEW_PREFERENCES_SETTINGS_PROVIDER
} }
static void BoolPrefsField (ref bool currentValue, string editorPrefsKey, GUIContent label) { static void BoolPrefsField (ref bool currentValue, string editorPrefsKey, GUIContent label) {

View File

@ -621,7 +621,7 @@ namespace Spine.Unity.Editor {
int[] triangles = attachment.Triangles; int[] triangles = attachment.Triangles;
Color color = new Color(attachment.R, attachment.G, attachment.B, attachment.A); Color color = new Color(attachment.R, attachment.G, attachment.B, attachment.A);
mesh = mesh ?? new Mesh(); mesh = (mesh == null) ? new Mesh() : mesh;
mesh.triangles = new int[0]; mesh.triangles = new int[0];

View File

@ -84,6 +84,9 @@ namespace Spine.Unity.Editor {
internal const bool DEFAULT_TEXTUREIMPORTER_WARNING = true; internal const bool DEFAULT_TEXTUREIMPORTER_WARNING = true;
public bool textureImporterWarning = DEFAULT_TEXTUREIMPORTER_WARNING; public bool textureImporterWarning = DEFAULT_TEXTUREIMPORTER_WARNING;
internal const bool DEFAULT_COMPONENTMATERIAL_WARNING = true;
public bool componentMaterialWarning = DEFAULT_COMPONENTMATERIAL_WARNING;
public const float DEFAULT_MIPMAPBIAS = -0.5f; public const float DEFAULT_MIPMAPBIAS = -0.5f;
public const bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true; public const bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true;
@ -108,6 +111,9 @@ namespace Spine.Unity.Editor {
internal static SpinePreferences GetOrCreateSettings () { internal static SpinePreferences GetOrCreateSettings () {
var settings = AssetDatabase.LoadAssetAtPath<SpinePreferences>(SPINE_SETTINGS_ASSET_PATH); var settings = AssetDatabase.LoadAssetAtPath<SpinePreferences>(SPINE_SETTINGS_ASSET_PATH);
if (settings == null)
settings = FindSpinePreferences();
if (settings == null) if (settings == null)
{ {
settings = ScriptableObject.CreateInstance<SpinePreferences>(); settings = ScriptableObject.CreateInstance<SpinePreferences>();
@ -123,6 +129,18 @@ namespace Spine.Unity.Editor {
return settings; return settings;
} }
static SpinePreferences FindSpinePreferences () {
string typeSearchString = " t:SpinePreferences";
string[] guids = AssetDatabase.FindAssets(typeSearchString);
foreach (string guid in guids) {
string path = AssetDatabase.GUIDToAssetPath(guid);
var preferences = AssetDatabase.LoadAssetAtPath<SpinePreferences>(path);
if (preferences != null)
return preferences;
}
return null;
}
public static void HandlePreferencesGUI (SerializedObject settings) { public static void HandlePreferencesGUI (SerializedObject settings) {
float prevLabelWidth = EditorGUIUtility.labelWidth; float prevLabelWidth = EditorGUIUtility.labelWidth;
@ -165,6 +183,7 @@ namespace Spine.Unity.Editor {
{ {
EditorGUILayout.PropertyField(settings.FindProperty("atlasTxtImportWarning"), new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found.")); EditorGUILayout.PropertyField(settings.FindProperty("atlasTxtImportWarning"), new GUIContent("Atlas Extension Warning", "Log a warning and recommendation whenever a `.atlas` file is found."));
EditorGUILayout.PropertyField(settings.FindProperty("textureImporterWarning"), new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts.")); EditorGUILayout.PropertyField(settings.FindProperty("textureImporterWarning"), new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts."));
EditorGUILayout.PropertyField(settings.FindProperty("componentMaterialWarning"), new GUIContent("Component & Material Warning", "Log a warning and recommendation whenever Component and Material settings are not compatible."));
} }
EditorGUILayout.Space(); EditorGUILayout.Space();

View File

@ -43,6 +43,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[AddComponentMenu("Spine/BoneFollower")] [AddComponentMenu("Spine/BoneFollower")]
[HelpURL("http://esotericsoftware.com/spine-unity#BoneFollower")]
public class BoneFollower : MonoBehaviour { public class BoneFollower : MonoBehaviour {
#region Inspector #region Inspector
@ -62,7 +63,7 @@ namespace Spine.Unity {
/// <summary>If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly.</summary> /// <summary>If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly.</summary>
[SpineBone(dataField: "skeletonRenderer")] [SpineBone(dataField: "skeletonRenderer")]
[SerializeField] public string boneName; public string boneName;
public bool followXYPosition = true; public bool followXYPosition = true;
public bool followZPosition = true; public bool followZPosition = true;

View File

@ -42,6 +42,7 @@ namespace Spine.Unity {
#endif #endif
[DisallowMultipleComponent] [DisallowMultipleComponent]
[AddComponentMenu("Spine/UI/BoneFollowerGraphic")] [AddComponentMenu("Spine/UI/BoneFollowerGraphic")]
[HelpURL("http://esotericsoftware.com/spine-unity#BoneFollowerGraphic")]
public class BoneFollowerGraphic : MonoBehaviour { public class BoneFollowerGraphic : MonoBehaviour {
public SkeletonGraphic skeletonGraphic; public SkeletonGraphic skeletonGraphic;
public SkeletonGraphic SkeletonGraphic { public SkeletonGraphic SkeletonGraphic {
@ -56,7 +57,7 @@ namespace Spine.Unity {
/// <summary>If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly.</summary> /// <summary>If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly.</summary>
[SpineBone(dataField: "skeletonGraphic")] [SpineBone(dataField: "skeletonGraphic")]
[SerializeField] public string boneName; public string boneName;
public bool followBoneRotation = true; public bool followBoneRotation = true;
[Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")]

View File

@ -41,6 +41,7 @@ namespace Spine.Unity {
#else #else
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[HelpURL("http://esotericsoftware.com/spine-unity#BoundingBoxFollower")]
public class BoundingBoxFollower : MonoBehaviour { public class BoundingBoxFollower : MonoBehaviour {
internal static bool DebugMessages = true; internal static bool DebugMessages = true;

View File

@ -41,9 +41,10 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[AddComponentMenu("Spine/Point Follower")] [AddComponentMenu("Spine/Point Follower")]
[HelpURL("http://esotericsoftware.com/spine-unity#PointFollower")]
public class PointFollower : MonoBehaviour, IHasSkeletonRenderer, IHasSkeletonComponent { public class PointFollower : MonoBehaviour, IHasSkeletonRenderer, IHasSkeletonComponent {
[SerializeField] public SkeletonRenderer skeletonRenderer; public SkeletonRenderer skeletonRenderer;
public SkeletonRenderer SkeletonRenderer { get { return this.skeletonRenderer; } } public SkeletonRenderer SkeletonRenderer { get { return this.skeletonRenderer; } }
public ISkeletonComponent SkeletonComponent { get { return skeletonRenderer as ISkeletonComponent; } } public ISkeletonComponent SkeletonComponent { get { return skeletonRenderer as ISkeletonComponent; } }

View File

@ -45,6 +45,7 @@ namespace Spine.Unity {
/// For <c>SkeletonAnimation</c> or <c>SkeletonGraphic</c> please use /// For <c>SkeletonAnimation</c> or <c>SkeletonGraphic</c> please use
/// <see cref="SkeletonRootMotion">SkeletonRootMotion</see> instead. /// <see cref="SkeletonRootMotion">SkeletonRootMotion</see> instead.
/// </remarks> /// </remarks>
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonMecanimRootMotion")]
public class SkeletonMecanimRootMotion : SkeletonRootMotionBase { public class SkeletonMecanimRootMotion : SkeletonRootMotionBase {
#region Inspector #region Inspector
const int DefaultMecanimLayerFlags = -1; const int DefaultMecanimLayerFlags = -1;
@ -60,6 +61,18 @@ namespace Spine.Unity {
} }
} }
public override Vector2 GetRemainingRootMotion (int layerIndex) {
var pair = skeletonMecanim.Translator.GetActiveAnimationAndTime(layerIndex);
var animation = pair.Key;
var time = pair.Value;
if (animation == null)
return Vector2.zero;
float start = time;
float end = animation.duration;
return GetAnimationRootMotion(start, end, animation);
}
protected override void Reset () { protected override void Reset () {
base.Reset(); base.Reset();
mecanimLayerFlags = DefaultMecanimLayerFlags; mecanimLayerFlags = DefaultMecanimLayerFlags;
@ -74,18 +87,17 @@ namespace Spine.Unity {
} }
} }
void OnClipApplied(Spine.Animation clip, int layerIndex, float weight, void OnClipApplied(Spine.Animation animation, int layerIndex, float weight,
float time, float lastTime, bool playsBackward) { float time, float lastTime, bool playsBackward) {
if (((mecanimLayerFlags & 1<<layerIndex) == 0) || weight == 0) if (((mecanimLayerFlags & 1<<layerIndex) == 0) || weight == 0)
return; return;
var timeline = clip.FindTranslateTimelineForBone(rootMotionBoneIndex); if (!playsBackward) {
if (timeline != null) { movementDelta += weight * GetAnimationRootMotion(lastTime, time, animation);
if (!playsBackward) }
movementDelta += weight * GetTimelineMovementDelta(lastTime, time, timeline, clip); else {
else movementDelta -= weight * GetAnimationRootMotion(time, lastTime, animation);
movementDelta -= weight * GetTimelineMovementDelta(time, lastTime, timeline, clip);
} }
} }

View File

@ -46,6 +46,7 @@ namespace Spine.Unity {
/// For <c>SkeletonMecanim</c> please use /// For <c>SkeletonMecanim</c> please use
/// <see cref="SkeletonMecanimRootMotion">SkeletonMecanimRootMotion</see> instead. /// <see cref="SkeletonMecanimRootMotion">SkeletonMecanimRootMotion</see> instead.
/// </remarks> /// </remarks>
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRootMotion")]
public class SkeletonRootMotion : SkeletonRootMotionBase { public class SkeletonRootMotion : SkeletonRootMotionBase {
#region Inspector #region Inspector
const int DefaultAnimationTrackFlags = -1; const int DefaultAnimationTrackFlags = -1;
@ -55,6 +56,17 @@ namespace Spine.Unity {
AnimationState animationState; AnimationState animationState;
Canvas canvas; Canvas canvas;
public override Vector2 GetRemainingRootMotion (int trackIndex) {
TrackEntry track = animationState.GetCurrent(trackIndex);
if (track == null)
return Vector2.zero;
var animation = track.Animation;
float start = track.AnimationTime;
float end = animation.duration;
return GetAnimationRootMotion(start, end, animation);
}
protected override float AdditionalScale { protected override float AdditionalScale {
get { get {
return canvas ? canvas.referencePixelsPerUnit: 1.0f; return canvas ? canvas.referencePixelsPerUnit: 1.0f;
@ -90,11 +102,14 @@ namespace Spine.Unity {
TrackEntry next = null; TrackEntry next = null;
while (track != null) { while (track != null) {
var animation = track.Animation; var animation = track.Animation;
var timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex); float start = track.animationLast;
if (timeline != null) { float end = track.AnimationTime;
var currentDelta = GetTrackMovementDelta(track, timeline, animation, next); var currentDelta = GetAnimationRootMotion(start, end, animation);
if (currentDelta != Vector2.zero) {
ApplyMixAlphaToDelta(ref currentDelta, next, track);
localDelta += currentDelta; localDelta += currentDelta;
} }
// Traverse mixingFrom chain. // Traverse mixingFrom chain.
next = track; next = track;
track = track.mixingFrom; track = track.mixingFrom;
@ -103,17 +118,6 @@ namespace Spine.Unity {
return localDelta; 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) { void ApplyMixAlphaToDelta (ref Vector2 currentDelta, TrackEntry next, TrackEntry track) {
// Apply mix alpha to the delta position (based on AnimationState.cs). // Apply mix alpha to the delta position (based on AnimationState.cs).
float mix; float mix;

View File

@ -37,14 +37,17 @@ namespace Spine.Unity {
/// Base class for skeleton root motion components. /// Base class for skeleton root motion components.
/// </summary> /// </summary>
abstract public class SkeletonRootMotionBase : MonoBehaviour { abstract public class SkeletonRootMotionBase : MonoBehaviour {
#region Inspector
#region Inspector
[SpineBone] [SpineBone]
[SerializeField] [SerializeField]
protected string rootMotionBoneName = "root"; protected string rootMotionBoneName = "root";
public bool transformPositionX = true; public bool transformPositionX = true;
public bool transformPositionY = true; public bool transformPositionY = true;
public float rootMotionScaleX = 1;
public float rootMotionScaleY = 1;
[Header("Optional")] [Header("Optional")]
public Rigidbody2D rigidBody2D; public Rigidbody2D rigidBody2D;
public Rigidbody rigidBody; public Rigidbody rigidBody;
@ -74,87 +77,11 @@ namespace Spine.Unity {
skeletonAnimation.UpdateLocal += HandleUpdateLocal; 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 () { protected virtual void FixedUpdate () {
if (!this.isActiveAndEnabled) if (!this.isActiveAndEnabled)
return; // Root motion is only applied when component is enabled. return; // Root motion is only applied when component is enabled.
if(rigidBody2D != null) { if (rigidBody2D != null) {
rigidBody2D.MovePosition(new Vector2(transform.position.x, transform.position.y) rigidBody2D.MovePosition(new Vector2(transform.position.x, transform.position.y)
+ rigidbodyDisplacement); + rigidbodyDisplacement);
} }
@ -180,5 +107,108 @@ namespace Spine.Unity {
rigidBody = this.GetComponentInParent<Rigidbody>(); rigidBody = this.GetComponentInParent<Rigidbody>();
} }
} }
protected virtual float AdditionalScale { get { return 1.0f; } }
abstract protected Vector2 CalculateAnimationsMovementDelta ();
abstract public Vector2 GetRemainingRootMotion (int trackIndex = 0);
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;
}
}
public void AdjustRootMotionToDistance (Vector2 distanceToTarget, int trackIndex = 0) {
Vector2 remainingRootMotion = GetRemainingRootMotion(trackIndex);
if (remainingRootMotion.x == 0)
remainingRootMotion.x = 0.0001f;
if (remainingRootMotion.y == 0)
remainingRootMotion.y = 0.0001f;
rootMotionScaleX = distanceToTarget.x / remainingRootMotion.x;
rootMotionScaleY = distanceToTarget.y / remainingRootMotion.y;
}
public Vector2 GetAnimationRootMotion (Animation animation) {
return GetAnimationRootMotion(0, animation.duration, animation);
}
public Vector2 GetAnimationRootMotion (float startTime, float endTime,
Animation animation) {
var timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex);
if (timeline != null) {
return GetTimelineMovementDelta(startTime, endTime, timeline, animation);
}
return Vector2.zero;
}
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);
}
}
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;
localDelta.x *= rootMotionScaleX;
localDelta.y *= rootMotionScaleY;
// 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;
}
}
} }
} }

View File

@ -41,6 +41,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[AddComponentMenu("Spine/SkeletonAnimation")] [AddComponentMenu("Spine/SkeletonAnimation")]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonAnimation-Component")]
public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, IAnimationStateComponent { public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, IAnimationStateComponent {
#region IAnimationStateComponent #region IAnimationStateComponent
@ -56,10 +57,17 @@ namespace Spine.Unity {
#endregion #endregion
#region Bone Callbacks ISkeletonAnimation #region Bone Callbacks ISkeletonAnimation
protected event UpdateBonesDelegate _BeforeApply;
protected event UpdateBonesDelegate _UpdateLocal; protected event UpdateBonesDelegate _UpdateLocal;
protected event UpdateBonesDelegate _UpdateWorld; protected event UpdateBonesDelegate _UpdateWorld;
protected event UpdateBonesDelegate _UpdateComplete; protected event UpdateBonesDelegate _UpdateComplete;
/// <summary>
/// Occurs before the animations are applied.
/// Use this callback when you want to change the skeleton state before animations are applied on top.
/// </summary>
public event UpdateBonesDelegate BeforeApply { add { _BeforeApply += value; } remove { _BeforeApply -= value; } }
/// <summary> /// <summary>
/// Occurs after the animations are applied and before world space values are resolved. /// Occurs after the animations are applied and before world space values are resolved.
/// Use this callback when you want to set bone local values. /// Use this callback when you want to set bone local values.
@ -202,6 +210,9 @@ namespace Spine.Unity {
} }
protected void ApplyAnimation () { protected void ApplyAnimation () {
if (_BeforeApply != null)
_BeforeApply(this);
state.Apply(skeleton); state.Apply(skeleton);
if (_UpdateLocal != null) if (_UpdateLocal != null)

View File

@ -43,6 +43,7 @@ namespace Spine.Unity {
#endif #endif
[RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] [RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent]
[AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonGraphic-Component")]
public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, IHasSkeletonDataAsset { public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, IHasSkeletonDataAsset {
#region Inspector #region Inspector
@ -259,6 +260,9 @@ namespace Spine.Unity {
} }
protected void ApplyAnimation () { protected void ApplyAnimation () {
if (BeforeApply != null)
BeforeApply(this);
state.Apply(skeleton); state.Apply(skeleton);
if (UpdateLocal != null) if (UpdateLocal != null)
@ -412,6 +416,7 @@ namespace Spine.Unity {
this.rectTransform.pivot = p; this.rectTransform.pivot = p;
} }
public event UpdateBonesDelegate BeforeApply;
public event UpdateBonesDelegate UpdateLocal; public event UpdateBonesDelegate UpdateLocal;
public event UpdateBonesDelegate UpdateWorld; public event UpdateBonesDelegate UpdateWorld;
public event UpdateBonesDelegate UpdateComplete; public event UpdateBonesDelegate UpdateComplete;

View File

@ -32,6 +32,7 @@ using System.Collections.Generic;
namespace Spine.Unity { namespace Spine.Unity {
[RequireComponent(typeof(Animator))] [RequireComponent(typeof(Animator))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonMecanim-Component")]
public class SkeletonMecanim : SkeletonRenderer, ISkeletonAnimation { public class SkeletonMecanim : SkeletonRenderer, ISkeletonAnimation {
[SerializeField] protected MecanimTranslator translator; [SerializeField] protected MecanimTranslator translator;
@ -39,10 +40,17 @@ namespace Spine.Unity {
private bool wasUpdatedAfterInit = true; private bool wasUpdatedAfterInit = true;
#region Bone Callbacks (ISkeletonAnimation) #region Bone Callbacks (ISkeletonAnimation)
protected event UpdateBonesDelegate _BeforeApply;
protected event UpdateBonesDelegate _UpdateLocal; protected event UpdateBonesDelegate _UpdateLocal;
protected event UpdateBonesDelegate _UpdateWorld; protected event UpdateBonesDelegate _UpdateWorld;
protected event UpdateBonesDelegate _UpdateComplete; protected event UpdateBonesDelegate _UpdateComplete;
/// <summary>
/// Occurs before the animations are applied.
/// Use this callback when you want to change the skeleton state before animations are applied on top.
/// </summary>
public event UpdateBonesDelegate BeforeApply { add { _BeforeApply += value; } remove { _BeforeApply -= value; } }
/// <summary> /// <summary>
/// Occurs after the animations are applied and before world space values are resolved. /// Occurs after the animations are applied and before world space values are resolved.
/// Use this callback when you want to set bone local values.</summary> /// Use this callback when you want to set bone local values.</summary>
@ -86,6 +94,9 @@ namespace Spine.Unity {
} }
protected void ApplyAnimation () { protected void ApplyAnimation () {
if (_BeforeApply != null)
_BeforeApply(this);
#if UNITY_EDITOR #if UNITY_EDITOR
var translatorAnimator = translator.Animator; var translatorAnimator = translator.Animator;
if (translatorAnimator != null && !translatorAnimator.isInitialized) if (translatorAnimator != null && !translatorAnimator.isInitialized)
@ -217,7 +228,7 @@ namespace Spine.Unity {
return false; return false;
var time = AnimationTime(stateInfo.normalizedTime, info.clip.length, var time = AnimationTime(stateInfo.normalizedTime, info.clip.length,
info.clip.isLooping, stateInfo.speed < 0); info.clip.isLooping);
weight = useClipWeight1 ? layerWeight : weight; weight = useClipWeight1 ? layerWeight : weight;
clip.Apply(skeleton, 0, time, info.clip.isLooping, null, clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
weight, layerBlendMode, MixDirection.In); weight, layerBlendMode, MixDirection.In);
@ -241,7 +252,7 @@ namespace Spine.Unity {
return false; return false;
var time = AnimationTime(stateInfo.normalizedTime + interruptingClipTimeAddition, var time = AnimationTime(stateInfo.normalizedTime + interruptingClipTimeAddition,
info.clip.length, stateInfo.speed < 0); info.clip.length);
weight = useClipWeight1 ? layerWeight : weight; weight = useClipWeight1 ? layerWeight : weight;
clip.Apply(skeleton, 0, time, info.clip.isLooping, null, clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
weight, layerBlendMode, MixDirection.In); weight, layerBlendMode, MixDirection.In);
@ -277,7 +288,7 @@ namespace Spine.Unity {
bool isAdditiveLayer = false; bool isAdditiveLayer = false;
if (layer < layerBlendModes.Length) if (layer < layerBlendModes.Length)
isAdditiveLayer = layerBlendModes[layer] == MixBlend.Add; isAdditiveLayer = layerBlendModes[layer] == MixBlend.Add;
layerMixModes[layer] = isAdditiveLayer ? MixMode.MixNext : MixMode.AlwaysMix; layerMixModes[layer] = isAdditiveLayer ? MixMode.AlwaysMix : MixMode.MixNext;
} }
} }
@ -432,17 +443,39 @@ namespace Spine.Unity {
} }
} }
static float AnimationTime (float normalizedTime, float clipLength, bool loop, bool reversed) { public KeyValuePair<Spine.Animation, float> GetActiveAnimationAndTime (int layer) {
float time = AnimationTime(normalizedTime, clipLength, reversed); if (layer >= layerClipInfos.Length)
return new KeyValuePair<Spine.Animation, float>(null, 0);
var layerInfos = layerClipInfos[layer];
bool isInterruptionActive = layerInfos.isInterruptionActive;
AnimationClip clip = null;
Spine.Animation animation = null;
AnimatorStateInfo stateInfo;
if (isInterruptionActive && layerInfos.interruptingClipInfoCount > 0) {
clip = layerInfos.interruptingClipInfos[0].clip;
stateInfo = layerInfos.interruptingStateInfo;
}
else {
clip = layerInfos.clipInfos[0].clip;
stateInfo = layerInfos.stateInfo;
}
animation = GetAnimation(clip);
float time = AnimationTime(stateInfo.normalizedTime, clip.length,
clip.isLooping);
return new KeyValuePair<Animation, float>(animation, time);
}
static float AnimationTime (float normalizedTime, float clipLength, bool loop) {
float time = AnimationTime(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;
} }
static float AnimationTime (float normalizedTime, float clipLength, bool reversed) { static float AnimationTime (float normalizedTime, float clipLength) {
if (reversed) if (normalizedTime < 0.0f)
normalizedTime = (1 - normalizedTime + (int)normalizedTime) + (int)normalizedTime; normalizedTime = (normalizedTime % 1.0f) + 1.0f;
return normalizedTime * clipLength; return normalizedTime * clipLength;
} }

View File

@ -31,6 +31,7 @@ using UnityEngine;
namespace Spine.Unity { namespace Spine.Unity {
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))] [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderSeparator")]
public class SkeletonPartsRenderer : MonoBehaviour { public class SkeletonPartsRenderer : MonoBehaviour {
#region Properties #region Properties
@ -59,6 +60,14 @@ namespace Spine.Unity {
} }
#endregion #endregion
#region Callback Delegates
public delegate void SkeletonPartsRendererDelegate (SkeletonPartsRenderer skeletonPartsRenderer);
/// <summary>OnMeshAndMaterialsUpdated is called at the end of LateUpdate after the Mesh and
/// all materials have been updated.</summary>
public event SkeletonPartsRendererDelegate OnMeshAndMaterialsUpdated;
#endregion
MeshRendererBuffers buffers; MeshRendererBuffers buffers;
SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction(); SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
@ -120,6 +129,9 @@ namespace Spine.Unity {
meshFilter.sharedMesh = mesh; meshFilter.sharedMesh = mesh;
smartMesh.instructionUsed.Set(currentInstructions); smartMesh.instructionUsed.Set(currentInstructions);
if (OnMeshAndMaterialsUpdated != null)
OnMeshAndMaterialsUpdated(this);
} }
public void SetPropertyBlock (MaterialPropertyBlock block) { public void SetPropertyBlock (MaterialPropertyBlock block) {

View File

@ -42,7 +42,7 @@ namespace Spine.Unity {
#else #else
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[HelpURL("http://esotericsoftware.com/spine-unity-skeletonrenderseparator")] [HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderSeparator")]
public class SkeletonRenderSeparator : MonoBehaviour { public class SkeletonRenderSeparator : MonoBehaviour {
public const int DefaultSortingOrderIncrement = 5; public const int DefaultSortingOrderIncrement = 5;
@ -77,6 +77,12 @@ namespace Spine.Unity {
#endif #endif
#endregion #endregion
#region Callback Delegates
/// <summary>OnMeshAndMaterialsUpdated is called at the end of LateUpdate after the Mesh and
/// all materials have been updated.</summary>
public event SkeletonRenderer.SkeletonRendererDelegate OnMeshAndMaterialsUpdated;
#endregion
#region Runtime Instantiation #region Runtime Instantiation
/// <summary>Adds a SkeletonRenderSeparator and child SkeletonPartsRenderer GameObjects to a given SkeletonRenderer.</summary> /// <summary>Adds a SkeletonRenderSeparator and child SkeletonPartsRenderer GameObjects to a given SkeletonRenderer.</summary>
/// <returns>The to skeleton renderer.</returns> /// <returns>The to skeleton renderer.</returns>
@ -247,6 +253,9 @@ namespace Spine.Unity {
} }
} }
if (OnMeshAndMaterialsUpdated != null)
OnMeshAndMaterialsUpdated(this.skeletonRenderer);
// Clear extra renderers if they exist. // Clear extra renderers if they exist.
for (; rendererIndex < rendererCount; rendererIndex++) { for (; rendererIndex < rendererCount; rendererIndex++) {
currentRenderer = partsRenderers[rendererIndex]; currentRenderer = partsRenderers[rendererIndex];

View File

@ -39,6 +39,10 @@
#define BUILT_IN_SPRITE_MASK_COMPONENT #define BUILT_IN_SPRITE_MASK_COMPONENT
#endif #endif
#if UNITY_2019_3_OR_NEWER
#define CONFIGURABLE_ENTER_PLAY_MODE
#endif
#define SPINE_OPTIONAL_RENDEROVERRIDE #define SPINE_OPTIONAL_RENDEROVERRIDE
#define SPINE_OPTIONAL_MATERIALOVERRIDE #define SPINE_OPTIONAL_MATERIALOVERRIDE
@ -53,7 +57,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent]
[HelpURL("http://esotericsoftware.com/spine-unity-rendering")] [HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderer-Component")]
public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, IHasSkeletonDataAsset { public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, IHasSkeletonDataAsset {
public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset skeletonDataAsset;
@ -236,7 +240,7 @@ namespace Spine.Unity {
/// <summary>OnRebuild is raised after the Skeleton is successfully initialized.</summary> /// <summary>OnRebuild is raised after the Skeleton is successfully initialized.</summary>
public event SkeletonRendererDelegate OnRebuild; public event SkeletonRendererDelegate OnRebuild;
/// <summary>OnMeshAndMaterialsUpdated is at the end of LateUpdate after the Mesh and /// <summary>OnMeshAndMaterialsUpdated is called at the end of LateUpdate after the Mesh and
/// all materials have been updated.</summary> /// all materials have been updated.</summary>
public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated; public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated;
@ -276,6 +280,12 @@ namespace Spine.Unity {
Initialize(false); Initialize(false);
} }
#if UNITY_EDITOR && CONFIGURABLE_ENTER_PLAY_MODE
public virtual void Start () {
Initialize(false);
}
#endif
void OnDisable () { void OnDisable () {
if (clearStateOnDisable && valid) if (clearStateOnDisable && valid)
ClearState(); ClearState();

View File

@ -41,6 +41,7 @@ namespace Spine.Unity {
#else #else
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonGraphicCustomMaterials")]
public class SkeletonGraphicCustomMaterials : MonoBehaviour { public class SkeletonGraphicCustomMaterials : MonoBehaviour {
#region Inspector #region Inspector

View File

@ -44,6 +44,7 @@ namespace Spine.Unity {
#else #else
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRendererCustomMaterials")]
public class SkeletonRendererCustomMaterials : MonoBehaviour { public class SkeletonRendererCustomMaterials : MonoBehaviour {
#region Inspector #region Inspector

View File

@ -42,6 +42,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[RequireComponent(typeof(ISkeletonAnimation))] [RequireComponent(typeof(ISkeletonAnimation))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonUtility")]
public sealed class SkeletonUtility : MonoBehaviour { public sealed class SkeletonUtility : MonoBehaviour {
#region BoundingBoxAttachment #region BoundingBoxAttachment

View File

@ -41,6 +41,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[AddComponentMenu("Spine/SkeletonUtilityBone")] [AddComponentMenu("Spine/SkeletonUtilityBone")]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonUtilityBone")]
public class SkeletonUtilityBone : MonoBehaviour { public class SkeletonUtilityBone : MonoBehaviour {
public enum Mode { public enum Mode {
Follow, Follow,

View File

@ -41,6 +41,7 @@ namespace Spine.Unity {
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[RequireComponent(typeof(SkeletonUtilityBone))] [RequireComponent(typeof(SkeletonUtilityBone))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonUtilityConstraint")]
public abstract class SkeletonUtilityConstraint : MonoBehaviour { public abstract class SkeletonUtilityConstraint : MonoBehaviour {
protected SkeletonUtilityBone bone; protected SkeletonUtilityBone bone;

View File

@ -68,6 +68,9 @@ namespace Spine.Unity {
[Header("Vertex Data")] [Header("Vertex Data")]
public bool pmaVertexColors; public bool pmaVertexColors;
public bool tintBlack; public bool tintBlack;
[Tooltip("Enable when using Additive blend mode at SkeletonGraphic under a CanvasGroup. " +
"When enabled, Additive alpha value is stored at uv2.g instead of color.a to capture CanvasGroup modifying color.a.")]
public bool canvasGroupTintBlack;
public bool calculateTangents; public bool calculateTangents;
public bool addNormals; public bool addNormals;
public bool immutableTriangles; public bool immutableTriangles;
@ -493,6 +496,7 @@ namespace Spine.Unity {
#else #else
bool useClipping = settings.useClipping; bool useClipping = settings.useClipping;
#endif #endif
bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
if (useClipping) { if (useClipping) {
if (instruction.preActiveClippingSlotSource >= 0) { if (instruction.preActiveClippingSlotSource >= 0) {
@ -556,12 +560,18 @@ namespace Spine.Unity {
} }
} }
float tintBlackAlpha = 1.0f;
if (pmaVertexColors) { if (pmaVertexColors) {
color.a = (byte)(skeletonA * slot.a * c.a * 255); color.a = (byte)(skeletonA * slot.a * c.a * 255);
color.r = (byte)(skeletonR * slot.r * c.r * color.a); color.r = (byte)(skeletonR * slot.r * c.r * color.a);
color.g = (byte)(skeletonG * slot.g * c.g * color.a); color.g = (byte)(skeletonG * slot.g * c.g * color.a);
color.b = (byte)(skeletonB * slot.b * c.b * color.a); color.b = (byte)(skeletonB * slot.b * c.b * color.a);
if (slot.data.blendMode == BlendMode.Additive) color.a = 0; if (slot.data.blendMode == BlendMode.Additive) {
if (canvasGroupTintBlack)
tintBlackAlpha = 0;
else
color.a = 0;
}
} else { } else {
color.a = (byte)(skeletonA * slot.a * c.a * 255); color.a = (byte)(skeletonA * slot.a * c.a * 255);
color.r = (byte)(skeletonR * slot.r * c.r * 255); color.r = (byte)(skeletonR * slot.r * c.r * 255);
@ -590,7 +600,7 @@ namespace Spine.Unity {
g2 *= alpha; g2 *= alpha;
b2 *= alpha; b2 *= alpha;
} }
AddAttachmentTintBlack(r2, g2, b2, attachmentVertexCount); AddAttachmentTintBlack(r2, g2, b2, tintBlackAlpha, attachmentVertexCount);
} }
//AddAttachment(workingVerts, uvs, color, attachmentTriangleIndices, attachmentVertexCount, attachmentIndexCount, ref meshBoundsMin, ref meshBoundsMax, z); //AddAttachment(workingVerts, uvs, color, attachmentTriangleIndices, attachmentVertexCount, attachmentIndexCount, ref meshBoundsMin, ref meshBoundsMax, z);
@ -694,6 +704,7 @@ namespace Spine.Unity {
// Use this faster method when no clipping is involved. // Use this faster method when no clipping is involved.
public void BuildMeshWithArrays (SkeletonRendererInstruction instruction, bool updateTriangles) { public void BuildMeshWithArrays (SkeletonRendererInstruction instruction, bool updateTriangles) {
var settings = this.settings; var settings = this.settings;
bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
int totalVertexCount = instruction.rawVertexCount; int totalVertexCount = instruction.rawVertexCount;
// Add data to vertex buffers // Add data to vertex buffers
@ -758,6 +769,7 @@ namespace Spine.Unity {
rg.x = slot.r2; //r rg.x = slot.r2; //r
rg.y = slot.g2; //g rg.y = slot.g2; //g
b2.x = slot.b2; //b b2.x = slot.b2; //b
b2.y = 1.0f;
var regionAttachment = attachment as RegionAttachment; var regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) { if (regionAttachment != null) {
@ -766,6 +778,7 @@ namespace Spine.Unity {
rg.x *= alpha; rg.x *= alpha;
rg.y *= alpha; rg.y *= alpha;
b2.x *= alpha; b2.x *= alpha;
b2.y = slot.data.blendMode == BlendMode.Additive ? 0 : alpha;
} }
uv2i[vi] = rg; uv2i[vi + 1] = rg; uv2i[vi + 2] = rg; uv2i[vi + 3] = rg; uv2i[vi] = rg; uv2i[vi + 1] = rg; uv2i[vi + 2] = rg; uv2i[vi + 3] = rg;
uv3i[vi] = b2; uv3i[vi + 1] = b2; uv3i[vi + 2] = b2; uv3i[vi + 3] = b2; uv3i[vi] = b2; uv3i[vi + 1] = b2; uv3i[vi + 2] = b2; uv3i[vi + 3] = b2;
@ -778,6 +791,7 @@ namespace Spine.Unity {
rg.x *= alpha; rg.x *= alpha;
rg.y *= alpha; rg.y *= alpha;
b2.x *= alpha; b2.x *= alpha;
b2.y = slot.data.blendMode == BlendMode.Additive ? 0 : alpha;
} }
int meshVertexCount = meshAttachment.worldVerticesLength; int meshVertexCount = meshAttachment.worldVerticesLength;
for (int iii = 0; iii < meshVertexCount; iii += 2) { for (int iii = 0; iii < meshVertexCount; iii += 2) {
@ -814,7 +828,7 @@ namespace Spine.Unity {
color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a);
color.b = (byte)(b * slot.b * regionAttachment.b * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a);
if (slot.data.blendMode == BlendMode.Additive) color.a = 0; if (slot.data.blendMode == BlendMode.Additive && !canvasGroupTintBlack) color.a = 0;
} else { } else {
color.a = (byte)(a * slot.a * regionAttachment.a * 255); color.a = (byte)(a * slot.a * regionAttachment.a * 255);
color.r = (byte)(r * slot.r * regionAttachment.r * 255); color.r = (byte)(r * slot.r * regionAttachment.r * 255);
@ -861,7 +875,7 @@ namespace Spine.Unity {
color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
color.b = (byte)(b * slot.b * meshAttachment.b * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
if (slot.data.blendMode == BlendMode.Additive) color.a = 0; if (slot.data.blendMode == BlendMode.Additive && !canvasGroupTintBlack) color.a = 0;
} else { } else {
color.a = (byte)(a * slot.a * meshAttachment.a * 255); color.a = (byte)(a * slot.a * meshAttachment.a * 255);
color.r = (byte)(r * slot.r * meshAttachment.r * 255); color.r = (byte)(r * slot.r * meshAttachment.r * 255);
@ -985,9 +999,9 @@ namespace Spine.Unity {
meshBoundsThickness *= scale; meshBoundsThickness *= scale;
} }
void AddAttachmentTintBlack (float r2, float g2, float b2, int vertexCount) { void AddAttachmentTintBlack (float r2, float g2, float b2, float a, int vertexCount) {
var rg = new Vector2(r2, g2); var rg = new Vector2(r2, g2);
var bo = new Vector2(b2, 1f); var bo = new Vector2(b2, a);
int ovc = vertexBuffer.Count; int ovc = vertexBuffer.Count;
int newVertexCount = ovc + vertexCount; int newVertexCount = ovc + vertexCount;

View File

@ -0,0 +1,41 @@
#ifndef SPRITES_DEPTH_ONLY_PASS_INCLUDED
#define SPRITES_DEPTH_ONLY_PASS_INCLUDED
#include "UnityCG.cginc"
sampler2D _MainTex;
float _Cutoff;
float _ZWriteOffset;
struct VertexInput {
float4 positionOS : POSITION;
float2 texcoord : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 positionCS : SV_POSITION;
float4 texcoordAndAlpha: TEXCOORD0;
};
VertexOutput DepthOnlyVertex (VertexInput v) {
VertexOutput o;
o.positionCS = UnityObjectToClipPos(v.positionOS - float4(0, 0, _ZWriteOffset, 0));
o.texcoordAndAlpha.xy = v.texcoord;
o.texcoordAndAlpha.z = 0;
o.texcoordAndAlpha.a = v.vertexColor.a;
return o;
}
float4 DepthOnlyFragment (VertexOutput input) : SV_Target{
float4 texColor = tex2D(_MainTex, input.texcoordAndAlpha.rg);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
clip(texColor.a * input.texcoordAndAlpha.a - _Cutoff);
return 0;
}
#endif

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 27351ce55d3beb643ae8d9385db21941
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
#ifndef SKELETON_TINT_COMMON_INCLUDED
#define SKELETON_TINT_COMMON_INCLUDED
float4 fragTintedColor(float4 texColor, float3 darkTintColor, float4 lightTintColorPMA, float lightColorAlpha, float darkColorAlpha) {
float a = texColor.a * lightTintColorPMA.a;
#if !defined(_STRAIGHT_ALPHA_INPUT)
float3 texDarkColor = (texColor.a - texColor.rgb);
#else
float3 texDarkColor = (1 - texColor.rgb);
#endif
float3 darkColor = texDarkColor * darkTintColor.rgb * lightColorAlpha;
float3 lightColor = texColor.rgb * lightTintColorPMA.rgb;
float4 fragColor = float4(darkColor + lightColor, a);
#if defined(_STRAIGHT_ALPHA_INPUT)
fragColor.rgb *= texColor.a;
#endif
#if defined(_DARK_COLOR_ALPHA_ADDITIVE)
fragColor.a = a * (1 - darkColorAlpha);
#endif
return fragColor;
}
#endif

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: cc9439c8e75fb7e4c82ad725b649b047
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,62 @@
Shader "Spine/Outline/OutlineOnly-ZWrite" {
Properties {
_Cutoff ("Depth alpha cutoff", Range(0,1)) = 0.1
_ZWriteOffset ("Depth offset", Range(0,1)) = 0.01
[NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
Fog { Mode Off }
Cull Off
ZWrite Off
Blend One OneMinusSrcAlpha
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}
Pass
{
Name "DepthOnly"
ZWrite On
ColorMask 0
Cull Off
CGPROGRAM
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
#include "../CGIncludes/Spine-DepthOnlyPass.cginc"
ENDCG
}
Pass {
Name "Outline"
CGPROGRAM
#pragma vertex vertOutline
#pragma fragment fragOutline
#pragma shader_feature _ _USE8NEIGHBOURHOOD_ON
#include "CGIncludes/Spine-Outline-Pass.cginc"
ENDCG
}
}
FallBack "Spine/Skeleton"
CustomEditor "SpineShaderWithOutlineGUI"
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 177da18c3d2e0aa4cb39990ea011973c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -8,8 +8,9 @@ Shader "Spine/SkeletonGraphic Tint Black"
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
[Toggle(_CANVAS_GROUP_COMPATIBLE)] _CanvasGroupCompatible("CanvasGroup Compatible", Int) = 1 [Toggle(_CANVAS_GROUP_COMPATIBLE)] _CanvasGroupCompatible("CanvasGroup Compatible", Int) = 1
_Color ("Tint", Color) = (1,1,1,1) _Color ("Tint Color", Color) = (1,1,1,1)
_Black ("Black Point", Color) = (0,0,0,0) _Black ("Dark Color", Color) = (0,0,0,0)
[Toggle(_DARK_COLOR_ALPHA_ADDITIVE)] _DarkColorAlphaAdditive("Additive DarkColor.A", Int) = 0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Stencil Comparison", Float) = 8 [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Stencil Comparison", Float) = 8
[HideInInspector] _Stencil ("Stencil ID", Float) = 0 [HideInInspector] _Stencil ("Stencil ID", Float) = 0
@ -66,6 +67,7 @@ Shader "Spine/SkeletonGraphic Tint Black"
CGPROGRAM CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _CANVAS_GROUP_COMPATIBLE #pragma shader_feature _ _CANVAS_GROUP_COMPATIBLE
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert #pragma vertex vert
#pragma fragment frag #pragma fragment frag
@ -87,9 +89,8 @@ Shader "Spine/SkeletonGraphic Tint Black"
float4 vertex : SV_POSITION; float4 vertex : SV_POSITION;
fixed4 color : COLOR; fixed4 color : COLOR;
half2 texcoord : TEXCOORD0; half2 texcoord : TEXCOORD0;
float2 uv1 : TEXCOORD1; float4 darkColor : TEXCOORD1;
float2 uv2 : TEXCOORD2; float4 worldPosition : TEXCOORD2;
float4 worldPosition : TEXCOORD3;
UNITY_VERTEX_OUTPUT_STEREO UNITY_VERTEX_OUTPUT_STEREO
}; };
@ -108,34 +109,37 @@ Shader "Spine/SkeletonGraphic Tint Black"
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord; OUT.texcoord = IN.texcoord;
OUT.color = IN.color * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor. OUT.color = IN.color;
OUT.uv1 = IN.uv1; OUT.darkColor = float4(IN.uv1.r, IN.uv1.g, IN.uv2.r, IN.uv2.g);
OUT.uv2 = IN.uv2;
return OUT; return OUT;
} }
sampler2D _MainTex; sampler2D _MainTex;
#include "../CGIncludes/Spine-Skeleton-Tint-Common.cginc"
fixed4 frag (VertexOutput IN) : SV_Target fixed4 frag (VertexOutput IN) : SV_Target
{ {
half4 texColor = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd); half4 texColor = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
texColor *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); texColor *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP #ifdef UNITY_UI_ALPHACLIP
clip (texColor.a - 0.001); clip(texColor.a - 0.001);
#endif #endif
half4 color = (texColor * IN.color) + float4(((1-texColor.rgb) * (_Black.rgb + float3(IN.uv1.r, IN.uv1.g, IN.uv2.r)) * texColor.a * _Color.a * IN.color.a), 0); float4 vertexColor = IN.color * float4(_Color.rgb * _Color.a, _Color.a);
#ifdef _CANVAS_GROUP_COMPATIBLE #ifdef _CANVAS_GROUP_COMPATIBLE
// CanvasGroup alpha sets vertex color alpha, but does not premultiply it to rgb components. // CanvasGroup alpha multiplies existing vertex color alpha, but
color.rgb *= IN.color.a; // does not premultiply it to rgb components. This causes problems
#endif // with additive blending (alpha = 0), which is why we store the
return color; // alpha value in uv2.g (darkColor.a).
float originalAlpha = IN.darkColor.a;
float canvasAlpha = (originalAlpha == 0) ? IN.color.a : IN.color.a / originalAlpha;
vertexColor.a = originalAlpha * _Color.a;
#endif
float4 fragColor = fragTintedColor(texColor, _Black.rgb + IN.darkColor, vertexColor, _Color.a, _Black.a);
#ifdef _CANVAS_GROUP_COMPATIBLE
fragColor.rgba *= canvasAlpha;
#endif
return fragColor;
} }
ENDCG ENDCG
} }

View File

@ -7,10 +7,11 @@
Shader "Spine/Skeleton Tint" { Shader "Spine/Skeleton Tint" {
Properties { Properties {
_Color ("Tint Color", Color) = (1,1,1,1) _Color ("Tint Color", Color) = (1,1,1,1)
_Black ("Black Point", Color) = (0,0,0,0) _Black ("Dark Color", Color) = (0,0,0,0)
[NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_Cutoff("Shadow alpha cutoff", Range(0,1)) = 0.1 _Cutoff("Shadow alpha cutoff", Range(0,1)) = 0.1
[Toggle(_DARK_COLOR_ALPHA_ADDITIVE)] _DarkColorAlphaAdditive("Additive DarkColor.A", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
@ -44,6 +45,7 @@ Shader "Spine/Skeleton Tint" {
CGPROGRAM CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert #pragma vertex vert
#pragma fragment frag #pragma fragment frag
#include "UnityCG.cginc" #include "UnityCG.cginc"
@ -71,14 +73,11 @@ Shader "Spine/Skeleton Tint" {
return o; return o;
} }
#include "CGIncludes/Spine-Skeleton-Tint-Common.cginc"
float4 frag (VertexOutput i) : SV_Target { float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv); float4 texColor = tex2D(_MainTex, i.uv);
return fragTintedColor(texColor, _Black.rgb, i.vertexColor, _Color.a, _Black.a);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor) + float4(((1-texColor.rgb) * _Black.rgb * texColor.a*_Color.a*i.vertexColor.a), 0);
} }
ENDCG ENDCG
} }

View File

@ -9,10 +9,11 @@
Shader "Spine/Skeleton Tint Black" { Shader "Spine/Skeleton Tint Black" {
Properties { Properties {
_Color ("Tint Color", Color) = (1,1,1,1) _Color ("Tint Color", Color) = (1,1,1,1)
_Black ("Black Point", Color) = (0,0,0,0) _Black ("Dark Color", Color) = (0,0,0,0)
[NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {} [NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
[Toggle(_DARK_COLOR_ALPHA_ADDITIVE)] _DarkColorAlphaAdditive("Additive DarkColor.A", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
@ -47,6 +48,7 @@ Shader "Spine/Skeleton Tint Black" {
CGPROGRAM CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert #pragma vertex vert
#pragma fragment frag #pragma fragment frag
#include "UnityCG.cginc" #include "UnityCG.cginc"
@ -65,8 +67,7 @@ Shader "Spine/Skeleton Tint Black" {
struct VertexOutput { struct VertexOutput {
float4 pos : SV_POSITION; float4 pos : SV_POSITION;
float2 uv : TEXCOORD0; float2 uv : TEXCOORD0;
float2 uv1 : TEXCOORD1; float3 darkColor : TEXCOORD1;
float2 uv2 : TEXCOORD2;
float4 vertexColor : COLOR; float4 vertexColor : COLOR;
}; };
@ -75,19 +76,15 @@ Shader "Spine/Skeleton Tint Black" {
o.pos = UnityObjectToClipPos(v.vertex); // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' o.pos = UnityObjectToClipPos(v.vertex); // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
o.uv = v.uv; o.uv = v.uv;
o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor. o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
o.uv1 = v.uv1; o.darkColor = float3(v.uv1.r, v.uv1.g, v.uv2.r);
o.uv2 = v.uv2;
return o; return o;
} }
#include "CGIncludes/Spine-Skeleton-Tint-Common.cginc"
float4 frag (VertexOutput i) : SV_Target { float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv); float4 texColor = tex2D(_MainTex, i.uv);
return fragTintedColor(texColor, _Black.rgb + i.darkColor, i.vertexColor, _Color.a, _Black.a);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor) + float4(((1-texColor.rgb) * (_Black.rgb + float3(i.uv1.r, i.uv1.g, i.uv2.r)) * texColor.a*_Color.a), 0);
} }
ENDCG ENDCG
} }

View File

@ -2,7 +2,7 @@
#define SHADER_MATHS_INCLUDED #define SHADER_MATHS_INCLUDED
#if defined(USE_LWRP) #if defined(USE_LWRP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl"
#elif defined(USE_URP) #elif defined(USE_URP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#else #else

View File

@ -4,7 +4,7 @@
#define SHADER_SHARED_INCLUDED #define SHADER_SHARED_INCLUDED
#if defined(USE_LWRP) #if defined(USE_LWRP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl"
#elif defined(USE_URP) #elif defined(USE_URP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#else #else

View File

@ -39,24 +39,58 @@ namespace Spine.Unity {
static readonly int STRAIGHT_ALPHA_PARAM_ID = Shader.PropertyToID("_StraightAlphaInput"); static readonly int STRAIGHT_ALPHA_PARAM_ID = Shader.PropertyToID("_StraightAlphaInput");
static readonly string ALPHAPREMULTIPLY_ON_KEYWORD = "_ALPHAPREMULTIPLY_ON"; static readonly string ALPHAPREMULTIPLY_ON_KEYWORD = "_ALPHAPREMULTIPLY_ON";
static readonly string STRAIGHT_ALPHA_KEYWORD = "_STRAIGHT_ALPHA_INPUT"; static readonly string STRAIGHT_ALPHA_KEYWORD = "_STRAIGHT_ALPHA_INPUT";
static readonly string[] FIXED_NORMALS_KEYWORDS = {
"_FIXED_NORMALS_VIEWSPACE",
"_FIXED_NORMALS_VIEWSPACE_BACKFACE",
"_FIXED_NORMALS_MODELSPACE",
"_FIXED_NORMALS_MODELSPACE_BACKFACE",
"_FIXED_NORMALS_WORLDSPACE"
};
static readonly string NORMALMAP_KEYWORD = "_NORMALMAP";
static readonly string CANVAS_GROUP_COMPATIBLE_KEYWORD = "_CANVAS_GROUP_COMPATIBLE";
public static readonly string kPMANotSupportedLinearMessage = public static readonly string kPMANotSupportedLinearMessage =
"Warning: Premultiply-alpha atlas textures not supported in Linear color space!\n\nPlease\n" "\nWarning: Premultiply-alpha atlas textures not supported in Linear color space!\n\nPlease\n"
+ "a) re-export atlas as straight alpha texture with 'premultiply alpha' unchecked\n" + "a) re-export atlas as straight alpha texture with 'premultiply alpha' unchecked\n"
+ " (if you have already done this, please set the 'Straight Alpha Texture' Material parameter to 'true') or\n" + " (if you have already done this, please set the 'Straight Alpha Texture' Material parameter to 'true') or\n"
+ "b) switch to Gamma color space via\nProject Settings - Player - Other Settings - Color Space.\n"; + "b) switch to Gamma color space via\nProject Settings - Player - Other Settings - Color Space.\n";
public static readonly string kZSpacingRequiredMessage = public static readonly string kZSpacingRequiredMessage =
"Warning: Z Spacing required on selected shader! Otherwise you will receive incorrect results.\n\nPlease\n" "\nWarning: Z Spacing required on selected shader! Otherwise you will receive incorrect results.\n\nPlease\n"
+ "1) make sure at least minimal 'Z Spacing' is set at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' and\n" + "1) make sure at least minimal 'Z Spacing' is set at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' and\n"
+ "2) ensure that the skeleton has overlapping parts on different Z depth. You can adjust this in Spine via draw order.\n"; + "2) ensure that the skeleton has overlapping parts on different Z depth. You can adjust this in Spine via draw order.\n";
public static readonly string kZSpacingRecommendedMessage = public static readonly string kZSpacingRecommendedMessage =
"Warning: Z Spacing recommended on selected shader configuration!\n\nPlease\n" "\nWarning: Z Spacing recommended on selected shader configuration!\n\nPlease\n"
+ "1) make sure at least minimal 'Z Spacing' is set at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' and\n" + "1) make sure at least minimal 'Z Spacing' is set at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' and\n"
+ "2) ensure that the skeleton has overlapping parts on different Z depth. You can adjust this in Spine via draw order.\n"; + "2) ensure that the skeleton has overlapping parts on different Z depth. You can adjust this in Spine via draw order.\n";
public static readonly string kAddNormalsRequiredMessage = public static readonly string kAddNormalsMessage =
"Warning: 'Add Normals' required on URP shader to receive shadows!\n\nPlease\n" "\nWarning: 'Add Normals' required when not using 'Fixed Normals'!\n\nPlease\n"
+ "a) enable 'Add Normals' at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' or\n" + "a) enable 'Add Normals' at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' or\n"
+ "b) disable 'Receive Shadows' at the Material."; + "b) enable 'Fixed Normals' at the Material.\n";
public static readonly string kAddNormalsRequiredForURPShadowsMessage =
"\nWarning: 'Add Normals' required on URP shader to receive shadows!\n\nPlease\n"
+ "a) enable 'Add Normals' at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' or\n"
+ "b) disable 'Receive Shadows' at the Material.\n";
public static readonly string kSolveTangentsMessage =
"\nWarning: 'Solve Tangents' required when using a Normal Map!\n\nPlease\n"
+ "a) enable 'Solve Tangents' at the SkeletonRenderer/SkeletonAnimation component under 'Advanced' or\n"
+ "b) clear the 'Normal Map' parameter at the Material.\n";
public static readonly string kNoSkeletonGraphicMaterialMessage =
"\nWarning: Normal non-UI shaders other than 'Spine/SkeletonGraphic *' are not compatible with 'SkeletonGraphic' components! "
+ "This will lead to incorrect rendering on some devices.\n\n"
+ "Please change the assigned Material to e.g. 'SkeletonGraphicDefault' or change the used shader to one of the 'Spine/SkeletonGraphic *' shaders.\n\n"
+ "Note that 'Spine/SkeletonGraphic *' shall still be used when using URP.\n";
public static readonly string kTintBlackMessage =
"\nWarning: 'Advanced - Tint Black' required when using any 'Tint Black' shader!\n\nPlease\n"
+ "a) enable 'Tint Black' at the SkeletonRenderer/SkeletonGraphic component under 'Advanced' or\n"
+ "b) use a different shader at the Material.\n";
public static readonly string kCanvasTintBlackMessage =
"\nWarning: Canvas 'Additional Shader Channels' 'uv1' and 'uv2' are required when 'Advanced - Tint Black' is enabled!\n\n"
+ "Please enable both 'uv1' and 'uv2' channels at the parent Canvas component parameter 'Additional Shader Channels'.\n";
public static readonly string kCanvasGroupCompatibleMessage =
"\nWarning: 'Canvas Group Tint Black' is enabled at SkeletonGraphic but not 'CanvasGroup Compatible' at the Material!\n\nPlease\n"
+ "a) enable 'CanvasGroup Compatible' at the Material or\n"
+ "b) disable 'Canvas Group Tint Black' at the SkeletonGraphic component under 'Advanced'.\n"
+ "You may want to duplicate the 'SkeletonGraphicDefault' material and change settings at the duplicate to not affect all instances.";
public static bool IsMaterialSetupProblematic (SkeletonRenderer renderer, ref string errorMessage) { public static bool IsMaterialSetupProblematic (SkeletonRenderer renderer, ref string errorMessage) {
var materials = renderer.GetComponent<Renderer>().sharedMaterials; var materials = renderer.GetComponent<Renderer>().sharedMaterials;
@ -67,9 +101,51 @@ namespace Spine.Unity {
if (renderer.zSpacing == 0) { if (renderer.zSpacing == 0) {
isProblematic |= IsZSpacingRequired(material, ref errorMessage); isProblematic |= IsZSpacingRequired(material, ref errorMessage);
} }
if (IsURPMaterial(material) && !AreShadowsDisabled(material) && renderer.addNormals == false) { if (renderer.addNormals == false && RequiresMeshNormals(material)) {
isProblematic = true; isProblematic = true;
errorMessage += kAddNormalsRequiredMessage; errorMessage += kAddNormalsMessage;
}
if (renderer.calculateTangents == false && RequiresTangents(material)) {
isProblematic = true;
errorMessage += kSolveTangentsMessage;
}
if (renderer.tintBlack == false && RequiresTintBlack(material)) {
isProblematic = true;
errorMessage += kTintBlackMessage;
}
if (IsURP3DMaterial(material) && !AreShadowsDisabled(material) && renderer.addNormals == false) {
isProblematic = true;
errorMessage += kAddNormalsRequiredForURPShadowsMessage;
}
}
return isProblematic;
}
public static bool IsMaterialSetupProblematic(SkeletonGraphic skeletonGraphic, ref string errorMessage)
{
var material = skeletonGraphic.material;
bool isProblematic = false;
if (material) {
isProblematic |= IsMaterialSetupProblematic(material, ref errorMessage);
var settings = skeletonGraphic.MeshGenerator.settings;
if (settings.zSpacing == 0) {
isProblematic |= IsZSpacingRequired(material, ref errorMessage);
}
if (IsSpineNonSkeletonGraphicMaterial(material)) {
isProblematic = true;
errorMessage += kNoSkeletonGraphicMaterialMessage;
}
if (settings.tintBlack == false && RequiresTintBlack(material)) {
isProblematic = true;
errorMessage += kTintBlackMessage;
}
if (settings.tintBlack == true && CanvasNotSetupForTintBlack(skeletonGraphic)) {
isProblematic = true;
errorMessage += kCanvasTintBlackMessage;
}
if (settings.canvasGroupTintBlack == true && !IsCanvasGroupCompatible(material)) {
isProblematic = true;
errorMessage += kCanvasGroupCompatibleMessage;
} }
} }
return isProblematic; return isProblematic;
@ -177,13 +253,57 @@ namespace Spine.Unity {
material.IsKeywordEnabled(ALPHAPREMULTIPLY_ON_KEYWORD); material.IsKeywordEnabled(ALPHAPREMULTIPLY_ON_KEYWORD);
} }
static bool IsURPMaterial (Material material) { static bool IsURP3DMaterial (Material material) {
return material.shader.name.Contains("Universal Render Pipeline"); return material.shader.name.Contains("Universal Render Pipeline/Spine");
}
static bool IsSpineNonSkeletonGraphicMaterial (Material material) {
return material.shader.name.Contains("Spine") && !material.shader.name.Contains("SkeletonGraphic");
} }
static bool AreShadowsDisabled (Material material) { static bool AreShadowsDisabled (Material material) {
return material.IsKeywordEnabled("_RECEIVE_SHADOWS_OFF"); return material.IsKeywordEnabled("_RECEIVE_SHADOWS_OFF");
} }
static bool RequiresMeshNormals (Material material) {
bool anyFixedNormalSet = false;
foreach (string fixedNormalKeyword in FIXED_NORMALS_KEYWORDS) {
if (material.IsKeywordEnabled(fixedNormalKeyword)) {
anyFixedNormalSet = true;
break;
}
}
bool isShaderWithMeshNormals =
material.shader.name.Contains("Spine/Sprite/Pixel Lit") ||
material.shader.name.Contains("Spine/Sprite/Vertex Lit") ||
material.shader.name.Contains("2D/Spine/Sprite") || // covers both URP and LWRP
material.shader.name.Contains("Pipeline/Spine/Sprite"); // covers both URP and LWRP
return isShaderWithMeshNormals && !anyFixedNormalSet;
}
static bool RequiresTintBlack (Material material) {
bool isTintBlackShader =
material.shader.name.Contains("Spine") &&
material.shader.name.Contains("Tint Black");
return isTintBlackShader;
}
static bool RequiresTangents (Material material) {
return material.IsKeywordEnabled(NORMALMAP_KEYWORD);
}
static bool IsCanvasGroupCompatible (Material material) {
return material.IsKeywordEnabled(CANVAS_GROUP_COMPATIBLE_KEYWORD);
}
static bool CanvasNotSetupForTintBlack (SkeletonGraphic skeletonGraphic) {
Canvas canvas = skeletonGraphic.canvas;
if (!canvas)
return false;
var requiredChannels =
AdditionalCanvasShaderChannels.TexCoord1 |
AdditionalCanvasShaderChannels.TexCoord2;
return (canvas.additionalShaderChannels & requiredChannels) != requiredChannels;
}
} }
} }

View File

@ -38,7 +38,7 @@ using Spine.Unity.Editor;
public class SpineAnimationStateDrawer : PropertyDrawer { public class SpineAnimationStateDrawer : PropertyDrawer {
public override float GetPropertyHeight (SerializedProperty property, GUIContent label) { public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
const int fieldCount = 10; const int fieldCount = 11;
return fieldCount * EditorGUIUtility.singleLineHeight; return fieldCount * EditorGUIUtility.singleLineHeight;
} }
@ -49,6 +49,7 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
SerializedProperty customDurationProp = property.FindPropertyRelative("customDuration"); SerializedProperty customDurationProp = property.FindPropertyRelative("customDuration");
SerializedProperty useBlendDurationProp = property.FindPropertyRelative("useBlendDuration"); SerializedProperty useBlendDurationProp = property.FindPropertyRelative("useBlendDuration");
SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration"); SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration");
SerializedProperty holdPreviousProp = property.FindPropertyRelative("holdPrevious");
SerializedProperty eventProp = property.FindPropertyRelative("eventThreshold"); SerializedProperty eventProp = property.FindPropertyRelative("eventThreshold");
SerializedProperty attachmentProp = property.FindPropertyRelative("attachmentThreshold"); SerializedProperty attachmentProp = property.FindPropertyRelative("attachmentThreshold");
SerializedProperty drawOrderProp = property.FindPropertyRelative("drawOrderThreshold"); SerializedProperty drawOrderProp = property.FindPropertyRelative("drawOrderThreshold");
@ -87,6 +88,9 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
EditorGUI.PropertyField(singleFieldRect, mixDurationProp); EditorGUI.PropertyField(singleFieldRect, mixDurationProp);
} }
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, holdPreviousProp);
singleFieldRect.y += lineHeightWithSpacing; singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, eventProp); EditorGUI.PropertyField(singleFieldRect, eventProp);

View File

@ -48,8 +48,11 @@ namespace Spine.Unity.Playables {
public bool customDuration = false; public bool customDuration = false;
public bool useBlendDuration = true; public bool useBlendDuration = true;
[SerializeField] [SerializeField]
#pragma warning disable 414
private bool isInitialized = false; // required to read preferences values from editor side. private bool isInitialized = false; // required to read preferences values from editor side.
#pragma warning restore 414
public float mixDuration = 0.1f; public float mixDuration = 0.1f;
public bool holdPrevious = false;
[Range(0, 1f)] [Range(0, 1f)]
public float attachmentThreshold = 0.5f; public float attachmentThreshold = 0.5f;

View File

@ -94,6 +94,7 @@ namespace Spine.Unity.Playables {
trackEntry.TrackTime = (float)inputPlayable.GetTime() * (float)inputPlayable.GetSpeed(); trackEntry.TrackTime = (float)inputPlayable.GetTime() * (float)inputPlayable.GetSpeed();
trackEntry.TimeScale = (float)inputPlayable.GetSpeed(); trackEntry.TimeScale = (float)inputPlayable.GetSpeed();
trackEntry.AttachmentThreshold = clipData.attachmentThreshold; trackEntry.AttachmentThreshold = clipData.attachmentThreshold;
trackEntry.HoldPrevious = clipData.holdPrevious;
if (clipData.customDuration) if (clipData.customDuration)
trackEntry.MixDuration = clipData.mixDuration; trackEntry.MixDuration = clipData.mixDuration;
@ -182,8 +183,10 @@ namespace Spine.Unity.Playables {
dummyAnimationState.ClearTracks(); dummyAnimationState.ClearTracks();
fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop); fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop);
fromTrack.AllowImmediateQueue(); fromTrack.AllowImmediateQueue();
if (toAnimation != null) if (toAnimation != null) {
toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop); toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop);
toTrack.HoldPrevious = clipData.holdPrevious;
}
} }
// Update track times. // Update track times.

View File

@ -104,7 +104,7 @@ half4 CombinedShapeLightFragment(VertexOutputSpriteURP2D input) : SV_Target
#endif #endif
APPLY_EMISSION(pixel.rgb, input.texcoord) APPLY_EMISSION(pixel.rgb, input.texcoord)
pixel = prepareLitPixelForOutput(pixel, input.vertexColor);
COLORISE(pixel) COLORISE(pixel)
return pixel; return pixel;
} }

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