[v4] spine v3.8

This commit is contained in:
halx99 2020-01-05 03:09:32 +08:00
parent 0d5a07450d
commit a2eb8507bb
42 changed files with 10477 additions and 3659 deletions

View File

@ -49,7 +49,7 @@ include(audio/CMakeLists.txt)
# default value for cocos2dx extensions modules build
option(BUILD_EDITOR_COCOSTUDIO "Build editor support for cocostudio" ON)
option(BUILD_EDITOR_SPINE "Build editor support for spine" OFF)
option(BUILD_EDITOR_SPINE "Build editor support for spine" ON)
option(BUILD_EXTENSIONS "Build extension library" ON)
if(BUILD_EDITOR_COCOSTUDIO)
@ -58,7 +58,11 @@ if(BUILD_EDITOR_COCOSTUDIO)
endif(BUILD_EDITOR_COCOSTUDIO)
if(BUILD_EDITOR_SPINE)
include(editor-support/spine/CMakeLists.txt)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/editor-support/spine/CMakeLists.txt")
include(editor-support/spine/CMakeLists.txt)
else()
message(WARNING "${CMAKE_CURRENT_SOURCE_DIR}/editor-support/spine/CMakeLists.txt not found!")
endif()
set(COCOS_EDITOR_SUPPORT_SRC ${COCOS_EDITOR_SUPPORT_SRC} ${COCOS_SPINE_SRC} ${COCOS_SPINE_HEADER})
endif(BUILD_EDITOR_SPINE)

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,16 +15,16 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#include <spine/AttachmentVertices.h>
@ -35,6 +35,7 @@ namespace spine {
AttachmentVertices::AttachmentVertices (Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount) {
_texture = texture;
if (_texture) _texture->retain();
_triangles = new TrianglesCommand::Triangles();
_triangles->verts = new V3F_C4B_T2F[verticesCount];
@ -46,6 +47,7 @@ AttachmentVertices::AttachmentVertices (Texture2D* texture, int verticesCount, u
AttachmentVertices::~AttachmentVertices () {
delete [] _triangles->verts;
delete _triangles;
if (_texture) _texture->release();
}
}

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,16 +15,16 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_ATTACHMENTVERTICES_H_

View File

@ -1,17 +1,10 @@
set(COCOS_SPINE_HEADER
editor-support/spine/AttachmentVertices.h
editor-support/spine/SkeletonAnimation.h
editor-support/spine/SkeletonBatch.h
editor-support/spine/SkeletonRenderer.h
editor-support/spine/SkeletonTwoColorBatch.h
editor-support/spine/spine-cocos2dx.h
)
set(COCOS_SPINE_SRC
editor-support/spine/AttachmentVertices.cpp
editor-support/spine/SkeletonAnimation.cpp
editor-support/spine/SkeletonBatch.cpp
editor-support/spine/SkeletonRenderer.cpp
editor-support/spine/SkeletonTwoColorBatch.cpp
editor-support/spine/spine-cocos2dx.cpp
)
file(GLOB_RECURSE COCOS_SPINE_SRC
${CMAKE_CURRENT_LIST_DIR}/*.cpp
${CMAKE_CURRENT_LIST_DIR}/**/*.cpp
)
file(GLOB_RECURSE COCOS_SPINE_HEADER
${CMAKE_CURRENT_LIST_DIR}/*.h
${CMAKE_CURRENT_LIST_DIR}/**/*.h
)

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,16 +15,16 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#include <spine/SkeletonAnimation.h>
@ -40,25 +40,26 @@ using std::vector;
namespace spine {
typedef struct _TrackEntryListeners {
StartListener startListener;
InterruptListener interruptListener;
EndListener endListener;
DisposeListener disposeListener;
CompleteListener completeListener;
EventListener eventListener;
StartListener startListener;
InterruptListener interruptListener;
EndListener endListener;
DisposeListener disposeListener;
CompleteListener completeListener;
EventListener eventListener;
} _TrackEntryListeners;
void animationCallback (AnimationState* state, EventType type, TrackEntry* entry, Event* event) {
((SkeletonAnimation*)state->getRendererObject())->onAnimationStateEvent(entry, type, event);
}
void trackEntryCallback (AnimationState* state, EventType type, TrackEntry* entry, Event* event) {
((SkeletonAnimation*)state->getRendererObject())->onTrackEntryEvent(entry, type, event);
if (type == EventType_Dispose)
if (type == EventType_Dispose) {
if (entry->getRendererObject()) {
delete (spine::_TrackEntryListeners*)entry->getRendererObject();
entry->setRendererObject(NULL);
}
}
}
static _TrackEntryListeners* getListeners (TrackEntry* entry) {
@ -68,7 +69,7 @@ static _TrackEntryListeners* getListeners (TrackEntry* entry) {
}
return (_TrackEntryListeners*)entry->getRendererObject();
}
//
SkeletonAnimation* SkeletonAnimation::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) {
@ -111,6 +112,7 @@ void SkeletonAnimation::initialize () {
super::initialize();
_ownsAnimationStateData = true;
_updateOnlyIfVisible = false;
_state = new (__FILE__, __LINE__) AnimationState(new (__FILE__, __LINE__) AnimationStateData(_skeleton->getData()));
_state->setRendererObject(this);
_state->setListener(animationCallback);
@ -128,12 +130,16 @@ SkeletonAnimation::~SkeletonAnimation () {
}
void SkeletonAnimation::update (float deltaTime) {
if (_updateOnlyIfVisible && !isVisible()) return;
super::update(deltaTime);
deltaTime *= _timeScale;
if (_preUpdateListener) _preUpdateListener(this);
_state->update(deltaTime);
_state->apply(*_skeleton);
_skeleton->updateWorldTransform();
if (_postUpdateListener) _postUpdateListener(this);
}
void SkeletonAnimation::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t transformFlags) {
@ -147,7 +153,7 @@ void SkeletonAnimation::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &t
void SkeletonAnimation::setAnimationStateData (AnimationStateData* stateData) {
CCASSERT(stateData, "stateData cannot be null.");
if (_ownsAnimationStateData) delete _state->getData();
if (_ownsAnimationStateData) delete _state->getData();
delete _state;
_ownsAnimationStateData = false;
@ -177,7 +183,7 @@ TrackEntry* SkeletonAnimation::addAnimation (int trackIndex, const std::string&
}
return _state->addAnimation(trackIndex, animation, loop, delay);
}
TrackEntry* SkeletonAnimation::setEmptyAnimation (int trackIndex, float mixDuration) {
return _state->setEmptyAnimation(trackIndex, mixDuration);
}
@ -211,15 +217,15 @@ void SkeletonAnimation::onAnimationStateEvent (TrackEntry* entry, EventType type
case EventType_Start:
if (_startListener) _startListener(entry);
break;
case EventType_Interrupt:
if (_interruptListener) _interruptListener(entry);
break;
case EventType_Interrupt:
if (_interruptListener) _interruptListener(entry);
break;
case EventType_End:
if (_endListener) _endListener(entry);
break;
case EventType_Dispose:
if (_disposeListener) _disposeListener(entry);
break;
case EventType_Dispose:
if (_disposeListener) _disposeListener(entry);
break;
case EventType_Complete:
if (_completeListener) _completeListener(entry);
break;
@ -236,15 +242,15 @@ void SkeletonAnimation::onTrackEntryEvent (TrackEntry* entry, EventType type, Ev
case EventType_Start:
if (listeners->startListener) listeners->startListener(entry);
break;
case EventType_Interrupt:
if (listeners->interruptListener) listeners->interruptListener(entry);
break;
case EventType_Interrupt:
if (listeners->interruptListener) listeners->interruptListener(entry);
break;
case EventType_End:
if (listeners->endListener) listeners->endListener(entry);
break;
case EventType_Dispose:
if (listeners->disposeListener) listeners->disposeListener(entry);
break;
case EventType_Dispose:
if (listeners->disposeListener) listeners->disposeListener(entry);
break;
case EventType_Complete:
if (listeners->completeListener) listeners->completeListener(entry);
break;
@ -257,17 +263,17 @@ void SkeletonAnimation::onTrackEntryEvent (TrackEntry* entry, EventType type, Ev
void SkeletonAnimation::setStartListener (const StartListener& listener) {
_startListener = listener;
}
void SkeletonAnimation::setInterruptListener (const InterruptListener& listener) {
_interruptListener = listener;
_interruptListener = listener;
}
void SkeletonAnimation::setEndListener (const EndListener& listener) {
_endListener = listener;
}
void SkeletonAnimation::setDisposeListener (const DisposeListener& listener) {
_disposeListener = listener;
_disposeListener = listener;
}
void SkeletonAnimation::setCompleteListener (const CompleteListener& listener) {
@ -278,20 +284,28 @@ void SkeletonAnimation::setEventListener (const EventListener& listener) {
_eventListener = listener;
}
void SkeletonAnimation::setPreUpdateWorldTransformsListener(const UpdateWorldTransformsListener &listener) {
_preUpdateListener = listener;
}
void SkeletonAnimation::setPostUpdateWorldTransformsListener(const UpdateWorldTransformsListener &listener) {
_postUpdateListener = listener;
}
void SkeletonAnimation::setTrackStartListener (TrackEntry* entry, const StartListener& listener) {
getListeners(entry)->startListener = listener;
}
void SkeletonAnimation::setTrackInterruptListener (TrackEntry* entry, const InterruptListener& listener) {
getListeners(entry)->interruptListener = listener;
getListeners(entry)->interruptListener = listener;
}
void SkeletonAnimation::setTrackEndListener (TrackEntry* entry, const EndListener& listener) {
getListeners(entry)->endListener = listener;
}
void SkeletonAnimation::setTrackDisposeListener (TrackEntry* entry, const DisposeListener& listener) {
getListeners(entry)->disposeListener = listener;
getListeners(entry)->disposeListener = listener;
}
void SkeletonAnimation::setTrackCompleteListener (TrackEntry* entry, const CompleteListener& listener) {
@ -306,4 +320,8 @@ AnimationState* SkeletonAnimation::getState() const {
return _state;
}
void SkeletonAnimation::setUpdateOnlyIfVisible(bool status) {
_updateOnlyIfVisible = status;
}
}

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,33 +15,36 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_SKELETONANIMATION_H_
#define SPINE_SKELETONANIMATION_H_
#define SPINE_SHORT_NAMES
#include <spine/spine.h>
#include <spine/SkeletonRenderer.h>
#include <spine/spine-cocos2dx.h>
#include "cocos2d.h"
namespace spine {
class SkeletonAnimation;
typedef std::function<void(TrackEntry* entry)> StartListener;
typedef std::function<void(TrackEntry* entry)> InterruptListener;
typedef std::function<void(TrackEntry* entry)> EndListener;
typedef std::function<void(TrackEntry* entry)> DisposeListener;
typedef std::function<void(TrackEntry* entry)> CompleteListener;
typedef std::function<void(TrackEntry* entry, Event* event)> EventListener;
typedef std::function<void(SkeletonAnimation* node)> UpdateWorldTransformsListener;
/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be
* played later. */
@ -82,16 +85,18 @@ public:
void clearTrack (int trackIndex = 0);
void setStartListener (const StartListener& listener);
void setInterruptListener (const InterruptListener& listener);
void setInterruptListener (const InterruptListener& listener);
void setEndListener (const EndListener& listener);
void setDisposeListener (const DisposeListener& listener);
void setDisposeListener (const DisposeListener& listener);
void setCompleteListener (const CompleteListener& listener);
void setEventListener (const EventListener& listener);
void setPreUpdateWorldTransformsListener(const UpdateWorldTransformsListener& listener);
void setPostUpdateWorldTransformsListener(const UpdateWorldTransformsListener& listener);
void setTrackStartListener (TrackEntry* entry, const StartListener& listener);
void setTrackInterruptListener (TrackEntry* entry, const InterruptListener& listener);
void setTrackInterruptListener (TrackEntry* entry, const InterruptListener& listener);
void setTrackEndListener (TrackEntry* entry, const EndListener& listener);
void setTrackDisposeListener (TrackEntry* entry, const DisposeListener& listener);
void setTrackDisposeListener (TrackEntry* entry, const DisposeListener& listener);
void setTrackCompleteListener (TrackEntry* entry, const CompleteListener& listener);
void setTrackEventListener (TrackEntry* entry, const EventListener& listener);
@ -99,6 +104,7 @@ public:
virtual void onTrackEntryEvent (TrackEntry* entry, EventType type, Event* event);
AnimationState* getState() const;
void setUpdateOnlyIfVisible(bool status);
CC_CONSTRUCTOR_ACCESS:
SkeletonAnimation ();
@ -109,14 +115,17 @@ protected:
AnimationState* _state;
bool _ownsAnimationStateData;
bool _updateOnlyIfVisible;
bool _firstDraw;
StartListener _startListener;
InterruptListener _interruptListener;
InterruptListener _interruptListener;
EndListener _endListener;
DisposeListener _disposeListener;
DisposeListener _disposeListener;
CompleteListener _completeListener;
EventListener _eventListener;
UpdateWorldTransformsListener _preUpdateListener;
UpdateWorldTransformsListener _postUpdateListener;
private:
typedef SkeletonRenderer super;

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,28 +15,28 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_SKELETONRENDERER_H_
#define SPINE_SKELETONRENDERER_H_
#include <spine/spine.h>
#include "cocos2d.h"
#include <spine/spine.h>
namespace spine {
class AttachmentVertices;
/* Draws a skeleton. */
class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol {
public:
@ -45,48 +45,50 @@ namespace spine {
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 update (float deltaTime) override;
void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override;
cocos2d::Rect getBoundingBox () const override;
void onEnter () override;
void onExit () override;
Skeleton* getSkeleton() const;
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;
void setDebugBoundingRectEnabled(bool enabled);
bool getDebugBoundingRectEnabled() 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.
@ -94,55 +96,53 @@ namespace spine {
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();
void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
const cocos2d::BlendFunc& getBlendFunc () const override;
void setOpacityModifyRGB (bool value) override;
bool isOpacityModifyRGB () const override;
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);
virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags);
bool _ownsSkeletonData;
bool _ownsSkeleton;
bool _ownsAtlas;
bool _ownsAtlas = false;
Atlas* _atlas;
AttachmentLoader* _attachmentLoader;
cocos2d::CustomCommand _debugCommand;
cocos2d::BlendFunc _blendFunc;
bool _premultipliedAlpha;
Skeleton* _skeleton;
@ -150,13 +150,16 @@ namespace spine {
bool _debugSlots;
bool _debugBones;
bool _debugMeshes;
bool _debugBoundingRect;
SkeletonClipping* _clipper;
VertexEffect* _effect;
bool _twoColorTintEnabled = false;
cocos2d::Rect _boundingRect;
int _startSlotIndex;
int _endSlotIndex;
bool _twoColorTint;
};
}
#endif /* SPINE_SKELETONRENDERER_H_ */

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,16 +15,16 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#include <spine/spine-cocos2dx.h>
@ -48,7 +48,7 @@ static void setAttachmentVertices(RegionAttachment* attachment) {
vertices[i].texCoords.u = attachment->getUVs()[ii];
vertices[i].texCoords.v = attachment->getUVs()[ii + 1];
}
attachment->setRendererObject(attachmentVertices, deleteAttachmentVertices);
attachment->setRendererObject(attachmentVertices, deleteAttachmentVertices);
}
static void setAttachmentVertices(MeshAttachment* attachment) {
@ -63,7 +63,7 @@ static void setAttachmentVertices(MeshAttachment* attachment) {
attachment->setRendererObject(attachmentVertices, deleteAttachmentVertices);
}
Cocos2dAtlasAttachmentLoader::Cocos2dAtlasAttachmentLoader(Atlas* atlas): AtlasAttachmentLoader(atlas) {
Cocos2dAtlasAttachmentLoader::Cocos2dAtlasAttachmentLoader(Atlas* atlas): AtlasAttachmentLoader(atlas) {
}
Cocos2dAtlasAttachmentLoader::~Cocos2dAtlasAttachmentLoader() { }
@ -107,29 +107,29 @@ backend::SamplerFilter filter (TextureFilter filter) {
#else
GLuint wrap (TextureWrap wrap) {
return wrap == TextureWrap_ClampToEdge ? GL_CLAMP_TO_EDGE : GL_REPEAT;
return wrap == TextureWrap_ClampToEdge ? GL_CLAMP_TO_EDGE : GL_REPEAT;
}
GLuint filter (TextureFilter filter) {
switch (filter) {
case TextureFilter_Unknown:
break;
case TextureFilter_Nearest:
return GL_NEAREST;
case TextureFilter_Linear:
return GL_LINEAR;
case TextureFilter_MipMap:
return GL_LINEAR_MIPMAP_LINEAR;
case TextureFilter_MipMapNearestNearest:
return GL_NEAREST_MIPMAP_NEAREST;
case TextureFilter_MipMapLinearNearest:
return GL_LINEAR_MIPMAP_NEAREST;
case TextureFilter_MipMapNearestLinear:
return GL_NEAREST_MIPMAP_LINEAR;
case TextureFilter_MipMapLinearLinear:
return GL_LINEAR_MIPMAP_LINEAR;
}
return GL_LINEAR;
switch (filter) {
case TextureFilter_Unknown:
break;
case TextureFilter_Nearest:
return GL_NEAREST;
case TextureFilter_Linear:
return GL_LINEAR;
case TextureFilter_MipMap:
return GL_LINEAR_MIPMAP_LINEAR;
case TextureFilter_MipMapNearestNearest:
return GL_NEAREST_MIPMAP_NEAREST;
case TextureFilter_MipMapLinearNearest:
return GL_LINEAR_MIPMAP_NEAREST;
case TextureFilter_MipMapNearestLinear:
return GL_NEAREST_MIPMAP_LINEAR;
case TextureFilter_MipMapLinearLinear:
return GL_LINEAR_MIPMAP_LINEAR;
}
return GL_LINEAR;
}
#endif
@ -140,32 +140,36 @@ Cocos2dTextureLoader::~Cocos2dTextureLoader() { }
void Cocos2dTextureLoader::load(AtlasPage& page, const spine::String& path) {
Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(path.buffer());
CCASSERT(texture != nullptr, "Invalid image");
texture->retain();
if (texture) {
texture->retain();
#if COCOS2D_VERSION >= 0x0040000
Texture2D::TexParams textureParams(filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap));
Texture2D::TexParams textureParams(filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap));
#else
Texture2D::TexParams textureParams = {filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap)};
Texture2D::TexParams textureParams = {filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap)};
#endif
texture->setTexParameters(textureParams);
page.setRendererObject(texture);
page.width = texture->getPixelsWide();
page.height = texture->getPixelsHigh();
texture->setTexParameters(textureParams);
page.setRendererObject(texture);
page.width = texture->getPixelsWide();
page.height = texture->getPixelsHigh();
}
}
void Cocos2dTextureLoader::unload(void* texture) {
((Texture2D*)texture)->release();
if (texture) {
((Texture2D*)texture)->release();
}
}
Cocos2dExtension::Cocos2dExtension() : DefaultSpineExtension() { }
Cocos2dExtension::~Cocos2dExtension() { }
char *Cocos2dExtension::_readFile(const spine::String &path, int *length) {
Data data = FileUtils::getInstance()->getDataFromFile(FileUtils::getInstance()->fullPathForFilename(path.buffer()));
if (data.isNull()) return 0;
if (data.isNull()) return nullptr;
// avoid buffer overflow (int is shorter than ssize_t in certain platforms)
#if COCOS2D_VERSION >= 0x00031200
ssize_t tmpLen;
@ -180,8 +184,6 @@ char *Cocos2dExtension::_readFile(const spine::String &path, int *length) {
#endif
}
//SpineExtension *spine::getDefaultExtension () {
// return new Cocos2dExtension();
//}
static int __preinit_spine_extension = (spine::SpineExtension::setInstance(new Cocos2dExtension()), 0);
SpineExtension *spine::getDefaultExtension () {
return new Cocos2dExtension();
}

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,27 +15,35 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_COCOS2DX_H_
#define SPINE_COCOS2DX_H_
#define SPINE_SHORT_NAMES
#include <spine/spine.h>
#include "cocos2d.h"
#include <spine/SkeletonRenderer.h>
#if COCOS2D_VERSION < 0x00040000
#include <spine/v3/SkeletonBatch.h>
#include <spine/v3/SkeletonTwoColorBatch.h>
#else
#include <spine/v4/SkeletonBatch.h>
#include <spine/v4/SkeletonTwoColorBatch.h>
#endif
#include <spine/SkeletonAnimation.h>
#include <spine/SkeletonBatch.h>
namespace spine {
class Cocos2dAtlasAttachmentLoader: public AtlasAttachmentLoader {
@ -44,7 +52,7 @@ namespace spine {
virtual ~Cocos2dAtlasAttachmentLoader();
virtual void configureAttachment(Attachment* attachment);
};
class Cocos2dTextureLoader: public TextureLoader {
public:
Cocos2dTextureLoader();
@ -52,10 +60,10 @@ namespace spine {
virtual ~Cocos2dTextureLoader();
virtual void load(AtlasPage& page, const String& path);
virtual void unload(void* texture);
};
class Cocos2dExtension: public DefaultSpineExtension {
public:
Cocos2dExtension();

View File

@ -0,0 +1,155 @@
/******************************************************************************
* 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.
*****************************************************************************/
#include <spine/spine-cocos2dx.h>
#if COCOS2D_VERSION < 0x00040000
#include <spine/Extension.h>
#include <algorithm>
USING_NS_CC;
#define EVENT_AFTER_DRAW_RESET_POSITION "director_after_draw"
using std::max;
#define INITIAL_SIZE (10000)
namespace spine {
static SkeletonBatch* instance = nullptr;
SkeletonBatch* SkeletonBatch::getInstance () {
if (!instance) instance = new SkeletonBatch();
return instance;
}
void SkeletonBatch::destroyInstance () {
if (instance) {
delete instance;
instance = nullptr;
}
}
SkeletonBatch::SkeletonBatch () {
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(new TrianglesCommand());
}
reset ();
// callback after drawing is finished so we can clear out the batch state
// for the next frame
Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){
this->update(0);
});;
}
SkeletonBatch::~SkeletonBatch () {
Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
for (unsigned int i = 0; i < _commandsPool.size(); i++) {
delete _commandsPool[i];
_commandsPool[i] = nullptr;
}
}
void SkeletonBatch::update (float delta) {
reset();
}
cocos2d::V3F_C4B_T2F* SkeletonBatch::allocateVertices(uint32_t numVertices) {
if (_vertices.size() - _numVertices < numVertices) {
cocos2d::V3F_C4B_T2F* oldData = _vertices.data();
_vertices.resize((_vertices.size() + numVertices) * 2 + 1);
cocos2d::V3F_C4B_T2F* newData = _vertices.data();
for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
TrianglesCommand* command = _commandsPool[i];
cocos2d::TrianglesCommand::Triangles& triangles = (cocos2d::TrianglesCommand::Triangles&)command->getTriangles();
triangles.verts = newData + (triangles.verts - oldData);
}
}
cocos2d::V3F_C4B_T2F* vertices = _vertices.data() + _numVertices;
_numVertices += numVertices;
return vertices;
}
void SkeletonBatch::deallocateVertices(uint32_t numVertices) {
_numVertices -= numVertices;
}
unsigned short* SkeletonBatch::allocateIndices(uint32_t numIndices) {
if (_indices.getCapacity() - _indices.size() < numIndices) {
unsigned short* oldData = _indices.buffer();
int oldSize = _indices.size();
_indices.ensureCapacity(_indices.size() + numIndices);
unsigned short* newData = _indices.buffer();
for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
TrianglesCommand* command = _commandsPool[i];
cocos2d::TrianglesCommand::Triangles& triangles = (cocos2d::TrianglesCommand::Triangles&)command->getTriangles();
if (triangles.indices >= oldData && triangles.indices < oldData + oldSize) {
triangles.indices = newData + (triangles.indices - oldData);
}
}
}
unsigned short* indices = _indices.buffer() + _indices.size();
_indices.setSize(_indices.size() + numIndices, 0);
return indices;
}
void SkeletonBatch::deallocateIndices(uint32_t numIndices) {
_indices.setSize(_indices.size() - numIndices, 0);
}
cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
TrianglesCommand* command = nextFreeCommand();
command->init(globalOrder, texture, glProgramState, blendType, triangles, mv, flags);
renderer->addCommand(command);
return command;
}
void SkeletonBatch::reset() {
_nextFreeCommand = 0;
_numVertices = 0;
_indices.setSize(0, 0);
}
cocos2d::TrianglesCommand* SkeletonBatch::nextFreeCommand() {
if (_commandsPool.size() <= _nextFreeCommand) {
unsigned int newSize = _commandsPool.size() * 2 + 1;
for (int i = _commandsPool.size(); i < newSize; i++) {
_commandsPool.push_back(new TrianglesCommand());
}
}
return _commandsPool[_nextFreeCommand++];
}
}
#endif

View File

@ -0,0 +1,79 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#ifndef SPINE_SKELETONBATCH_H_
#define SPINE_SKELETONBATCH_H_
#include "cocos2d.h"
#if COCOS2D_VERSION < 0x00040000
#include <spine/spine.h>
#include <vector>
namespace spine {
class SkeletonBatch {
public:
static SkeletonBatch* getInstance ();
static void destroyInstance ();
void update (float delta);
cocos2d::V3F_C4B_T2F* allocateVertices(uint32_t numVertices);
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::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
protected:
SkeletonBatch ();
virtual ~SkeletonBatch ();
void reset ();
cocos2d::TrianglesCommand* nextFreeCommand ();
// pool of commands
std::vector<cocos2d::TrianglesCommand*> _commandsPool;
uint32_t _nextFreeCommand;
// pool of vertices
std::vector<cocos2d::V3F_C4B_T2F> _vertices;
uint32_t _numVertices;
// pool of indices
Vector<unsigned short> _indices;
};
}
#endif
#endif // SPINE_SKELETONBATCH_H_

View File

@ -0,0 +1,351 @@
/******************************************************************************
* 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.
*****************************************************************************/
#include <spine/spine-cocos2dx.h>
#if COCOS2D_VERSION < 0x00040000
#include <spine/Extension.h>
#include <algorithm>
USING_NS_CC;
#define EVENT_AFTER_DRAW_RESET_POSITION "director_after_draw"
using std::max;
#define INITIAL_SIZE (10000)
#define MAX_VERTICES 64000
#define MAX_INDICES 64000
#define STRINGIFY(A) #A
namespace spine {
TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _textureID(0), _glProgramState(nullptr), _glProgram(nullptr), _blendType(BlendFunc::DISABLE), _alphaTextureID(0) {
_type = RenderCommand::Type::CUSTOM_COMMAND;
func = [this]() { draw(); };
}
void TwoColorTrianglesCommand::init(float globalOrder, GLuint textureID, GLProgramState* glProgramState, BlendFunc blendType, const TwoColorTriangles& triangles, const Mat4& mv, uint32_t flags) {
CCASSERT(glProgramState, "Invalid GLProgramState");
CCASSERT(glProgramState->getVertexAttribsFlags() == 0, "No custom attributes are supported in QuadCommand");
RenderCommand::init(globalOrder, mv, flags);
_triangles = triangles;
if(_triangles.indexCount % 3 != 0) {
int count = _triangles.indexCount;
_triangles.indexCount = count / 3 * 3;
CCLOGERROR("Resize indexCount from %d to %d, size must be multiple times of 3", count, _triangles.indexCount);
}
_mv = mv;
if( _textureID != textureID || _blendType.src != blendType.src || _blendType.dst != blendType.dst ||
_glProgramState != glProgramState ||
_glProgram != glProgramState->getGLProgram()) {
_textureID = textureID;
_blendType = blendType;
_glProgramState = glProgramState;
_glProgram = glProgramState->getGLProgram();
generateMaterialID();
}
}
TwoColorTrianglesCommand::~TwoColorTrianglesCommand() {
}
void TwoColorTrianglesCommand::generateMaterialID() {
// do not batch if using custom uniforms (since we cannot batch) it
if(_glProgramState->getUniformCount() > 0) {
_materialID = Renderer::MATERIAL_ID_DO_NOT_BATCH;
setSkipBatching(true);
}
else {
int glProgram = (int)_glProgram->getProgram();
_materialID = glProgram + (int)_textureID + (int)_blendType.src + (int)_blendType.dst;
}
}
void TwoColorTrianglesCommand::useMaterial() const {
//Set texture
GL::bindTexture2D(_textureID);
if (_alphaTextureID > 0) {
// ANDROID ETC1 ALPHA supports.
GL::bindTexture2DN(1, _alphaTextureID);
}
//set blend mode
GL::blendFunc(_blendType.src, _blendType.dst);
_glProgramState->apply(_mv);
}
void TwoColorTrianglesCommand::draw() {
SkeletonTwoColorBatch::getInstance()->batch(this);
}
const char* TWO_COLOR_TINT_VERTEX_SHADER = STRINGIFY(
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec4 a_color2;
attribute vec2 a_texCoords;
\n#ifdef GL_ES\n
varying lowp vec4 v_light;
varying lowp vec4 v_dark;
varying mediump vec2 v_texCoord;
\n#else\n
varying vec4 v_light;
varying vec4 v_dark;
varying vec2 v_texCoord;
\n#endif\n
void main() {
v_light = a_color;
v_dark = a_color2;
v_texCoord = a_texCoords;
gl_Position = CC_PMatrix * a_position;
}
);
const char* TWO_COLOR_TINT_FRAGMENT_SHADER = STRINGIFY(
\n#ifdef GL_ES\n
precision lowp float;
\n#endif\n
varying vec4 v_light;
varying vec4 v_dark;
varying vec2 v_texCoord;
void main() {
vec4 texColor = texture2D(CC_Texture0, v_texCoord);
float alpha = texColor.a * v_light.a;
gl_FragColor.a = alpha;
gl_FragColor.rgb = ((texColor.a - 1.0) * v_dark.a + 1.0 - texColor.rgb) * v_dark.rgb + texColor.rgb * v_light.rgb;
}
);
static SkeletonTwoColorBatch* instance = nullptr;
SkeletonTwoColorBatch* SkeletonTwoColorBatch::getInstance () {
if (!instance) instance = new SkeletonTwoColorBatch();
return instance;
}
void SkeletonTwoColorBatch::destroyInstance () {
if (instance) {
delete instance;
instance = nullptr;
}
}
SkeletonTwoColorBatch::SkeletonTwoColorBatch () : _vertexBuffer(0), _indexBuffer(0) {
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(new TwoColorTrianglesCommand());
}
reset ();
// callback after drawing is finished so we can clear out the batch state
// for the next frame
Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){
this->update(0);
});
_twoColorTintShader = cocos2d::GLProgram::createWithByteArrays(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
_twoColorTintShaderState = GLProgramState::getOrCreateWithGLProgram(_twoColorTintShader);
_twoColorTintShaderState->retain();
glGenBuffers(1, &_vertexBufferHandle);
_vertexBuffer = new V3F_C4B_C4B_T2F[MAX_VERTICES];
glGenBuffers(1, &_indexBufferHandle);
_indexBuffer = new unsigned short[MAX_INDICES];
_positionAttributeLocation = _twoColorTintShader->getAttribLocation("a_position");
_colorAttributeLocation = _twoColorTintShader->getAttribLocation("a_color");
_color2AttributeLocation = _twoColorTintShader->getAttribLocation("a_color2");
_texCoordsAttributeLocation = _twoColorTintShader->getAttribLocation("a_texCoords");
}
SkeletonTwoColorBatch::~SkeletonTwoColorBatch () {
Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
for (unsigned int i = 0; i < _commandsPool.size(); i++) {
delete _commandsPool[i];
_commandsPool[i] = nullptr;
}
_twoColorTintShader->release();
delete[] _vertexBuffer;
delete[] _indexBuffer;
}
void SkeletonTwoColorBatch::update (float delta) {
reset();
}
V3F_C4B_C4B_T2F* SkeletonTwoColorBatch::allocateVertices(uint32_t numVertices) {
if (_vertices.size() - _numVertices < numVertices) {
V3F_C4B_C4B_T2F* oldData = _vertices.data();
_vertices.resize((_vertices.size() + numVertices) * 2 + 1);
V3F_C4B_C4B_T2F* newData = _vertices.data();
for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
TwoColorTrianglesCommand* command = _commandsPool[i];
TwoColorTriangles& triangles = (TwoColorTriangles&)command->getTriangles();
triangles.verts = newData + (triangles.verts - oldData);
}
}
V3F_C4B_C4B_T2F* vertices = _vertices.data() + _numVertices;
_numVertices += numVertices;
return vertices;
}
void SkeletonTwoColorBatch::deallocateVertices(uint32_t numVertices) {
_numVertices -= numVertices;
}
unsigned short* SkeletonTwoColorBatch::allocateIndices(uint32_t numIndices) {
if (_indices.getCapacity() - _indices.size() < numIndices) {
unsigned short* oldData = _indices.buffer();
int oldSize =_indices.size();
_indices.ensureCapacity(_indices.size() + numIndices);
unsigned short* newData = _indices.buffer();
for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
TwoColorTrianglesCommand* command = _commandsPool[i];
TwoColorTriangles& triangles = (TwoColorTriangles&)command->getTriangles();
if (triangles.indices >= oldData && triangles.indices < oldData + oldSize) {
triangles.indices = newData + (triangles.indices - oldData);
}
}
}
unsigned short* indices = _indices.buffer() + _indices.size();
_indices.setSize(_indices.size() + numIndices, 0);
return indices;
}
void SkeletonTwoColorBatch::deallocateIndices(uint32_t numIndices) {
_indices.setSize(_indices.size() - numIndices, 0);
}
TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
TwoColorTrianglesCommand* command = nextFreeCommand();
command->init(globalOrder, textureID, glProgramState, blendType, triangles, mv, flags);
renderer->addCommand(command);
return command;
}
void SkeletonTwoColorBatch::batch (TwoColorTrianglesCommand* command) {
if (_numVerticesBuffer + command->getTriangles().vertCount >= MAX_VERTICES || _numIndicesBuffer + command->getTriangles().indexCount >= MAX_INDICES) {
flush(_lastCommand);
}
uint32_t materialID = command->getMaterialID();
if (_lastCommand && _lastCommand->getMaterialID() != materialID) {
flush(_lastCommand);
}
memcpy(_vertexBuffer + _numVerticesBuffer, command->getTriangles().verts, sizeof(V3F_C4B_C4B_T2F) * command->getTriangles().vertCount);
const Mat4& modelView = command->getModelView();
for (int i = _numVerticesBuffer; i < _numVerticesBuffer + command->getTriangles().vertCount; i++) {
modelView.transformPoint(&_vertexBuffer[i].position);
}
unsigned short vertexOffset = (unsigned short)_numVerticesBuffer;
unsigned short* indices = command->getTriangles().indices;
for (int i = 0, j = _numIndicesBuffer; i < command->getTriangles().indexCount; i++, j++) {
_indexBuffer[j] = indices[i] + vertexOffset;
}
_numVerticesBuffer += command->getTriangles().vertCount;
_numIndicesBuffer += command->getTriangles().indexCount;
if (command->isForceFlush()) {
flush(command);
}
_lastCommand = command;
}
void SkeletonTwoColorBatch::flush (TwoColorTrianglesCommand* materialCommand) {
if (!materialCommand)
return;
materialCommand->useMaterial();
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferHandle);
glBufferData(GL_ARRAY_BUFFER, sizeof(V3F_C4B_C4B_T2F) * _numVerticesBuffer , _vertexBuffer, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(_positionAttributeLocation);
glEnableVertexAttribArray(_colorAttributeLocation);
glEnableVertexAttribArray(_color2AttributeLocation);
glEnableVertexAttribArray(_texCoordsAttributeLocation);
glVertexAttribPointer(_positionAttributeLocation, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_C4B_T2F, position));
glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_C4B_T2F, color));
glVertexAttribPointer(_color2AttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_C4B_T2F, color2));
glVertexAttribPointer(_texCoordsAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_C4B_T2F, texCoords));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * _numIndicesBuffer, _indexBuffer, GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, (GLsizei)_numIndicesBuffer, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
_numVerticesBuffer = 0;
_numIndicesBuffer = 0;
_numBatches++;
}
void SkeletonTwoColorBatch::reset() {
_nextFreeCommand = 0;
_numVertices = 0;
_indices.setSize(0, 0);
_numVerticesBuffer = 0;
_numIndicesBuffer = 0;
_lastCommand = nullptr;
_numBatches = 0;
}
TwoColorTrianglesCommand* SkeletonTwoColorBatch::nextFreeCommand() {
if (_commandsPool.size() <= _nextFreeCommand) {
unsigned int newSize = _commandsPool.size() * 2 + 1;
for (int i = _commandsPool.size(); i < newSize; i++) {
_commandsPool.push_back(new TwoColorTrianglesCommand());
}
}
TwoColorTrianglesCommand* command = _commandsPool[_nextFreeCommand++];
command->setForceFlush(false);
return command;
}
}
#endif

