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

View File

@ -60,22 +60,8 @@ void SkeletonBatch::destroyInstance () {
SkeletonBatch::SkeletonBatch () {
auto program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR);
_programState = std::make_shared<backend::ProgramState>(program);
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");
_programState = new backend::ProgramState(program); // new default program state
updateProgramStateLayout(_programState);
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(createNewTrianglesCommand());
}
@ -95,6 +81,25 @@ SkeletonBatch::~SkeletonBatch () {
delete _commandsPool[i];
_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) {
@ -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();
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto programState = command->getPipelineDescriptor().programState;
if (programState == nullptr)
programState = _programState;
CCASSERT(programState, "programState should not be null");
programState->setUniform(_locMVP, projectionMat.m, sizeof(projectionMat.m));
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);
renderer->addCommand(command);
@ -177,12 +194,6 @@ cocos2d::TrianglesCommand* SkeletonBatch::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;
}

View File

@ -35,6 +35,7 @@
#include <spine/spine.h>
#include <vector>
#include "renderer/backend/ProgramState.h"
namespace spine {
@ -50,7 +51,9 @@ namespace spine {
void deallocateVertices(uint32_t numVertices);
unsigned short* allocateIndices(uint32_t numIndices);
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:
SkeletonBatch ();
@ -61,7 +64,9 @@ namespace spine {
cocos2d::TrianglesCommand* nextFreeCommand ();
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 _locTexture;

View File

@ -99,16 +99,7 @@ namespace {
backend::UniformLocation __locPMatrix;
backend::UniformLocation __locTexture;
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->autorelease();
static void updateProgramStateLayout(backend::ProgramState* programState) {
__locPMatrix = programState->getUniformLocation("u_PMatrix");
__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_texCoords", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false);
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);
}
@ -136,9 +140,9 @@ TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _texture(n
_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);
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)
{
initTwoColorProgramState();
}
CC_SAFE_RELEASE_NULL(_programState);
bool needsUpdateStateLayout = false;
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;
_locTexture = __locTexture;
_pipelineDescriptor.programState = _programState;
}
TwoColorTrianglesCommand::~TwoColorTrianglesCommand()
@ -330,9 +355,9 @@ void SkeletonTwoColorBatch::deallocateIndices(uint32_t numIndices) {
_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();
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);
renderer->addCommand(command);
return command;

View File

@ -35,6 +35,7 @@
#include <spine/spine.h>
#include <vector>
#include "renderer/backend/ProgramState.h"
namespace spine {
struct V3F_C4B_C4B_T2F {
@ -57,9 +58,9 @@ namespace spine {
~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; }
@ -118,7 +119,7 @@ namespace spine {
unsigned short* allocateIndices(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);

View File

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

View File

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

View File

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

View File

@ -610,8 +610,9 @@ void test (SkeletonData* skeletonData, Atlas* atlas) {
}
}
DebugExtension dbgExtension(SpineExtension::getInstance());
int main () {
DebugExtension dbgExtension(SpineExtension::getInstance());
SpineExtension::setInstance(&dbgExtension);
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;
loadText(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;
private updateClientAssets;
isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
}
declare module spine {
abstract class Texture {
protected _image: HTMLImageElement;
constructor(image: HTMLImageElement);
getImage(): HTMLImageElement;
protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void;
@ -1400,7 +1400,7 @@ declare module spine.webgl {
private boundUnit;
private useMipMaps;
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;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
@ -1786,7 +1786,7 @@ declare module spine.webgl {
canvas: HTMLCanvasElement | OffscreenCanvas;
gl: WebGLRenderingContext;
private restorables;
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, contextConfig?: any);
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
addRestorable(restorable: Restorable): void;
removeRestorable(restorable: Restorable): void;
}

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];
@ -11000,7 +11032,7 @@ var spine;
var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) {
if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas_1 = canvasOrContext;
this.gl = (canvas_1.getContext("webgl2", contextConfig) || canvas_1.getContext("webgl", contextConfig));
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;
loadText(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;
private updateClientAssets;
isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
}
declare module spine {
abstract class Texture {
protected _image: HTMLImageElement;
constructor(image: HTMLImageElement);
getImage(): HTMLImageElement;
protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void;

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];

File diff suppressed because one or more lines are too long

View File

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

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];

File diff suppressed because one or more lines are too long

View File

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

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];
@ -10732,7 +10764,7 @@ var spine;
var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) {
if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas = canvasOrContext;
this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
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;
loadText(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;
private updateClientAssets;
isLoadingComplete(clientId: string): boolean;
@ -881,9 +881,9 @@ declare module spine {
}
declare module spine {
abstract class Texture {
protected _image: HTMLImageElement;
constructor(image: HTMLImageElement);
getImage(): HTMLImageElement;
protected _image: HTMLImageElement | ImageBitmap;
constructor(image: HTMLImageElement | ImageBitmap);
getImage(): HTMLImageElement | ImageBitmap;
abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
abstract dispose(): void;

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];

File diff suppressed because one or more lines are too long

View File

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

View File

@ -2,7 +2,7 @@ var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __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 function (d, b) {
@ -3572,15 +3572,35 @@ var spine;
path = this.pathPrefix + path;
if (!this.queueAsset(clientId, textureLoader, path))
return;
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function (ev) {
_this.rawAssets[path] = img;
var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
var isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
if (isWebWorker) {
var options = { mode: "cors" };
fetch(path, options).then(function (response) {
if (!response.ok) {
_this.errors[path] = "Couldn't load image " + 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.onerror = function (ev) {
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
};
img.src = path;
img_1.src = path;
}
};
SharedAssetManager.prototype.get = function (clientId, path) {
path = this.pathPrefix + path;
@ -3590,6 +3610,8 @@ var spine;
return clientAssets.assets[path];
};
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++) {
var path = clientAssets.toLoad[i];
var asset = clientAssets.assets[path];
@ -3597,6 +3619,15 @@ var spine;
var rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined)
continue;
if (isWebWorker) {
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
else {
clientAssets.assets[path] = rawAsset;
}
}
else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(rawAsset);
}
@ -3605,6 +3636,7 @@ var spine;
}
}
}
}
};
SharedAssetManager.prototype.isLoadingComplete = function (clientId) {
var clientAssets = this.clientAssets[clientId];
@ -10732,7 +10764,7 @@ var spine;
var _this = this;
if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
this.restorables = new Array();
if (canvasOrContext instanceof HTMLCanvasElement) {
if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
var canvas = canvasOrContext;
this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
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) {
regionAttachment = <RegionAttachment>attachment;
region = <TextureAtlasRegion>regionAttachment.region;
image = (<CanvasTexture>region.texture).getImage();
image = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else continue;
let skeleton = slot.bone.skeleton;
@ -131,13 +131,13 @@ module spine.canvas {
vertices = this.computeRegionVertices(slot, regionAttachment, false);
triangles = SkeletonRenderer.QUAD_TRIANGLES;
region = <TextureAtlasRegion>regionAttachment.region;
texture = (<CanvasTexture>region.texture).getImage();
texture = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else if (attachment instanceof MeshAttachment) {
let mesh = <MeshAttachment>attachment;
vertices = this.computeMeshVertices(slot, mesh, false);
triangles = mesh.triangles;
texture = (<TextureAtlasRegion>mesh.region.renderObject).texture.getImage();
texture = (<TextureAtlasRegion>mesh.region.renderObject).texture.getImage() as HTMLImageElement;
} else continue;
if (texture != null) {

View File

@ -32,7 +32,7 @@ module spine {
clientId: string;
toLoad = new Array<string>();
assets: Map<any> = {};
textureLoader: (image: HTMLImageElement) => any;
textureLoader: (image: HTMLImageElement | ImageBitmap) => any;
constructor(clientId: string) {
this.clientId = clientId;
@ -56,7 +56,7 @@ module spine {
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];
if (clientAssets === null || clientAssets === undefined) {
clientAssets = new Assets(clientId);
@ -111,10 +111,30 @@ module spine {
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;
if (!this.queueAsset(clientId, textureLoader, path)) return;
let isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document);
let isWebWorker = !isBrowser && typeof importScripts !== 'undefined';
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) => {
@ -125,6 +145,7 @@ module spine {
}
img.src = path;
}
}
get (clientId: string, path: string) {
path = this.pathPrefix + path;
@ -134,12 +155,24 @@ module spine {
}
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++) {
let path = clientAssets.toLoad[i];
let asset = clientAssets.assets[path];
if (asset === null || asset === undefined) {
let rawAsset = this.rawAssets[path];
if (rawAsset === null || rawAsset === undefined) continue;
if (isWebWorker)
{
if (rawAsset instanceof ImageBitmap) {
clientAssets.assets[path] = clientAssets.textureLoader(<ImageBitmap>rawAsset);
} else {
clientAssets.assets[path] = rawAsset;
}
} else {
if (rawAsset instanceof HTMLImageElement) {
clientAssets.assets[path] = clientAssets.textureLoader(<HTMLImageElement>rawAsset);
} else {
@ -148,6 +181,7 @@ module spine {
}
}
}
}
isLoadingComplete (clientId: string): boolean {
let clientAssets = this.clientAssets[clientId];

View File

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

View File

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

View File

@ -36,7 +36,7 @@ module spine.webgl {
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);
this.context = context instanceof ManagedWebGLRenderingContext? context : new ManagedWebGLRenderingContext(context);
this.useMipMaps = useMipMaps;

View File

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

View File

@ -1093,6 +1093,84 @@ CanvasRenderer:
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
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
GameObject:
m_ObjectHideFlags: 0
@ -1368,6 +1446,7 @@ RectTransform:
- {fileID: 906692069}
- {fileID: 1315482509}
- {fileID: 748959554}
- {fileID: 1259836959}
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -1678,6 +1757,8 @@ MonoBehaviour:
initialSkinName: base
initialFlipX: 0
initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: []
zSpacing: 0
useClipping: 1

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -173,7 +173,15 @@ MonoBehaviour:
startingLoop: 1
timeScale: 1
freeze: 0
updateMode: 3
updateWhenInvisible: 3
unscaledTime: 0
allowMultipleCanvasRenderers: 0
canvasRenderers: []
separatorSlotNames: []
enableSeparatorSlots: 0
separatorParts: []
updateSeparatorPartLocation: 1
meshGenerator:
settings:
useClipping: 1
@ -613,14 +621,236 @@ RectTransform:
- {fileID: 1290113543}
- {fileID: 1028287914}
- {fileID: 1758924602}
- {fileID: 1612003163}
m_Father: {fileID: 0}
m_RootOrder: 5
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {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
GameObject:
m_ObjectHideFlags: 0
@ -762,13 +992,90 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: SkeletonAnimation
m_Text: 'SkeletonAnimation
Outline Only'
--- !u!222 &1290113545
CanvasRenderer:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
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
GameObject:
m_ObjectHideFlags: 0
@ -1086,6 +1393,8 @@ MonoBehaviour:
initialSkinName:
initialFlipX: 0
initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: []
zSpacing: 0
useClipping: 1
@ -1215,7 +1524,7 @@ GameObject:
- component: {fileID: 2051539995}
- component: {fileID: 2051539996}
m_Layer: 0
m_Name: Spine GameObject (spineboy-pro)
m_Name: Spine GameObject (hero-pro)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -1227,7 +1536,7 @@ MonoBehaviour:
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2051539989}
m_Enabled: 0
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 26947ae098a8447408d80c0c86e35b48, type: 3}
m_Name:
@ -1237,7 +1546,7 @@ MonoBehaviour:
customMaterialOverrides:
- overrideDisabled: 0
originalMaterial: {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2}
replacementMaterial: {fileID: 2100000, guid: fd9012d511e32e04c84b87ea9276448d,
replacementMaterial: {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192,
type: 2}
--- !u!114 &2051539991
MonoBehaviour:
@ -1254,6 +1563,8 @@ MonoBehaviour:
initialSkinName: weapon/sword
initialFlipX: 0
initialFlipY: 0
updateMode: 3
updateWhenInvisible: 3
separatorSlotNames: []
zSpacing: 0
useClipping: 1
@ -1286,7 +1597,7 @@ MeshRenderer:
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_Materials:
- {fileID: 2100000, guid: 9aa2023c2c91b254f9cb0a4fba19af00, type: 2}
- {fileID: 2100000, guid: aadb1a26bea9b8d4381c38e65e64c192, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
@ -1319,8 +1630,8 @@ Transform:
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2051539989}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.52, y: -2.0300002, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_LocalPosition: {x: -1.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: 4

View File

@ -70,7 +70,7 @@ namespace Spine.Unity.Examples {
}
void Apply (SkeletonRenderer skeletonRenderer) {
StartCoroutine("Blink");
StartCoroutine(Blink());
}
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();
atlasAsset = atlasAsset ?? (SpineAtlasAsset)target;
atlasAsset = (atlasAsset == null) ? (SpineAtlasAsset)target : atlasAsset;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);

View File

@ -71,7 +71,7 @@ namespace Spine.Unity.Editor {
}
serializedObject.Update();
atlasAsset = atlasAsset ?? (SpineSpriteAtlasAsset)target;
atlasAsset = (atlasAsset == null) ? (SpineSpriteAtlasAsset)target : atlasAsset;
if (atlasAsset.RegionsNeedLoading) {
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;
}
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 isSeparationEnabledButNotMultipleRenderers =
isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true);

View File

@ -289,7 +289,8 @@ namespace Spine.Unity.Editor {
return;
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);
}

View File

@ -37,12 +37,16 @@ namespace Spine.Unity.Editor {
protected SerializedProperty rootMotionBoneName;
protected SerializedProperty transformPositionX;
protected SerializedProperty transformPositionY;
protected SerializedProperty rootMotionScaleX;
protected SerializedProperty rootMotionScaleY;
protected SerializedProperty rigidBody2D;
protected SerializedProperty rigidBody;
protected GUIContent rootMotionBoneNameLabel;
protected GUIContent transformPositionXLabel;
protected GUIContent transformPositionYLabel;
protected GUIContent rootMotionScaleXLabel;
protected GUIContent rootMotionScaleYLabel;
protected GUIContent rigidBody2DLabel;
protected GUIContent rigidBodyLabel;
@ -51,12 +55,16 @@ namespace Spine.Unity.Editor {
rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName");
transformPositionX = serializedObject.FindProperty("transformPositionX");
transformPositionY = serializedObject.FindProperty("transformPositionY");
rootMotionScaleX = serializedObject.FindProperty("rootMotionScaleX");
rootMotionScaleY = serializedObject.FindProperty("rootMotionScaleY");
rigidBody2D = serializedObject.FindProperty("rigidBody2D");
rigidBody = serializedObject.FindProperty("rigidBody");
rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from.");
transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)");
transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone.");
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",
"Optional Rigidbody2D: Assign a Rigidbody2D here if you want " +
" 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(transformPositionX, transformPositionXLabel);
EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel);
EditorGUILayout.PropertyField(rootMotionScaleX, rootMotionScaleXLabel);
EditorGUILayout.PropertyField(rootMotionScaleY, rootMotionScaleYLabel);
}
protected virtual void OptionalPropertyFields () {

View File

@ -130,6 +130,9 @@ namespace Spine.Unity.Editor {
const string TEXTUREIMPORTER_WARNING_KEY = "SPINE_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 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);
atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_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);
handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
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.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_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.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(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning);
EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning);
EditorPrefs.SetBool(COMPONENTMATERIAL_WARNING_KEY, preferences.componentMaterialWarning);
EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration);
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);
if (EditorGUI.EndChangeCheck()) {
EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons);
#if NEWPLAYMODECALLBACKS
#if NEWPLAYMODECALLBACKS
HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
#else
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."));
@ -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 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();
@ -278,11 +285,11 @@ namespace Spine.Unity.Editor {
}
}
#if SPINE_TK2D_DEFINE
#if SPINE_TK2D_DEFINE
bool isTK2DDefineSet = true;
#else
#else
bool isTK2DDefineSet = false;
#endif
#endif
bool isTK2DAllowed = SpineTK2DEditorUtility.IsTK2DAllowed;
if (SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) {
GUILayout.Space(20);
@ -294,12 +301,12 @@ namespace Spine.Unity.Editor {
if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineTK2DEditorUtility.DisableTK2D();
}
#if !SPINE_TK2D_DEFINE
#if !SPINE_TK2D_DEFINE
if (!isTK2DAllowed) {
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);
}
#endif
#endif
}
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'."));
}
}
#endif // !NEW_PREFERENCES_SETTINGS_PROVIDER
#endif // !NEW_PREFERENCES_SETTINGS_PROVIDER
}
static void BoolPrefsField (ref bool currentValue, string editorPrefsKey, GUIContent label) {

View File

@ -621,7 +621,7 @@ namespace Spine.Unity.Editor {
int[] triangles = attachment.Triangles;
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];

View File

@ -84,6 +84,9 @@ namespace Spine.Unity.Editor {
internal const bool DEFAULT_TEXTUREIMPORTER_WARNING = true;
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 bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true;
@ -108,6 +111,9 @@ namespace Spine.Unity.Editor {
internal static SpinePreferences GetOrCreateSettings () {
var settings = AssetDatabase.LoadAssetAtPath<SpinePreferences>(SPINE_SETTINGS_ASSET_PATH);
if (settings == null)
settings = FindSpinePreferences();
if (settings == null)
{
settings = ScriptableObject.CreateInstance<SpinePreferences>();
@ -123,6 +129,18 @@ namespace Spine.Unity.Editor {
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) {
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("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();

View File

@ -43,6 +43,7 @@ namespace Spine.Unity {
[ExecuteInEditMode]
#endif
[AddComponentMenu("Spine/BoneFollower")]
[HelpURL("http://esotericsoftware.com/spine-unity#BoneFollower")]
public class BoneFollower : MonoBehaviour {
#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>
[SpineBone(dataField: "skeletonRenderer")]
[SerializeField] public string boneName;
public string boneName;
public bool followXYPosition = true;
public bool followZPosition = true;

View File

@ -42,6 +42,7 @@ namespace Spine.Unity {
#endif
[DisallowMultipleComponent]
[AddComponentMenu("Spine/UI/BoneFollowerGraphic")]
[HelpURL("http://esotericsoftware.com/spine-unity#BoneFollowerGraphic")]
public class BoneFollowerGraphic : MonoBehaviour {
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>
[SpineBone(dataField: "skeletonGraphic")]
[SerializeField] public string boneName;
public string boneName;
public bool followBoneRotation = true;
[Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")]

View File

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

View File

@ -41,9 +41,10 @@ namespace Spine.Unity {
[ExecuteInEditMode]
#endif
[AddComponentMenu("Spine/Point Follower")]
[HelpURL("http://esotericsoftware.com/spine-unity#PointFollower")]
public class PointFollower : MonoBehaviour, IHasSkeletonRenderer, IHasSkeletonComponent {
[SerializeField] public SkeletonRenderer skeletonRenderer;
public SkeletonRenderer skeletonRenderer;
public SkeletonRenderer SkeletonRenderer { get { return this.skeletonRenderer; } }
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
/// <see cref="SkeletonRootMotion">SkeletonRootMotion</see> instead.
/// </remarks>
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonMecanimRootMotion")]
public class SkeletonMecanimRootMotion : SkeletonRootMotionBase {
#region Inspector
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 () {
base.Reset();
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) {
if (((mecanimLayerFlags & 1<<layerIndex) == 0) || weight == 0)
return;
var timeline = clip.FindTranslateTimelineForBone(rootMotionBoneIndex);
if (timeline != null) {
if (!playsBackward)
movementDelta += weight * GetTimelineMovementDelta(lastTime, time, timeline, clip);
else
movementDelta -= weight * GetTimelineMovementDelta(time, lastTime, timeline, clip);
if (!playsBackward) {
movementDelta += weight * GetAnimationRootMotion(lastTime, time, animation);
}
else {
movementDelta -= weight * GetAnimationRootMotion(time, lastTime, animation);
}
}

View File

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

View File

@ -37,14 +37,17 @@ namespace Spine.Unity {
/// Base class for skeleton root motion components.
/// </summary>
abstract public class SkeletonRootMotionBase : MonoBehaviour {
#region Inspector
#region Inspector
[SpineBone]
[SerializeField]
protected string rootMotionBoneName = "root";
public bool transformPositionX = true;
public bool transformPositionY = true;
public float rootMotionScaleX = 1;
public float rootMotionScaleY = 1;
[Header("Optional")]
public Rigidbody2D rigidBody2D;
public Rigidbody rigidBody;
@ -74,87 +77,11 @@ namespace Spine.Unity {
skeletonAnimation.UpdateLocal += HandleUpdateLocal;
}
abstract protected Vector2 CalculateAnimationsMovementDelta ();
protected virtual float AdditionalScale { get { return 1.0f; } }
protected Vector2 GetTimelineMovementDelta (float startTime, float endTime,
TranslateTimeline timeline, Animation animation) {
Vector2 currentDelta;
if (startTime > endTime) // Looped
currentDelta = (timeline.Evaluate(animation.duration) - timeline.Evaluate(startTime))
+ (timeline.Evaluate(endTime) - timeline.Evaluate(0));
else if (startTime != endTime) // Non-looped
currentDelta = timeline.Evaluate(endTime) - timeline.Evaluate(startTime);
else
currentDelta = Vector2.zero;
return currentDelta;
}
void GatherTopLevelBones () {
topLevelBones.Clear();
var skeleton = skeletonComponent.Skeleton;
foreach (var bone in skeleton.Bones) {
if (bone.Parent == null)
topLevelBones.Add(bone);
}
}
public void SetRootMotionBone (string name) {
var skeleton = skeletonComponent.Skeleton;
int index = skeleton.FindBoneIndex(name);
if (index >= 0) {
this.rootMotionBoneIndex = index;
this.rootMotionBone = skeleton.bones.Items[index];
}
else {
Debug.Log("Bone named \"" + name + "\" could not be found.");
this.rootMotionBoneIndex = 0;
this.rootMotionBone = skeleton.RootBone;
}
}
void HandleUpdateLocal (ISkeletonAnimation animatedSkeletonComponent) {
if (!this.isActiveAndEnabled)
return; // Root motion is only applied when component is enabled.
var movementDelta = CalculateAnimationsMovementDelta();
AdjustMovementDeltaToConfiguration(ref movementDelta, animatedSkeletonComponent.Skeleton);
ApplyRootMotion(movementDelta);
}
void AdjustMovementDeltaToConfiguration (ref Vector2 localDelta, Skeleton skeleton) {
if (skeleton.ScaleX < 0) localDelta.x = -localDelta.x;
if (skeleton.ScaleY < 0) localDelta.y = -localDelta.y;
if (!transformPositionX) localDelta.x = 0f;
if (!transformPositionY) localDelta.y = 0f;
}
void ApplyRootMotion (Vector2 localDelta) {
localDelta *= AdditionalScale;
// Apply root motion to Transform or RigidBody;
if (UsesRigidbody) {
rigidbodyDisplacement += (Vector2)transform.TransformVector(localDelta);
// Accumulated displacement is applied on the next Physics update (FixedUpdate)
}
else {
transform.position += transform.TransformVector(localDelta);
}
// Move top level bones in opposite direction of the root motion bone
foreach (var topLevelBone in topLevelBones) {
if (transformPositionX) topLevelBone.x -= rootMotionBone.x;
if (transformPositionY) topLevelBone.y -= rootMotionBone.y;
}
}
protected virtual void FixedUpdate () {
if (!this.isActiveAndEnabled)
return; // Root motion is only applied when component is enabled.
if(rigidBody2D != null) {
if (rigidBody2D != null) {
rigidBody2D.MovePosition(new Vector2(transform.position.x, transform.position.y)
+ rigidbodyDisplacement);
}
@ -180,5 +107,108 @@ namespace Spine.Unity {
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]
#endif
[AddComponentMenu("Spine/SkeletonAnimation")]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonAnimation-Component")]
public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, IAnimationStateComponent {
#region IAnimationStateComponent
@ -56,10 +57,17 @@ namespace Spine.Unity {
#endregion
#region Bone Callbacks ISkeletonAnimation
protected event UpdateBonesDelegate _BeforeApply;
protected event UpdateBonesDelegate _UpdateLocal;
protected event UpdateBonesDelegate _UpdateWorld;
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>
/// Occurs after the animations are applied and before world space values are resolved.
/// Use this callback when you want to set bone local values.
@ -202,6 +210,9 @@ namespace Spine.Unity {
}
protected void ApplyAnimation () {
if (_BeforeApply != null)
_BeforeApply(this);
state.Apply(skeleton);
if (_UpdateLocal != null)

View File

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

View File

@ -32,6 +32,7 @@ using System.Collections.Generic;
namespace Spine.Unity {
[RequireComponent(typeof(Animator))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonMecanim-Component")]
public class SkeletonMecanim : SkeletonRenderer, ISkeletonAnimation {
[SerializeField] protected MecanimTranslator translator;
@ -39,10 +40,17 @@ namespace Spine.Unity {
private bool wasUpdatedAfterInit = true;
#region Bone Callbacks (ISkeletonAnimation)
protected event UpdateBonesDelegate _BeforeApply;
protected event UpdateBonesDelegate _UpdateLocal;
protected event UpdateBonesDelegate _UpdateWorld;
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>
/// 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>
@ -86,6 +94,9 @@ namespace Spine.Unity {
}
protected void ApplyAnimation () {
if (_BeforeApply != null)
_BeforeApply(this);
#if UNITY_EDITOR
var translatorAnimator = translator.Animator;
if (translatorAnimator != null && !translatorAnimator.isInitialized)
@ -217,7 +228,7 @@ namespace Spine.Unity {
return false;
var time = AnimationTime(stateInfo.normalizedTime, info.clip.length,
info.clip.isLooping, stateInfo.speed < 0);
info.clip.isLooping);
weight = useClipWeight1 ? layerWeight : weight;
clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
weight, layerBlendMode, MixDirection.In);
@ -241,7 +252,7 @@ namespace Spine.Unity {
return false;
var time = AnimationTime(stateInfo.normalizedTime + interruptingClipTimeAddition,
info.clip.length, stateInfo.speed < 0);
info.clip.length);
weight = useClipWeight1 ? layerWeight : weight;
clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
weight, layerBlendMode, MixDirection.In);
@ -277,7 +288,7 @@ namespace Spine.Unity {
bool isAdditiveLayer = false;
if (layer < layerBlendModes.Length)
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) {
float time = AnimationTime(normalizedTime, clipLength, reversed);
public KeyValuePair<Spine.Animation, float> GetActiveAnimationAndTime (int layer) {
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;
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;
}
static float AnimationTime (float normalizedTime, float clipLength, bool reversed) {
if (reversed)
normalizedTime = (1 - normalizedTime + (int)normalizedTime) + (int)normalizedTime;
static float AnimationTime (float normalizedTime, float clipLength) {
if (normalizedTime < 0.0f)
normalizedTime = (normalizedTime % 1.0f) + 1.0f;
return normalizedTime * clipLength;
}

View File

@ -31,6 +31,7 @@ using UnityEngine;
namespace Spine.Unity {
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderSeparator")]
public class SkeletonPartsRenderer : MonoBehaviour {
#region Properties
@ -59,6 +60,14 @@ namespace Spine.Unity {
}
#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;
SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
@ -120,6 +129,9 @@ namespace Spine.Unity {
meshFilter.sharedMesh = mesh;
smartMesh.instructionUsed.Set(currentInstructions);
if (OnMeshAndMaterialsUpdated != null)
OnMeshAndMaterialsUpdated(this);
}
public void SetPropertyBlock (MaterialPropertyBlock block) {

View File

@ -42,7 +42,7 @@ namespace Spine.Unity {
#else
[ExecuteInEditMode]
#endif
[HelpURL("http://esotericsoftware.com/spine-unity-skeletonrenderseparator")]
[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderSeparator")]
public class SkeletonRenderSeparator : MonoBehaviour {
public const int DefaultSortingOrderIncrement = 5;
@ -77,6 +77,12 @@ namespace Spine.Unity {
#endif
#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
/// <summary>Adds a SkeletonRenderSeparator and child SkeletonPartsRenderer GameObjects to a given SkeletonRenderer.</summary>
/// <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.
for (; rendererIndex < rendererCount; rendererIndex++) {
currentRenderer = partsRenderers[rendererIndex];

View File

@ -39,6 +39,10 @@
#define BUILT_IN_SPRITE_MASK_COMPONENT
#endif
#if UNITY_2019_3_OR_NEWER
#define CONFIGURABLE_ENTER_PLAY_MODE
#endif
#define SPINE_OPTIONAL_RENDEROVERRIDE
#define SPINE_OPTIONAL_MATERIALOVERRIDE
@ -53,7 +57,7 @@ namespace Spine.Unity {
[ExecuteInEditMode]
#endif
[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 SkeletonDataAsset skeletonDataAsset;
@ -236,7 +240,7 @@ namespace Spine.Unity {
/// <summary>OnRebuild is raised after the Skeleton is successfully initialized.</summary>
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>
public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated;
@ -276,6 +280,12 @@ namespace Spine.Unity {
Initialize(false);
}
#if UNITY_EDITOR && CONFIGURABLE_ENTER_PLAY_MODE
public virtual void Start () {
Initialize(false);
}
#endif
void OnDisable () {
if (clearStateOnDisable && valid)
ClearState();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,6 +68,9 @@ namespace Spine.Unity {
[Header("Vertex Data")]
public bool pmaVertexColors;
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 addNormals;
public bool immutableTriangles;
@ -493,6 +496,7 @@ namespace Spine.Unity {
#else
bool useClipping = settings.useClipping;
#endif
bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
if (useClipping) {
if (instruction.preActiveClippingSlotSource >= 0) {
@ -556,12 +560,18 @@ namespace Spine.Unity {
}
}
float tintBlackAlpha = 1.0f;
if (pmaVertexColors) {
color.a = (byte)(skeletonA * slot.a * c.a * 255);
color.r = (byte)(skeletonR * slot.r * c.r * color.a);
color.g = (byte)(skeletonG * slot.g * c.g * 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 {
color.a = (byte)(skeletonA * slot.a * c.a * 255);
color.r = (byte)(skeletonR * slot.r * c.r * 255);
@ -590,7 +600,7 @@ namespace Spine.Unity {
g2 *= 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);
@ -694,6 +704,7 @@ namespace Spine.Unity {
// Use this faster method when no clipping is involved.
public void BuildMeshWithArrays (SkeletonRendererInstruction instruction, bool updateTriangles) {
var settings = this.settings;
bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
int totalVertexCount = instruction.rawVertexCount;
// Add data to vertex buffers
@ -758,6 +769,7 @@ namespace Spine.Unity {
rg.x = slot.r2; //r
rg.y = slot.g2; //g
b2.x = slot.b2; //b
b2.y = 1.0f;
var regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) {
@ -766,6 +778,7 @@ namespace Spine.Unity {
rg.x *= alpha;
rg.y *= 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;
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.y *= alpha;
b2.x *= alpha;
b2.y = slot.data.blendMode == BlendMode.Additive ? 0 : alpha;
}
int meshVertexCount = meshAttachment.worldVerticesLength;
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.g = (byte)(g * slot.g * regionAttachment.g * 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 {
color.a = (byte)(a * slot.a * regionAttachment.a * 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.g = (byte)(g * slot.g * meshAttachment.g * 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 {
color.a = (byte)(a * slot.a * meshAttachment.a * 255);
color.r = (byte)(r * slot.r * meshAttachment.r * 255);
@ -985,9 +999,9 @@ namespace Spine.Unity {
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 bo = new Vector2(b2, 1f);
var bo = new Vector2(b2, a);
int ovc = vertexBuffer.Count;
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(_CANVAS_GROUP_COMPATIBLE)] _CanvasGroupCompatible("CanvasGroup Compatible", Int) = 1
_Color ("Tint", Color) = (1,1,1,1)
_Black ("Black Point", Color) = (0,0,0,0)
_Color ("Tint Color", Color) = (1,1,1,1)
_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] _Stencil ("Stencil ID", Float) = 0
@ -66,6 +67,7 @@ Shader "Spine/SkeletonGraphic Tint Black"
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _CANVAS_GROUP_COMPATIBLE
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert
#pragma fragment frag
@ -87,9 +89,8 @@ Shader "Spine/SkeletonGraphic Tint Black"
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float2 uv2 : TEXCOORD2;
float4 worldPosition : TEXCOORD3;
float4 darkColor : TEXCOORD1;
float4 worldPosition : TEXCOORD2;
UNITY_VERTEX_OUTPUT_STEREO
};
@ -108,34 +109,37 @@ Shader "Spine/SkeletonGraphic Tint Black"
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
OUT.uv1 = IN.uv1;
OUT.uv2 = IN.uv2;
OUT.color = IN.color;
OUT.darkColor = float4(IN.uv1.r, IN.uv1.g, IN.uv2.r, IN.uv2.g);
return OUT;
}
sampler2D _MainTex;
#include "../CGIncludes/Spine-Skeleton-Tint-Common.cginc"
fixed4 frag (VertexOutput IN) : SV_Target
{
half4 texColor = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
texColor *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP
clip (texColor.a - 0.001);
clip(texColor.a - 0.001);
#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
// CanvasGroup alpha sets vertex color alpha, but does not premultiply it to rgb components.
color.rgb *= IN.color.a;
// CanvasGroup alpha multiplies existing vertex color alpha, but
// does not premultiply it to rgb components. This causes problems
// with additive blending (alpha = 0), which is why we store the
// 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
return color;
float4 fragColor = fragTintedColor(texColor, _Black.rgb + IN.darkColor, vertexColor, _Color.a, _Black.a);
#ifdef _CANVAS_GROUP_COMPATIBLE
fragColor.rgba *= canvasAlpha;
#endif
return fragColor;
}
ENDCG
}

View File

@ -7,10 +7,11 @@
Shader "Spine/Skeleton Tint" {
Properties {
_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" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_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][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
@ -44,6 +45,7 @@ Shader "Spine/Skeleton Tint" {
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
@ -71,14 +73,11 @@ Shader "Spine/Skeleton Tint" {
return o;
}
#include "CGIncludes/Spine-Skeleton-Tint-Common.cginc"
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#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);
return fragTintedColor(texColor, _Black.rgb, i.vertexColor, _Color.a, _Black.a);
}
ENDCG
}

View File

@ -9,10 +9,11 @@
Shader "Spine/Skeleton Tint Black" {
Properties {
_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" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_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][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
@ -47,6 +48,7 @@ Shader "Spine/Skeleton Tint Black" {
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma shader_feature _ _DARK_COLOR_ALPHA_ADDITIVE
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
@ -65,8 +67,7 @@ Shader "Spine/Skeleton Tint Black" {
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float2 uv2 : TEXCOORD2;
float3 darkColor : TEXCOORD1;
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.uv = v.uv;
o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
o.uv1 = v.uv1;
o.uv2 = v.uv2;
o.darkColor = float3(v.uv1.r, v.uv1.g, v.uv2.r);
return o;
}
#include "CGIncludes/Spine-Skeleton-Tint-Common.cginc"
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#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);
return fragTintedColor(texColor, _Black.rgb + i.darkColor, i.vertexColor, _Color.a, _Black.a);
}
ENDCG
}

View File

@ -2,7 +2,7 @@
#define SHADER_MATHS_INCLUDED
#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)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#else

View File

@ -4,7 +4,7 @@
#define SHADER_SHARED_INCLUDED
#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)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#else

View File

@ -39,24 +39,58 @@ namespace Spine.Unity {
static readonly int STRAIGHT_ALPHA_PARAM_ID = Shader.PropertyToID("_StraightAlphaInput");
static readonly string ALPHAPREMULTIPLY_ON_KEYWORD = "_ALPHAPREMULTIPLY_ON";
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 =
"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"
+ " (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";
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"
+ "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 =
"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"
+ "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 =
"Warning: 'Add Normals' required on URP shader to receive shadows!\n\nPlease\n"
public static readonly string kAddNormalsMessage =
"\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"
+ "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) {
var materials = renderer.GetComponent<Renderer>().sharedMaterials;
@ -67,9 +101,51 @@ namespace Spine.Unity {
if (renderer.zSpacing == 0) {
isProblematic |= IsZSpacingRequired(material, ref errorMessage);
}
if (IsURPMaterial(material) && !AreShadowsDisabled(material) && renderer.addNormals == false) {
if (renderer.addNormals == false && RequiresMeshNormals(material)) {
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;
@ -177,13 +253,57 @@ namespace Spine.Unity {
material.IsKeywordEnabled(ALPHAPREMULTIPLY_ON_KEYWORD);
}
static bool IsURPMaterial (Material material) {
return material.shader.name.Contains("Universal Render Pipeline");
static bool IsURP3DMaterial (Material material) {
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) {
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 override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
const int fieldCount = 10;
const int fieldCount = 11;
return fieldCount * EditorGUIUtility.singleLineHeight;
}
@ -49,6 +49,7 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
SerializedProperty customDurationProp = property.FindPropertyRelative("customDuration");
SerializedProperty useBlendDurationProp = property.FindPropertyRelative("useBlendDuration");
SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration");
SerializedProperty holdPreviousProp = property.FindPropertyRelative("holdPrevious");
SerializedProperty eventProp = property.FindPropertyRelative("eventThreshold");
SerializedProperty attachmentProp = property.FindPropertyRelative("attachmentThreshold");
SerializedProperty drawOrderProp = property.FindPropertyRelative("drawOrderThreshold");
@ -87,6 +88,9 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
EditorGUI.PropertyField(singleFieldRect, mixDurationProp);
}
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, holdPreviousProp);
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, eventProp);

View File

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

View File

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

View File

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

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