mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Merge branch '3.7-beta' into 3.7-beta-cpp
This commit is contained in:
commit
bb1bdd7046
1
.gitignore
vendored
1
.gitignore
vendored
@ -41,6 +41,7 @@ spine-cocos2dx/example/cocos2d
|
||||
spine-cocos2dx/example/proj.win32/spine-cocos2d-x.VC.opendb
|
||||
spine-cocos2dx/example/proj.win32/spine-cocos2d-x.VC.db
|
||||
xcuserdata/
|
||||
xcshareddata/
|
||||
|
||||
spine-cocos2d-objc/cocos2d/*
|
||||
spine-cocos2d-objc/spine-cocos2d-iphone-objc.xcodeproj/project.xcworkspace/xcshareddata/
|
||||
|
||||
@ -74,7 +74,7 @@ bool AppDelegate::applicationDidFinishLaunching () {
|
||||
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
|
||||
#endif
|
||||
|
||||
Size frameSize = glview->getFrameSize();
|
||||
cocos2d::Size frameSize = glview->getFrameSize();
|
||||
|
||||
vector<string> searchPath;
|
||||
|
||||
|
||||
@ -70,14 +70,14 @@ bool BatchingExample::init () {
|
||||
|
||||
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
|
||||
int yMin = 0, yMax = _contentSize.height * 0.7f;
|
||||
for (int i = 0, j = 0; i < NUM_SKELETONS; i++) {
|
||||
for (int i = 0; i < NUM_SKELETONS; i++) {
|
||||
// Each skeleton node shares the same atlas, skeleton data, and mix times.
|
||||
SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
|
||||
skeletonNode->setAnimationStateData(_stateData);
|
||||
|
||||
skeletonNode->setAnimation(0, "walk", true);
|
||||
skeletonNode->addAnimation(0, "jump", true, RandomHelper::random_int(0, 300) / 100.0f);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
|
||||
// alternative setting two color tint for groups of 10 skeletons
|
||||
// should end up with #skeletons / 10 batches
|
||||
|
||||
@ -44,14 +44,14 @@ bool CoinExample::init () {
|
||||
if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false;
|
||||
|
||||
skeletonNode = SkeletonAnimation::createWithBinaryFile("coin-pro.skel", "coin.atlas", 1);
|
||||
skeletonNode->setAnimation(0, "rotate", true);
|
||||
// skeletonNode->setTwoColorTint(true);
|
||||
|
||||
skeletonNode->setAnimation(0, "rotate", true);
|
||||
// skeletonNode->setTwoColorTint(true);
|
||||
|
||||
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 100));
|
||||
addChild(skeletonNode);
|
||||
|
||||
scheduleUpdate();
|
||||
|
||||
|
||||
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!skeletonNode->getDebugBonesEnabled())
|
||||
|
||||
@ -51,7 +51,7 @@ bool GoblinsExample::init () {
|
||||
addChild(skeletonNode);
|
||||
|
||||
scheduleUpdate();
|
||||
|
||||
|
||||
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!skeletonNode->getDebugBonesEnabled())
|
||||
|
||||
@ -34,9 +34,9 @@
|
||||
|
||||
USING_NS_CC;
|
||||
using namespace spine;
|
||||
|
||||
PowInterpolation pow2(2);
|
||||
PowOutInterpolation powOut2(2);
|
||||
|
||||
PowInterpolation pow2(2);
|
||||
PowOutInterpolation powOut2(2);
|
||||
SwirlVertexEffect effect(400, powOut2);
|
||||
|
||||
Scene* RaptorExample::scene () {
|
||||
@ -67,7 +67,7 @@ bool RaptorExample::init () {
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!skeletonNode->getDebugBonesEnabled()) {
|
||||
skeletonNode->setDebugBonesEnabled(true);
|
||||
skeletonNode->setDebugMeshesEnabled(true);
|
||||
skeletonNode->setDebugMeshesEnabled(true);
|
||||
} else if (skeletonNode->getTimeScale() == 1)
|
||||
skeletonNode->setTimeScale(0.3f);
|
||||
else
|
||||
@ -80,8 +80,8 @@ bool RaptorExample::init () {
|
||||
}
|
||||
|
||||
void RaptorExample::update(float fDelta) {
|
||||
swirlTime += fDelta;
|
||||
float percent = spine::MathUtil::fmod(swirlTime, 2);
|
||||
if (percent > 1) percent = 1 - (percent - 1);
|
||||
swirlTime += fDelta;
|
||||
float percent = spine::MathUtil::fmod(swirlTime, 2);
|
||||
if (percent > 1) percent = 1 - (percent - 1);
|
||||
effect.setAngle(pow2.interpolate(-60.0f, 60.0f, percent));
|
||||
}
|
||||
|
||||
@ -42,39 +42,39 @@ Scene* SkeletonRendererSeparatorExample::scene () {
|
||||
|
||||
bool SkeletonRendererSeparatorExample::init () {
|
||||
if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false;
|
||||
|
||||
// Spineboy's back, which will manage the animation and GPU resources
|
||||
|
||||
// Spineboy's back, which will manage the animation and GPU resources
|
||||
// will render only the front slots of Spineboy
|
||||
backNode = SkeletonAnimation::createWithJsonFile("spineboy-ess.json", "spineboy.atlas", 0.6f);
|
||||
backNode->setMix("walk", "jump", 0.4);
|
||||
backNode->setAnimation(0, "walk", true);
|
||||
backNode->setSlotsRange(backNode->findSlot("rear-upper-arm")->getData().getIndex(), backNode->findSlot("rear-shin")->getData().getIndex());
|
||||
backNode->setPosition(Vec2(_contentSize.width / 2, 20));
|
||||
|
||||
// A simple rectangle to go between the front and back slots of Spineboy
|
||||
betweenNode = DrawNode::create();
|
||||
Vec2 rect[4];
|
||||
rect[0] = Vec2(0, 0);
|
||||
rect[1] = Vec2(40, 0);
|
||||
rect[2] = Vec2(40, 200);
|
||||
rect[3] = Vec2(0, 200);
|
||||
betweenNode->drawPolygon(rect, 4, Color4F(1, 0, 0, 1), 1, Color4F(1, 0, 0, 1));
|
||||
betweenNode->setPosition(Vec2(_contentSize.width / 2 + 30, 20));
|
||||
|
||||
// Spineboy's front, doesn't manage any skeleton, animation or GPU resources, but simply
|
||||
// renders the back slots of Spineboy. The skeleton, animatio state and GPU resources
|
||||
// are shared with the front node!
|
||||
frontNode = SkeletonRenderer::createWithSkeleton(backNode->getSkeleton());
|
||||
frontNode->setSlotsRange(frontNode->findSlot("neck")->getData().getIndex(), -1);
|
||||
frontNode->setPosition(Vec2(_contentSize.width / 2, 20));
|
||||
|
||||
// Add the front, between and back node in the correct order to this scene
|
||||
addChild(backNode);
|
||||
addChild(betweenNode);
|
||||
backNode = SkeletonAnimation::createWithJsonFile("spineboy-ess.json", "spineboy.atlas", 0.6f);
|
||||
backNode->setMix("walk", "jump", 0.4);
|
||||
backNode->setAnimation(0, "walk", true);
|
||||
backNode->setSlotsRange(backNode->findSlot("rear-upper-arm")->getData().getIndex(), backNode->findSlot("rear-shin")->getData().getIndex());
|
||||
backNode->setPosition(Vec2(_contentSize.width / 2, 20));
|
||||
|
||||
// A simple rectangle to go between the front and back slots of Spineboy
|
||||
betweenNode = DrawNode::create();
|
||||
Vec2 rect[4];
|
||||
rect[0] = Vec2(0, 0);
|
||||
rect[1] = Vec2(40, 0);
|
||||
rect[2] = Vec2(40, 200);
|
||||
rect[3] = Vec2(0, 200);
|
||||
betweenNode->drawPolygon(rect, 4, Color4F(1, 0, 0, 1), 1, Color4F(1, 0, 0, 1));
|
||||
betweenNode->setPosition(Vec2(_contentSize.width / 2 + 30, 20));
|
||||
|
||||
// Spineboy's front, doesn't manage any skeleton, animation or GPU resources, but simply
|
||||
// renders the back slots of Spineboy. The skeleton, animatio state and GPU resources
|
||||
// are shared with the front node!
|
||||
frontNode = SkeletonRenderer::createWithSkeleton(backNode->getSkeleton());
|
||||
frontNode->setSlotsRange(frontNode->findSlot("neck")->getData().getIndex(), -1);
|
||||
frontNode->setPosition(Vec2(_contentSize.width / 2, 20));
|
||||
|
||||
// Add the front, between and back node in the correct order to this scene
|
||||
addChild(backNode);
|
||||
addChild(betweenNode);
|
||||
addChild(frontNode);
|
||||
|
||||
scheduleUpdate();
|
||||
|
||||
|
||||
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!backNode->getDebugBonesEnabled())
|
||||
|
||||
@ -68,7 +68,7 @@ bool SpineboyExample::init () {
|
||||
skeletonNode->setMix("jump", "run", 0.4);
|
||||
skeletonNode->setAnimation(0, "walk", true);
|
||||
TrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 1);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
|
||||
skeletonNode->setTrackStartListener(jumpEntry, [] (TrackEntry* entry) {
|
||||
log("jumped!");
|
||||
@ -81,7 +81,7 @@ bool SpineboyExample::init () {
|
||||
addChild(skeletonNode);
|
||||
|
||||
scheduleUpdate();
|
||||
|
||||
|
||||
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!skeletonNode->getDebugBonesEnabled())
|
||||
|
||||
@ -50,7 +50,7 @@ bool TankExample::init () {
|
||||
addChild(skeletonNode);
|
||||
|
||||
scheduleUpdate();
|
||||
|
||||
|
||||
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
|
||||
listener->onTouchBegan = [this] (Touch* touch, cocos2d::Event* event) -> bool {
|
||||
if (!skeletonNode->getDebugBonesEnabled())
|
||||
|
||||
@ -35,129 +35,129 @@
|
||||
#include "cocos2d.h"
|
||||
|
||||
namespace spine {
|
||||
|
||||
class AttachmentVertices;
|
||||
|
||||
/* Draws a skeleton. */
|
||||
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
|
||||
public:
|
||||
CREATE_FUNC(SkeletonRenderer);
|
||||
static SkeletonRenderer* createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false);
|
||||
static SkeletonRenderer* createWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual void update (float deltaTime) override;
|
||||
virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
|
||||
virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags);
|
||||
virtual cocos2d::Rect getBoundingBox () const override;
|
||||
virtual void onEnter () override;
|
||||
virtual void onExit () override;
|
||||
|
||||
Skeleton* getSkeleton();
|
||||
|
||||
void setTimeScale(float scale);
|
||||
float getTimeScale() const;
|
||||
|
||||
/* */
|
||||
void setDebugSlotsEnabled(bool enabled);
|
||||
bool getDebugSlotsEnabled() const;
|
||||
|
||||
void setDebugBonesEnabled(bool enabled);
|
||||
bool getDebugBonesEnabled() const;
|
||||
|
||||
void setDebugMeshesEnabled(bool enabled);
|
||||
bool getDebugMeshesEnabled() const;
|
||||
|
||||
// --- Convenience methods for common Skeleton_* functions.
|
||||
void updateWorldTransform ();
|
||||
|
||||
void setToSetupPose ();
|
||||
void setBonesToSetupPose ();
|
||||
void setSlotsToSetupPose ();
|
||||
|
||||
/* Returns 0 if the bone was not found. */
|
||||
Bone* findBone (const std::string& boneName) const;
|
||||
/* Returns 0 if the slot was not found. */
|
||||
Slot* findSlot (const std::string& slotName) const;
|
||||
class AttachmentVertices;
|
||||
|
||||
/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are
|
||||
* attached if the corresponding attachment from the old skin was attached.
|
||||
* @param skin May be empty string ("") for no skin.*/
|
||||
void setSkin (const std::string& skinName);
|
||||
/** @param skin May be 0 for no skin.*/
|
||||
void setSkin (const char* skinName);
|
||||
/* Draws a skeleton. */
|
||||
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
|
||||
public:
|
||||
CREATE_FUNC(SkeletonRenderer);
|
||||
static SkeletonRenderer* createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false);
|
||||
static SkeletonRenderer* createWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual void update (float deltaTime) override;
|
||||
virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
|
||||
virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags);
|
||||
virtual cocos2d::Rect getBoundingBox () const override;
|
||||
virtual void onEnter () override;
|
||||
virtual void onExit () override;
|
||||
|
||||
Skeleton* getSkeleton();
|
||||
|
||||
void setTimeScale(float scale);
|
||||
float getTimeScale() const;
|
||||
|
||||
/* */
|
||||
void setDebugSlotsEnabled(bool enabled);
|
||||
bool getDebugSlotsEnabled() const;
|
||||
|
||||
void setDebugBonesEnabled(bool enabled);
|
||||
bool getDebugBonesEnabled() const;
|
||||
|
||||
void setDebugMeshesEnabled(bool enabled);
|
||||
bool getDebugMeshesEnabled() const;
|
||||
|
||||
// --- Convenience methods for common Skeleton_* functions.
|
||||
void updateWorldTransform ();
|
||||
|
||||
void setToSetupPose ();
|
||||
void setBonesToSetupPose ();
|
||||
void setSlotsToSetupPose ();
|
||||
|
||||
/* Returns 0 if the bone was not found. */
|
||||
Bone* findBone (const std::string& boneName) const;
|
||||
/* Returns 0 if the slot was not found. */
|
||||
Slot* findSlot (const std::string& slotName) const;
|
||||
|
||||
/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are
|
||||
* attached if the corresponding attachment from the old skin was attached.
|
||||
* @param skin May be empty string ("") for no skin.*/
|
||||
void setSkin (const std::string& skinName);
|
||||
/** @param skin May be 0 for no skin.*/
|
||||
void setSkin (const char* skinName);
|
||||
|
||||
/* Returns 0 if the slot or attachment was not found. */
|
||||
Attachment* getAttachment (const std::string& slotName, const std::string& attachmentName) const;
|
||||
/* Returns false if the slot or attachment was not found.
|
||||
* @param attachmentName May be empty string ("") for no attachment. */
|
||||
bool setAttachment (const std::string& slotName, const std::string& attachmentName);
|
||||
/* @param attachmentName May be 0 for no attachment. */
|
||||
bool setAttachment (const std::string& slotName, const char* attachmentName);
|
||||
|
||||
/* Enables/disables two color tinting for this instance. May break batching */
|
||||
void setTwoColorTint(bool enabled);
|
||||
/* Whether two color tinting is enabled */
|
||||
bool isTwoColorTint();
|
||||
|
||||
/* Sets the vertex effect to be used, set to 0 to disable vertex effects */
|
||||
void setVertexEffect(VertexEffect* effect);
|
||||
|
||||
/* Sets the range of slots that should be rendered. Use -1, -1 to clear the range */
|
||||
void setSlotsRange(int startSlotIndex, int endSlotIndex);
|
||||
|
||||
// --- BlendProtocol
|
||||
virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
|
||||
virtual const cocos2d::BlendFunc& getBlendFunc () const override;
|
||||
virtual void setOpacityModifyRGB (bool value) override;
|
||||
virtual bool isOpacityModifyRGB () const override;
|
||||
|
||||
// Frees global memory used for temporay vertex transformations.
|
||||
static void destroyScratchBuffers();
|
||||
|
||||
CC_CONSTRUCTOR_ACCESS:
|
||||
SkeletonRenderer ();
|
||||
SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
|
||||
SkeletonRenderer (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual ~SkeletonRenderer ();
|
||||
|
||||
void initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
|
||||
void initWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
void initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
void initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
void initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
void initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual void initialize ();
|
||||
|
||||
protected:
|
||||
void setSkeletonData (SkeletonData* skeletonData, bool ownsSkeletonData);
|
||||
void setupGLProgramState(bool twoColorTintEnabled);
|
||||
|
||||
bool _ownsSkeletonData;
|
||||
bool _ownsSkeleton;
|
||||
bool _ownsAtlas;
|
||||
Atlas* _atlas;
|
||||
AttachmentLoader* _attachmentLoader;
|
||||
cocos2d::CustomCommand _debugCommand;
|
||||
cocos2d::BlendFunc _blendFunc;
|
||||
bool _premultipliedAlpha;
|
||||
Skeleton* _skeleton;
|
||||
float _timeScale;
|
||||
bool _debugSlots;
|
||||
bool _debugBones;
|
||||
bool _debugMeshes;
|
||||
SkeletonClipping* _clipper;
|
||||
VertexEffect* _effect;
|
||||
|
||||
int _startSlotIndex;
|
||||
int _endSlotIndex;
|
||||
};
|
||||
|
||||
/* Returns 0 if the slot or attachment was not found. */
|
||||
Attachment* getAttachment (const std::string& slotName, const std::string& attachmentName) const;
|
||||
/* Returns false if the slot or attachment was not found.
|
||||
* @param attachmentName May be empty string ("") for no attachment. */
|
||||
bool setAttachment (const std::string& slotName, const std::string& attachmentName);
|
||||
/* @param attachmentName May be 0 for no attachment. */
|
||||
bool setAttachment (const std::string& slotName, const char* attachmentName);
|
||||
|
||||
/* Enables/disables two color tinting for this instance. May break batching */
|
||||
void setTwoColorTint(bool enabled);
|
||||
/* Whether two color tinting is enabled */
|
||||
bool isTwoColorTint();
|
||||
|
||||
/* Sets the vertex effect to be used, set to 0 to disable vertex effects */
|
||||
void setVertexEffect(VertexEffect* effect);
|
||||
|
||||
/* Sets the range of slots that should be rendered. Use -1, -1 to clear the range */
|
||||
void setSlotsRange(int startSlotIndex, int endSlotIndex);
|
||||
|
||||
// --- BlendProtocol
|
||||
virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
|
||||
virtual const cocos2d::BlendFunc& getBlendFunc () const override;
|
||||
virtual void setOpacityModifyRGB (bool value) override;
|
||||
virtual bool isOpacityModifyRGB () const override;
|
||||
|
||||
// Frees global memory used for temporay vertex transformations.
|
||||
static void destroyScratchBuffers();
|
||||
|
||||
CC_CONSTRUCTOR_ACCESS:
|
||||
SkeletonRenderer ();
|
||||
SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
|
||||
SkeletonRenderer (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual ~SkeletonRenderer ();
|
||||
|
||||
void initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
|
||||
void initWithData (SkeletonData* skeletonData, bool ownsSkeletonData = false);
|
||||
void initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
void initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
void initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale = 1);
|
||||
void initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
|
||||
|
||||
virtual void initialize ();
|
||||
|
||||
protected:
|
||||
void setSkeletonData (SkeletonData* skeletonData, bool ownsSkeletonData);
|
||||
void setupGLProgramState(bool twoColorTintEnabled);
|
||||
|
||||
bool _ownsSkeletonData;
|
||||
bool _ownsSkeleton;
|
||||
bool _ownsAtlas;
|
||||
Atlas* _atlas;
|
||||
AttachmentLoader* _attachmentLoader;
|
||||
cocos2d::CustomCommand _debugCommand;
|
||||
cocos2d::BlendFunc _blendFunc;
|
||||
bool _premultipliedAlpha;
|
||||
Skeleton* _skeleton;
|
||||
float _timeScale;
|
||||
bool _debugSlots;
|
||||
bool _debugBones;
|
||||
bool _debugMeshes;
|
||||
SkeletonClipping* _clipper;
|
||||
VertexEffect* _effect;
|
||||
|
||||
int _startSlotIndex;
|
||||
int _endSlotIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SPINE_SKELETONRENDERER_H_ */
|
||||
|
||||
@ -57,7 +57,7 @@ void TwoColorTrianglesCommand::init(float globalOrder, GLuint textureID, GLProgr
|
||||
if(_triangles.indexCount % 3 != 0) {
|
||||
int count = _triangles.indexCount;
|
||||
_triangles.indexCount = count / 3 * 3;
|
||||
CCLOGERROR("Resize indexCount from %zd to %zd, size must be multiple times of 3", count, _triangles.indexCount);
|
||||
CCLOGERROR("Resize indexCount from %d to %d, size must be multiple times of 3", count, _triangles.indexCount);
|
||||
}
|
||||
_mv = mv;
|
||||
|
||||
|
||||
@ -329,10 +329,11 @@ namespace Spine {
|
||||
|
||||
public float WorldToLocalRotation (float worldRotation) {
|
||||
float sin = MathUtils.SinDeg(worldRotation), cos = MathUtils.CosDeg(worldRotation);
|
||||
return MathUtils.Atan2(a * sin - c * cos, d * cos - b * sin) * MathUtils.RadDeg;
|
||||
return MathUtils.Atan2(a * sin - c * cos, d * cos - b * sin) * MathUtils.RadDeg + rotation - shearX;
|
||||
}
|
||||
|
||||
public float LocalToWorldRotation (float localRotation) {
|
||||
localRotation -= rotation - shearX;
|
||||
float sin = MathUtils.SinDeg(localRotation), cos = MathUtils.CosDeg(localRotation);
|
||||
return MathUtils.Atan2(cos * c + sin * d, cos * a + sin * b) * MathUtils.RadDeg;
|
||||
}
|
||||
|
||||
@ -127,11 +127,11 @@ public class AnimationState {
|
||||
float nextTime = current.trackLast - next.delay;
|
||||
if (nextTime >= 0) {
|
||||
next.delay = 0;
|
||||
next.trackTime = nextTime + delta * next.timeScale;
|
||||
next.trackTime = (nextTime / current.timeScale + delta) * next.timeScale;
|
||||
current.trackTime += currentDelta;
|
||||
setCurrent(i, next, true);
|
||||
while (next.mixingFrom != null) {
|
||||
next.mixTime += currentDelta;
|
||||
next.mixTime += delta;
|
||||
next = next.mixingFrom;
|
||||
}
|
||||
continue;
|
||||
@ -182,15 +182,8 @@ public class AnimationState {
|
||||
return finished;
|
||||
}
|
||||
|
||||
// If to has 0 timeScale and is not the first entry, remove the mix and apply it one more time to return to the setup pose.
|
||||
if (to.timeScale == 0 && to.mixingTo != null) {
|
||||
to.timeScale = 1;
|
||||
to.mixTime = 0;
|
||||
to.mixDuration = 0;
|
||||
}
|
||||
|
||||
from.trackTime += delta * from.timeScale;
|
||||
to.mixTime += delta * to.timeScale;
|
||||
to.mixTime += delta;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -424,10 +417,10 @@ public class AnimationState {
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes all animations from all tracks, leaving skeletons in their previous pose.
|
||||
/** Removes all animations from all tracks, leaving skeletons in their current pose.
|
||||
* <p>
|
||||
* It may be desired to use {@link AnimationState#setEmptyAnimations(float)} to mix the skeletons back to the setup pose,
|
||||
* rather than leaving them in their previous pose. */
|
||||
* rather than leaving them in their current pose. */
|
||||
public void clearTracks () {
|
||||
boolean oldDrainDisabled = queue.drainDisabled;
|
||||
queue.drainDisabled = true;
|
||||
@ -438,10 +431,10 @@ public class AnimationState {
|
||||
queue.drain();
|
||||
}
|
||||
|
||||
/** Removes all animations from the track, leaving skeletons in their previous pose.
|
||||
/** Removes all animations from the track, leaving skeletons in their current pose.
|
||||
* <p>
|
||||
* It may be desired to use {@link AnimationState#setEmptyAnimation(int, float)} to mix the skeletons back to the setup pose,
|
||||
* rather than leaving them in their previous pose. */
|
||||
* rather than leaving them in their current pose. */
|
||||
public void clearTrack (int trackIndex) {
|
||||
if (trackIndex >= tracks.size) return;
|
||||
TrackEntry current = tracks.get(trackIndex);
|
||||
@ -534,9 +527,10 @@ public class AnimationState {
|
||||
|
||||
/** Adds an animation to be played after the current or last queued animation for a track. If the track is empty, it is
|
||||
* equivalent to calling {@link #setAnimation(int, Animation, boolean)}.
|
||||
* @param delay Seconds to begin this animation after the start of the previous animation. If <= 0, uses the duration of the
|
||||
* previous track entry minus any mix duration plus the specified <code>delay</code>. If the previous entry is
|
||||
* looping, its next loop completion is used instead of the duration.
|
||||
* @param delay If > 0, sets {@link TrackEntry#getDelay()}. If <= 0, the delay set is the duration of the previous track entry
|
||||
* minus any mix duration (from the {@link AnimationStateData}) plus the specified <code>delay</code> (ie the mix
|
||||
* ends at (<code>delay</code> = 0) or before (<code>delay</code> < 0) the previous track entry duration). If the
|
||||
* previous entry is looping, its next loop completion is used instead of its duration.
|
||||
* @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
|
||||
* after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */
|
||||
public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) {
|
||||
@ -598,9 +592,10 @@ public class AnimationState {
|
||||
* {@link #setEmptyAnimation(int, float)}.
|
||||
* <p>
|
||||
* See {@link #setEmptyAnimation(int, float)}.
|
||||
* @param delay Seconds to begin this animation after the start of the previous animation. If <= 0, uses the duration of the
|
||||
* previous track entry minus any mix duration plus the specified <code>delay</code>. If the previous entry is
|
||||
* looping, its next loop completion is used instead of the duration.
|
||||
* @param delay If > 0, sets {@link TrackEntry#getDelay()}. If <= 0, the delay set is the duration of the previous track entry
|
||||
* minus any mix duration plus the specified <code>delay</code> (ie the mix ends at (<code>delay</code> = 0) or
|
||||
* before (<code>delay</code> < 0) the previous track entry duration). If the previous entry is looping, its next
|
||||
* loop completion is used instead of its duration.
|
||||
* @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
|
||||
* after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */
|
||||
public TrackEntry addEmptyAnimation (int trackIndex, float mixDuration, float delay) {
|
||||
@ -764,8 +759,8 @@ public class AnimationState {
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
/** Multiplier for the delta time when the animation state is updated, causing time for all animations to play slower or
|
||||
* faster. Defaults to 1.
|
||||
/** Multiplier for the delta time when the animation state is updated, causing time for all animations and mixes to play slower
|
||||
* or faster. Defaults to 1.
|
||||
* <p>
|
||||
* See TrackEntry {@link TrackEntry#getTimeScale()} for affecting a single animation. */
|
||||
public float getTimeScale () {
|
||||
@ -859,9 +854,12 @@ public class AnimationState {
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
/** Seconds to postpone playing the animation. When a track entry is the current track entry, <code>delay</code> postpones
|
||||
* incrementing the {@link #getTrackTime()}. When a track entry is queued, <code>delay</code> is the time from the start of
|
||||
* the previous animation to when the track entry will become the current track entry. */
|
||||
/** Seconds to postpone playing the animation. When this track entry is the current track entry, <code>delay</code>
|
||||
* postpones incrementing the {@link #getTrackTime()}. When this track entry is queued, <code>delay</code> is the time from
|
||||
* the start of the previous animation to when this track entry will become the current track entry (ie when the previous
|
||||
* track entry {@link TrackEntry#getTrackTime()} >= this track entry's <code>delay</code>).
|
||||
* <p>
|
||||
* {@link #getTimeScale()} affects the delay. */
|
||||
public float getDelay () {
|
||||
return delay;
|
||||
}
|
||||
@ -943,10 +941,15 @@ public class AnimationState {
|
||||
return Math.min(trackTime + animationStart, animationEnd);
|
||||
}
|
||||
|
||||
/** Multiplier for the delta time when the animation state is updated, causing time for this animation to pass slower or
|
||||
/** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or
|
||||
* faster. Defaults to 1.
|
||||
* <p>
|
||||
* If <code>timeScale</code> is 0, any {@link #getMixDuration()} will be ignored.
|
||||
* {@link #getMixTime()} is not affected by track entry time scale, so {@link #getMixDuration()} may need to be adjusted to
|
||||
* match the animation speed.
|
||||
* <p>
|
||||
* When using {@link AnimationState#addAnimation(int, Animation, boolean, float)} with a <code>delay</code> <= 0, note the
|
||||
* {@link #getDelay()} is set using the mix duration from the {@link AnimationStateData}, assuming time scale to be 1. If
|
||||
* the time scale is not 1, the delay may need to be adjusted.
|
||||
* <p>
|
||||
* See AnimationState {@link AnimationState#getTimeScale()} for affecting all animations. */
|
||||
public float getTimeScale () {
|
||||
@ -970,11 +973,11 @@ public class AnimationState {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/** Values < 1 mix this animation with the setup pose or the skeleton's previous pose. Defaults to 1, which overwrites the
|
||||
* skeleton's previous pose with this animation.
|
||||
/** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults
|
||||
* to 1, which overwrites the skeleton's current pose with this animation.
|
||||
* <p>
|
||||
* Typically track 0 is used to completely pose the skeleton, then alpha can be used on higher tracks. It doesn't make sense
|
||||
* to use alpha on track 0 if the skeleton pose is from the last frame render. */
|
||||
* Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to
|
||||
* use alpha on track 0 if the skeleton pose is from the last frame render. */
|
||||
public float getAlpha () {
|
||||
return alpha;
|
||||
}
|
||||
@ -984,7 +987,7 @@ public class AnimationState {
|
||||
}
|
||||
|
||||
/** When the mix percentage ({@link #getMixTime()} / {@link #getMixDuration()}) is less than the
|
||||
* <code>eventThreshold</code>, event timelines for the animation being mixed out will be applied. Defaults to 0, so event
|
||||
* <code>eventThreshold</code>, event timelines are applied while this animation is being mixed out. Defaults to 0, so event
|
||||
* timelines are not applied for an animation being mixed out. */
|
||||
public float getEventThreshold () {
|
||||
return eventThreshold;
|
||||
@ -995,8 +998,8 @@ public class AnimationState {
|
||||
}
|
||||
|
||||
/** When the mix percentage ({@link #getMixTime()} / {@link #getMixDuration()}) is less than the
|
||||
* <code>attachmentThreshold</code>, attachment timelines for the animation being mixed out will be applied. Defaults to 0,
|
||||
* so attachment timelines are not applied for an animation being mixed out. */
|
||||
* <code>attachmentThreshold</code>, attachment timelines are applied while this animation is being mixed out. Defaults to
|
||||
* 0, so attachment timelines are not applied for an animation being mixed out. */
|
||||
public float getAttachmentThreshold () {
|
||||
return attachmentThreshold;
|
||||
}
|
||||
@ -1006,7 +1009,7 @@ public class AnimationState {
|
||||
}
|
||||
|
||||
/** When the mix percentage ({@link #getMixTime()} / {@link #getMixDuration()}) is less than the
|
||||
* <code>drawOrderThreshold</code>, draw order timelines for the animation being mixed out will be applied. Defaults to 0,
|
||||
* <code>drawOrderThreshold</code>, draw order timelines are applied while this animation is being mixed out. Defaults to 0,
|
||||
* so draw order timelines are not applied for an animation being mixed out. */
|
||||
public float getDrawOrderThreshold () {
|
||||
return drawOrderThreshold;
|
||||
@ -1046,7 +1049,8 @@ public class AnimationState {
|
||||
* track entry only before {@link AnimationState#update(float)} is first called.
|
||||
* <p>
|
||||
* When using {@link AnimationState#addAnimation(int, Animation, boolean, float)} with a <code>delay</code> <= 0, note the
|
||||
* {@link #getDelay()} is set using the mix duration from the {@link AnimationStateData}. */
|
||||
* {@link #getDelay()} is set using the mix duration from the {@link AnimationStateData}, not a mix duration set
|
||||
* afterward. */
|
||||
public float getMixDuration () {
|
||||
return mixDuration;
|
||||
}
|
||||
|
||||
@ -547,11 +547,12 @@ public class Bone implements Updatable {
|
||||
/** Transforms a world rotation to a local rotation. */
|
||||
public float worldToLocalRotation (float worldRotation) {
|
||||
float sin = sinDeg(worldRotation), cos = cosDeg(worldRotation);
|
||||
return atan2(a * sin - c * cos, d * cos - b * sin) * radDeg;
|
||||
return atan2(a * sin - c * cos, d * cos - b * sin) * radDeg + rotation - shearX;
|
||||
}
|
||||
|
||||
/** Transforms a local rotation to a world rotation. */
|
||||
public float localToWorldRotation (float localRotation) {
|
||||
localRotation -= rotation - shearX;
|
||||
float sin = sinDeg(localRotation), cos = cosDeg(localRotation);
|
||||
return atan2(cos * c + sin * d, cos * a + sin * b) * radDeg;
|
||||
}
|
||||
|
||||
@ -430,14 +430,23 @@ public class PathConstraint implements Constraint {
|
||||
|
||||
private void addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
|
||||
float[] out, int o, boolean tangents) {
|
||||
if (p < epsilon || Float.isNaN(p)) p = epsilon;
|
||||
if (p < epsilon || Float.isNaN(p)) {
|
||||
out[o] = x1;
|
||||
out[o + 1] = y1;
|
||||
out[o + 2] = (float)Math.atan2(cy1 - y1, cx1 - x1);
|
||||
return;
|
||||
}
|
||||
float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
|
||||
float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
|
||||
float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
|
||||
out[o] = x;
|
||||
out[o + 1] = y;
|
||||
if (tangents)
|
||||
out[o + 2] = (float)Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
|
||||
if (tangents) {
|
||||
if (p < 0.001f)
|
||||
out[o + 2] = (float)Math.atan2(cy1 - y1, cx1 - x1);
|
||||
else
|
||||
out[o + 2] = (float)Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrder () {
|
||||
|
||||
@ -70,12 +70,12 @@ public class SkeletonRenderer {
|
||||
* previous blend function is not restored, since that could result in unnecessary flushes, depending on what is rendered
|
||||
* next. */
|
||||
public void draw (Batch batch, Skeleton skeleton) {
|
||||
if (batch instanceof PolygonSpriteBatch) {
|
||||
draw((PolygonSpriteBatch)batch, skeleton);
|
||||
return;
|
||||
} else if (batch instanceof TwoColorPolygonBatch) {
|
||||
if (batch instanceof TwoColorPolygonBatch) {
|
||||
draw((TwoColorPolygonBatch)batch, skeleton);
|
||||
return;
|
||||
} else if (batch instanceof PolygonSpriteBatch) {
|
||||
draw((PolygonSpriteBatch)batch, skeleton);
|
||||
return;
|
||||
}
|
||||
|
||||
VertexEffect vertexEffect = this.vertexEffect;
|
||||
@ -357,7 +357,7 @@ public class SkeletonRenderer {
|
||||
FloatArray clippedVertices = clipper.getClippedVertices();
|
||||
ShortArray clippedTriangles = clipper.getClippedTriangles();
|
||||
if (vertexEffect != null) applyVertexEffect(clippedVertices.items, clippedVertices.size, 6, light, dark);
|
||||
batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0,
|
||||
batch.drawTwoColor(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0,
|
||||
clippedTriangles.size);
|
||||
} else {
|
||||
if (vertexEffect != null) {
|
||||
@ -386,7 +386,7 @@ public class SkeletonRenderer {
|
||||
vertices[v + 3] = uvs[u + 1];
|
||||
}
|
||||
}
|
||||
batch.draw(texture, vertices, 0, verticesLength, triangles, 0, triangles.length);
|
||||
batch.drawTwoColor(texture, vertices, 0, verticesLength, triangles, 0, triangles.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,10 +31,15 @@
|
||||
package com.esotericsoftware.spine.utils;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.*;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Mesh;
|
||||
import com.badlogic.gdx.graphics.Mesh.VertexDataType;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.VertexAttribute;
|
||||
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.PolygonBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
@ -43,13 +48,18 @@ import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import com.badlogic.gdx.utils.NumberUtils;
|
||||
|
||||
public class TwoColorPolygonBatch implements Batch {
|
||||
/** A batch that renders polygons and performs tinting using a light and dark color.
|
||||
* <p>
|
||||
* Because an additional vertex attribute is used, the {@link Batch} and {@link PolygonBatch} methods that accept float[] vertex
|
||||
* data do not perform two color tinting. {@link #drawTwoColor(Texture, float[], int, int)} and
|
||||
* {@link #drawTwoColor(Texture, float[], int, int, short[], int, int)} are provided to accept float[] vertex data that contains
|
||||
* two colors per vertex. */
|
||||
public class TwoColorPolygonBatch implements PolygonBatch {
|
||||
static final int VERTEX_SIZE = 2 + 1 + 1 + 2;
|
||||
static final int SPRITE_SIZE = 4 * VERTEX_SIZE;
|
||||
|
||||
private final Mesh mesh;
|
||||
private final float[] vertices;
|
||||
private final float[] tempSpriteVertices = new float[SPRITE_SIZE];
|
||||
private final short[] triangles;
|
||||
private final Matrix4 transformMatrix = new Matrix4();
|
||||
private final Matrix4 projectionMatrix = new Matrix4();
|
||||
@ -313,30 +323,6 @@ public class TwoColorPolygonBatch implements Batch {
|
||||
this.vertexIndex = vertexIndex;
|
||||
}
|
||||
|
||||
public void draw (Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount, short[] polygonTriangles,
|
||||
int trianglesOffset, int trianglesCount) {
|
||||
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||
|
||||
final short[] triangles = this.triangles;
|
||||
final float[] vertices = this.vertices;
|
||||
|
||||
if (texture != lastTexture) {
|
||||
switchTexture(texture);
|
||||
} else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount > vertices.length) //
|
||||
flush();
|
||||
|
||||
int triangleIndex = this.triangleIndex;
|
||||
final int vertexIndex = this.vertexIndex;
|
||||
final int startVertex = vertexIndex / 6;
|
||||
|
||||
for (int i = trianglesOffset, n = i + trianglesCount; i < n; i++)
|
||||
triangles[triangleIndex++] = (short)(polygonTriangles[i] + startVertex);
|
||||
this.triangleIndex = triangleIndex;
|
||||
|
||||
System.arraycopy(polygonVertices, verticesOffset, vertices, vertexIndex, verticesCount);
|
||||
this.vertexIndex += verticesCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw (Texture texture, float x, float y, float originX, float originY, float width, float height, float scaleX,
|
||||
float scaleY, float rotation, int srcX, int srcY, int srcWidth, int srcHeight, boolean flipX, boolean flipY) {
|
||||
@ -746,28 +732,74 @@ public class TwoColorPolygonBatch implements Batch {
|
||||
this.vertexIndex = idx;
|
||||
}
|
||||
|
||||
/** Draws a rectangle using the given vertices. There must be 4 vertices, each made up of 6 elements in this order: x, y,
|
||||
* lightColor, darkColor, u, v. The {@link #getColor()} and {@link #getDarkColor()} from the TwoColorPolygonBatch is not
|
||||
/** Draws polygons using the given vertices and triangles. There must be 4 vertices, each made up of 6 elements in this order:
|
||||
* x, y, lightColor, darkColor, u, v. The {@link #getColor()} and {@link #getDarkColor()} from the TwoColorPolygonBatch is not
|
||||
* applied. */
|
||||
@Override
|
||||
public void draw (Texture texture, float[] spriteVertices, int offset, int count) {
|
||||
public void drawTwoColor (Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount,
|
||||
short[] polygonTriangles, int trianglesOffset, int trianglesCount) {
|
||||
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||
|
||||
// odds are this is a sprite, we meed to convert it
|
||||
if (spriteVertices.length == 20 && offset == 0 && count == 20) {
|
||||
final float[] vertices = tempSpriteVertices;
|
||||
int idx = 0;
|
||||
for (int i = 0; i < 20; i += 5) {
|
||||
vertices[idx++] = spriteVertices[i];
|
||||
vertices[idx++] = spriteVertices[i + 1];
|
||||
vertices[idx++] = spriteVertices[i + 2];
|
||||
vertices[idx++] = 0; // dark
|
||||
vertices[idx++] = spriteVertices[i + 3];
|
||||
vertices[idx++] = spriteVertices[i + 4];
|
||||
}
|
||||
spriteVertices = vertices;
|
||||
count = SPRITE_SIZE;
|
||||
final short[] triangles = this.triangles;
|
||||
final float[] vertices = this.vertices;
|
||||
|
||||
if (texture != lastTexture) {
|
||||
switchTexture(texture);
|
||||
} else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount > vertices.length) //
|
||||
flush();
|
||||
|
||||
int triangleIndex = this.triangleIndex;
|
||||
final int vertexIndex = this.vertexIndex;
|
||||
final int startVertex = vertexIndex / 6;
|
||||
|
||||
for (int i = trianglesOffset, n = i + trianglesCount; i < n; i++)
|
||||
triangles[triangleIndex++] = (short)(polygonTriangles[i] + startVertex);
|
||||
this.triangleIndex = triangleIndex;
|
||||
|
||||
System.arraycopy(polygonVertices, verticesOffset, vertices, vertexIndex, verticesCount);
|
||||
this.vertexIndex += verticesCount;
|
||||
}
|
||||
|
||||
/** Draws polygons using the given vertices and triangles in the {@link PolygonBatch} format. There must be 4 vertices, each
|
||||
* made up of 5 elements in this order: x, y, color, u, v. The {@link #getColor()} and {@link #getDarkColor()} from the
|
||||
* TwoColorPolygonBatch is not applied. */
|
||||
public void draw (Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount, short[] polygonTriangles,
|
||||
int trianglesOffset, int trianglesCount) {
|
||||
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||
|
||||
final short[] triangles = this.triangles;
|
||||
final float[] vertices = this.vertices;
|
||||
|
||||
if (texture != lastTexture) {
|
||||
switchTexture(texture);
|
||||
} else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount / 5 * 6 > vertices.length) //
|
||||
flush();
|
||||
|
||||
int triangleIndex = this.triangleIndex;
|
||||
final int vertexIndex = this.vertexIndex;
|
||||
final int startVertex = vertexIndex / 6;
|
||||
|
||||
for (int i = trianglesOffset, n = i + trianglesCount; i < n; i++)
|
||||
triangles[triangleIndex++] = (short)(polygonTriangles[i] + startVertex);
|
||||
this.triangleIndex = triangleIndex;
|
||||
|
||||
int idx = this.vertexIndex;
|
||||
for (int i = verticesOffset, n = verticesOffset + verticesCount; i < n; i += 5) {
|
||||
vertices[idx++] = polygonVertices[i];
|
||||
vertices[idx++] = polygonVertices[i + 1];
|
||||
vertices[idx++] = polygonVertices[i + 2];
|
||||
vertices[idx++] = 0; // dark
|
||||
vertices[idx++] = polygonVertices[i + 3];
|
||||
vertices[idx++] = polygonVertices[i + 4];
|
||||
}
|
||||
this.vertexIndex = idx;
|
||||
}
|
||||
|
||||
/** Draws rectangles using the given vertices. There must be 4 vertices, each made up of 6 elements in this order: x, y,
|
||||
* lightColor, darkColor, u, v. The {@link #getColor()} and {@link #getDarkColor()} from the TwoColorPolygonBatch is not
|
||||
* applied. */
|
||||
public void drawTwoColor (Texture texture, float[] spriteVertices, int offset, int count) {
|
||||
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||
|
||||
final short[] triangles = this.triangles;
|
||||
final float[] vertices = this.vertices;
|
||||
|
||||
@ -794,6 +826,47 @@ public class TwoColorPolygonBatch implements Batch {
|
||||
this.vertexIndex += count;
|
||||
}
|
||||
|
||||
/** Draws rectangles using the given vertices in the {@link Batch} format. There must be 4 vertices, each made up of 5 elements
|
||||
* in this order: x, y, color, u, v. The {@link #getColor()} and {@link #getDarkColor()} from the TwoColorPolygonBatch is not
|
||||
* applied. */
|
||||
@Override
|
||||
public void draw (Texture texture, float[] spriteVertices, int offset, int count) {
|
||||
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||
|
||||
final short[] triangles = this.triangles;
|
||||
final float[] vertices = this.vertices;
|
||||
|
||||
final int triangleCount = count / 20 * 6;
|
||||
if (texture != lastTexture)
|
||||
switchTexture(texture);
|
||||
else if (triangleIndex + triangleCount > triangles.length || vertexIndex + count / 5 * 6 > vertices.length) //
|
||||
flush();
|
||||
|
||||
final int vertexIndex = this.vertexIndex;
|
||||
int triangleIndex = this.triangleIndex;
|
||||
short vertex = (short)(vertexIndex / VERTEX_SIZE);
|
||||
for (int n = triangleIndex + triangleCount; triangleIndex < n; triangleIndex += 6, vertex += 4) {
|
||||
triangles[triangleIndex] = vertex;
|
||||
triangles[triangleIndex + 1] = (short)(vertex + 1);
|
||||
triangles[triangleIndex + 2] = (short)(vertex + 2);
|
||||
triangles[triangleIndex + 3] = (short)(vertex + 2);
|
||||
triangles[triangleIndex + 4] = (short)(vertex + 3);
|
||||
triangles[triangleIndex + 5] = vertex;
|
||||
}
|
||||
this.triangleIndex = triangleIndex;
|
||||
|
||||
int idx = this.vertexIndex;
|
||||
for (int i = offset, n = offset + count; i < n; i += 5) {
|
||||
vertices[idx++] = spriteVertices[i];
|
||||
vertices[idx++] = spriteVertices[i + 1];
|
||||
vertices[idx++] = spriteVertices[i + 2];
|
||||
vertices[idx++] = 0; // dark
|
||||
vertices[idx++] = spriteVertices[i + 3];
|
||||
vertices[idx++] = spriteVertices[i + 4];
|
||||
}
|
||||
this.vertexIndex = idx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw (TextureRegion region, float x, float y) {
|
||||
draw(region, x, y, region.getRegionWidth(), region.getRegionHeight());
|
||||
|
||||
@ -244,6 +244,10 @@ namespace Spine.Unity.Editor {
|
||||
const string DEFAULT_ZSPACING_KEY = "SPINE_DEFAULT_ZSPACING";
|
||||
public static float defaultZSpacing = DEFAULT_DEFAULT_ZSPACING;
|
||||
|
||||
const bool DEFAULT_DEFAULT_INSTANTIATE_LOOP = true;
|
||||
const string DEFAULT_INSTANTIATE_LOOP_KEY = "SPINE_DEFAULT_INSTANTIATE_LOOP";
|
||||
public static bool defaultInstantiateLoop = DEFAULT_DEFAULT_INSTANTIATE_LOOP;
|
||||
|
||||
const bool DEFAULT_SHOW_HIERARCHY_ICONS = true;
|
||||
const string SHOW_HIERARCHY_ICONS_KEY = "SPINE_SHOW_HIERARCHY_ICONS";
|
||||
public static bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS;
|
||||
@ -327,6 +331,11 @@ namespace Spine.Unity.Editor {
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorPrefs.SetFloat(DEFAULT_ZSPACING_KEY, defaultZSpacing);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
defaultInstantiateLoop = EditorGUILayout.Toggle(new GUIContent("Default Loop", "Spawn Spine GameObjects with loop enabled."), defaultInstantiateLoop);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorPrefs.SetBool(DEFAULT_INSTANTIATE_LOOP_KEY, defaultInstantiateLoop);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
@ -1246,6 +1255,7 @@ namespace Spine.Unity.Editor {
|
||||
throw e;
|
||||
}
|
||||
|
||||
newSkeletonAnimation.loop = SpineEditorUtilities.Preferences.defaultInstantiateLoop;
|
||||
newSkeletonAnimation.skeleton.Update(0);
|
||||
newSkeletonAnimation.state.Update(0);
|
||||
newSkeletonAnimation.state.Apply(newSkeletonAnimation.skeleton);
|
||||
|
||||
@ -195,6 +195,7 @@ namespace Spine.Unity.Editor {
|
||||
skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0];
|
||||
graphic.MeshGenerator.settings.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing;
|
||||
|
||||
graphic.startingLoop = SpineEditorUtilities.Preferences.defaultInstantiateLoop;
|
||||
graphic.Initialize(false);
|
||||
if (skin != null) graphic.Skeleton.SetSkin(skin);
|
||||
graphic.initialSkinName = skin.Name;
|
||||
|
||||
@ -258,12 +258,12 @@ namespace Spine.Unity.Editor {
|
||||
GameObject go = skeletonUtility.SpawnBoneRecursively(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
|
||||
SkeletonUtilityBone[] newUtilityBones = go.GetComponentsInChildren<SkeletonUtilityBone>();
|
||||
foreach (SkeletonUtilityBone utilBone in newUtilityBones)
|
||||
SkeletonGameObjectsInspector.AttachIcon(utilBone);
|
||||
SkeletonUtilityInspector.AttachIcon(utilBone);
|
||||
}
|
||||
} else {
|
||||
var bone = (Bone)obj;
|
||||
GameObject go = skeletonUtility.SpawnBone(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
|
||||
SkeletonGameObjectsInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
|
||||
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
|
||||
Selection.activeGameObject = go;
|
||||
EditorGUIUtility.PingObject(go);
|
||||
}
|
||||
@ -272,7 +272,7 @@ namespace Spine.Unity.Editor {
|
||||
void SpawnOverride () {
|
||||
GameObject go = skeletonUtility.SpawnBone(utilityBone.bone, utilityBone.transform.parent, SkeletonUtilityBone.Mode.Override, utilityBone.position, utilityBone.rotation, utilityBone.scale);
|
||||
go.name = go.name + " [Override]";
|
||||
SkeletonGameObjectsInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
|
||||
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
|
||||
Selection.activeGameObject = go;
|
||||
EditorGUIUtility.PingObject(go);
|
||||
}
|
||||
|
||||
@ -41,17 +41,17 @@ namespace Spine.Unity.Editor {
|
||||
using Icons = SpineEditorUtilities.Icons;
|
||||
|
||||
[CustomEditor(typeof(SkeletonUtility))]
|
||||
public class SkeletonGameObjectsInspector : UnityEditor.Editor {
|
||||
public class SkeletonUtilityInspector : UnityEditor.Editor {
|
||||
|
||||
SkeletonUtility skeletonGameObjects;
|
||||
SkeletonUtility skeletonUtility;
|
||||
Skeleton skeleton;
|
||||
SkeletonRenderer skeletonRenderer;
|
||||
bool isPrefab;
|
||||
readonly GUIContent SpawnHierarchyButtonLabel = new GUIContent("Spawn Hierarchy", Icons.skeleton);
|
||||
|
||||
void OnEnable () {
|
||||
skeletonGameObjects = (SkeletonUtility)target;
|
||||
skeletonRenderer = skeletonGameObjects.GetComponent<SkeletonRenderer>();
|
||||
skeletonUtility = (SkeletonUtility)target;
|
||||
skeletonRenderer = skeletonUtility.GetComponent<SkeletonRenderer>();
|
||||
skeleton = skeletonRenderer.Skeleton;
|
||||
|
||||
if (skeleton == null) {
|
||||
@ -78,7 +78,7 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("boneRoot"), SpineInspectorUtility.TempContent("Skeleton Root"));
|
||||
|
||||
bool hasRootBone = skeletonGameObjects.boneRoot != null;
|
||||
bool hasRootBone = skeletonUtility.boneRoot != null;
|
||||
|
||||
if (!hasRootBone)
|
||||
EditorGUILayout.HelpBox("No hierarchy found. Use Spawn Hierarchy to generate GameObjects for bones.", MessageType.Info);
|
||||
@ -90,9 +90,9 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
if (hasRootBone) {
|
||||
if (SpineInspectorUtility.CenteredButton(new GUIContent("Remove Hierarchy"))) {
|
||||
Undo.RegisterCompleteObjectUndo(skeletonGameObjects, "Remove Hierarchy");
|
||||
Undo.DestroyObjectImmediate(skeletonGameObjects.boneRoot.gameObject);
|
||||
skeletonGameObjects.boneRoot = null;
|
||||
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Remove Hierarchy");
|
||||
Undo.DestroyObjectImmediate(skeletonUtility.boneRoot.gameObject);
|
||||
skeletonUtility.boneRoot = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,23 +134,23 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
|
||||
void SpawnFollowHierarchy () {
|
||||
Selection.activeGameObject = skeletonGameObjects.SpawnHierarchy(SkeletonUtilityBone.Mode.Follow, true, true, true);
|
||||
AttachIconsToChildren(skeletonGameObjects.boneRoot);
|
||||
Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Follow, true, true, true);
|
||||
AttachIconsToChildren(skeletonUtility.boneRoot);
|
||||
}
|
||||
|
||||
void SpawnFollowHierarchyRootOnly () {
|
||||
Selection.activeGameObject = skeletonGameObjects.SpawnRoot(SkeletonUtilityBone.Mode.Follow, true, true, true);
|
||||
AttachIconsToChildren(skeletonGameObjects.boneRoot);
|
||||
Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Follow, true, true, true);
|
||||
AttachIconsToChildren(skeletonUtility.boneRoot);
|
||||
}
|
||||
|
||||
void SpawnOverrideHierarchy () {
|
||||
Selection.activeGameObject = skeletonGameObjects.SpawnHierarchy(SkeletonUtilityBone.Mode.Override, true, true, true);
|
||||
AttachIconsToChildren(skeletonGameObjects.boneRoot);
|
||||
Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Override, true, true, true);
|
||||
AttachIconsToChildren(skeletonUtility.boneRoot);
|
||||
}
|
||||
|
||||
void SpawnOverrideHierarchyRootOnly () {
|
||||
Selection.activeGameObject = skeletonGameObjects.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true);
|
||||
AttachIconsToChildren(skeletonGameObjects.boneRoot);
|
||||
Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true);
|
||||
AttachIconsToChildren(skeletonUtility.boneRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -172,6 +172,13 @@ namespace Spine.Unity {
|
||||
if (skeleton != null) skeleton.SetToSetupPose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a minimum buffer size for the internal MeshGenerator to prevent excess allocations during animation.
|
||||
/// </summary>
|
||||
public void EnsureMeshGeneratorCapacity (int minimumVertexCount) {
|
||||
meshGenerator.EnsureVertexCapacity(minimumVertexCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize this component. Attempts to load the SkeletonData and creates the internal Skeleton object and buffers.</summary>
|
||||
/// <param name="overwrite">If set to <c>true</c>, it will overwrite internal objects if they were already generated. Otherwise, the initialized component will ignore subsequent calls to initialize.</param>
|
||||
|
||||
@ -455,12 +455,13 @@ namespace Spine.Unity {
|
||||
public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = true) {
|
||||
var settings = this.settings;
|
||||
|
||||
if (submeshes.Count - 1 < submeshIndex) {
|
||||
submeshes.Resize(submeshIndex + 1);
|
||||
if (submeshes.Items[submeshIndex] == null)
|
||||
submeshes.Items[submeshIndex] = new ExposedList<int>();
|
||||
}
|
||||
int newSubmeshCount = submeshIndex + 1;
|
||||
if (submeshes.Items.Length < newSubmeshCount)
|
||||
submeshes.Resize(newSubmeshCount);
|
||||
submeshes.Count = newSubmeshCount;
|
||||
var submesh = submeshes.Items[submeshIndex];
|
||||
if (submesh == null)
|
||||
submeshes.Items[submeshIndex] = submesh = new ExposedList<int>();
|
||||
submesh.Clear(false);
|
||||
|
||||
var skeleton = instruction.skeleton;
|
||||
@ -570,10 +571,13 @@ namespace Spine.Unity {
|
||||
// Add data to vertex buffers
|
||||
{
|
||||
int newVertexCount = ovc + attachmentVertexCount;
|
||||
if (newVertexCount > vertexBuffer.Items.Length) { // Manual ExposedList.Resize()
|
||||
Array.Resize(ref vertexBuffer.Items, newVertexCount);
|
||||
Array.Resize(ref uvBuffer.Items, newVertexCount);
|
||||
Array.Resize(ref colorBuffer.Items, newVertexCount);
|
||||
int oldArraySize = vertexBuffer.Items.Length;
|
||||
if (newVertexCount > oldArraySize) {
|
||||
int newArraySize = (int)(oldArraySize * 1.3f);
|
||||
if (newArraySize < newVertexCount) newArraySize = newVertexCount;
|
||||
Array.Resize(ref vertexBuffer.Items, newArraySize);
|
||||
Array.Resize(ref uvBuffer.Items, newArraySize);
|
||||
Array.Resize(ref colorBuffer.Items, newArraySize);
|
||||
}
|
||||
vertexBuffer.Count = uvBuffer.Count = colorBuffer.Count = newVertexCount;
|
||||
}
|
||||
@ -1057,6 +1061,38 @@ namespace Spine.Unity {
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void EnsureVertexCapacity (int minimumVertexCount, bool inlcudeTintBlack = false, bool includeTangents = false, bool includeNormals = false) {
|
||||
if (minimumVertexCount > vertexBuffer.Items.Length) {
|
||||
Array.Resize(ref vertexBuffer.Items, minimumVertexCount);
|
||||
Array.Resize(ref uvBuffer.Items, minimumVertexCount);
|
||||
Array.Resize(ref colorBuffer.Items, minimumVertexCount);
|
||||
|
||||
if (inlcudeTintBlack) {
|
||||
if (uv2 == null) {
|
||||
uv2 = new ExposedList<Vector2>(minimumVertexCount);
|
||||
uv3 = new ExposedList<Vector2>(minimumVertexCount);
|
||||
}
|
||||
uv2.Resize(minimumVertexCount);
|
||||
uv3.Resize(minimumVertexCount);
|
||||
}
|
||||
|
||||
if (includeNormals) {
|
||||
if (normals == null)
|
||||
normals = new Vector3[minimumVertexCount];
|
||||
else
|
||||
Array.Resize(ref normals, minimumVertexCount);
|
||||
|
||||
}
|
||||
|
||||
if (includeTangents) {
|
||||
if (tangents == null)
|
||||
tangents = new Vector4[minimumVertexCount];
|
||||
else
|
||||
Array.Resize(ref tangents, minimumVertexCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TrimExcess () {
|
||||
vertexBuffer.TrimExcess();
|
||||
uvBuffer.TrimExcess();
|
||||
@ -1437,13 +1473,13 @@ namespace Spine.Unity {
|
||||
this.hasActiveClipping = other.hasActiveClipping;
|
||||
this.rawVertexCount = other.rawVertexCount;
|
||||
this.attachments.Clear(false);
|
||||
this.attachments.GrowIfNeeded(other.attachments.Capacity);
|
||||
this.attachments.EnsureCapacity(other.attachments.Capacity);
|
||||
this.attachments.Count = other.attachments.Count;
|
||||
other.attachments.CopyTo(this.attachments.Items);
|
||||
#endif
|
||||
|
||||
this.submeshInstructions.Clear(false);
|
||||
this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity);
|
||||
this.submeshInstructions.EnsureCapacity(other.submeshInstructions.Capacity);
|
||||
this.submeshInstructions.Count = other.submeshInstructions.Count;
|
||||
other.submeshInstructions.CopyTo(this.submeshInstructions.Items);
|
||||
}
|
||||
|
||||
@ -0,0 +1,105 @@
|
||||
// - Unlit
|
||||
// - Premultiplied Alpha Blending (Optional straight alpha input)
|
||||
// - Double-sided, no depth
|
||||
|
||||
Shader "Spine/Special/Skeleton Grayscale" {
|
||||
Properties {
|
||||
_GrayPhase ("Phase", Range(0, 1)) = 1
|
||||
[NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {}
|
||||
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
|
||||
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
|
||||
}
|
||||
SubShader {
|
||||
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
|
||||
Blend One OneMinusSrcAlpha
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
Lighting Off
|
||||
|
||||
Pass {
|
||||
CGPROGRAM
|
||||
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
sampler2D _MainTex;
|
||||
float _GrayPhase;
|
||||
|
||||
struct VertexInput {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertexColor : COLOR;
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
float4 pos : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertexColor : COLOR;
|
||||
};
|
||||
|
||||
VertexOutput vert (VertexInput v) {
|
||||
VertexOutput o = (VertexOutput)0;
|
||||
o.uv = v.uv;
|
||||
o.vertexColor = v.vertexColor;
|
||||
o.pos = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 frag (VertexOutput i) : COLOR {
|
||||
float4 rawColor = tex2D(_MainTex,i.uv);
|
||||
float finalAlpha = (rawColor.a * i.vertexColor.a);
|
||||
|
||||
#if defined(_STRAIGHT_ALPHA_INPUT)
|
||||
rawColor.rgb *= rawColor.a;
|
||||
#endif
|
||||
|
||||
rawColor.rgb *= i.vertexColor.rgb;
|
||||
|
||||
float3 finalColor = lerp(rawColor.rgb, dot(rawColor.rgb, float3(0.3, 0.59, 0.11)), _GrayPhase);
|
||||
return fixed4(finalColor, finalAlpha);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
|
||||
Pass {
|
||||
Name "Caster"
|
||||
Tags { "LightMode"="ShadowCaster" }
|
||||
Offset 1, 1
|
||||
ZWrite On
|
||||
ZTest LEqual
|
||||
|
||||
Fog { Mode Off }
|
||||
Cull Off
|
||||
Lighting Off
|
||||
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile_shadowcaster
|
||||
#pragma fragmentoption ARB_precision_hint_fastest
|
||||
#include "UnityCG.cginc"
|
||||
sampler2D _MainTex;
|
||||
fixed _Cutoff;
|
||||
|
||||
struct VertexOutput {
|
||||
V2F_SHADOW_CASTER;
|
||||
float2 uv : TEXCOORD1;
|
||||
};
|
||||
|
||||
VertexOutput vert (appdata_base v) {
|
||||
VertexOutput o;
|
||||
o.uv = v.texcoord;
|
||||
TRANSFER_SHADOW_CASTER(o)
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 frag (VertexOutput i) : COLOR {
|
||||
fixed4 texcol = tex2D(_MainTex, i.uv);
|
||||
clip(texcol.a - _Cutoff);
|
||||
SHADOW_CASTER_FRAGMENT(i)
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
FallBack "Diffuse"
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea7e7c05f36541b4bb280f98ebda8ba1
|
||||
timeCreated: 1492385797
|
||||
licenseType: Free
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -557,7 +557,8 @@ namespace Spine {
|
||||
|
||||
var drawOrder = skeleton.drawOrder;
|
||||
drawOrder.Clear(false);
|
||||
drawOrder.GrowIfNeeded(n);
|
||||
drawOrder.EnsureCapacity(n);
|
||||
drawOrder.Count = n;
|
||||
System.Array.Copy(slotsItems, drawOrder.Items, n);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user