View File

@ -0,0 +1,172 @@
/******************************************************************************
* 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.
*****************************************************************************/
#ifndef SPINE_SKELETONTWOCOLORBATCH_H_
#define SPINE_SKELETONTWOCOLORBATCH_H_
#include "cocos2d.h"
#if COCOS2D_VERSION < 0x00040000
#include <spine/spine.h>
#include <vector>
namespace spine {
struct V3F_C4B_C4B_T2F {
cocos2d::Vec3 position;
cocos2d::Color4B color;
cocos2d::Color4B color2;
cocos2d::Tex2F texCoords;
};
struct TwoColorTriangles {
V3F_C4B_C4B_T2F* verts;
unsigned short* indices;
int vertCount;
int indexCount;
};
class TwoColorTrianglesCommand : public cocos2d::CustomCommand {
public:
TwoColorTrianglesCommand();
~TwoColorTrianglesCommand();
void init(float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
void useMaterial() const;
inline uint32_t getMaterialID() const { return _materialID; }
inline GLuint getTextureID() const { return _textureID; }
inline const TwoColorTriangles& getTriangles() const { return _triangles; }
inline ssize_t getVertexCount() const { return _triangles.vertCount; }
inline ssize_t getIndexCount() const { return _triangles.indexCount; }
inline const V3F_C4B_C4B_T2F* getVertices() const { return _triangles.verts; }
inline const unsigned short* getIndices() const { return _triangles.indices; }
inline cocos2d::GLProgramState* getGLProgramState() const { return _glProgramState; }
inline cocos2d::BlendFunc getBlendType() const { return _blendType; }
inline const cocos2d::Mat4& getModelView() const { return _mv; }
void draw ();
void setForceFlush (bool forceFlush) { _forceFlush = forceFlush; }
bool isForceFlush () { return _forceFlush; };
protected:
void generateMaterialID();
uint32_t _materialID;
GLuint _textureID;
cocos2d::GLProgramState* _glProgramState;
cocos2d::GLProgram* _glProgram;
cocos2d::BlendFunc _blendType;
TwoColorTriangles _triangles;
cocos2d::Mat4 _mv;
GLuint _alphaTextureID;
bool _forceFlush;
};
class SkeletonTwoColorBatch {
public:
static SkeletonTwoColorBatch* getInstance ();
static void destroyInstance ();
void update (float delta);
V3F_C4B_C4B_T2F* allocateVertices(uint32_t numVertices);
void deallocateVertices(uint32_t numVertices);
unsigned short* allocateIndices(uint32_t numIndices);
void deallocateIndices(uint32_t numIndices);
TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
cocos2d::GLProgramState* getTwoColorTintProgramState () { return _twoColorTintShaderState; }
void batch (TwoColorTrianglesCommand* command);
void flush (TwoColorTrianglesCommand* materialCommand);
uint32_t getNumBatches () { return _numBatches; };
protected:
SkeletonTwoColorBatch ();
virtual ~SkeletonTwoColorBatch ();
void reset ();
TwoColorTrianglesCommand* nextFreeCommand ();
// pool of commands
std::vector<TwoColorTrianglesCommand*> _commandsPool;
uint32_t _nextFreeCommand;
// pool of vertices
std::vector<V3F_C4B_C4B_T2F> _vertices;
uint32_t _numVertices;
// pool of indices
Vector<unsigned short> _indices;
// two color tint shader and state
cocos2d::GLProgram* _twoColorTintShader;
cocos2d::GLProgramState* _twoColorTintShaderState;
// VBO handles & attribute locations
GLuint _vertexBufferHandle;
V3F_C4B_C4B_T2F* _vertexBuffer;
uint32_t _numVerticesBuffer;
GLuint _indexBufferHandle;
uint32_t _numIndicesBuffer;
unsigned short* _indexBuffer;
GLint _positionAttributeLocation;
GLint _colorAttributeLocation;
GLint _color2AttributeLocation;
GLint _texCoordsAttributeLocation;
// last batched command, needed for flushing to set material
TwoColorTrianglesCommand* _lastCommand;
// number of batches in the last frame
uint32_t _numBatches;
};
}
#endif
#endif // SPINE_SKELETONTWOCOLORBATCH_H_

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,19 +15,21 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#include <spine/SkeletonBatch.h>
#include <spine/spine-cocos2dx.h>
#if COCOS2D_VERSION >= 0x00040000
#include <spine/Extension.h>
#include <algorithm>
@ -56,36 +58,38 @@ void SkeletonBatch::destroyInstance () {
}
SkeletonBatch::SkeletonBatch () {
auto program = backend::Device::getInstance()->newProgram(positionTextureColor_vert, positionTextureColor_frag);
_programState = std::make_shared<backend::ProgramState>(program);
program->autorelease();
auto program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR);
_programState = std::make_shared<backend::ProgramState>(program);
auto vertexLayout = _programState->getVertexLayout();
vertexLayout->setAttribute("a_position", 0, backend::VertexFormat::FLOAT3, offsetof(V3F_C4B_T2F, vertices), false);
vertexLayout->setAttribute("a_color", 2, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
vertexLayout->setAttribute("a_texCoord", 1, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false);
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");
_locMVP = _programState->getUniformLocation("u_MVPMatrix");
_locTexture = _programState->getUniformLocation("u_texture");
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(createNewTrianglesCommand());
}
reset ();
// callback after drawing is finished so we can clear out the batch state
// for the next frame
Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){
this->update(0);
});;
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(createNewTrianglesCommand());
}
reset();
// callback after drawing is finished so we can clear out the batch state
// for the next frame
Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom) {
this->update(0);
});;
}
SkeletonBatch::~SkeletonBatch () {
Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
for (unsigned int i = 0; i < _commandsPool.size(); i++) {
CC_SAFE_RELEASE(_commandsPool[i]->getPipelineDescriptor().programState);
delete _commandsPool[i];
@ -96,7 +100,7 @@ SkeletonBatch::~SkeletonBatch () {
void SkeletonBatch::update (float delta) {
reset();
}
cocos2d::V3F_C4B_T2F* SkeletonBatch::allocateVertices(uint32_t numVertices) {
if (_vertices.size() - _numVertices < numVertices) {
cocos2d::V3F_C4B_T2F* oldData = _vertices.data();
@ -108,18 +112,18 @@ cocos2d::V3F_C4B_T2F* SkeletonBatch::allocateVertices(uint32_t numVertices) {
triangles.verts = newData + (triangles.verts - oldData);
}
}
cocos2d::V3F_C4B_T2F* vertices = _vertices.data() + _numVertices;
_numVertices += numVertices;
return vertices;
}
void SkeletonBatch::deallocateVertices(uint32_t numVertices) {
_numVertices -= numVertices;
}
unsigned short* SkeletonBatch::allocateIndices(uint32_t numIndices) {
unsigned short* SkeletonBatch::allocateIndices(uint32_t numIndices) {
if (_indices.getCapacity() - _indices.size() < numIndices) {
unsigned short* oldData = _indices.buffer();
int oldSize = _indices.size();
@ -133,7 +137,7 @@ unsigned short* SkeletonBatch::allocateIndices(uint32_t numIndices) {
}
}
}
unsigned short* indices = _indices.buffer() + _indices.size();
_indices.setSize(_indices.size() + numIndices, 0);
return indices;
@ -143,11 +147,10 @@ void SkeletonBatch::deallocateIndices(uint32_t numIndices) {
_indices.setSize(_indices.size() - numIndices, 0);
}
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) {
TrianglesCommand* command = nextFreeCommand();
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto &pipelineDescriptor = command->getPipelineDescriptor();
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto programState = command->getPipelineDescriptor().programState;
CCASSERT(programState, "programState should not be null");
@ -167,13 +170,13 @@ void SkeletonBatch::reset() {
}
cocos2d::TrianglesCommand* SkeletonBatch::nextFreeCommand() {
if (_commandsPool.size() <= _nextFreeCommand) {
unsigned int newSize = _commandsPool.size() * 2 + 1;
for (int i = _commandsPool.size(); i < newSize; i++) {
_commandsPool.push_back(createNewTrianglesCommand());
}
}
auto *command = _commandsPool[_nextFreeCommand++];
if (_commandsPool.size() <= _nextFreeCommand) {
unsigned int newSize = _commandsPool.size() * 2 + 1;
for (int i = _commandsPool.size(); i < newSize; i++) {
_commandsPool.push_back(createNewTrianglesCommand());
}
}
auto* command = _commandsPool[_nextFreeCommand++];
auto& pipelineDescriptor = command->getPipelineDescriptor();
if (pipelineDescriptor.programState == nullptr)
{
@ -188,3 +191,5 @@ cocos2d::TrianglesCommand *SkeletonBatch::createNewTrianglesCommand() {
return command;
}
}
#endif

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,23 +15,25 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_SKELETONBATCH_H_
#define SPINE_SKELETONBATCH_H_
#define SPINE_SHORT_NAMES
#include <spine/spine.h>
#include "cocos2d.h"
#if COCOS2D_VERSION >= 0x00040000
#include <spine/spine.h>
#include <vector>
namespace spine {
@ -77,4 +79,6 @@ namespace spine {
}
#endif
#endif // SPINE_SKELETONBATCH_H_

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,18 +15,21 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#include <spine/SkeletonTwoColorBatch.h>
#include <spine/spine-cocos2dx.h>
#if COCOS2D_VERSION >= 0x00040000
#include <spine/Extension.h>
#include <algorithm>
#include <stddef.h> // offsetof
@ -103,7 +106,7 @@ namespace {
return;
}
auto program = backend::Device::getInstance()->newProgram(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
auto *programState = new backend::ProgramState(program);
auto* programState = new backend::ProgramState(program);
program->autorelease();
__locPMatrix = programState->getUniformLocation("u_PMatrix");
@ -111,10 +114,15 @@ namespace {
auto layout = programState->getVertexLayout();
layout->setAttribute("a_position", 0, backend::VertexFormat::FLOAT3, offsetof(spine::V3F_C4B_C4B_T2F, position), false);
layout->setAttribute("a_color", 1, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color), true);
layout->setAttribute("a_color2", 2, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color2), true);
layout->setAttribute("a_texCoords", 3, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false);
auto locPosition = programState->getAttributeLocation("a_position");
auto locTexcoord = programState->getAttributeLocation("a_texCoords");
auto locColor = programState->getAttributeLocation("a_color");
auto locColor2 = programState->getAttributeLocation("a_color2");
layout->setAttribute("a_position", locPosition, backend::VertexFormat::FLOAT3, offsetof(spine::V3F_C4B_C4B_T2F, position), false);
layout->setAttribute("a_color", locColor, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color), true);
layout->setAttribute("a_color2", locColor2, backend::VertexFormat::UBYTE4, offsetof(spine::V3F_C4B_C4B_T2F, color2), true);
layout->setAttribute("a_texCoords", locTexcoord, backend::VertexFormat::FLOAT2, offsetof(spine::V3F_C4B_C4B_T2F, texCoords), false);
layout->setLayout(sizeof(spine::V3F_C4B_C4B_T2F));
__twoColorProgramState = std::shared_ptr<backend::ProgramState>(programState);
@ -124,7 +132,7 @@ namespace {
namespace spine {
TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _texture(nullptr), _blendType(BlendFunc::DISABLE), _alphaTextureID(0) {
TwoColorTrianglesCommand::TwoColorTrianglesCommand() :_materialID(0), _texture(nullptr), _blendType(BlendFunc::DISABLE) {
_type = RenderCommand::Type::CUSTOM_COMMAND;
}
@ -132,7 +140,7 @@ void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *textu
updateCommandPipelineDescriptor();
const cocos2d::Mat4& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto finalMatrix = projectionMat * mv;
_programState->setUniform(_locPMatrix, finalMatrix.m, sizeof(finalMatrix.m));
@ -151,11 +159,11 @@ void TwoColorTrianglesCommand::init(float globalOrder, cocos2d::Texture2D *textu
_mv = mv;
if (_blendType.src != blendType.src || _blendType.dst != blendType.dst ||
_texture != texture->getBackendTexture() || _pipelineDescriptor.programState != _programState)
_texture != texture->getBackendTexture() || _pipelineDescriptor.programState != _programState)
{
_texture = texture->getBackendTexture();
_blendType = blendType;
_prog = _programState->getProgram();
auto& blendDescriptor = _pipelineDescriptor.blendDescriptor;
@ -177,13 +185,13 @@ void TwoColorTrianglesCommand::updateCommandPipelineDescriptor()
}
CC_SAFE_RELEASE_NULL(_programState);
_programState = __twoColorProgramState->clone();
_locPMatrix = __locPMatrix;
_locTexture = __locTexture;
_pipelineDescriptor.programState = _programState;
_programState = __twoColorProgramState->clone();
_locPMatrix = __locPMatrix;
_locTexture = __locTexture;
_pipelineDescriptor.programState = _programState;
}
TwoColorTrianglesCommand::~TwoColorTrianglesCommand()
TwoColorTrianglesCommand::~TwoColorTrianglesCommand()
{
CC_SAFE_RELEASE_NULL(_programState);
}
@ -223,7 +231,7 @@ void TwoColorTrianglesCommand::updateVertexAndIndexBuffer(Renderer *r, V3F_C4B_C
createVertexBuffer(sizeof(V3F_C4B_C4B_T2F), verticesSize, CustomCommand::BufferUsage::DYNAMIC);
if(indicesSize != _indexCapacity)
createIndexBuffer(CustomCommand::IndexFormat::U_SHORT, indicesSize, CustomCommand::BufferUsage::DYNAMIC);
updateVertexBuffer(vertices, sizeof(V3F_C4B_C4B_T2F) * verticesSize);
updateIndexBuffer(indices, sizeof(uint16_t) * indicesSize);
}
@ -248,20 +256,20 @@ SkeletonTwoColorBatch::SkeletonTwoColorBatch () : _vertexBuffer(0), _indexBuffer
for (unsigned int i = 0; i < INITIAL_SIZE; i++) {
_commandsPool.push_back(new TwoColorTrianglesCommand());
}
reset ();
// callback after drawing is finished so we can clear out the batch state
// for the next frame
Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){
this->update(0);
});
}
SkeletonTwoColorBatch::~SkeletonTwoColorBatch () {
Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
for (unsigned int i = 0; i < _commandsPool.size(); i++) {
delete _commandsPool[i];
_commandsPool[i] = nullptr;
@ -271,7 +279,7 @@ SkeletonTwoColorBatch::~SkeletonTwoColorBatch () {
delete[] _indexBuffer;
}
void SkeletonTwoColorBatch::update (float delta) {
void SkeletonTwoColorBatch::update (float delta) {
reset();
}
@ -286,13 +294,13 @@ V3F_C4B_C4B_T2F* SkeletonTwoColorBatch::allocateVertices(uint32_t numVertices) {
triangles.verts = newData + (triangles.verts - oldData);
}
}
V3F_C4B_C4B_T2F* vertices = _vertices.data() + _numVertices;
_numVertices += numVertices;
return vertices;
}
void SkeletonTwoColorBatch::deallocateVertices(uint32_t numVertices) {
_numVertices -= numVertices;
}
@ -312,7 +320,7 @@ unsigned short* SkeletonTwoColorBatch::allocateIndices(uint32_t numIndices) {
}
}
}
unsigned short* indices = _indices.buffer() + _indices.size();
_indices.setSize(_indices.size() + numIndices, 0);
return indices;
@ -326,45 +334,45 @@ TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* r
TwoColorTrianglesCommand* command = nextFreeCommand();
command->init(globalOrder, texture, blendType, triangles, mv, flags);
command->updateVertexAndIndexBuffer(renderer, triangles.verts, triangles.vertCount, triangles.indices, triangles.indexCount);
renderer->addCommand(command);
renderer->addCommand(command);
return command;
}
void SkeletonTwoColorBatch::batch (cocos2d::Renderer *renderer, TwoColorTrianglesCommand* command) {
if (_numVerticesBuffer + command->getTriangles().vertCount >= MAX_VERTICES || _numIndicesBuffer + command->getTriangles().indexCount >= MAX_INDICES) {
flush(renderer, _lastCommand);
}
uint32_t materialID = command->getMaterialID();
if (_lastCommand && _lastCommand->getMaterialID() != materialID) {
flush(renderer, _lastCommand);
}
memcpy(_vertexBuffer + _numVerticesBuffer, command->getTriangles().verts, sizeof(V3F_C4B_C4B_T2F) * command->getTriangles().vertCount);
const Mat4& modelView = command->getModelView();
for (int i = _numVerticesBuffer; i < _numVerticesBuffer + command->getTriangles().vertCount; i++) {
modelView.transformPoint(&_vertexBuffer[i].position);
}
unsigned short vertexOffset = (unsigned short)_numVerticesBuffer;
unsigned short* indices = command->getTriangles().indices;
for (int i = 0, j = _numIndicesBuffer; i < command->getTriangles().indexCount; i++, j++) {
_indexBuffer[j] = indices[i] + vertexOffset;
}
_numVerticesBuffer += command->getTriangles().vertCount;
_numIndicesBuffer += command->getTriangles().indexCount;
if (command->isForceFlush()) {
flush(renderer, command);
}
_lastCommand = command;
}
void SkeletonTwoColorBatch::flush (cocos2d::Renderer *renderer, TwoColorTrianglesCommand* materialCommand) {
if (!materialCommand)
return;
materialCommand->updateVertexAndIndexBuffer(renderer, _vertexBuffer, _numVerticesBuffer, _indexBuffer, _numIndicesBuffer);
renderer->addCommand(materialCommand);
@ -396,3 +404,5 @@ TwoColorTrianglesCommand* SkeletonTwoColorBatch::nextFreeCommand() {
return command;
}
}
#endif

View File

@ -1,8 +1,8 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
* 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
@ -15,23 +15,25 @@
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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.
*****************************************************************************/
#ifndef SPINE_SKELETONTWOCOLORBATCH_H_
#define SPINE_SKELETONTWOCOLORBATCH_H_
#define SPINE_SHORT_NAMES
#include <spine/spine.h>
#include "cocos2d.h"
#if COCOS2D_VERSION >= 0x00040000
#include <spine/spine.h>
#include <vector>
namespace spine {
@ -99,7 +101,6 @@ namespace spine {
cocos2d::BlendFunc _blendType;
TwoColorTriangles _triangles;
cocos2d::Mat4 _mv;
GLuint _alphaTextureID;
bool _forceFlush;
};
@ -146,7 +147,6 @@ namespace spine {
// VBO handles & attribute locations
GLuint _vertexBufferHandle;
V3F_C4B_C4B_T2F* _vertexBuffer;
uint32_t _numVerticesBuffer;
uint32_t _numIndicesBuffer;
@ -160,4 +160,6 @@ namespace spine {
};
}
#endif
#endif // SPINE_SKELETONTWOCOLORBATCH_H_

View File

@ -43,12 +43,12 @@ namespace cocos2d { namespace network {
DownloadTask::DownloadTask(const std::string& srcUrl,
const std::string& storagePath,
const std::string& md5checksum,
const std::string& checksum,
const std::string& identifier)
{
this->requestURL = srcUrl;
this->storagePath = storagePath;
this->md5checksum = md5checksum;
this->checksum = checksum;
this->identifier = identifier;
}

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,14 @@ int register_all_cocos2dx_spine(lua_State* tolua_S);

View File

@ -48,8 +48,7 @@ LuaSkeletonAnimation::~LuaSkeletonAnimation()
LuaSkeletonAnimation* LuaSkeletonAnimation::createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale)
{
LuaSkeletonAnimation* node = new (std::nothrow) LuaSkeletonAnimation();
static spine::Cocos2dTextureLoader s_loader;
spine::Atlas* atlas = new spine::Atlas(atlasFile, &s_loader);
spine::Atlas* atlas = new spine::Atlas(atlasFile, nullptr);
node->initWithJsonFile(skeletonDataFile, atlas, scale);
node->autorelease();
return node;

View File

@ -153,8 +153,8 @@ list(APPEND GAME_HEADER
Classes/SceneTest/SceneTest.h
Classes/ReleasePoolTest/ReleasePoolTest.h
Classes/InputTest/MouseTest.h
# Classes/SpineTest/SpineTest.h
# Classes/Scene3DTest/Scene3DTest.h
Classes/SpineTest/SpineTest.h
# Classes/Scene3DTest/Scene3DTest.h
Classes/ParticleTest/ParticleTest.h
Classes/EffectsTest/EffectsTest.h
Classes/UITest/UITest.h
@ -278,8 +278,8 @@ list(APPEND GAME_SOURCE
Classes/SchedulerTest/SchedulerTest.cpp
Classes/ShaderTest/ShaderTest.cpp
Classes/ShaderTest/ShaderTest2.cpp
#Classes/SpineTest/SpineTest.cpp
# Classes/Scene3DTest/Scene3DTest.cpp
Classes/SpineTest/SpineTest.cpp
# Classes/Scene3DTest/Scene3DTest.cpp
Classes/Sprite3DTest/DrawNode3D.cpp
Classes/Sprite3DTest/Sprite3DTest.cpp
Classes/SpritePolygonTest/SpritePolygonTest.cpp

View File

@ -33,204 +33,452 @@ using namespace cocos2d;
using namespace std;
using namespace spine;
#define NUM_SKELETONS 50
#define SPINE_NODE_SCALE_FACTOR 0.4
static Cocos2dTextureLoader textureLoader;
PowInterpolation pow2(2);
PowOutInterpolation powOut2(2);
SwirlVertexEffect effect(400, powOut2);
#define SCALE_SKELETON_NODE(node) do { if(node) node->setScale(SPINE_NODE_SCALE_FACTOR); } while(false)
//------------------------------------------------------------------
//
// SpineTestScene
//
//------------------------------------------------------------------
SpineTests::SpineTests()
{
auto fu = FileUtils::getInstance();
_searchPaths = fu->getSearchPaths();
fu->addSearchPath("spine", true);
ADD_TEST_CASE(BatchingExample);
ADD_TEST_CASE(CoinExample);
ADD_TEST_CASE(GoblinsExample);
ADD_TEST_CASE(IKExample);
ADD_TEST_CASE(MixAndMatchExample);
ADD_TEST_CASE(RaptorExample);
ADD_TEST_CASE(SkeletonRendererSeparatorExample);
ADD_TEST_CASE(SpineboyExample);
ADD_TEST_CASE(TankExample);
#ifdef COCOS2D_DEBUG
debugExtension = new DebugExtension(SpineExtension::getInstance());
#endif
}
SpineTests::~SpineTests()
{
FileUtils::getInstance()->setSearchPaths(_searchPaths);
SkeletonBatch::destroyInstance();
SkeletonTwoColorBatch::destroyInstance();
#ifdef COCOS2D_DEBUG
debugExtension->reportLeaks();
delete debugExtension;
#endif
}
SpineTestLayer::SpineTestLayer()
: _title("")
{}
SpineTestLayer::~SpineTestLayer()
{
}
std::string SpineTestLayer::title() const
{
return _title;
}
bool SpineTestLayer::init()
{
if (!TestCase::init()) return false;
EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [this](Touch* touch, cocos2d::Event* event) -> bool {
if (!skeletonNode) return true;
_touchIndex = (_touchIndex + 1) % 3;
if (_touchIndex == 0)
{
skeletonNode->setDebugBonesEnabled(false);
skeletonNode->setTimeScale(1.0f);
}
else if (_touchIndex == 1)
{
skeletonNode->setDebugBonesEnabled(true);
skeletonNode->setTimeScale(1.0f);
}
else if (_touchIndex == 2)
{
skeletonNode->setDebugBonesEnabled(true);
skeletonNode->setTimeScale(0.3f);
}
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
// BatchingExample
bool BatchingExample::init () {
if (!SpineTestLayer::init()) return false;
_title = "BatchingExample";
// Load the texture atlas.
_atlas = spAtlas_createFromFile("spine/spineboy.atlas", 0);
_title = "Batching";
_atlas = new (__FILE__, __LINE__) Atlas("spineboy.atlas", &textureLoader, true);
CCASSERT(_atlas, "Error reading atlas file.");
// This attachment loader configures attachments with data needed for cocos2d-x rendering.
// Do not dispose the attachment loader until the skeleton data is disposed!
_attachmentLoader = (spAttachmentLoader*)Cocos2dAttachmentLoader_create(_atlas);
_attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
// Load the skeleton data.
spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
json->scale = 0.6f; // Resizes skeleton data to 60% of the size it was in Spine.
_skeletonData = spSkeletonJson_readSkeletonDataFile(json, "spine/spineboy-ess.json");
CCASSERT(_skeletonData, json->error ? json->error : "Error reading skeleton data file.");
spSkeletonJson_dispose(json);
SkeletonJson* json = new (__FILE__, __LINE__) SkeletonJson(_attachmentLoader);
json->setScale(0.6f); // Resizes skeleton data to 60% of the size it was in Spine.
_skeletonData = json->readSkeletonDataFile("spineboy-pro.json");
CCASSERT(_skeletonData, json->getError().isEmpty() ? json->getError().buffer() : "Error reading skeleton data file.");
delete json;
// Setup mix times.
_stateData = spAnimationStateData_create(_skeletonData);
spAnimationStateData_setMixByName(_stateData, "walk", "jump", 0.2f);
spAnimationStateData_setMixByName(_stateData, "jump", "run", 0.2f);
_stateData = new (__FILE__, __LINE__) AnimationStateData(_skeletonData);
_stateData->setMix("walk", "jump", 0.2f);
_stateData->setMix("jump", "run", 0.2f);
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
int yMin = 0, yMax = _contentSize.height * 0.7f;
for (int i = 0; i < 50; 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", false, 3);
skeletonNode->addAnimation(0, "jump", true, RandomHelper::random_int(0, 300) / 100.0f);
skeletonNode->addAnimation(0, "run", true);
// alternative setting two color tint for groups of 10 skeletons
// should end up with #skeletons / 10 batches
// if (j++ < 10)
// skeletonNode->setTwoColorTint(true);
// if (j == 20) j = 0;
// skeletonNode->setTwoColorTint(true);
skeletonNode->setPosition(Vec2(
RandomHelper::random_int(xMin, xMax),
RandomHelper::random_int(yMin, yMax)
));
skeletonNode->setScale(0.8);
RandomHelper::random_int(xMin, xMax),
RandomHelper::random_int(yMin, yMax)
));
addChild(skeletonNode);
}
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
BatchingExample::~BatchingExample () {
BatchingExample::~BatchingExample() {
// SkeletonAnimation instances are cocos2d-x nodes and are disposed of automatically as normal, but the data created
// manually to be shared across multiple SkeletonAnimations needs to be disposed of manually.
spSkeletonData_dispose(_skeletonData);
spAnimationStateData_dispose(_stateData);
spAttachmentLoader_dispose(_attachmentLoader);
spAtlas_dispose(_atlas);
delete _skeletonData;
delete _stateData;
delete _attachmentLoader;
delete _atlas;
}
// CoinExample
bool CoinExample::init () {
bool CoinExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "CoinExample";
skeletonNode = SkeletonAnimation::createWithJsonFile("spine/coin-pro.json", "spine/coin.atlas", 1.f);
skeletonNode->setAnimation(0, "rotate", true);
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 100));
_title = "Coin";
skeletonNode = SkeletonAnimation::createWithBinaryFile("coin-pro.skel", "coin.atlas", 1);
skeletonNode->setAnimation(0, "animation", true);
skeletonNode->setPosition(Vec2(_contentSize.width / 2, _contentSize.height / 2));
addChild(skeletonNode);
scheduleUpdate();
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
// GoblinsExample
bool GoblinsExample::init () {
bool GoblinsExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "GoblinsExample";
skeletonNode = SkeletonAnimation::createWithJsonFile("spine/goblins-pro.json", "spine/goblins.atlas", 1.5f);
_title = "Goblins";
skeletonNode = SkeletonAnimation::createWithJsonFile("goblins-pro.json", "goblins.atlas", 1.5f);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->setSkin("goblin");
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
skeletonNode->setScale(0.6);
addChild(skeletonNode);
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
// RaptorExample
bool RaptorExample::init () {
bool IKExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "RaptorExample";
skeletonNode = SkeletonAnimation::createWithJsonFile("spine/raptor-pro.json", "spine/raptor.atlas", 0.5f);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->setAnimation(1, "empty", false);
skeletonNode->addAnimation(1, "gungrab", false, 2);
_title = "IKExample";
// Load the Spineboy skeleton and create a SkeletonAnimation node from it
// centered on the screen.
skeletonNode = SkeletonAnimation::createWithJsonFile("spineboy-pro.json", "spineboy.atlas", 0.6f);
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
skeletonNode->setScale(0.6);
addChild(skeletonNode);
// Queue the "walk" animation on the first track.
skeletonNode->setAnimation(0, "walk", true);
// Queue the "aim" animation on a higher track.
// It consists of a single frame that positions
// the back arm and gun such that they point at
// the "crosshair" bone. By setting this
// animation on a higher track, it overrides
// any changes to the back arm and gun made
// by the walk animation, allowing us to
// mix the two. The mouse position following
// is performed in the lambda below.
skeletonNode->setAnimation(1, "aim", true);
// Next we setup a listener that receives and stores
// the current mouse location. The location is converted
// to the skeleton's coordinate system.
EventListenerMouse* mouseListener = EventListenerMouse::create();
mouseListener->onMouseMove = [this](cocos2d::Event* event) -> void {
// convert the mosue location to the skeleton's coordinate space
// and store it.
EventMouse* mouseEvent = dynamic_cast<EventMouse*>(event);
position = skeletonNode->convertToNodeSpace(mouseEvent->getLocationInView());
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);
// Position the "crosshair" bone at the mouse
// location.
//
// When setting the crosshair bone position
// to the mouse position, we need to translate
// from "skeleton space" to "local bone space".
// Note that the local bone space is calculated
// using the bone's parent worldToLocal() function!
//
// After updating the bone position based on the
// converted mouse location, we call updateWorldTransforms()
// again so the change of the IK target position is
// applied to the rest of the skeleton.
skeletonNode->setPostUpdateWorldTransformsListener([this](SkeletonAnimation* node) -> void {
Bone* crosshair = node->findBone("crosshair"); // The bone should be cached
float localX = 0, localY = 0;
crosshair->getParent()->worldToLocal(position.x, position.y, localX, localY);
crosshair->setX(localX);
crosshair->setY(localY);
crosshair->setAppliedValid(false);
node->getSkeleton()->updateWorldTransform();
});
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
// SpineboyExample
bool SpineboyExample::init () {
MixAndMatchExample::~MixAndMatchExample() {
delete skin;
}
bool MixAndMatchExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "SpineboyExample";
skeletonNode = SkeletonAnimation::createWithJsonFile("spine/spineboy-ess.json", "spine/spineboy.atlas", 0.6f);
skeletonNode->setStartListener( [] (spTrackEntry* entry) {
log("%d start: %s", entry->trackIndex, entry->animation->name);
});
skeletonNode->setInterruptListener( [] (spTrackEntry* entry) {
log("%d interrupt", entry->trackIndex);
});
skeletonNode->setEndListener( [] (spTrackEntry* entry) {
log("%d end", entry->trackIndex);
});
skeletonNode->setCompleteListener( [] (spTrackEntry* entry) {
log("%d complete", entry->trackIndex);
});
skeletonNode->setDisposeListener( [] (spTrackEntry* entry) {
log("%d dispose", entry->trackIndex);
});
skeletonNode->setEventListener( [] (spTrackEntry* entry, spEvent* event) {
log("%d event: %s, %d, %f, %s", entry->trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue);
});
skeletonNode->setMix("walk", "jump", 0.4);
skeletonNode->setMix("jump", "run", 0.4);
skeletonNode->setAnimation(0, "walk", true);
spTrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 1);
skeletonNode->addAnimation(0, "run", true);
skeletonNode->setTrackStartListener(jumpEntry, [] (spTrackEntry* entry) {
log("jumped!");
});
// skeletonNode->addAnimation(1, "test", true);
// skeletonNode->runAction(RepeatForever::create(Sequence::create(FadeOut::create(1), FadeIn::create(1), DelayTime::create(5), NULL)));
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
skeletonNode->setScale(0.8);
_title = "Mix and Match";
skeletonNode = SkeletonAnimation::createWithBinaryFile("mix-and-match-pro.skel", "mix-and-match.atlas", 0.5);
skeletonNode->setAnimation(0, "dance", true);
// Create a new skin, by mixing and matching other skins
// that fit together. Items making up the girl are individual
// skins. Using the skin API, a new skin is created which is
// a combination of all these individual item skins.
SkeletonData* skeletonData = skeletonNode->getSkeleton()->getData();
skin = new (__FILE__, __LINE__) Skin("mix-and-match");
skin->addSkin(skeletonData->findSkin("skin-base"));
skin->addSkin(skeletonData->findSkin("nose/short"));
skin->addSkin(skeletonData->findSkin("eyelids/girly"));
skin->addSkin(skeletonData->findSkin("eyes/violet"));
skin->addSkin(skeletonData->findSkin("hair/brown"));
skin->addSkin(skeletonData->findSkin("clothes/hoodie-orange"));
skin->addSkin(skeletonData->findSkin("legs/pants-jeans"));
skin->addSkin(skeletonData->findSkin("accessories/bag"));
skin->addSkin(skeletonData->findSkin("accessories/hat-red-yellow"));
skeletonNode->getSkeleton()->setSkin(skin);
skeletonNode->setPosition(Vec2(_contentSize.width / 2, _contentSize.height / 2 - 100 ));
addChild(skeletonNode);
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
bool RaptorExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "Raptor";
skeletonNode = SkeletonAnimation::createWithJsonFile("raptor-pro.json", "raptor.atlas", 0.5f);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->addAnimation(1, "gun-grab", false, 2);
skeletonNode->setTwoColorTint(true);
effect.setCenterY(200);
swirlTime = 0;
skeletonNode->setVertexEffect(&effect);
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
addChild(skeletonNode);
scheduleUpdate();
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
void SpineboyExample::update (float deltaTime) {
void RaptorExample::update(float fDelta) {
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));
}
bool SkeletonRendererSeparatorExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "Seperator";
// Spineboy's back, which will manage the animation and GPU resources
// will render only the front slots of Spineboy
skeletonNode = SkeletonAnimation::createWithJsonFile("spineboy-pro.json", "spineboy.atlas", 0.6f);
skeletonNode->setMix("walk", "jump", 0.4);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->setSlotsRange(skeletonNode->findSlot("rear-upper-arm")->getData().getIndex(), skeletonNode->findSlot("rear-shin")->getData().getIndex());
skeletonNode->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(skeletonNode->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(skeletonNode);
addChild(betweenNode);
addChild(frontNode);
scheduleUpdate();
SCALE_SKELETON_NODE(skeletonNode);
SCALE_SKELETON_NODE(frontNode);
return true;
}
void SkeletonRendererSeparatorExample::update(float deltaTime) {
// Test releasing memory.
// Director::getInstance()->replaceScene(SpineboyExample::scene());
}
// TankExample
bool TankExample::init () {
bool SpineboyExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "TankExample";
skeletonNode = SkeletonAnimation::createWithJsonFile("spine/tank-pro.json", "spine/tank.atlas", 0.5f);
skeletonNode->setAnimation(0, "drive", true);
skeletonNode->setPosition(Vec2(_contentSize.width / 2 + 400, 20));
skeletonNode->setScale(0.8);
_title = "Spineboy";
skeletonNode = SkeletonAnimation::createWithJsonFile("spineboy-pro.json", "spineboy.atlas", 0.6f);
skeletonNode->setStartListener([](TrackEntry* entry) {
log("%d start: %s", entry->getTrackIndex(), entry->getAnimation()->getName().buffer());
});
skeletonNode->setInterruptListener([](TrackEntry* entry) {
log("%d interrupt", entry->getTrackIndex());
});
skeletonNode->setEndListener([](TrackEntry* entry) {
log("%d end", entry->getTrackIndex());
});
skeletonNode->setCompleteListener([](TrackEntry* entry) {
log("%d complete", entry->getTrackIndex());
});
skeletonNode->setDisposeListener([](TrackEntry* entry) {
log("%d dispose", entry->getTrackIndex());
});
skeletonNode->setEventListener([](TrackEntry* entry, spine::Event* event) {
log("%d event: %s, %d, %f, %s", entry->getTrackIndex(), event->getData().getName().buffer(), event->getIntValue(), event->getFloatValue(), event->getStringValue().buffer());
});
skeletonNode->setMix("walk", "jump", 0.4);
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->setTrackStartListener(jumpEntry, [](TrackEntry* entry) {
log("jumped!");
});
// skeletonNode->addAnimation(1, "test", true);
// skeletonNode->runAction(RepeatForever::create(Sequence::create(FadeOut::create(1), FadeIn::create(1), DelayTime::create(5), NULL)));
skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
addChild(skeletonNode);
scheduleUpdate();
SCALE_SKELETON_NODE(skeletonNode);
return true;
}
void SpineboyExample::update(float deltaTime) {
// Test releasing memory.
// Director::getInstance()->replaceScene(SpineboyExample::scene());
}
bool TankExample::init() {
if (!SpineTestLayer::init()) return false;
_title = "Tank";
skeletonNode = SkeletonAnimation::createWithBinaryFile("tank-pro.skel", "tank.atlas", 0.5f);
skeletonNode->setAnimation(0, "shoot", true);
skeletonNode->setPosition(Vec2(_contentSize.width / 2 + 400, 20));
addChild(skeletonNode);
SCALE_SKELETON_NODE(skeletonNode);
return true;
}

View File

@ -30,83 +30,138 @@
#include "../BaseTest.h"
#include <spine/spine-cocos2dx.h>
DEFINE_TEST_SUITE(SpineTests);
#ifdef COCOS2D_DEBUG
#include <spine/Debug.h>
#endif
//DEFINE_TEST_SUITE(SpineTests);
class SpineTests : public TestSuite
{
public:
SpineTests();
virtual ~SpineTests();
private:
std::vector<std::string> _searchPaths;
#ifdef COCOS2D_DEBUG
spine::DebugExtension* debugExtension = nullptr;
#endif
};
class SpineTestLayer : public TestCase
{
public:
SpineTestLayer();
virtual std::string title() const;
virtual ~SpineTestLayer();
virtual bool init();
virtual std::string title() const override;
protected:
std::string _title;
spine::SkeletonAnimation* skeletonNode = nullptr;
int _touchIndex = 0;
};
class BatchingExample: public SpineTestLayer {
class BatchingExample : public SpineTestLayer {
public:
CREATE_FUNC(BatchingExample);
~BatchingExample ();
virtual bool init ();
protected:
spAtlas* _atlas;
spAttachmentLoader* _attachmentLoader;
spSkeletonData* _skeletonData;
spAnimationStateData* _stateData;
};
~BatchingExample();
class CoinExample: public SpineTestLayer
{
public:
CREATE_FUNC(CoinExample);
virtual bool init();
private:
spine::SkeletonAnimation* skeletonNode;
protected:
spine::Atlas* _atlas;
spine::AttachmentLoader* _attachmentLoader;
spine::SkeletonData* _skeletonData;
spine::AnimationStateData* _stateData;
};
class CoinExample : public SpineTestLayer {
public:
CREATE_FUNC(CoinExample);
virtual bool init();
};
class GoblinsExample : public SpineTestLayer {
public:
CREATE_FUNC(GoblinsExample);
virtual bool init ();
};
class IKExample : public SpineTestLayer {
public:
CREATE_FUNC(IKExample);
virtual bool init();
private:
spine::SkeletonAnimation* skeletonNode;
cocos2d::Vec2 position;
};
class MixAndMatchExample : public SpineTestLayer {
public:
CREATE_FUNC(MixAndMatchExample);
virtual bool init();
virtual ~MixAndMatchExample();
private:
spine::Skin* skin;
};
class RaptorExample : public SpineTestLayer {
public:
CREATE_FUNC(RaptorExample);
virtual bool init ();
virtual bool init();
virtual void update(float fDelta);
private:
spine::SkeletonAnimation* skeletonNode;
float swirlTime;
};
class SkeletonRendererSeparatorExample : public SpineTestLayer {
public:
CREATE_FUNC(SkeletonRendererSeparatorExample);
virtual bool init();
virtual void update(float deltaTime);
private:
spine::SkeletonRenderer* frontNode;
cocos2d::DrawNode* betweenNode;
};
class SpineboyExample : public SpineTestLayer {
public:
CREATE_FUNC (SpineboyExample);
virtual bool init ();
virtual void update (float deltaTime);
private:
spine::SkeletonAnimation* skeletonNode;
CREATE_FUNC(SpineboyExample);
virtual bool init();
virtual void update(float deltaTime);
};
class TankExample : public SpineTestLayer {
public:
CREATE_FUNC(TankExample);
virtual bool init ();
private:
spine::SkeletonAnimation* skeletonNode;
virtual bool init();
};
#endif // _EXAMPLELAYER_H_

View File

@ -93,7 +93,7 @@ public:
addTest("Node: Physics3D", []() { return new Physics3DTests(); } );
addTest("Node: RenderTexture", [](){return new RenderTextureTests(); });
addTest("Node: Scene", [](){return new SceneTests(); });
// addTest("Node: Spine", [](){return new SpineTests(); });
addTest("Node: Spine", [](){return new SpineTests(); });
addTest("Node: Sprite", [](){return new SpriteTests(); });
addTest("Node: Sprite3D", [](){ return new Sprite3DTests(); });
addTest("Node: SpritePolygon", [](){return new (std::nothrow) SpritePolygonTest(); });

Binary file not shown.

View File

@ -1,26 +1,54 @@
coin.png
size: 1024,256
size: 1024,1024
format: RGBA8888
filter: Linear,Linear
repeat: none
coin
coin-front-logo
rotate: false
xy: 2, 2
size: 259, 245
orig: 259, 245
xy: 2, 609
size: 305, 302
orig: 305, 302
offset: 0, 0
index: -1
coin-invert
coin-front-shine-logo
rotate: false
xy: 263, 2
size: 259, 245
orig: 259, 245
xy: 309, 629
size: 282, 282
orig: 282, 282
offset: 0, 0
index: -1
coin-front-shine-spineboy
rotate: false
xy: 2, 21
size: 282, 282
orig: 282, 282
offset: 0, 0
index: -1
coin-front-spineboy
rotate: false
xy: 2, 305
size: 305, 302
orig: 305, 302
offset: 0, 0
index: -1
coin-side-round
rotate: false
xy: 309, 345
size: 144, 282
orig: 144, 282
offset: 0, 0
index: -1
coin-side-straight
rotate: true
xy: 2, 2
size: 17, 282
orig: 17, 282
offset: 0, 0
index: -1
shine
rotate: false
xy: 524, 2
xy: 593, 666
size: 72, 245
orig: 72, 245
offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 393 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,299 +1,271 @@
raptor.png
size: 1024,1024
size: 1024,512
format: RGBA8888
filter: Linear,Linear
repeat: none
back-arm
rotate: true
xy: 274, 394
size: 46, 29
orig: 46, 29
rotate: false
xy: 895, 295
size: 46, 25
orig: 46, 25
offset: 0, 0
index: -1
back-bracer
rotate: true
xy: 140, 247
xy: 992, 216
size: 39, 28
orig: 39, 28
offset: 0, 0
index: -1
back-hand
rotate: false
xy: 824, 699
xy: 594, 58
size: 36, 34
orig: 36, 34
offset: 0, 0
index: -1
back-knee
rotate: false
xy: 360, 507
rotate: true
xy: 729, 86
size: 49, 67
orig: 49, 67
offset: 0, 0
index: -1
back-thigh
rotate: true
xy: 140, 206
rotate: false
xy: 379, 2
size: 39, 24
orig: 39, 24
offset: 0, 0
index: -1
dust01
rotate: false
xy: 219, 299
size: 48, 37
orig: 48, 37
offset: 0, 0
index: -1
dust02
rotate: false
xy: 895, 833
size: 43, 44
orig: 43, 44
offset: 0, 0
index: -1
dust03
rotate: true
xy: 167, 445
size: 31, 26
orig: 31, 26
offset: 0, 0
index: -1
eyes-open
rotate: true
xy: 2, 2
xy: 902, 194
size: 47, 45
orig: 47, 45
offset: 0, 0
index: -1
front-arm
rotate: false
xy: 470, 544
size: 48, 30
orig: 48, 30
xy: 945, 306
size: 48, 26
orig: 48, 26
offset: 0, 0
index: -1
front-bracer
rotate: true
xy: 274, 351
rotate: false
xy: 949, 197
size: 41, 29
orig: 41, 29
offset: 0, 0
index: -1
front-hand
rotate: false
xy: 827, 773
xy: 949, 266
size: 41, 38
orig: 41, 38
offset: 0, 0
index: -1
front-open-hand
rotate: false
xy: 360, 461
xy: 875, 148
size: 43, 44
orig: 43, 44
offset: 0, 0
index: -1
front-thigh
rotate: false
xy: 411, 545
rotate: true
xy: 793, 171
size: 57, 29
orig: 57, 29
offset: 0, 0
index: -1
gun
rotate: false
xy: 195, 442
rotate: true
xy: 379, 28
size: 107, 103
orig: 107, 103
offset: 0, 0
index: -1
gun-nohand
rotate: false
xy: 167, 338
xy: 487, 87
size: 105, 102
orig: 105, 102
offset: 0, 0
index: -1
head
rotate: false
xy: 2, 137
xy: 807, 361
size: 136, 149
orig: 136, 149
offset: 0, 0
index: -1
lower-leg
rotate: true
xy: 648, 667
rotate: false
xy: 827, 195
size: 73, 98
orig: 73, 98
offset: 0, 0
index: -1
mouth-grind
rotate: true
xy: 49, 2
xy: 920, 145
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
mouth-smile
rotate: true
xy: 81, 2
xy: 992, 257
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
neck
rotate: false
xy: 626, 631
xy: 359, 114
size: 18, 21
orig: 18, 21
offset: 0, 0
index: -1
raptor-arm-back
rotate: true
xy: 538, 570
raptor-back-arm
rotate: false
xy: 653, 142
size: 82, 86
orig: 82, 86
offset: 0, 0
index: -1
raptor-body
rotate: false
xy: 2, 737
size: 632, 285
orig: 632, 285
xy: 2, 277
size: 632, 233
orig: 632, 233
offset: 0, 0
index: -1
raptor-front-arm
rotate: true
xy: 544, 654
xy: 484, 4
size: 81, 102
orig: 81, 102
offset: 0, 0
index: -1
raptor-front-leg
rotate: false
xy: 2, 478
xy: 2, 18
size: 191, 257
orig: 191, 257
offset: 0, 0
index: -1
raptor-hindleg-back
rotate: false
xy: 636, 807
xy: 636, 295
size: 169, 215
orig: 169, 215
offset: 0, 0
index: -1
raptor-horn
rotate: false
xy: 360, 655
xy: 195, 22
size: 182, 80
orig: 182, 80
offset: 0, 0
index: -1
raptor-horn-back
rotate: false
xy: 360, 576
rotate: true
xy: 945, 334
size: 176, 77
orig: 176, 77
offset: 0, 0
index: -1
raptor-jaw
rotate: false
xy: 807, 879
size: 153, 143
orig: 153, 143
xy: 359, 137
size: 126, 138
orig: 126, 138
offset: 0, 0
index: -1
raptor-jaw-tooth
rotate: true
xy: 940, 840
xy: 895, 322
size: 37, 48
orig: 37, 48
offset: 0, 0
index: -1
raptor-mouth-inside
rotate: true
xy: 827, 735
xy: 949, 228
size: 36, 41
orig: 36, 41
offset: 0, 0
index: -1
raptor-saddle-noshadow
rotate: false
xy: 2, 288
size: 163, 188
orig: 163, 188
offset: 0, 0
index: -1
raptor-saddle-strap-front
rotate: false
xy: 962, 927
size: 57, 95
orig: 57, 95
offset: 0, 0
index: -1
raptor-saddle-strap-rear
raptor-saddle-strap-back
rotate: true
xy: 748, 686
xy: 653, 86
size: 54, 74
orig: 54, 74
offset: 0, 0
index: -1
raptor-saddle-strap-front
rotate: false
xy: 594, 94
size: 57, 95
orig: 57, 95
offset: 0, 0
index: -1
raptor-saddle-w-shadow
rotate: false
xy: 195, 547
size: 163, 188
orig: 163, 188
xy: 195, 104
size: 162, 171
orig: 162, 171
offset: 0, 0
index: -1
raptor-tail-shadow
rotate: false
xy: 636, 742
xy: 636, 230
size: 189, 63
orig: 189, 63
offset: 0, 0
index: -1
raptor-tongue
rotate: false
xy: 807, 813
xy: 807, 295
size: 86, 64
orig: 86, 64
offset: 0, 0
index: -1
stirrup-back
rotate: false
xy: 411, 508
rotate: true
xy: 952, 151
size: 44, 35
orig: 44, 35
offset: 0, 0
index: -1
stirrup-front
rotate: true
xy: 167, 291
rotate: false
xy: 902, 243
size: 45, 50
orig: 45, 50
offset: 0, 0
index: -1
stirrup-strap
rotate: false
xy: 962, 879
xy: 824, 147
size: 49, 46
orig: 49, 46
offset: 0, 0
index: -1
torso
rotate: false
xy: 304, 454
xy: 737, 137
size: 54, 91
orig: 54, 91
offset: 0, 0
index: -1
visor
rotate: false
xy: 2, 51
xy: 487, 191
size: 131, 84
orig: 131, 84
offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 KiB

After

Width:  |  Height:  |  Size: 469 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,306 +1,285 @@
spineboy.png
size: 1024,512
size: 1024,256
format: RGBA8888
filter: Linear,Linear
repeat: none
crosshair
rotate: false
xy: 794, 167
xy: 352, 7
size: 45, 45
orig: 45, 45
offset: 0, 0
index: -1
dust01
rotate: false
xy: 960, 190
size: 48, 37
orig: 48, 37
offset: 0, 0
index: -1
dust02
rotate: false
xy: 392, 2
size: 43, 44
orig: 43, 44
offset: 0, 0
index: -1
dust03
rotate: false
xy: 841, 163
size: 31, 26
orig: 31, 26
offset: 0, 0
index: -1
eye-indifferent
rotate: false
xy: 960, 229
xy: 862, 105
size: 47, 45
orig: 47, 45
offset: 0, 0
index: -1
eye-surprised
rotate: false
xy: 745, 167
xy: 505, 79
size: 47, 45
orig: 47, 45
offset: 0, 0
index: -1
front-bracer
rotate: false
xy: 547, 2
xy: 826, 66
size: 29, 40
orig: 29, 40
offset: 0, 0
index: -1
front-fist-closed
rotate: false
xy: 920, 190
xy: 786, 65
size: 38, 41
orig: 38, 41
offset: 0, 0
index: -1
front-fist-open
rotate: false
xy: 437, 2
rotate: true
xy: 710, 51
size: 43, 44
orig: 43, 44
offset: 0, 0
index: -1
front-foot
rotate: false
xy: 482, 11
xy: 210, 6
size: 63, 35
orig: 63, 35
offset: 0, 0
index: -1
front-shin
rotate: true
xy: 866, 233
xy: 665, 128
size: 41, 92
orig: 41, 92
offset: 0, 0
index: -1
front-thigh
rotate: false
xy: 719, 155
size: 24, 56
orig: 24, 56
rotate: true
xy: 2, 2
size: 23, 56
orig: 23, 56
offset: 0, 0
index: -1
front-upper-arm
rotate: false
xy: 719, 104
size: 27, 49
orig: 27, 49
xy: 250, 205
size: 23, 49
orig: 23, 49
offset: 0, 0
index: -1
goggles
rotate: false
xy: 881, 276
xy: 665, 171
size: 131, 83
orig: 131, 83
offset: 0, 0
index: -1
gun
rotate: false
xy: 612, 109
xy: 798, 152
size: 105, 102
orig: 105, 102
offset: 0, 0
index: -1
head
rotate: false
xy: 881, 361
xy: 2, 27
size: 136, 149
orig: 136, 149
offset: 0, 0
index: -1
hoverboard-board
rotate: false
xy: 2, 38
xy: 2, 178
size: 246, 76
orig: 246, 76
offset: 0, 0
index: -1
hoverboard-thruster
rotate: true
xy: 578, 12
xy: 722, 96
size: 30, 32
orig: 30, 32
offset: 0, 0
index: -1
hoverglow-small
rotate: true
xy: 572, 44
rotate: false
xy: 275, 81
size: 137, 38
orig: 137, 38
offset: 0, 0
index: -1
mouth-grind
rotate: true
xy: 713, 55
rotate: false
xy: 614, 97
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
mouth-oooo
rotate: true
xy: 713, 6
rotate: false
xy: 612, 65
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
mouth-smile
rotate: false
xy: 748, 135
xy: 661, 64
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
muzzle-glow
rotate: false
xy: 612, 8
size: 99, 99
orig: 99, 99
xy: 382, 54
size: 25, 25
orig: 25, 25
offset: 0, 0
index: -1
muzzle-ring
rotate: false
xy: 302, 190
rotate: true
xy: 275, 54
size: 25, 105
orig: 25, 105
offset: 0, 0
index: -1
muzzle01
rotate: false
xy: 336, 335
size: 271, 175
orig: 271, 175
rotate: true
xy: 911, 95
size: 67, 40
orig: 67, 40
offset: 0, 0
index: -1
muzzle02
rotate: false
xy: 609, 341
size: 270, 169
orig: 270, 169
xy: 792, 108
size: 68, 42
orig: 68, 42
offset: 0, 0
index: -1
muzzle03
rotate: false
xy: 2, 297
size: 332, 213
orig: 332, 213
rotate: true
xy: 956, 171
size: 83, 53
orig: 83, 53
offset: 0, 0
index: -1
muzzle04
rotate: false
xy: 2, 116
size: 298, 179
orig: 298, 179
xy: 275, 7
size: 75, 45
orig: 75, 45
offset: 0, 0
index: -1
muzzle05
rotate: false
xy: 336, 183
size: 269, 150
orig: 269, 150
xy: 140, 3
size: 68, 38
orig: 68, 38
offset: 0, 0
index: -1
neck
rotate: false
xy: 841, 191
xy: 250, 182
size: 18, 21
orig: 18, 21
offset: 0, 0
index: -1
portal-bg
rotate: false
xy: 302, 48
xy: 140, 43
size: 133, 133
orig: 133, 133
offset: 0, 0
index: -1
portal-flare1
rotate: false
xy: 180, 6
xy: 554, 65
size: 56, 30
orig: 56, 30
offset: 0, 0
index: -1
portal-flare2
rotate: false
xy: 2, 5
rotate: true
xy: 759, 112
size: 57, 31
orig: 57, 31
offset: 0, 0
index: -1
portal-flare3
rotate: false
xy: 61, 6
xy: 554, 97
size: 58, 30
orig: 58, 30
offset: 0, 0
index: -1
portal-shade
rotate: false
xy: 437, 48
xy: 275, 121
size: 133, 133
orig: 133, 133
offset: 0, 0
index: -1
portal-streaks1
rotate: true
xy: 609, 213
rotate: false
xy: 410, 126
size: 126, 128
orig: 126, 128
offset: 0, 0
index: -1
portsl-streaks2
portal-streaks2
rotate: false
xy: 739, 214
xy: 538, 129
size: 125, 125
orig: 125, 125
offset: 0, 0
index: -1
rear-bracer
rotate: true
xy: 797, 137
rotate: false
xy: 857, 67
size: 28, 36
orig: 28, 36
offset: 0, 0
index: -1
rear-foot
rotate: false
xy: 121, 6
xy: 663, 96
size: 57, 30
orig: 57, 30
offset: 0, 0
index: -1
rear-shin
rotate: true
xy: 301, 8
xy: 414, 86
size: 38, 89
orig: 38, 89
offset: 0, 0
index: -1
rear-thigh
rotate: true
xy: 866, 198
size: 33, 52
orig: 33, 52
rotate: false
xy: 756, 63
size: 28, 47
orig: 28, 47
offset: 0, 0
index: -1
rear-upper-arm
rotate: true
xy: 748, 109
size: 24, 44
orig: 24, 44
xy: 60, 5
size: 20, 44
orig: 20, 44
offset: 0, 0
index: -1
torso
rotate: false
xy: 250, 24
xy: 905, 164
size: 49, 90
orig: 49, 90
offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 KiB

After

Width:  |  Height:  |  Size: 597 KiB